1/*- 2 * Copyright (c) 1984, 1985, 1986, 1987, 1993 3 * The Regents of the University of California. 4 * Copyright (c) 2004-2009 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: releng/10.2/sys/netipx/ipx_input.c 263478 2014-03-21 15:15:30Z glebius $"); 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/lock.h> 76#include <sys/rwlock.h> 77#include <sys/sysctl.h> 78 79#include <net/if.h> 80#include <net/route.h> 81#include <net/netisr.h> 82 83#include <netipx/ipx.h> 84#include <netipx/spx.h> 85#include <netipx/ipx_if.h> 86#include <netipx/ipx_pcb.h> 87#include <netipx/ipx_var.h> 88 89int ipxcksum = 0; 90SYSCTL_INT(_net_ipx_ipx, OID_AUTO, checksum, CTLFLAG_RW, 91 &ipxcksum, 0, "Compute ipx checksum"); 92 93static int ipxprintfs = 0; /* printing forwarding information */ 94SYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxprintfs, CTLFLAG_RW, 95 &ipxprintfs, 0, "Printing forwarding information"); 96 97static int ipxforwarding = 0; 98SYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxforwarding, CTLFLAG_RW, 99 &ipxforwarding, 0, "Enable ipx forwarding"); 100 101static int ipxnetbios = 0; 102SYSCTL_INT(_net_ipx, OID_AUTO, ipxnetbios, CTLFLAG_RW, 103 &ipxnetbios, 0, "Propagate netbios over ipx"); 104 105static int ipx_do_route(struct ipx_addr *src, struct route *ro); 106static void ipx_undo_route(struct route *ro); 107static void ipx_forward(struct mbuf *m); 108static void ipxintr(struct mbuf *m); 109 110const union ipx_net ipx_zeronet; 111 112const union ipx_net ipx_broadnet = { .s_net[0] = 0xffff, 113 .s_net[1] = 0xffff }; 114const union ipx_host ipx_broadhost = { .s_host[0] = 0xffff, 115 .s_host[1] = 0xffff, 116 .s_host[2] = 0xffff }; 117 118struct ipxstat ipxstat; 119struct sockaddr_ipx ipx_netmask, ipx_hostmask; 120 121/* 122 * IPX protocol control block (pcb) lists. 123 */ 124struct mtx ipxpcb_list_mtx; 125struct ipxpcbhead ipxpcb_list; 126struct ipxpcbhead ipxrawpcb_list; 127 128static struct netisr_handler ipx_nh = { 129 .nh_name = "ipx", 130 .nh_handler = ipxintr, 131 .nh_proto = NETISR_IPX, 132 .nh_policy = NETISR_POLICY_SOURCE, 133}; 134 135long ipx_pexseq; /* Locked with ipxpcb_list_mtx. */ 136 137/* 138 * IPX initialization. 139 */ 140 141void 142ipx_init(void) 143{ 144 145 read_random(&ipx_pexseq, sizeof ipx_pexseq); 146 147 LIST_INIT(&ipxpcb_list); 148 LIST_INIT(&ipxrawpcb_list); 149 TAILQ_INIT(&ipx_ifaddrhead); 150 151 IPX_LIST_LOCK_INIT(); 152 IPX_IFADDR_LOCK_INIT(); 153 154 ipx_netmask.sipx_len = 6; 155 ipx_netmask.sipx_addr.x_net = ipx_broadnet; 156 157 ipx_hostmask.sipx_len = 12; 158 ipx_hostmask.sipx_addr.x_net = ipx_broadnet; 159 ipx_hostmask.sipx_addr.x_host = ipx_broadhost; 160 161 netisr_register(&ipx_nh); 162} 163 164/* 165 * IPX input routine. Pass to next level. 166 */ 167static void 168ipxintr(struct mbuf *m) 169{ 170 struct ipx *ipx; 171 struct ipxpcb *ipxp; 172 struct ipx_ifaddr *ia; 173 int len; 174 175 /* 176 * If no IPX addresses have been set yet but the interfaces 177 * are receiving, can't do anything with incoming packets yet. 178 */ 179 if (TAILQ_EMPTY(&ipx_ifaddrhead)) { 180 m_freem(m); 181 return; 182 } 183 184 ipxstat.ipxs_total++; 185 186 if ((m->m_flags & M_EXT || m->m_len < sizeof(struct ipx)) && 187 (m = m_pullup(m, sizeof(struct ipx))) == NULL) { 188 ipxstat.ipxs_toosmall++; 189 return; 190 } 191 192 /* 193 * Give any raw listeners a crack at the packet 194 */ 195 IPX_LIST_LOCK(); 196 LIST_FOREACH(ipxp, &ipxrawpcb_list, ipxp_list) { 197 struct mbuf *m1 = m_copy(m, 0, (int)M_COPYALL); 198 if (m1 != NULL) { 199 IPX_LOCK(ipxp); 200 ipx_input(m1, ipxp); 201 IPX_UNLOCK(ipxp); 202 } 203 } 204 IPX_LIST_UNLOCK(); 205 206 ipx = mtod(m, struct ipx *); 207 len = ntohs(ipx->ipx_len); 208 /* 209 * Check that the amount of data in the buffers 210 * is as at least much as the IPX header would have us expect. 211 * Trim mbufs if longer than we expect. 212 * Drop packet if shorter than we expect. 213 */ 214 if (m->m_pkthdr.len < len) { 215 ipxstat.ipxs_tooshort++; 216 m_freem(m); 217 return; 218 } 219 if (m->m_pkthdr.len > len) { 220 if (m->m_len == m->m_pkthdr.len) { 221 m->m_len = len; 222 m->m_pkthdr.len = len; 223 } else 224 m_adj(m, len - m->m_pkthdr.len); 225 } 226 if (ipxcksum && ipx->ipx_sum != 0xffff) { 227 if (ipx->ipx_sum != ipx_cksum(m, len)) { 228 ipxstat.ipxs_badsum++; 229 m_freem(m); 230 return; 231 } 232 } 233 234 /* 235 * Propagated (Netbios) packets (type 20) has to be handled 236 * different. :-( 237 */ 238 if (ipx->ipx_pt == IPXPROTO_NETBIOS) { 239 if (ipxnetbios) { 240 ipx_output_type20(m); 241 return; 242 } else { 243 m_freem(m); 244 return; 245 } 246 } 247 248 /* 249 * Is this a directed broadcast? 250 */ 251 if (ipx_hosteqnh(ipx_broadhost,ipx->ipx_dna.x_host)) { 252 if ((!ipx_neteq(ipx->ipx_dna, ipx->ipx_sna)) && 253 (!ipx_neteqnn(ipx->ipx_dna.x_net, ipx_broadnet)) && 254 (!ipx_neteqnn(ipx->ipx_sna.x_net, ipx_zeronet)) && 255 (!ipx_neteqnn(ipx->ipx_dna.x_net, ipx_zeronet)) ) { 256 /* 257 * If it is a broadcast to the net where it was 258 * received from, treat it as ours. 259 */ 260 IPX_IFADDR_RLOCK(); 261 TAILQ_FOREACH(ia, &ipx_ifaddrhead, ia_link) { 262 if ((ia->ia_ifa.ifa_ifp == m->m_pkthdr.rcvif) 263 && ipx_neteq(ia->ia_addr.sipx_addr, 264 ipx->ipx_dna)) { 265 IPX_IFADDR_RUNLOCK(); 266 goto ours; 267 } 268 } 269 IPX_IFADDR_RUNLOCK(); 270 271 /* 272 * Look to see if I need to eat this packet. 273 * Algorithm is to forward all young packets 274 * and prematurely age any packets which will 275 * by physically broadcasted. 276 * Any very old packets eaten without forwarding 277 * would die anyway. 278 * 279 * Suggestion of Bill Nesheim, Cornell U. 280 */ 281 if (ipx->ipx_tc < IPX_MAXHOPS) { 282 ipx_forward(m); 283 return; 284 } 285 } 286 /* 287 * Is this our packet? If not, forward. 288 */ 289 } else { 290 IPX_IFADDR_RLOCK(); 291 TAILQ_FOREACH(ia, &ipx_ifaddrhead, ia_link) { 292 if (ipx_hosteq(ipx->ipx_dna, ia->ia_addr.sipx_addr) && 293 (ipx_neteq(ipx->ipx_dna, ia->ia_addr.sipx_addr) || 294 ipx_neteqnn(ipx->ipx_dna.x_net, ipx_zeronet))) 295 break; 296 } 297 IPX_IFADDR_RUNLOCK(); 298 if (ia == NULL) { 299 ipx_forward(m); 300 return; 301 } 302 } 303ours: 304 /* 305 * Locate pcb for datagram. 306 */ 307 IPX_LIST_LOCK(); 308 ipxp = ipx_pcblookup(&ipx->ipx_sna, ipx->ipx_dna.x_port, IPX_WILDCARD); 309 /* 310 * Switch out to protocol's input routine. 311 */ 312 if (ipxp != NULL) { 313 ipxstat.ipxs_delivered++; 314 if ((ipxp->ipxp_flags & IPXP_ALL_PACKETS) == 0) 315 switch (ipx->ipx_pt) { 316 case IPXPROTO_SPX: 317 IPX_LOCK(ipxp); 318 /* Will release both locks. */ 319 spx_input(m, ipxp); 320 return; 321 } 322 IPX_LOCK(ipxp); 323 ipx_input(m, ipxp); 324 IPX_UNLOCK(ipxp); 325 } else 326 m_freem(m); 327 IPX_LIST_UNLOCK(); 328} 329 330void 331ipx_ctlinput(cmd, arg_as_sa, dummy) 332 int cmd; 333 struct sockaddr *arg_as_sa; /* XXX should be swapped with dummy */ 334 void *dummy; 335{ 336 337 /* Currently, nothing. */ 338} 339 340/* 341 * Forward a packet. If some error occurs drop the packet. IPX don't 342 * have a way to return errors to the sender. 343 */ 344 345static struct route ipx_droute; 346static struct route ipx_sroute; 347 348static void 349ipx_forward(struct mbuf *m) 350{ 351 struct ipx *ipx = mtod(m, struct ipx *); 352 int error; 353 int agedelta = 1; 354 int flags = IPX_FORWARDING; 355 int ok_there = 0; 356 int ok_back = 0; 357 358 if (ipxforwarding == 0) { 359 /* can't tell difference between net and host */ 360 ipxstat.ipxs_cantforward++; 361 m_freem(m); 362 goto cleanup; 363 } 364 ipx->ipx_tc++; 365 if (ipx->ipx_tc > IPX_MAXHOPS) { 366 ipxstat.ipxs_cantforward++; 367 m_freem(m); 368 goto cleanup; 369 } 370 371 if ((ok_there = ipx_do_route(&ipx->ipx_dna,&ipx_droute)) == 0) { 372 ipxstat.ipxs_noroute++; 373 m_freem(m); 374 goto cleanup; 375 } 376 /* 377 * Here we think about forwarding broadcast packets, 378 * so we try to insure that it doesn't go back out 379 * on the interface it came in on. Also, if we 380 * are going to physically broadcast this, let us 381 * age the packet so we can eat it safely the second time around. 382 */ 383 if (ipx->ipx_dna.x_host.c_host[0] & 0x1) { 384 struct ipx_ifaddr *ia; 385 struct ifnet *ifp; 386 387 IPX_IFADDR_RLOCK(); 388 ia = ipx_iaonnetof(&ipx->ipx_dna); 389 if (ia != NULL) { 390 /* I'm gonna hafta eat this packet */ 391 agedelta += IPX_MAXHOPS - ipx->ipx_tc; 392 ipx->ipx_tc = IPX_MAXHOPS; 393 } 394 IPX_IFADDR_RUNLOCK(); 395 if ((ok_back = ipx_do_route(&ipx->ipx_sna,&ipx_sroute)) == 0) { 396 /* error = ENETUNREACH; He'll never get it! */ 397 ipxstat.ipxs_noroute++; 398 m_freem(m); 399 goto cleanup; 400 } 401 if (ipx_droute.ro_rt && 402 (ifp = ipx_droute.ro_rt->rt_ifp) && 403 ipx_sroute.ro_rt && 404 (ifp != ipx_sroute.ro_rt->rt_ifp)) { 405 flags |= IPX_ALLOWBROADCAST; 406 } else { 407 ipxstat.ipxs_noroute++; 408 m_freem(m); 409 goto cleanup; 410 } 411 } 412 /* 413 * We don't need to recompute checksum because ipx_tc field 414 * is ignored by checksum calculation routine, however 415 * it may be desirable to reset checksum if ipxcksum == 0 416 */ 417#if 0 418 if (!ipxcksum) 419 ipx->ipx_sum = 0xffff; 420#endif 421 422 error = ipx_outputfl(m, &ipx_droute, flags); 423 if (error == 0) { 424 ipxstat.ipxs_forward++; 425 426 if (ipxprintfs) { 427 printf("forward: "); 428 ipx_printhost(&ipx->ipx_sna); 429 printf(" to "); 430 ipx_printhost(&ipx->ipx_dna); 431 printf(" hops %d\n", ipx->ipx_tc); 432 } 433 } 434cleanup: 435 if (ok_there) 436 ipx_undo_route(&ipx_droute); 437 if (ok_back) 438 ipx_undo_route(&ipx_sroute); 439} 440 441static int 442ipx_do_route(struct ipx_addr *src, struct route *ro) 443{ 444 struct sockaddr_ipx *dst; 445 446 bzero((caddr_t)ro, sizeof(*ro)); 447 dst = (struct sockaddr_ipx *)&ro->ro_dst; 448 449 dst->sipx_len = sizeof(*dst); 450 dst->sipx_family = AF_IPX; 451 dst->sipx_addr = *src; 452 dst->sipx_addr.x_port = 0; 453 rtalloc_ign(ro, 0); 454 if (ro->ro_rt == NULL || ro->ro_rt->rt_ifp == NULL) { 455 return (0); 456 } 457 counter_u64_add(ro->ro_rt->rt_pksent, 1); 458 return (1); 459} 460 461static void 462ipx_undo_route(struct route *ro) 463{ 464 465 if (ro->ro_rt != NULL) { 466 RTFREE(ro->ro_rt); 467 } 468} 469