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