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