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