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