ddp_usrreq.c revision 33181
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;
33static u_long	ddp_sendspace = DDP_MAXSZ; /* Max ddp size + 1 (ddp_type) */
34static u_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    *addr = dup_sockaddr((struct sockaddr *)&ddp->ddp_lsat, 0);
221}
222
223static int
224at_pcbsetaddr(struct ddpcb *ddp, struct sockaddr *addr, struct proc *p)
225{
226    struct sockaddr_at	lsat, *sat;
227    struct at_ifaddr	*aa;
228    struct ddpcb	*ddpp;
229
230    if ( ddp->ddp_lsat.sat_port != ATADDR_ANYPORT ) { /* shouldn't be bound */
231	return( EINVAL );
232    }
233
234    if (addr != 0) {			/* validate passed address */
235	sat = (struct sockaddr_at *)addr;
236	if (sat->sat_family != AF_APPLETALK) {
237	    return(EAFNOSUPPORT);
238	}
239
240	if ( sat->sat_addr.s_node != ATADDR_ANYNODE ||
241		sat->sat_addr.s_net != ATADDR_ANYNET ) {
242	    for ( aa = at_ifaddr; aa; aa = aa->aa_next ) {
243		if (( sat->sat_addr.s_net == AA_SAT( aa )->sat_addr.s_net ) &&
244		 ( sat->sat_addr.s_node == AA_SAT( aa )->sat_addr.s_node )) {
245		    break;
246		}
247	    }
248	    if ( !aa ) {
249		return( EADDRNOTAVAIL );
250	    }
251	}
252
253	if ( sat->sat_port != ATADDR_ANYPORT ) {
254	    if ( sat->sat_port < ATPORT_FIRST ||
255		    sat->sat_port >= ATPORT_LAST ) {
256		return( EINVAL );
257	    }
258	    if ( sat->sat_port < ATPORT_RESERVED &&
259		 suser( p->p_ucred, &p->p_acflag ) ) {
260		return( EACCES );
261	    }
262	}
263    } else {
264	bzero( (caddr_t)&lsat, sizeof( struct sockaddr_at ));
265	lsat.sat_len = sizeof(struct sockaddr_at);
266	lsat.sat_addr.s_node = ATADDR_ANYNODE;
267	lsat.sat_addr.s_net = ATADDR_ANYNET;
268	lsat.sat_family = AF_APPLETALK;
269	sat = &lsat;
270    }
271
272    if ( sat->sat_addr.s_node == ATADDR_ANYNODE &&
273	    sat->sat_addr.s_net == ATADDR_ANYNET ) {
274	if ( at_ifaddr == NULL ) {
275	    return( EADDRNOTAVAIL );
276	}
277	sat->sat_addr = AA_SAT( at_ifaddr )->sat_addr;
278    }
279    ddp->ddp_lsat = *sat;
280
281    /*
282     * Choose port.
283     */
284    if ( sat->sat_port == ATADDR_ANYPORT ) {
285	for ( sat->sat_port = ATPORT_RESERVED;
286		sat->sat_port < ATPORT_LAST; sat->sat_port++ ) {
287	    if ( ddp_ports[ sat->sat_port - 1 ] == 0 ) {
288		break;
289	    }
290	}
291	if ( sat->sat_port == ATPORT_LAST ) {
292	    return( EADDRNOTAVAIL );
293	}
294	ddp->ddp_lsat.sat_port = sat->sat_port;
295	ddp_ports[ sat->sat_port - 1 ] = ddp;
296    } else {
297	for ( ddpp = ddp_ports[ sat->sat_port - 1 ]; ddpp;
298		ddpp = ddpp->ddp_pnext ) {
299	    if ( ddpp->ddp_lsat.sat_addr.s_net == sat->sat_addr.s_net &&
300		    ddpp->ddp_lsat.sat_addr.s_node == sat->sat_addr.s_node ) {
301		break;
302	    }
303	}
304	if ( ddpp != NULL ) {
305	    return( EADDRINUSE );
306	}
307	ddp->ddp_pnext = ddp_ports[ sat->sat_port - 1 ];
308	ddp_ports[ sat->sat_port - 1 ] = ddp;
309	if ( ddp->ddp_pnext ) {
310	    ddp->ddp_pnext->ddp_pprev = ddp;
311	}
312    }
313
314    return( 0 );
315}
316
317static int
318at_pcbconnect(struct ddpcb *ddp, struct sockaddr *addr, struct proc *p)
319{
320    struct sockaddr_at	*sat = (struct sockaddr_at *)addr;
321    struct route	*ro;
322    struct at_ifaddr	*aa = 0;
323    struct ifnet	*ifp;
324    u_short		hintnet = 0, net;
325
326    if (sat->sat_family != AF_APPLETALK) {
327	return(EAFNOSUPPORT);
328    }
329
330    /*
331     * Under phase 2, network 0 means "the network".  We take "the
332     * network" to mean the network the control block is bound to.
333     * If the control block is not bound, there is an error.
334     */
335    if ( sat->sat_addr.s_net == ATADDR_ANYNET
336		&& sat->sat_addr.s_node != ATADDR_ANYNODE ) {
337	if ( ddp->ddp_lsat.sat_port == ATADDR_ANYPORT ) {
338	    return( EADDRNOTAVAIL );
339	}
340	hintnet = ddp->ddp_lsat.sat_addr.s_net;
341    }
342
343    ro = &ddp->ddp_route;
344    /*
345     * If we've got an old route for this pcb, check that it is valid.
346     * If we've changed our address, we may have an old "good looking"
347     * route here.  Attempt to detect it.
348     */
349    if ( ro->ro_rt ) {
350	if ( hintnet ) {
351	    net = hintnet;
352	} else {
353	    net = sat->sat_addr.s_net;
354	}
355	aa = 0;
356	if ( ifp = ro->ro_rt->rt_ifp ) {
357	    for ( aa = at_ifaddr; aa; aa = aa->aa_next ) {
358		if ( aa->aa_ifp == ifp &&
359			ntohs( net ) >= ntohs( aa->aa_firstnet ) &&
360			ntohs( net ) <= ntohs( aa->aa_lastnet )) {
361		    break;
362		}
363	    }
364	}
365	if ( aa == NULL || ( satosat( &ro->ro_dst )->sat_addr.s_net !=
366		( hintnet ? hintnet : sat->sat_addr.s_net ) ||
367		satosat( &ro->ro_dst )->sat_addr.s_node !=
368		sat->sat_addr.s_node )) {
369	    RTFREE( ro->ro_rt );
370	    ro->ro_rt = (struct rtentry *)0;
371	}
372    }
373
374    /*
375     * If we've got no route for this interface, try to find one.
376     */
377    if ( ro->ro_rt == (struct rtentry *)0 ||
378	 ro->ro_rt->rt_ifp == (struct ifnet *)0 ) {
379	ro->ro_dst.sa_len = sizeof( struct sockaddr_at );
380	ro->ro_dst.sa_family = AF_APPLETALK;
381	if ( hintnet ) {
382	    satosat( &ro->ro_dst )->sat_addr.s_net = hintnet;
383	} else {
384	    satosat( &ro->ro_dst )->sat_addr.s_net = sat->sat_addr.s_net;
385	}
386	satosat( &ro->ro_dst )->sat_addr.s_node = sat->sat_addr.s_node;
387	rtalloc( ro );
388    }
389
390    /*
391     * Make sure any route that we have has a valid interface.
392     */
393    aa = 0;
394    if ( ro->ro_rt && ( ifp = ro->ro_rt->rt_ifp )) {
395	for ( aa = at_ifaddr; aa; aa = aa->aa_next ) {
396	    if ( aa->aa_ifp == ifp ) {
397		break;
398	    }
399	}
400    }
401    if ( aa == 0 ) {
402	return( ENETUNREACH );
403    }
404
405    ddp->ddp_fsat = *sat;
406    if ( ddp->ddp_lsat.sat_port == ATADDR_ANYPORT ) {
407	return(at_pcbsetaddr(ddp, (struct sockaddr *)0, p));
408    }
409    return( 0 );
410}
411
412static void
413at_pcbdisconnect( struct ddpcb	*ddp )
414{
415    ddp->ddp_fsat.sat_addr.s_net = ATADDR_ANYNET;
416    ddp->ddp_fsat.sat_addr.s_node = ATADDR_ANYNODE;
417    ddp->ddp_fsat.sat_port = ATADDR_ANYPORT;
418}
419
420static int
421at_pcballoc( struct socket *so )
422{
423	struct ddpcb	*ddp;
424
425	MALLOC(ddp, struct ddpcb *, sizeof *ddp, M_PCB, M_WAITOK);
426	bzero(ddp, sizeof *ddp);
427	ddp->ddp_lsat.sat_port = ATADDR_ANYPORT;
428
429	ddp->ddp_next = ddpcb;
430	ddp->ddp_prev = NULL;
431	ddp->ddp_pprev = NULL;
432	ddp->ddp_pnext = NULL;
433	if (ddpcb) {
434		ddpcb->ddp_prev = ddp;
435	}
436	ddpcb = ddp;
437
438	ddp->ddp_socket = so;
439	so->so_pcb = (caddr_t)ddp;
440	return(0);
441}
442
443static void
444at_pcbdetach( struct socket *so, struct ddpcb *ddp)
445{
446    soisdisconnected( so );
447    so->so_pcb = 0;
448    sofree( so );
449
450    /* remove ddp from ddp_ports list */
451    if ( ddp->ddp_lsat.sat_port != ATADDR_ANYPORT &&
452	    ddp_ports[ ddp->ddp_lsat.sat_port - 1 ] != NULL ) {
453	if ( ddp->ddp_pprev != NULL ) {
454	    ddp->ddp_pprev->ddp_pnext = ddp->ddp_pnext;
455	} else {
456	    ddp_ports[ ddp->ddp_lsat.sat_port - 1 ] = ddp->ddp_pnext;
457	}
458	if ( ddp->ddp_pnext != NULL ) {
459	    ddp->ddp_pnext->ddp_pprev = ddp->ddp_pprev;
460	}
461    }
462
463    if ( ddp->ddp_route.ro_rt ) {
464	rtfree( ddp->ddp_route.ro_rt );
465    }
466
467    if ( ddp->ddp_prev ) {
468	ddp->ddp_prev->ddp_next = ddp->ddp_next;
469    } else {
470	ddpcb = ddp->ddp_next;
471    }
472    if ( ddp->ddp_next ) {
473	ddp->ddp_next->ddp_prev = ddp->ddp_prev;
474    }
475    FREE(ddp, M_PCB);
476}
477
478/*
479 * For the moment, this just find the pcb with the correct local address.
480 * In the future, this will actually do some real searching, so we can use
481 * the sender's address to do de-multiplexing on a single port to many
482 * sockets (pcbs).
483 */
484struct ddpcb *
485ddp_search( struct sockaddr_at *from, struct sockaddr_at *to,
486			struct at_ifaddr *aa)
487{
488    struct ddpcb	*ddp;
489
490    /*
491     * Check for bad ports.
492     */
493    if ( to->sat_port < ATPORT_FIRST || to->sat_port >= ATPORT_LAST ) {
494	return( NULL );
495    }
496
497    /*
498     * Make sure the local address matches the sent address.  What about
499     * the interface?
500     */
501    for ( ddp = ddp_ports[ to->sat_port - 1 ]; ddp; ddp = ddp->ddp_pnext ) {
502	/* XXX should we handle 0.YY? */
503
504	/* XXXX.YY to socket on destination interface */
505	if ( to->sat_addr.s_net == ddp->ddp_lsat.sat_addr.s_net &&
506		to->sat_addr.s_node == ddp->ddp_lsat.sat_addr.s_node ) {
507	    break;
508	}
509
510	/* 0.255 to socket on receiving interface */
511	if ( to->sat_addr.s_node == ATADDR_BCAST && ( to->sat_addr.s_net == 0 ||
512		to->sat_addr.s_net == ddp->ddp_lsat.sat_addr.s_net ) &&
513		ddp->ddp_lsat.sat_addr.s_net == AA_SAT( aa )->sat_addr.s_net ) {
514	    break;
515	}
516
517	/* XXXX.0 to socket on destination interface */
518	if ( to->sat_addr.s_net == aa->aa_firstnet &&
519		to->sat_addr.s_node == 0 &&
520		ntohs( ddp->ddp_lsat.sat_addr.s_net ) >=
521		ntohs( aa->aa_firstnet ) &&
522		ntohs( ddp->ddp_lsat.sat_addr.s_net ) <=
523		ntohs( aa->aa_lastnet )) {
524	    break;
525	}
526    }
527    return( ddp );
528}
529static int
530at_setpeeraddr(struct socket *so, struct sockaddr **nam)
531{
532	return(EOPNOTSUPP);
533}
534
535static int
536at_setsockaddr(struct socket *so, struct sockaddr **nam)
537{
538	struct ddpcb	*ddp;
539	int		error = 0;
540	int		s;
541
542	ddp = sotoddpcb( so );
543	if ( ddp == NULL ) {
544	    return( EINVAL);
545	}
546	at_sockaddr( ddp, nam );
547	return(0);
548}
549
550
551void
552ddp_init(void )
553{
554    atintrq1.ifq_maxlen = IFQ_MAXLEN;
555    atintrq2.ifq_maxlen = IFQ_MAXLEN;
556}
557
558#if 0
559static void
560ddp_clean(void )
561{
562    struct ddpcb	*ddp;
563
564    for ( ddp = ddpcb; ddp; ddp = ddp->ddp_next ) {
565	at_pcbdetach( ddp->ddp_socket, ddp );
566    }
567}
568#endif
569
570struct pr_usrreqs ddp_usrreqs = {
571	ddp_abort,
572	pru_accept_notsupp,
573	ddp_attach,
574	ddp_bind,
575	ddp_connect,
576	pru_connect2_notsupp,
577	at_control,
578	ddp_detach,
579	ddp_disconnect,
580	pru_listen_notsupp,
581	at_setpeeraddr,
582	pru_rcvd_notsupp,
583	pru_rcvoob_notsupp,
584	ddp_send,
585	pru_sense_null,
586	ddp_shutdown,
587	at_setsockaddr,
588	sosend,
589	soreceive,
590	sopoll
591};
592