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