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