ipx_input.c revision 180816
1/*- 2 * Copyright (c) 1984, 1985, 1986, 1987, 1993 3 * The Regents of the University of California. 4 * Copyright (c) 2004-2005 Robert N. M. Watson 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 4. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 * 31 * Copyright (c) 1995, Mike Mitchell 32 * All rights reserved. 33 * 34 * Redistribution and use in source and binary forms, with or without 35 * modification, are permitted provided that the following conditions 36 * are met: 37 * 1. Redistributions of source code must retain the above copyright 38 * notice, this list of conditions and the following disclaimer. 39 * 2. Redistributions in binary form must reproduce the above copyright 40 * notice, this list of conditions and the following disclaimer in the 41 * documentation and/or other materials provided with the distribution. 42 * 3. All advertising materials mentioning features or use of this software 43 * must display the following acknowledgement: 44 * This product includes software developed by the University of 45 * California, Berkeley and its contributors. 46 * 4. Neither the name of the University nor the names of its contributors 47 * may be used to endorse or promote products derived from this software 48 * without specific prior written permission. 49 * 50 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 51 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 52 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 53 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 54 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 55 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 56 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 57 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 58 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 59 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 60 * SUCH DAMAGE. 61 * 62 * @(#)ipx_input.c 63 */ 64 65#include <sys/cdefs.h> 66__FBSDID("$FreeBSD: head/sys/netipx/ipx_input.c 180816 2008-07-25 23:54:07Z trhodes $"); 67 68#include <sys/param.h> 69#include <sys/systm.h> 70#include <sys/mbuf.h> 71#include <sys/protosw.h> 72#include <sys/socket.h> 73#include <sys/kernel.h> 74#include <sys/random.h> 75#include <sys/sysctl.h> 76 77#include <net/if.h> 78#include <net/route.h> 79#include <net/netisr.h> 80 81#include <netipx/ipx.h> 82#include <netipx/spx.h> 83#include <netipx/ipx_if.h> 84#include <netipx/ipx_pcb.h> 85#include <netipx/ipx_var.h> 86 87int ipxcksum = 0; 88SYSCTL_INT(_net_ipx_ipx, OID_AUTO, checksum, CTLFLAG_RW, 89 &ipxcksum, 0, "Compute ipx checksum"); 90 91static int ipxprintfs = 0; /* printing forwarding information */ 92SYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxprintfs, CTLFLAG_RW, 93 &ipxprintfs, 0, "Printing forwarding information"); 94 95static int ipxforwarding = 0; 96SYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxforwarding, CTLFLAG_RW, 97 &ipxforwarding, 0, "Enable ipx forwarding"); 98 99static int ipxnetbios = 0; 100SYSCTL_INT(_net_ipx, OID_AUTO, ipxnetbios, CTLFLAG_RW, 101 &ipxnetbios, 0, "Propagate netbios over ipx"); 102 103const union ipx_net ipx_zeronet; 104const union ipx_host ipx_zerohost; 105 106const union ipx_net ipx_broadnet = { .s_net[0] = 0xffff, 107 .s_net[1] = 0xffff }; 108const union ipx_host ipx_broadhost = { .s_host[0] = 0xffff, 109 .s_host[1] = 0xffff, 110 .s_host[2] = 0xffff }; 111 112struct ipxstat ipxstat; 113struct sockaddr_ipx ipx_netmask, ipx_hostmask; 114 115/* 116 * IPX protocol control block (pcb) lists. 117 */ 118struct mtx ipxpcb_list_mtx; 119struct ipxpcbhead ipxpcb_list; 120struct ipxpcbhead ipxrawpcb_list; 121 122static int ipxqmaxlen = IFQ_MAXLEN; 123static struct ifqueue ipxintrq; 124 125long ipx_pexseq; /* Locked with ipxpcb_list_mtx. */ 126 127static int ipx_do_route(struct ipx_addr *src, struct route *ro); 128static void ipx_undo_route(struct route *ro); 129static void ipx_forward(struct mbuf *m); 130static void ipxintr(struct mbuf *m); 131 132/* 133 * IPX initialization. 134 */ 135 136void 137ipx_init(void) 138{ 139 140 read_random(&ipx_pexseq, sizeof ipx_pexseq); 141 142 LIST_INIT(&ipxpcb_list); 143 LIST_INIT(&ipxrawpcb_list); 144 145 IPX_LIST_LOCK_INIT(); 146 147 ipx_netmask.sipx_len = 6; 148 ipx_netmask.sipx_addr.x_net = ipx_broadnet; 149 150 ipx_hostmask.sipx_len = 12; 151 ipx_hostmask.sipx_addr.x_net = ipx_broadnet; 152 ipx_hostmask.sipx_addr.x_host = ipx_broadhost; 153 154 ipxintrq.ifq_maxlen = ipxqmaxlen; 155 mtx_init(&ipxintrq.ifq_mtx, "ipx_inq", NULL, MTX_DEF); 156 netisr_register(NETISR_IPX, ipxintr, &ipxintrq, 0); 157} 158 159/* 160 * IPX input routine. Pass to next level. 161 */ 162static void 163ipxintr(struct mbuf *m) 164{ 165 struct ipx *ipx; 166 struct ipxpcb *ipxp; 167 struct ipx_ifaddr *ia; 168 int len; 169 170 /* 171 * If no IPX addresses have been set yet but the interfaces 172 * are receiving, can't do anything with incoming packets yet. 173 */ 174 if (ipx_ifaddr == NULL) { 175 m_freem(m); 176 return; 177 } 178 179 ipxstat.ipxs_total++; 180 181 if ((m->m_flags & M_EXT || m->m_len < sizeof(struct ipx)) && 182 (m = m_pullup(m, sizeof(struct ipx))) == NULL) { 183 ipxstat.ipxs_toosmall++; 184 return; 185 } 186 187 /* 188 * Give any raw listeners a crack at the packet 189 */ 190 IPX_LIST_LOCK(); 191 LIST_FOREACH(ipxp, &ipxrawpcb_list, ipxp_list) { 192 struct mbuf *m1 = m_copy(m, 0, (int)M_COPYALL); 193 if (m1 != NULL) { 194 IPX_LOCK(ipxp); 195 ipx_input(m1, ipxp); 196 IPX_UNLOCK(ipxp); 197 } 198 } 199 IPX_LIST_UNLOCK(); 200 201 ipx = mtod(m, struct ipx *); 202 len = ntohs(ipx->ipx_len); 203 /* 204 * Check that the amount of data in the buffers 205 * is as at least much as the IPX header would have us expect. 206 * Trim mbufs if longer than we expect. 207 * Drop packet if shorter than we expect. 208 */ 209 if (m->m_pkthdr.len < len) { 210 ipxstat.ipxs_tooshort++; 211 m_freem(m); 212 return; 213 } 214 if (m->m_pkthdr.len > len) { 215 if (m->m_len == m->m_pkthdr.len) { 216 m->m_len = len; 217 m->m_pkthdr.len = len; 218 } else 219 m_adj(m, len - m->m_pkthdr.len); 220 } 221 if (ipxcksum && ipx->ipx_sum != 0xffff) { 222 if (ipx->ipx_sum != ipx_cksum(m, len)) { 223 ipxstat.ipxs_badsum++; 224 m_freem(m); 225 return; 226 } 227 } 228 229 /* 230 * Propagated (Netbios) packets (type 20) has to be handled 231 * different. :-( 232 */ 233 if (ipx->ipx_pt == IPXPROTO_NETBIOS) { 234 if (ipxnetbios) { 235 ipx_output_type20(m); 236 return; 237 } else { 238 m_freem(m); 239 return; 240 } 241 } 242 243 /* 244 * Is this a directed broadcast? 245 */ 246 if (ipx_hosteqnh(ipx_broadhost,ipx->ipx_dna.x_host)) { 247 if ((!ipx_neteq(ipx->ipx_dna, ipx->ipx_sna)) && 248 (!ipx_neteqnn(ipx->ipx_dna.x_net, ipx_broadnet)) && 249 (!ipx_neteqnn(ipx->ipx_sna.x_net, ipx_zeronet)) && 250 (!ipx_neteqnn(ipx->ipx_dna.x_net, ipx_zeronet)) ) { 251 /* 252 * If it is a broadcast to the net where it was 253 * received from, treat it as ours. 254 */ 255 for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next) 256 if((ia->ia_ifa.ifa_ifp == m->m_pkthdr.rcvif) && 257 ipx_neteq(ia->ia_addr.sipx_addr, 258 ipx->ipx_dna)) 259 goto ours; 260 261 /* 262 * Look to see if I need to eat this packet. 263 * Algorithm is to forward all young packets 264 * and prematurely age any packets which will 265 * by physically broadcasted. 266 * Any very old packets eaten without forwarding 267 * would die anyway. 268 * 269 * Suggestion of Bill Nesheim, Cornell U. 270 */ 271 if (ipx->ipx_tc < IPX_MAXHOPS) { 272 ipx_forward(m); 273 return; 274 } 275 } 276 /* 277 * Is this our packet? If not, forward. 278 */ 279 } else { 280 for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next) 281 if (ipx_hosteq(ipx->ipx_dna, ia->ia_addr.sipx_addr) && 282 (ipx_neteq(ipx->ipx_dna, ia->ia_addr.sipx_addr) || 283 ipx_neteqnn(ipx->ipx_dna.x_net, ipx_zeronet))) 284 break; 285 286 if (ia == NULL) { 287 ipx_forward(m); 288 return; 289 } 290 } 291ours: 292 /* 293 * Locate pcb for datagram. 294 */ 295 IPX_LIST_LOCK(); 296 ipxp = ipx_pcblookup(&ipx->ipx_sna, ipx->ipx_dna.x_port, IPX_WILDCARD); 297 /* 298 * Switch out to protocol's input routine. 299 */ 300 if (ipxp != NULL) { 301 ipxstat.ipxs_delivered++; 302 if ((ipxp->ipxp_flags & IPXP_ALL_PACKETS) == 0) 303 switch (ipx->ipx_pt) { 304 case IPXPROTO_SPX: 305 IPX_LOCK(ipxp); 306 /* Will release both locks. */ 307 spx_input(m, ipxp); 308 return; 309 } 310 IPX_LOCK(ipxp); 311 ipx_input(m, ipxp); 312 IPX_UNLOCK(ipxp); 313 } else 314 m_freem(m); 315 IPX_LIST_UNLOCK(); 316} 317 318void 319ipx_ctlinput(cmd, arg_as_sa, dummy) 320 int cmd; 321 struct sockaddr *arg_as_sa; /* XXX should be swapped with dummy */ 322 void *dummy; 323{ 324 325 /* Currently, nothing. */ 326} 327 328/* 329 * Forward a packet. If some error occurs drop the packet. IPX don't 330 * have a way to return errors to the sender. 331 */ 332 333static struct route ipx_droute; 334static struct route ipx_sroute; 335 336static void 337ipx_forward(struct mbuf *m) 338{ 339 struct ipx *ipx = mtod(m, struct ipx *); 340 int error; 341 int agedelta = 1; 342 int flags = IPX_FORWARDING; 343 int ok_there = 0; 344 int ok_back = 0; 345 346 if (ipxforwarding == 0) { 347 /* can't tell difference between net and host */ 348 ipxstat.ipxs_cantforward++; 349 m_freem(m); 350 goto cleanup; 351 } 352 ipx->ipx_tc++; 353 if (ipx->ipx_tc > IPX_MAXHOPS) { 354 ipxstat.ipxs_cantforward++; 355 m_freem(m); 356 goto cleanup; 357 } 358 359 if ((ok_there = ipx_do_route(&ipx->ipx_dna,&ipx_droute)) == 0) { 360 ipxstat.ipxs_noroute++; 361 m_freem(m); 362 goto cleanup; 363 } 364 /* 365 * Here we think about forwarding broadcast packets, 366 * so we try to insure that it doesn't go back out 367 * on the interface it came in on. Also, if we 368 * are going to physically broadcast this, let us 369 * age the packet so we can eat it safely the second time around. 370 */ 371 if (ipx->ipx_dna.x_host.c_host[0] & 0x1) { 372 struct ipx_ifaddr *ia = ipx_iaonnetof(&ipx->ipx_dna); 373 struct ifnet *ifp; 374 if (ia != NULL) { 375 /* I'm gonna hafta eat this packet */ 376 agedelta += IPX_MAXHOPS - ipx->ipx_tc; 377 ipx->ipx_tc = IPX_MAXHOPS; 378 } 379 if ((ok_back = ipx_do_route(&ipx->ipx_sna,&ipx_sroute)) == 0) { 380 /* error = ENETUNREACH; He'll never get it! */ 381 ipxstat.ipxs_noroute++; 382 m_freem(m); 383 goto cleanup; 384 } 385 if (ipx_droute.ro_rt && 386 (ifp = ipx_droute.ro_rt->rt_ifp) && 387 ipx_sroute.ro_rt && 388 (ifp != ipx_sroute.ro_rt->rt_ifp)) { 389 flags |= IPX_ALLOWBROADCAST; 390 } else { 391 ipxstat.ipxs_noroute++; 392 m_freem(m); 393 goto cleanup; 394 } 395 } 396 /* 397 * We don't need to recompute checksum because ipx_tc field 398 * is ignored by checksum calculation routine, however 399 * it may be desirable to reset checksum if ipxcksum == 0 400 */ 401#if 0 402 if (!ipxcksum) 403 ipx->ipx_sum = 0xffff; 404#endif 405 406 error = ipx_outputfl(m, &ipx_droute, flags); 407 if (error == 0) { 408 ipxstat.ipxs_forward++; 409 410 if (ipxprintfs) { 411 printf("forward: "); 412 ipx_printhost(&ipx->ipx_sna); 413 printf(" to "); 414 ipx_printhost(&ipx->ipx_dna); 415 printf(" hops %d\n", ipx->ipx_tc); 416 } 417 } 418cleanup: 419 if (ok_there) 420 ipx_undo_route(&ipx_droute); 421 if (ok_back) 422 ipx_undo_route(&ipx_sroute); 423} 424 425static int 426ipx_do_route(struct ipx_addr *src, struct route *ro) 427{ 428 struct sockaddr_ipx *dst; 429 430 bzero((caddr_t)ro, sizeof(*ro)); 431 dst = (struct sockaddr_ipx *)&ro->ro_dst; 432 433 dst->sipx_len = sizeof(*dst); 434 dst->sipx_family = AF_IPX; 435 dst->sipx_addr = *src; 436 dst->sipx_addr.x_port = 0; 437 rtalloc_ign(ro, 0); 438 if (ro->ro_rt == NULL || ro->ro_rt->rt_ifp == NULL) { 439 return (0); 440 } 441 ro->ro_rt->rt_use++; 442 return (1); 443} 444 445static void 446ipx_undo_route(struct route *ro) 447{ 448 449 if (ro->ro_rt != NULL) { 450 RTFREE(ro->ro_rt); 451 } 452} 453 454/* 455 * XXXRW: This code should be run in its own netisr dispatch to avoid a call 456 * back into the socket code from the IPX output path. 457 */ 458void 459ipx_watch_output(struct mbuf *m, struct ifnet *ifp) 460{ 461 struct ipxpcb *ipxp; 462 struct ifaddr *ifa; 463 struct ipx_ifaddr *ia; 464 465 /* 466 * Give any raw listeners a crack at the packet 467 */ 468 IPX_LIST_LOCK(); 469 LIST_FOREACH(ipxp, &ipxrawpcb_list, ipxp_list) { 470 struct mbuf *m0 = m_copy(m, 0, (int)M_COPYALL); 471 if (m0 != NULL) { 472 struct ipx *ipx; 473 474 M_PREPEND(m0, sizeof(*ipx), M_DONTWAIT); 475 if (m0 == NULL) 476 continue; 477 ipx = mtod(m0, struct ipx *); 478 ipx->ipx_sna.x_net = ipx_zeronet; 479 for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next) 480 if (ifp == ia->ia_ifp) 481 break; 482 if (ia == NULL) 483 ipx->ipx_sna.x_host = ipx_zerohost; 484 else 485 ipx->ipx_sna.x_host = 486 ia->ia_addr.sipx_addr.x_host; 487 488 if (ifp != NULL && (ifp->if_flags & IFF_POINTOPOINT)) 489 TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 490 if (ifa->ifa_addr->sa_family == AF_IPX) { 491 ipx->ipx_sna = IA_SIPX(ifa)->sipx_addr; 492 break; 493 } 494 } 495 ipx->ipx_len = ntohl(m0->m_pkthdr.len); 496 IPX_LOCK(ipxp); 497 ipx_input(m0, ipxp); 498 IPX_UNLOCK(ipxp); 499 } 500 } 501 IPX_LIST_UNLOCK(); 502} 503