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