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