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