ddp_usrreq.c revision 16478
1/*
2 * Copyright (c) 1990,1994 Regents of The University of Michigan.
3 * All Rights Reserved.  See COPYRIGHT.
4 */
5
6#include <sys/errno.h>
7#include <sys/types.h>
8#include <sys/param.h>
9#include <sys/systm.h>
10#if defined( __FreeBSD__ )
11#include <sys/proc.h>
12#endif __FreeBSD__
13#ifdef ibm032
14#include <sys/dir.h>
15#endif ibm032
16#ifndef	__FreeBSD__
17#include <sys/user.h>
18#endif
19#include <sys/mbuf.h>
20#include <sys/ioctl.h>
21#include <sys/socket.h>
22#include <sys/socketvar.h>
23#include <sys/protosw.h>
24#include <net/if.h>
25#include <net/route.h>
26#include <netinet/in.h>
27#include <netinet/if_ether.h>
28#ifdef _IBMR2
29#include <net/spl.h>
30#endif _IBMR2
31
32#include "at.h"
33#include "at_var.h"
34#include "ddp_var.h"
35#include "aarp.h"
36#include "endian.h"
37#include <netatalk/at_extern.h>
38
39static void at_pcbdisconnect( struct ddpcb *ddp );
40static void at_sockaddr( struct ddpcb *ddp, struct mbuf *addr );
41static int at_pcbsetaddr( struct ddpcb *ddp, struct mbuf *addr, struct proc *p);
42static int at_pcbconnect( struct ddpcb *ddp, struct mbuf *addr, struct proc *p);
43static void at_pcbdetach( struct socket *so, struct ddpcb *ddp);
44static int at_pcballoc( struct socket *so );
45
46struct ddpcb	*ddp_ports[ ATPORT_LAST ];
47struct ddpcb	*ddpcb = NULL;
48u_long		ddp_sendspace = DDP_MAXSZ; /* Max ddp size + 1 (ddp_type) */
49u_long		ddp_recvspace = 10 * ( 587 + sizeof( struct sockaddr_at ));
50
51/*ARGSUSED*/
52int
53ddp_usrreq( struct socket *so, int req, struct mbuf *m,
54		struct mbuf  *addr, struct mbuf *rights)
55{
56#if defined( __FreeBSD__ )
57    struct proc *p = curproc;           /* XXX */
58#endif __FreeBSD__
59    struct ddpcb	*ddp;
60    int			error = 0;
61
62    ddp = sotoddpcb( so );
63
64    if ( req == PRU_CONTROL ) {
65	return( at_control( (int) m, (caddr_t) addr,
66		(struct ifnet *) rights
67#if defined( __FreeBSD__ )
68			    , (struct proc *)p
69#endif __FreeBSD__
70	    ));
71    }
72
73    if ( rights && rights->m_len ) {
74	error = EINVAL;
75	goto release;
76    }
77
78    if ( ddp == NULL && req != PRU_ATTACH ) {
79	error = EINVAL;
80	goto release;
81    }
82
83    switch ( req ) {
84    case PRU_ATTACH :
85	if ( ddp != NULL ) {
86	    error = EINVAL;
87	    break;
88	}
89	if (( error = at_pcballoc( so )) != 0 ) {
90	    break;
91	}
92	error = soreserve( so, ddp_sendspace, ddp_recvspace );
93	break;
94
95    case PRU_DETACH :
96	at_pcbdetach( so, ddp );
97	break;
98
99    case PRU_BIND :
100	error = at_pcbsetaddr( ddp, addr
101#if defined( __FreeBSD__ )
102			       , p
103#endif __FreeBSD__
104	    );
105	break;
106
107    case PRU_SOCKADDR :
108	at_sockaddr( ddp, addr );
109	break;
110
111    case PRU_CONNECT:
112	if ( ddp->ddp_fsat.sat_port != ATADDR_ANYPORT ) {
113	    error = EISCONN;
114	    break;
115	}
116
117	error = at_pcbconnect( ddp, addr
118#if defined( __FreeBSD__ )
119	    , p
120#endif __FreeBSD__
121	    );
122	if ( error == 0 )
123	    soisconnected( so );
124	break;
125
126    case PRU_DISCONNECT:
127	if ( ddp->ddp_fsat.sat_addr.s_node == ATADDR_ANYNODE ) {
128	    error = ENOTCONN;
129	    break;
130	}
131	at_pcbdisconnect( ddp );
132	soisdisconnected( so );
133	break;
134
135    case PRU_SHUTDOWN:
136	socantsendmore( so );
137	break;
138
139    case PRU_SEND: {
140	int	s = 0;
141
142	if ( addr ) {
143	    if ( ddp->ddp_fsat.sat_port != ATADDR_ANYPORT ) {
144		error = EISCONN;
145		break;
146	    }
147
148	    s = splnet();
149	    error = at_pcbconnect( ddp, addr
150#if defined( __FreeBSD__ )
151		, p
152#endif __FreeBSD__
153		);
154	    if ( error ) {
155		splx( s );
156		break;
157	    }
158	} else {
159	    if ( ddp->ddp_fsat.sat_port == ATADDR_ANYPORT ) {
160		error = ENOTCONN;
161		break;
162	    }
163	}
164
165	error = ddp_output( ddp, m );
166	m = NULL;
167	if ( addr ) {
168	    at_pcbdisconnect( ddp );
169	    splx( s );
170	}
171	}
172	break;
173
174    case PRU_ABORT:
175	soisdisconnected( so );
176	at_pcbdetach( so, ddp );
177	break;
178
179    case PRU_LISTEN:
180    case PRU_CONNECT2:
181    case PRU_ACCEPT:
182    case PRU_SENDOOB:
183    case PRU_FASTTIMO:
184    case PRU_SLOWTIMO:
185    case PRU_PROTORCV:
186    case PRU_PROTOSEND:
187	error = EOPNOTSUPP;
188	break;
189
190    case PRU_RCVD:
191    case PRU_RCVOOB:
192	/*
193	 * Don't mfree. Good architecture...
194	 */
195	return( EOPNOTSUPP );
196
197    case PRU_SENSE:
198	/*
199	 * 1. Don't return block size.
200	 * 2. Don't mfree.
201	 */
202	return( 0 );
203
204    default:
205	error = EOPNOTSUPP;
206    }
207
208release:
209    if ( m != NULL ) {
210	m_freem( m );
211    }
212    return( error );
213}
214
215static void
216at_sockaddr( struct ddpcb *ddp, struct mbuf *addr)
217{
218    struct sockaddr_at	*sat;
219
220    addr->m_len = sizeof( struct sockaddr_at );
221    sat = mtod( addr, struct sockaddr_at *);
222    *sat = ddp->ddp_lsat;
223}
224
225static int
226at_pcbsetaddr( struct ddpcb *ddp, struct mbuf *addr, struct proc *p )
227{
228    struct sockaddr_at	lsat, *sat;
229    struct at_ifaddr	*aa;
230    struct ddpcb	*ddpp;
231
232    if ( ddp->ddp_lsat.sat_port != ATADDR_ANYPORT ) { /* shouldn't be bound */
233	return( EINVAL );
234    }
235
236    if ( addr != 0 ) {			/* validate passed address */
237	sat = mtod( addr, struct sockaddr_at *);
238	if ( addr->m_len != sizeof( *sat )) {
239	    return( EINVAL );
240	}
241	if ( sat->sat_family != AF_APPLETALK ) {
242	    return( EAFNOSUPPORT );
243	}
244
245	if ( sat->sat_addr.s_node != ATADDR_ANYNODE ||
246		sat->sat_addr.s_net != ATADDR_ANYNET ) {
247	    for ( aa = at_ifaddr; aa; aa = aa->aa_next ) {
248		if (( sat->sat_addr.s_net == AA_SAT( aa )->sat_addr.s_net ) &&
249		 ( sat->sat_addr.s_node == AA_SAT( aa )->sat_addr.s_node )) {
250		    break;
251		}
252	    }
253	    if ( !aa ) {
254		return( EADDRNOTAVAIL );
255	    }
256	}
257
258	if ( sat->sat_port != ATADDR_ANYPORT ) {
259	    if ( sat->sat_port < ATPORT_FIRST ||
260		    sat->sat_port >= ATPORT_LAST ) {
261		return( EINVAL );
262	    }
263#ifdef BSD4_4
264	    if ( sat->sat_port < ATPORT_RESERVED &&
265#if defined( __FreeBSD__ )
266		 suser( p->p_ucred, &p->p_acflag )
267#else
268		    suser( u.u_cred, &u.u_acflag )
269#endif __FreeBSD__
270		) {
271		return( EACCES );
272	    }
273#else BSD4_4
274	    if ( sat->sat_port < ATPORT_RESERVED && ( !suser())) {
275		return( EACCES );
276	    }
277#endif BSD4_4
278	}
279    } else {
280	bzero( (caddr_t)&lsat, sizeof( struct sockaddr_at ));
281#ifdef BSD4_4
282	lsat.sat_len = sizeof(struct sockaddr_at);
283	lsat.sat_addr.s_node = ATADDR_ANYNODE;
284	lsat.sat_addr.s_net = ATADDR_ANYNET;
285#endif BSD4_4
286	lsat.sat_family = AF_APPLETALK;
287	sat = &lsat;
288    }
289
290    if ( sat->sat_addr.s_node == ATADDR_ANYNODE &&
291	    sat->sat_addr.s_net == ATADDR_ANYNET ) {
292	if ( at_ifaddr == NULL ) {
293	    return( EADDRNOTAVAIL );
294	}
295	sat->sat_addr = AA_SAT( at_ifaddr )->sat_addr;
296    }
297    ddp->ddp_lsat = *sat;
298
299    /*
300     * Choose port.
301     */
302    if ( sat->sat_port == ATADDR_ANYPORT ) {
303	for ( sat->sat_port = ATPORT_RESERVED;
304		sat->sat_port < ATPORT_LAST; sat->sat_port++ ) {
305	    if ( ddp_ports[ sat->sat_port - 1 ] == 0 ) {
306		break;
307	    }
308	}
309	if ( sat->sat_port == ATPORT_LAST ) {
310	    return( EADDRNOTAVAIL );
311	}
312	ddp->ddp_lsat.sat_port = sat->sat_port;
313	ddp_ports[ sat->sat_port - 1 ] = ddp;
314    } else {
315	for ( ddpp = ddp_ports[ sat->sat_port - 1 ]; ddpp;
316		ddpp = ddpp->ddp_pnext ) {
317	    if ( ddpp->ddp_lsat.sat_addr.s_net == sat->sat_addr.s_net &&
318		    ddpp->ddp_lsat.sat_addr.s_node == sat->sat_addr.s_node ) {
319		break;
320	    }
321	}
322	if ( ddpp != NULL ) {
323	    return( EADDRINUSE );
324	}
325	ddp->ddp_pnext = ddp_ports[ sat->sat_port - 1 ];
326	ddp_ports[ sat->sat_port - 1 ] = ddp;
327	if ( ddp->ddp_pnext ) {
328	    ddp->ddp_pnext->ddp_pprev = ddp;
329	}
330    }
331
332    return( 0 );
333}
334
335static int
336at_pcbconnect( struct ddpcb *ddp, struct mbuf *addr, struct proc *p)
337{
338    struct sockaddr_at	*sat = mtod( addr, struct sockaddr_at *);
339    struct route	*ro;
340    struct at_ifaddr	*aa = 0;
341    struct ifnet	*ifp;
342    u_short		hintnet = 0, net;
343
344    if ( addr->m_len != sizeof( *sat ))
345	return( EINVAL );
346    if ( sat->sat_family != AF_APPLETALK ) {
347	return( EAFNOSUPPORT );
348    }
349
350    /*
351     * Under phase 2, network 0 means "the network".  We take "the
352     * network" to mean the network the control block is bound to.
353     * If the control block is not bound, there is an error.
354     */
355    if ( sat->sat_addr.s_net == ATADDR_ANYNET
356		&& sat->sat_addr.s_node != ATADDR_ANYNODE ) {
357	if ( ddp->ddp_lsat.sat_port == ATADDR_ANYPORT ) {
358	    return( EADDRNOTAVAIL );
359	}
360	hintnet = ddp->ddp_lsat.sat_addr.s_net;
361    }
362
363    ro = &ddp->ddp_route;
364    /*
365     * If we've got an old route for this pcb, check that it is valid.
366     * If we've changed our address, we may have an old "good looking"
367     * route here.  Attempt to detect it.
368     */
369    if ( ro->ro_rt ) {
370	if ( hintnet ) {
371	    net = hintnet;
372	} else {
373	    net = sat->sat_addr.s_net;
374	}
375	aa = 0;
376	if ( ifp = ro->ro_rt->rt_ifp ) {
377	    for ( aa = at_ifaddr; aa; aa = aa->aa_next ) {
378		if ( aa->aa_ifp == ifp &&
379			ntohs( net ) >= ntohs( aa->aa_firstnet ) &&
380			ntohs( net ) <= ntohs( aa->aa_lastnet )) {
381		    break;
382		}
383	    }
384	}
385	if ( aa == NULL || ( satosat( &ro->ro_dst )->sat_addr.s_net !=
386		( hintnet ? hintnet : sat->sat_addr.s_net ) ||
387		satosat( &ro->ro_dst )->sat_addr.s_node !=
388		sat->sat_addr.s_node )) {
389#ifdef ultrix
390	    rtfree( ro->ro_rt );
391#else ultrix
392	    RTFREE( ro->ro_rt );
393#endif ultrix
394	    ro->ro_rt = (struct rtentry *)0;
395	}
396    }
397
398    /*
399     * If we've got no route for this interface, try to find one.
400     */
401    if ( ro->ro_rt == (struct rtentry *)0 ||
402	 ro->ro_rt->rt_ifp == (struct ifnet *)0 ) {
403#ifdef BSD4_4
404	ro->ro_dst.sa_len = sizeof( struct sockaddr_at );
405#endif BSD4_4
406	ro->ro_dst.sa_family = AF_APPLETALK;
407	if ( hintnet ) {
408	    satosat( &ro->ro_dst )->sat_addr.s_net = hintnet;
409	} else {
410	    satosat( &ro->ro_dst )->sat_addr.s_net = sat->sat_addr.s_net;
411	}
412	satosat( &ro->ro_dst )->sat_addr.s_node = sat->sat_addr.s_node;
413	rtalloc( ro );
414    }
415
416    /*
417     * Make sure any route that we have has a valid interface.
418     */
419    aa = 0;
420    if ( ro->ro_rt && ( ifp = ro->ro_rt->rt_ifp )) {
421	for ( aa = at_ifaddr; aa; aa = aa->aa_next ) {
422	    if ( aa->aa_ifp == ifp ) {
423		break;
424	    }
425	}
426    }
427    if ( aa == 0 ) {
428	return( ENETUNREACH );
429    }
430
431    ddp->ddp_fsat = *sat;
432    if ( ddp->ddp_lsat.sat_port == ATADDR_ANYPORT ) {
433	return( at_pcbsetaddr( ddp, (struct mbuf *)0
434#if defined( __FreeBSD__ )
435			       , p
436#endif __FreeBSD__
437	    ));
438    }
439    return( 0 );
440}
441
442static void
443at_pcbdisconnect( struct ddpcb	*ddp )
444{
445    ddp->ddp_fsat.sat_addr.s_net = ATADDR_ANYNET;
446    ddp->ddp_fsat.sat_addr.s_node = ATADDR_ANYNODE;
447    ddp->ddp_fsat.sat_port = ATADDR_ANYPORT;
448}
449
450static int
451at_pcballoc( struct socket *so )
452{
453    struct ddpcb	*ddp;
454    struct mbuf		*m;
455
456    m = m_getclr( M_WAIT, MT_PCB );
457    ddp = mtod( m, struct ddpcb * );
458    ddp->ddp_lsat.sat_port = ATADDR_ANYPORT;
459
460    ddp->ddp_next = ddpcb;
461    ddp->ddp_prev = NULL;
462    ddp->ddp_pprev = NULL;
463    ddp->ddp_pnext = NULL;
464    if ( ddpcb ) {
465	ddpcb->ddp_prev = ddp;
466    }
467    ddpcb = ddp;
468
469    ddp->ddp_socket = so;
470    so->so_pcb = (caddr_t)ddp;
471    return( 0 );
472}
473
474static void
475at_pcbdetach( struct socket *so, struct ddpcb *ddp)
476{
477    soisdisconnected( so );
478    so->so_pcb = 0;
479    sofree( so );
480
481    /* remove ddp from ddp_ports list */
482    if ( ddp->ddp_lsat.sat_port != ATADDR_ANYPORT &&
483	    ddp_ports[ ddp->ddp_lsat.sat_port - 1 ] != NULL ) {
484	if ( ddp->ddp_pprev != NULL ) {
485	    ddp->ddp_pprev->ddp_pnext = ddp->ddp_pnext;
486	} else {
487	    ddp_ports[ ddp->ddp_lsat.sat_port - 1 ] = ddp->ddp_pnext;
488	}
489	if ( ddp->ddp_pnext != NULL ) {
490	    ddp->ddp_pnext->ddp_pprev = ddp->ddp_pprev;
491	}
492    }
493
494    if ( ddp->ddp_route.ro_rt ) {
495	rtfree( ddp->ddp_route.ro_rt );
496    }
497
498    if ( ddp->ddp_prev ) {
499	ddp->ddp_prev->ddp_next = ddp->ddp_next;
500    } else {
501	ddpcb = ddp->ddp_next;
502    }
503    if ( ddp->ddp_next ) {
504	ddp->ddp_next->ddp_prev = ddp->ddp_prev;
505    }
506
507    (void) m_free( dtom( ddp ));
508}
509
510/*
511 * For the moment, this just find the pcb with the correct local address.
512 * In the future, this will actually do some real searching, so we can use
513 * the sender's address to do de-multiplexing on a single port to many
514 * sockets (pcbs).
515 */
516struct ddpcb *
517ddp_search( struct sockaddr_at *from, struct sockaddr_at *to,
518			struct at_ifaddr *aa)
519{
520    struct ddpcb	*ddp;
521
522    /*
523     * Check for bad ports.
524     */
525    if ( to->sat_port < ATPORT_FIRST || to->sat_port >= ATPORT_LAST ) {
526	return( NULL );
527    }
528
529    /*
530     * Make sure the local address matches the sent address.  What about
531     * the interface?
532     */
533    for ( ddp = ddp_ports[ to->sat_port - 1 ]; ddp; ddp = ddp->ddp_pnext ) {
534	/* XXX should we handle 0.YY? */
535
536	/* XXXX.YY to socket on destination interface */
537	if ( to->sat_addr.s_net == ddp->ddp_lsat.sat_addr.s_net &&
538		to->sat_addr.s_node == ddp->ddp_lsat.sat_addr.s_node ) {
539	    break;
540	}
541
542	/* 0.255 to socket on receiving interface */
543	if ( to->sat_addr.s_node == ATADDR_BCAST && ( to->sat_addr.s_net == 0 ||
544		to->sat_addr.s_net == ddp->ddp_lsat.sat_addr.s_net ) &&
545		ddp->ddp_lsat.sat_addr.s_net == AA_SAT( aa )->sat_addr.s_net ) {
546	    break;
547	}
548
549	/* XXXX.0 to socket on destination interface */
550	if ( to->sat_addr.s_net == aa->aa_firstnet &&
551		to->sat_addr.s_node == 0 &&
552		ntohs( ddp->ddp_lsat.sat_addr.s_net ) >=
553		ntohs( aa->aa_firstnet ) &&
554		ntohs( ddp->ddp_lsat.sat_addr.s_net ) <=
555		ntohs( aa->aa_lastnet )) {
556	    break;
557	}
558    }
559    return( ddp );
560}
561
562void
563ddp_init(void )
564{
565    atintrq1.ifq_maxlen = IFQ_MAXLEN;
566    atintrq2.ifq_maxlen = IFQ_MAXLEN;
567}
568
569static void
570ddp_clean(void )
571{
572    struct ddpcb	*ddp;
573
574    for ( ddp = ddpcb; ddp; ddp = ddp->ddp_next ) {
575	at_pcbdetach( ddp->ddp_socket, ddp );
576    }
577}
578