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 }
Cache object: a932b7181e1047ef9a807de142bcc85c
|