FreeBSD/Linux Kernel Cross Reference
sys/netipx/ipx_pcb.c
1 /*-
2 * Copyright (c) 1984, 1985, 1986, 1987, 1993
3 * The Regents of the University of California.
4 * Copyright (c) 1995, Mike Mitchell
5 * Copyright (c) 2004-2006 Robert N. M. Watson
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 * @(#)ipx_pcb.c
37 */
38
39 #include <sys/cdefs.h>
40 __FBSDID("$FreeBSD: releng/6.4/sys/netipx/ipx_pcb.c 159433 2006-06-08 23:31:16Z rwatson $");
41
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/malloc.h>
45 #include <sys/socket.h>
46 #include <sys/socketvar.h>
47
48 #include <net/if.h>
49 #include <net/route.h>
50
51 #include <netipx/ipx.h>
52 #include <netipx/ipx_if.h>
53 #include <netipx/ipx_pcb.h>
54 #include <netipx/ipx_var.h>
55
56 static struct ipx_addr zeroipx_addr;
57 static u_short ipxpcb_lport_cache;
58
59 int
60 ipx_pcballoc(so, head, td)
61 struct socket *so;
62 struct ipxpcbhead *head;
63 struct thread *td;
64 {
65 register struct ipxpcb *ipxp;
66
67 KASSERT(so->so_pcb == NULL, ("ipx_pcballoc: so_pcb != NULL"));
68 IPX_LIST_LOCK_ASSERT();
69
70 MALLOC(ipxp, struct ipxpcb *, sizeof *ipxp, M_PCB, M_NOWAIT | M_ZERO);
71 if (ipxp == NULL)
72 return (ENOBUFS);
73 IPX_LOCK_INIT(ipxp);
74 ipxp->ipxp_socket = so;
75 if (ipxcksum)
76 ipxp->ipxp_flags |= IPXP_CHECKSUM;
77 LIST_INSERT_HEAD(head, ipxp, ipxp_list);
78 so->so_pcb = (caddr_t)ipxp;
79 return (0);
80 }
81
82 int
83 ipx_pcbbind(ipxp, nam, td)
84 register struct ipxpcb *ipxp;
85 struct sockaddr *nam;
86 struct thread *td;
87 {
88 register struct sockaddr_ipx *sipx;
89 u_short lport = 0;
90
91 IPX_LIST_LOCK_ASSERT();
92 IPX_LOCK_ASSERT(ipxp);
93
94 if (ipxp->ipxp_lport || !ipx_nullhost(ipxp->ipxp_laddr))
95 return (EINVAL);
96 if (nam == NULL)
97 goto noname;
98 sipx = (struct sockaddr_ipx *)nam;
99 if (!ipx_nullhost(sipx->sipx_addr)) {
100 int tport = sipx->sipx_port;
101
102 sipx->sipx_port = 0; /* yech... */
103 if (ifa_ifwithaddr((struct sockaddr *)sipx) == NULL)
104 return (EADDRNOTAVAIL);
105 sipx->sipx_port = tport;
106 }
107 lport = sipx->sipx_port;
108 if (lport) {
109 u_short aport = ntohs(lport);
110 int error;
111
112 if (aport < IPXPORT_RESERVED &&
113 td != NULL && (error = suser(td)) != 0)
114 return (error);
115 if (ipx_pcblookup(&zeroipx_addr, lport, 0))
116 return (EADDRINUSE);
117 }
118 ipxp->ipxp_laddr = sipx->sipx_addr;
119 noname:
120 if (lport == 0)
121 do {
122 ipxpcb_lport_cache++;
123 if ((ipxpcb_lport_cache < IPXPORT_RESERVED) ||
124 (ipxpcb_lport_cache >= IPXPORT_WELLKNOWN))
125 ipxpcb_lport_cache = IPXPORT_RESERVED;
126 lport = htons(ipxpcb_lport_cache);
127 } while (ipx_pcblookup(&zeroipx_addr, lport, 0));
128 ipxp->ipxp_lport = lport;
129 return (0);
130 }
131
132 /*
133 * Connect from a socket to a specified address.
134 * Both address and port must be specified in argument sipx.
135 * If don't have a local address for this socket yet,
136 * then pick one.
137 */
138 int
139 ipx_pcbconnect(ipxp, nam, td)
140 struct ipxpcb *ipxp;
141 struct sockaddr *nam;
142 struct thread *td;
143 {
144 struct ipx_ifaddr *ia;
145 register struct sockaddr_ipx *sipx = (struct sockaddr_ipx *)nam;
146 register struct ipx_addr *dst;
147 register struct route *ro;
148 struct ifnet *ifp;
149
150 IPX_LIST_LOCK_ASSERT();
151 IPX_LOCK_ASSERT(ipxp);
152
153 ia = NULL;
154
155 if (sipx->sipx_family != AF_IPX)
156 return (EAFNOSUPPORT);
157 if (sipx->sipx_port == 0 || ipx_nullhost(sipx->sipx_addr))
158 return (EADDRNOTAVAIL);
159 /*
160 * If we haven't bound which network number to use as ours,
161 * we will use the number of the outgoing interface.
162 * This depends on having done a routing lookup, which
163 * we will probably have to do anyway, so we might
164 * as well do it now. On the other hand if we are
165 * sending to multiple destinations we may have already
166 * done the lookup, so see if we can use the route
167 * from before. In any case, we only
168 * chose a port number once, even if sending to multiple
169 * destinations.
170 */
171 ro = &ipxp->ipxp_route;
172 dst = &satoipx_addr(ro->ro_dst);
173 if (ipxp->ipxp_socket->so_options & SO_DONTROUTE)
174 goto flush;
175 if (!ipx_neteq(ipxp->ipxp_lastdst, sipx->sipx_addr))
176 goto flush;
177 if (!ipx_hosteq(ipxp->ipxp_lastdst, sipx->sipx_addr)) {
178 if (ro->ro_rt != NULL && !(ro->ro_rt->rt_flags & RTF_HOST)) {
179 /* can patch route to avoid rtalloc */
180 *dst = sipx->sipx_addr;
181 } else {
182 flush:
183 if (ro->ro_rt != NULL)
184 RTFREE(ro->ro_rt);
185 ro->ro_rt = NULL;
186 }
187 }/* else cached route is ok; do nothing */
188 ipxp->ipxp_lastdst = sipx->sipx_addr;
189 if ((ipxp->ipxp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/
190 (ro->ro_rt == NULL || ro->ro_rt->rt_ifp == NULL)) {
191 /* No route yet, so try to acquire one */
192 ro->ro_dst.sa_family = AF_IPX;
193 ro->ro_dst.sa_len = sizeof(ro->ro_dst);
194 *dst = sipx->sipx_addr;
195 dst->x_port = 0;
196 rtalloc_ign(ro, 0);
197 }
198 if (ipx_neteqnn(ipxp->ipxp_laddr.x_net, ipx_zeronet)) {
199 /*
200 * If route is known or can be allocated now,
201 * our src addr is taken from the i/f, else punt.
202 */
203
204 /*
205 * If we found a route, use the address
206 * corresponding to the outgoing interface
207 */
208 if (ro->ro_rt != NULL && (ifp = ro->ro_rt->rt_ifp) != NULL)
209 for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next)
210 if (ia->ia_ifp == ifp)
211 break;
212 if (ia == NULL) {
213 u_short fport = sipx->sipx_addr.x_port;
214 sipx->sipx_addr.x_port = 0;
215 ia = (struct ipx_ifaddr *)
216 ifa_ifwithdstaddr((struct sockaddr *)sipx);
217 sipx->sipx_addr.x_port = fport;
218 if (ia == NULL)
219 ia = ipx_iaonnetof(&sipx->sipx_addr);
220 if (ia == NULL)
221 ia = ipx_ifaddr;
222 if (ia == NULL)
223 return (EADDRNOTAVAIL);
224 }
225 ipxp->ipxp_laddr.x_net = satoipx_addr(ia->ia_addr).x_net;
226 }
227 if (ipx_nullhost(ipxp->ipxp_laddr)) {
228 /*
229 * If route is known or can be allocated now,
230 * our src addr is taken from the i/f, else punt.
231 */
232
233 /*
234 * If we found a route, use the address
235 * corresponding to the outgoing interface
236 */
237 if (ro->ro_rt != NULL && (ifp = ro->ro_rt->rt_ifp) != NULL)
238 for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next)
239 if (ia->ia_ifp == ifp)
240 break;
241 if (ia == NULL) {
242 u_short fport = sipx->sipx_addr.x_port;
243 sipx->sipx_addr.x_port = 0;
244 ia = (struct ipx_ifaddr *)
245 ifa_ifwithdstaddr((struct sockaddr *)sipx);
246 sipx->sipx_addr.x_port = fport;
247 if (ia == NULL)
248 ia = ipx_iaonnetof(&sipx->sipx_addr);
249 if (ia == NULL)
250 ia = ipx_ifaddr;
251 if (ia == NULL)
252 return (EADDRNOTAVAIL);
253 }
254 ipxp->ipxp_laddr.x_host = satoipx_addr(ia->ia_addr).x_host;
255 }
256 if (ipx_pcblookup(&sipx->sipx_addr, ipxp->ipxp_lport, 0))
257 return (EADDRINUSE);
258 if (ipxp->ipxp_lport == 0)
259 ipx_pcbbind(ipxp, (struct sockaddr *)NULL, td);
260
261 /* XXX just leave it zero if we can't find a route */
262
263 ipxp->ipxp_faddr = sipx->sipx_addr;
264 /* Includes ipxp->ipxp_fport = sipx->sipx_port; */
265 return (0);
266 }
267
268 void
269 ipx_pcbdisconnect(ipxp)
270 struct ipxpcb *ipxp;
271 {
272
273 IPX_LIST_LOCK_ASSERT();
274 IPX_LOCK_ASSERT(ipxp);
275
276 ipxp->ipxp_faddr = zeroipx_addr;
277 }
278
279 void
280 ipx_pcbdetach(ipxp)
281 struct ipxpcb *ipxp;
282 {
283 struct socket *so = ipxp->ipxp_socket;
284
285 IPX_LIST_LOCK_ASSERT();
286 IPX_LOCK_ASSERT(ipxp);
287
288 so->so_pcb = NULL;
289 ipxp->ipxp_socket = NULL;
290 }
291
292 void
293 ipx_pcbfree(ipxp)
294 struct ipxpcb *ipxp;
295 {
296
297 KASSERT(ipxp->ipxp_socket == NULL,
298 ("ipx_pcbfree: ipxp_socket != NULL"));
299 IPX_LIST_LOCK_ASSERT();
300 IPX_LOCK_ASSERT(ipxp);
301
302 if (ipxp->ipxp_route.ro_rt != NULL)
303 RTFREE(ipxp->ipxp_route.ro_rt);
304 LIST_REMOVE(ipxp, ipxp_list);
305 IPX_LOCK_DESTROY(ipxp);
306 FREE(ipxp, M_PCB);
307 }
308
309 void
310 ipx_setsockaddr(ipxp, nam)
311 register struct ipxpcb *ipxp;
312 struct sockaddr **nam;
313 {
314 struct sockaddr_ipx *sipx, ssipx;
315
316 sipx = &ssipx;
317 bzero((caddr_t)sipx, sizeof(*sipx));
318 sipx->sipx_len = sizeof(*sipx);
319 sipx->sipx_family = AF_IPX;
320 IPX_LOCK(ipxp);
321 sipx->sipx_addr = ipxp->ipxp_laddr;
322 IPX_UNLOCK(ipxp);
323 *nam = sodupsockaddr((struct sockaddr *)sipx, M_WAITOK);
324 }
325
326 void
327 ipx_setpeeraddr(ipxp, nam)
328 register struct ipxpcb *ipxp;
329 struct sockaddr **nam;
330 {
331 struct sockaddr_ipx *sipx, ssipx;
332
333 sipx = &ssipx;
334 bzero(sipx, sizeof(*sipx));
335 sipx->sipx_len = sizeof(*sipx);
336 sipx->sipx_family = AF_IPX;
337 IPX_LOCK(ipxp);
338 sipx->sipx_addr = ipxp->ipxp_faddr;
339 IPX_UNLOCK(ipxp);
340 *nam = sodupsockaddr((struct sockaddr *)sipx, M_WAITOK);
341 }
342
343 struct ipxpcb *
344 ipx_pcblookup(faddr, lport, wildp)
345 struct ipx_addr *faddr;
346 u_short lport;
347 int wildp;
348 {
349 register struct ipxpcb *ipxp, *match = NULL;
350 int matchwild = 3, wildcard;
351 u_short fport;
352
353 IPX_LIST_LOCK_ASSERT();
354
355 fport = faddr->x_port;
356 LIST_FOREACH(ipxp, &ipxpcb_list, ipxp_list) {
357 if (ipxp->ipxp_lport != lport)
358 continue;
359 wildcard = 0;
360 if (ipx_nullhost(ipxp->ipxp_faddr)) {
361 if (!ipx_nullhost(*faddr))
362 wildcard++;
363 } else {
364 if (ipx_nullhost(*faddr))
365 wildcard++;
366 else {
367 if (!ipx_hosteq(ipxp->ipxp_faddr, *faddr))
368 continue;
369 if (ipxp->ipxp_fport != fport) {
370 if (ipxp->ipxp_fport != 0)
371 continue;
372 else
373 wildcard++;
374 }
375 }
376 }
377 if (wildcard && wildp == 0)
378 continue;
379 if (wildcard < matchwild) {
380 match = ipxp;
381 matchwild = wildcard;
382 if (wildcard == 0)
383 break;
384 }
385 }
386 return (match);
387 }
Cache object: 53ac7c05fbb12fa7493985584874ebbf
|