]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/netatalk/ddp_pcb.c
merge fix for boot-time hang on centos' xen
[FreeBSD/FreeBSD.git] / sys / netatalk / ddp_pcb.c
1 /*-
2  * Copyright (c) 2004-2005 Robert N. M. Watson
3  * Copyright (c) 1990,1994 Regents of The University of Michigan.
4  * All Rights Reserved.
5  *
6  * Permission to use, copy, modify, and distribute this software and
7  * its documentation for any purpose and without fee is hereby granted,
8  * provided that the above copyright notice appears in all copies and
9  * that both that copyright notice and this permission notice appear
10  * in supporting documentation, and that the name of The University
11  * of Michigan not be used in advertising or publicity pertaining to
12  * distribution of the software without specific, written prior
13  * permission. This software is supplied as is without expressed or
14  * implied warranties of any kind.
15  *
16  * This product includes software developed by the University of
17  * California, Berkeley and its contributors.
18  *
19  *      Research Systems Unix Group
20  *      The University of Michigan
21  *      c/o Wesley Craig
22  *      535 W. William Street
23  *      Ann Arbor, Michigan
24  *      +1-313-764-2278
25  *      netatalk@umich.edu
26  * $FreeBSD$
27  */
28
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/malloc.h>
32 #include <sys/mbuf.h>
33 #include <sys/socket.h>
34 #include <sys/socketvar.h>
35 #include <sys/protosw.h>
36 #include <net/if.h>
37 #include <net/route.h>
38 #include <net/netisr.h>
39
40 #include <netatalk/at.h>
41 #include <netatalk/at_var.h>
42 #include <netatalk/ddp_var.h>
43 #include <netatalk/ddp_pcb.h>
44 #include <netatalk/at_extern.h>
45
46 struct mtx               ddp_list_mtx;
47 static struct ddpcb     *ddp_ports[ ATPORT_LAST ];
48 struct ddpcb            *ddpcb_list = NULL;
49
50 void
51 at_sockaddr(struct ddpcb *ddp, struct sockaddr **addr)
52 {
53
54     /*
55      * Prevent modification of ddp during copy of addr.
56      */
57     DDP_LOCK_ASSERT(ddp);
58     *addr = sodupsockaddr((struct sockaddr *)&ddp->ddp_lsat, M_NOWAIT);
59 }
60
61 int 
62 at_pcbsetaddr(struct ddpcb *ddp, struct sockaddr *addr, struct thread *td)
63 {
64     struct sockaddr_at  lsat, *sat;
65     struct at_ifaddr    *aa;
66     struct ddpcb        *ddpp;
67
68     /*
69      * We read and write both the ddp passed in, and also ddp_ports.
70      */
71     DDP_LIST_XLOCK_ASSERT();
72     DDP_LOCK_ASSERT(ddp);
73
74     if (ddp->ddp_lsat.sat_port != ATADDR_ANYPORT) { /* shouldn't be bound */
75         return (EINVAL);
76     }
77
78     if (addr != NULL) {                 /* validate passed address */
79         sat = (struct sockaddr_at *)addr;
80         if (sat->sat_family != AF_APPLETALK) {
81             return (EAFNOSUPPORT);
82         }
83
84         if (sat->sat_addr.s_node != ATADDR_ANYNODE ||
85                 sat->sat_addr.s_net != ATADDR_ANYNET) {
86             for (aa = at_ifaddr_list; aa != NULL; aa = aa->aa_next) {
87                 if ((sat->sat_addr.s_net == AA_SAT(aa)->sat_addr.s_net) &&
88                  (sat->sat_addr.s_node == AA_SAT(aa)->sat_addr.s_node)) {
89                     break;
90                 }
91             }
92             if (!aa) {
93                 return (EADDRNOTAVAIL);
94             }
95         }
96
97         if (sat->sat_port != ATADDR_ANYPORT) {
98             if (sat->sat_port < ATPORT_FIRST ||
99                     sat->sat_port >= ATPORT_LAST) {
100                 return (EINVAL);
101             }
102             if (sat->sat_port < ATPORT_RESERVED &&
103                  suser(td)) {
104                 return (EACCES);
105             }
106         }
107     } else {
108         bzero((caddr_t)&lsat, sizeof(struct sockaddr_at));
109         lsat.sat_len = sizeof(struct sockaddr_at);
110         lsat.sat_addr.s_node = ATADDR_ANYNODE;
111         lsat.sat_addr.s_net = ATADDR_ANYNET;
112         lsat.sat_family = AF_APPLETALK;
113         sat = &lsat;
114     }
115
116     if (sat->sat_addr.s_node == ATADDR_ANYNODE &&
117             sat->sat_addr.s_net == ATADDR_ANYNET) {
118         if (at_ifaddr_list == NULL) {
119             return (EADDRNOTAVAIL);
120         }
121         sat->sat_addr = AA_SAT(at_ifaddr_list)->sat_addr;
122     }
123     ddp->ddp_lsat = *sat;
124
125     /*
126      * Choose port.
127      */
128     if (sat->sat_port == ATADDR_ANYPORT) {
129         for (sat->sat_port = ATPORT_RESERVED;
130                 sat->sat_port < ATPORT_LAST; sat->sat_port++) {
131             if (ddp_ports[ sat->sat_port - 1 ] == NULL) {
132                 break;
133             }
134         }
135         if (sat->sat_port == ATPORT_LAST) {
136             return (EADDRNOTAVAIL);
137         }
138         ddp->ddp_lsat.sat_port = sat->sat_port;
139         ddp_ports[ sat->sat_port - 1 ] = ddp;
140     } else {
141         for (ddpp = ddp_ports[ sat->sat_port - 1 ]; ddpp;
142                 ddpp = ddpp->ddp_pnext) {
143             if (ddpp->ddp_lsat.sat_addr.s_net == sat->sat_addr.s_net &&
144                     ddpp->ddp_lsat.sat_addr.s_node == sat->sat_addr.s_node) {
145                 break;
146             }
147         }
148         if (ddpp != NULL) {
149             return (EADDRINUSE);
150         }
151         ddp->ddp_pnext = ddp_ports[ sat->sat_port - 1 ];
152         ddp_ports[ sat->sat_port - 1 ] = ddp;
153         if (ddp->ddp_pnext) {
154             ddp->ddp_pnext->ddp_pprev = ddp;
155         }
156     }
157
158     return (0);
159 }
160
161 int
162 at_pcbconnect(struct ddpcb *ddp, struct sockaddr *addr, struct thread *td)
163 {
164     struct sockaddr_at  *sat = (struct sockaddr_at *)addr;
165     struct route        *ro;
166     struct at_ifaddr    *aa = NULL;
167     struct ifnet        *ifp;
168     u_short             hintnet = 0, net;
169
170     DDP_LIST_XLOCK_ASSERT();
171     DDP_LOCK_ASSERT(ddp);
172
173     if (sat->sat_family != AF_APPLETALK) {
174         return (EAFNOSUPPORT);
175     }
176
177     /*
178      * Under phase 2, network 0 means "the network".  We take "the
179      * network" to mean the network the control block is bound to.
180      * If the control block is not bound, there is an error.
181      */
182     if (sat->sat_addr.s_net == ATADDR_ANYNET
183                 && sat->sat_addr.s_node != ATADDR_ANYNODE) {
184         if (ddp->ddp_lsat.sat_port == ATADDR_ANYPORT) {
185             return (EADDRNOTAVAIL);
186         }
187         hintnet = ddp->ddp_lsat.sat_addr.s_net;
188     }
189
190     ro = &ddp->ddp_route;
191     /*
192      * If we've got an old route for this pcb, check that it is valid.
193      * If we've changed our address, we may have an old "good looking"
194      * route here.  Attempt to detect it.
195      */
196     if (ro->ro_rt) {
197         if (hintnet) {
198             net = hintnet;
199         } else {
200             net = sat->sat_addr.s_net;
201         }
202         aa = NULL;
203         if ((ifp = ro->ro_rt->rt_ifp) != NULL) {
204             for (aa = at_ifaddr_list; aa != NULL; aa = aa->aa_next) {
205                 if (aa->aa_ifp == ifp &&
206                         ntohs(net) >= ntohs(aa->aa_firstnet) &&
207                         ntohs(net) <= ntohs(aa->aa_lastnet)) {
208                     break;
209                 }
210             }
211         }
212         if (aa == NULL || (satosat(&ro->ro_dst)->sat_addr.s_net !=
213                 (hintnet ? hintnet : sat->sat_addr.s_net) ||
214                 satosat(&ro->ro_dst)->sat_addr.s_node !=
215                 sat->sat_addr.s_node)) {
216             RTFREE(ro->ro_rt);
217             ro->ro_rt = NULL;
218         }
219     }
220
221     /*
222      * If we've got no route for this interface, try to find one.
223      */
224     if (ro->ro_rt == NULL || ro->ro_rt->rt_ifp == NULL) {
225         ro->ro_dst.sa_len = sizeof(struct sockaddr_at);
226         ro->ro_dst.sa_family = AF_APPLETALK;
227         if (hintnet) {
228             satosat(&ro->ro_dst)->sat_addr.s_net = hintnet;
229         } else {
230             satosat(&ro->ro_dst)->sat_addr.s_net = sat->sat_addr.s_net;
231         }
232         satosat(&ro->ro_dst)->sat_addr.s_node = sat->sat_addr.s_node;
233         rtalloc(ro);
234     }
235
236     /*
237      * Make sure any route that we have has a valid interface.
238      */
239     aa = NULL;
240     if (ro->ro_rt && (ifp = ro->ro_rt->rt_ifp)) {
241         for (aa = at_ifaddr_list; aa != NULL; aa = aa->aa_next) {
242             if (aa->aa_ifp == ifp) {
243                 break;
244             }
245         }
246     }
247     if (aa == NULL) {
248         return (ENETUNREACH);
249     }
250
251     ddp->ddp_fsat = *sat;
252     if (ddp->ddp_lsat.sat_port == ATADDR_ANYPORT) {
253         return (at_pcbsetaddr(ddp, NULL, td));
254     }
255     return (0);
256 }
257
258 void 
259 at_pcbdisconnect(struct ddpcb   *ddp)
260 {
261
262     DDP_LOCK_ASSERT(ddp);
263
264     ddp->ddp_fsat.sat_addr.s_net = ATADDR_ANYNET;
265     ddp->ddp_fsat.sat_addr.s_node = ATADDR_ANYNODE;
266     ddp->ddp_fsat.sat_port = ATADDR_ANYPORT;
267 }
268
269 int
270 at_pcballoc(struct socket *so)
271 {
272         struct ddpcb    *ddp;
273
274         DDP_LIST_XLOCK_ASSERT();
275
276         MALLOC(ddp, struct ddpcb *, sizeof *ddp, M_PCB, M_NOWAIT | M_ZERO);
277         if (ddp == NULL)
278                 return (ENOBUFS);
279         DDP_LOCK_INIT(ddp);
280         ddp->ddp_lsat.sat_port = ATADDR_ANYPORT;
281
282         ddp->ddp_socket = so;
283         so->so_pcb = (caddr_t)ddp;
284
285         ddp->ddp_next = ddpcb_list;
286         ddp->ddp_prev = NULL;
287         ddp->ddp_pprev = NULL;
288         ddp->ddp_pnext = NULL;
289         if (ddpcb_list != NULL) {
290                 ddpcb_list->ddp_prev = ddp;
291         }
292         ddpcb_list = ddp;
293         return(0);
294 }
295
296 void
297 at_pcbdetach(struct socket *so, struct ddpcb *ddp)
298 {
299
300     /*
301      * We modify ddp, ddp_ports, and the global list.
302      */
303     DDP_LIST_XLOCK_ASSERT();
304     DDP_LOCK_ASSERT(ddp);
305
306     soisdisconnected(so);
307     ACCEPT_LOCK();
308     SOCK_LOCK(so);
309     so->so_pcb = NULL;
310     sotryfree(so);
311
312     /* remove ddp from ddp_ports list */
313     if (ddp->ddp_lsat.sat_port != ATADDR_ANYPORT &&
314             ddp_ports[ ddp->ddp_lsat.sat_port - 1 ] != NULL) {
315         if (ddp->ddp_pprev != NULL) {
316             ddp->ddp_pprev->ddp_pnext = ddp->ddp_pnext;
317         } else {
318             ddp_ports[ ddp->ddp_lsat.sat_port - 1 ] = ddp->ddp_pnext;
319         }
320         if (ddp->ddp_pnext != NULL) {
321             ddp->ddp_pnext->ddp_pprev = ddp->ddp_pprev;
322         }
323     }
324
325     if (ddp->ddp_route.ro_rt) {
326         RTFREE(ddp->ddp_route.ro_rt);
327     }
328
329     if (ddp->ddp_prev) {
330         ddp->ddp_prev->ddp_next = ddp->ddp_next;
331     } else {
332         ddpcb_list = ddp->ddp_next;
333     }
334     if (ddp->ddp_next) {
335         ddp->ddp_next->ddp_prev = ddp->ddp_prev;
336     }
337     DDP_UNLOCK(ddp);
338     DDP_LOCK_DESTROY(ddp);
339     FREE(ddp, M_PCB);
340 }
341
342 /*
343  * For the moment, this just find the pcb with the correct local address.
344  * In the future, this will actually do some real searching, so we can use
345  * the sender's address to do de-multiplexing on a single port to many
346  * sockets (pcbs).
347  */
348 struct ddpcb *
349 ddp_search(struct sockaddr_at *from, struct sockaddr_at *to,
350                         struct at_ifaddr *aa)
351 {
352     struct ddpcb        *ddp;
353
354     DDP_LIST_SLOCK_ASSERT();
355
356     /*
357      * Check for bad ports.
358      */
359     if (to->sat_port < ATPORT_FIRST || to->sat_port >= ATPORT_LAST) {
360         return (NULL);
361     }
362
363     /*
364      * Make sure the local address matches the sent address.  What about
365      * the interface?
366      */
367     for (ddp = ddp_ports[ to->sat_port - 1 ]; ddp; ddp = ddp->ddp_pnext) {
368         DDP_LOCK(ddp);
369         /* XXX should we handle 0.YY? */
370
371         /* XXXX.YY to socket on destination interface */
372         if (to->sat_addr.s_net == ddp->ddp_lsat.sat_addr.s_net &&
373                 to->sat_addr.s_node == ddp->ddp_lsat.sat_addr.s_node) {
374             DDP_UNLOCK(ddp);
375             break;
376         }
377
378         /* 0.255 to socket on receiving interface */
379         if (to->sat_addr.s_node == ATADDR_BCAST && (to->sat_addr.s_net == 0 ||
380                 to->sat_addr.s_net == ddp->ddp_lsat.sat_addr.s_net) &&
381                 ddp->ddp_lsat.sat_addr.s_net == AA_SAT(aa)->sat_addr.s_net) {
382             DDP_UNLOCK(ddp);
383             break;
384         }
385
386         /* XXXX.0 to socket on destination interface */
387         if (to->sat_addr.s_net == aa->aa_firstnet &&
388                 to->sat_addr.s_node == 0 &&
389                 ntohs(ddp->ddp_lsat.sat_addr.s_net) >=
390                 ntohs(aa->aa_firstnet) &&
391                 ntohs(ddp->ddp_lsat.sat_addr.s_net) <=
392                 ntohs(aa->aa_lastnet)) {
393             DDP_UNLOCK(ddp);
394             break;
395         }
396         DDP_UNLOCK(ddp);
397     }
398     return (ddp);
399 }