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