]> arthur.barton.de Git - netatalk.git/blob - sys/netatalk/ddp_usrreq.c
Remove bdb env on exit
[netatalk.git] / sys / netatalk / ddp_usrreq.c
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
36 struct ddpcb    *ddpcb = NULL;
37 u_int32_t               ddp_sendspace = DDP_MAXSZ; /* Max ddp size + 1 (ddp_type) */
38 u_int32_t               ddp_recvspace = 10 * ( 587 + sizeof( struct sockaddr_at ));
39
40 /*ARGSUSED*/
41 ddp_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
179 release:
180     if ( m != NULL ) {
181         m_freem( m );
182     }
183     return( error );
184 }
185
186 at_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
197 at_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
298 at_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
401 at_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
409 at_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
433 at_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 *
477 ddp_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
523 ddp_init()
524 {
525     atintrq1.ifq_maxlen = IFQ_MAXLEN;
526     atintrq2.ifq_maxlen = IFQ_MAXLEN;
527 }
528
529 ddp_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 }