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