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