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