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