1139823Simp/*- 2157170Srwatson * Copyright (c) 1984, 1985, 1986, 1987, 1993 3157170Srwatson * The Regents of the University of California. 4194905Srwatson * Copyright (c) 2004-2009 Robert N. M. Watson 5157170Srwatson * All rights reserved. 611819Sjulian * 711819Sjulian * Redistribution and use in source and binary forms, with or without 811819Sjulian * modification, are permitted provided that the following conditions 911819Sjulian * are met: 1011819Sjulian * 1. Redistributions of source code must retain the above copyright 1111819Sjulian * notice, this list of conditions and the following disclaimer. 1211819Sjulian * 2. Redistributions in binary form must reproduce the above copyright 1311819Sjulian * notice, this list of conditions and the following disclaimer in the 1411819Sjulian * documentation and/or other materials provided with the distribution. 15165899Srwatson * 4. Neither the name of the University nor the names of its contributors 16165899Srwatson * may be used to endorse or promote products derived from this software 17165899Srwatson * without specific prior written permission. 18165899Srwatson * 19165899Srwatson * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20165899Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21165899Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22165899Srwatson * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23165899Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24165899Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25165899Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26165899Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27165899Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28165899Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29165899Srwatson * SUCH DAMAGE. 30165899Srwatson * 31165899Srwatson * Copyright (c) 1995, Mike Mitchell 32165899Srwatson * All rights reserved. 33165899Srwatson * 34165899Srwatson * Redistribution and use in source and binary forms, with or without 35165899Srwatson * modification, are permitted provided that the following conditions 36165899Srwatson * are met: 37165899Srwatson * 1. Redistributions of source code must retain the above copyright 38165899Srwatson * notice, this list of conditions and the following disclaimer. 39165899Srwatson * 2. Redistributions in binary form must reproduce the above copyright 40165899Srwatson * notice, this list of conditions and the following disclaimer in the 41165899Srwatson * documentation and/or other materials provided with the distribution. 4211819Sjulian * 3. All advertising materials mentioning features or use of this software 4311819Sjulian * must display the following acknowledgement: 4411819Sjulian * This product includes software developed by the University of 4511819Sjulian * California, Berkeley and its contributors. 4611819Sjulian * 4. Neither the name of the University nor the names of its contributors 4711819Sjulian * may be used to endorse or promote products derived from this software 4811819Sjulian * without specific prior written permission. 4911819Sjulian * 5011819Sjulian * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 5111819Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 5211819Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 5311819Sjulian * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 5411819Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 5511819Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 5611819Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 5711819Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 5811819Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 5911819Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 6011819Sjulian * SUCH DAMAGE. 6111819Sjulian * 6212057Sjulian * @(#)ipx_input.c 6311819Sjulian */ 6411819Sjulian 65116189Sobrien#include <sys/cdefs.h> 66116189Sobrien__FBSDID("$FreeBSD: releng/10.2/sys/netipx/ipx_input.c 263478 2014-03-21 15:15:30Z glebius $"); 67116189Sobrien 6811819Sjulian#include <sys/param.h> 6911819Sjulian#include <sys/systm.h> 7011819Sjulian#include <sys/mbuf.h> 7111819Sjulian#include <sys/protosw.h> 7211819Sjulian#include <sys/socket.h> 7311819Sjulian#include <sys/kernel.h> 7459604Sobrien#include <sys/random.h> 75194750Scognet#include <sys/lock.h> 76194608Srwatson#include <sys/rwlock.h> 7713266Swollman#include <sys/sysctl.h> 7811819Sjulian 7911819Sjulian#include <net/if.h> 8011819Sjulian#include <net/route.h> 8111819Sjulian#include <net/netisr.h> 8211819Sjulian 8311819Sjulian#include <netipx/ipx.h> 8411819Sjulian#include <netipx/spx.h> 8511819Sjulian#include <netipx/ipx_if.h> 8611819Sjulian#include <netipx/ipx_pcb.h> 8711819Sjulian#include <netipx/ipx_var.h> 8811819Sjulian 8925652Sjhayint ipxcksum = 0; 9013266SwollmanSYSCTL_INT(_net_ipx_ipx, OID_AUTO, checksum, CTLFLAG_RW, 91180816Strhodes &ipxcksum, 0, "Compute ipx checksum"); 9211819Sjulian 9326965Sjhaystatic int ipxprintfs = 0; /* printing forwarding information */ 9425652SjhaySYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxprintfs, CTLFLAG_RW, 95180816Strhodes &ipxprintfs, 0, "Printing forwarding information"); 9611819Sjulian 9726965Sjhaystatic int ipxforwarding = 0; 9813266SwollmanSYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxforwarding, CTLFLAG_RW, 99180816Strhodes &ipxforwarding, 0, "Enable ipx forwarding"); 10013266Swollman 10126965Sjhaystatic int ipxnetbios = 0; 10225652SjhaySYSCTL_INT(_net_ipx, OID_AUTO, ipxnetbios, CTLFLAG_RW, 103180816Strhodes &ipxnetbios, 0, "Propagate netbios over ipx"); 10411819Sjulian 105193219Srwatsonstatic int ipx_do_route(struct ipx_addr *src, struct route *ro); 106193219Srwatsonstatic void ipx_undo_route(struct route *ro); 107193219Srwatsonstatic void ipx_forward(struct mbuf *m); 108193219Srwatsonstatic void ipxintr(struct mbuf *m); 109193219Srwatson 110139442Srwatsonconst union ipx_net ipx_zeronet; 11111819Sjulian 112139442Srwatsonconst union ipx_net ipx_broadnet = { .s_net[0] = 0xffff, 113139442Srwatson .s_net[1] = 0xffff }; 114139442Srwatsonconst union ipx_host ipx_broadhost = { .s_host[0] = 0xffff, 115139442Srwatson .s_host[1] = 0xffff, 116139442Srwatson .s_host[2] = 0xffff }; 11711819Sjulian 11825652Sjhaystruct ipxstat ipxstat; 11925652Sjhaystruct sockaddr_ipx ipx_netmask, ipx_hostmask; 12011819Sjulian 121139444Srwatson/* 122139444Srwatson * IPX protocol control block (pcb) lists. 123139444Srwatson */ 124139925Srwatsonstruct mtx ipxpcb_list_mtx; 125139444Srwatsonstruct ipxpcbhead ipxpcb_list; 126139444Srwatsonstruct ipxpcbhead ipxrawpcb_list; 12711819Sjulian 128193219Srwatsonstatic struct netisr_handler ipx_nh = { 129193219Srwatson .nh_name = "ipx", 130193219Srwatson .nh_handler = ipxintr, 131193219Srwatson .nh_proto = NETISR_IPX, 132193219Srwatson .nh_policy = NETISR_POLICY_SOURCE, 133193219Srwatson}; 13411819Sjulian 135139930Srwatsonlong ipx_pexseq; /* Locked with ipxpcb_list_mtx. */ 13611819Sjulian 13711819Sjulian/* 13811819Sjulian * IPX initialization. 13911819Sjulian */ 14011819Sjulian 14111819Sjulianvoid 142169463Srwatsonipx_init(void) 14311819Sjulian{ 14411819Sjulian 14535060Sphk read_random(&ipx_pexseq, sizeof ipx_pexseq); 14611819Sjulian 147139444Srwatson LIST_INIT(&ipxpcb_list); 148139444Srwatson LIST_INIT(&ipxrawpcb_list); 149194905Srwatson TAILQ_INIT(&ipx_ifaddrhead); 150139444Srwatson 151139925Srwatson IPX_LIST_LOCK_INIT(); 152194608Srwatson IPX_IFADDR_LOCK_INIT(); 153139925Srwatson 15411819Sjulian ipx_netmask.sipx_len = 6; 15511819Sjulian ipx_netmask.sipx_addr.x_net = ipx_broadnet; 15611819Sjulian 15711819Sjulian ipx_hostmask.sipx_len = 12; 15811819Sjulian ipx_hostmask.sipx_addr.x_net = ipx_broadnet; 15911819Sjulian ipx_hostmask.sipx_addr.x_host = ipx_broadhost; 16057178Speter 161193219Srwatson netisr_register(&ipx_nh); 16211819Sjulian} 16311819Sjulian 16411819Sjulian/* 16511819Sjulian * IPX input routine. Pass to next level. 16611819Sjulian */ 167111888Sjlemonstatic void 168111888Sjlemonipxintr(struct mbuf *m) 16911819Sjulian{ 170169463Srwatson struct ipx *ipx; 171169463Srwatson struct ipxpcb *ipxp; 17225652Sjhay struct ipx_ifaddr *ia; 173111888Sjlemon int len; 17411819Sjulian 17511819Sjulian /* 17625652Sjhay * If no IPX addresses have been set yet but the interfaces 17725652Sjhay * are receiving, can't do anything with incoming packets yet. 17825652Sjhay */ 179194905Srwatson if (TAILQ_EMPTY(&ipx_ifaddrhead)) { 180139923Srwatson m_freem(m); 181139923Srwatson return; 182139923Srwatson } 18325652Sjhay 18425652Sjhay ipxstat.ipxs_total++; 18525652Sjhay 18625652Sjhay if ((m->m_flags & M_EXT || m->m_len < sizeof(struct ipx)) && 187144866Srwatson (m = m_pullup(m, sizeof(struct ipx))) == NULL) { 18811819Sjulian ipxstat.ipxs_toosmall++; 189111888Sjlemon return; 19011819Sjulian } 19111819Sjulian 19211819Sjulian /* 19311819Sjulian * Give any raw listeners a crack at the packet 19411819Sjulian */ 195139926Srwatson IPX_LIST_LOCK(); 196139444Srwatson LIST_FOREACH(ipxp, &ipxrawpcb_list, ipxp_list) { 19711819Sjulian struct mbuf *m1 = m_copy(m, 0, (int)M_COPYALL); 198139927Srwatson if (m1 != NULL) { 199139927Srwatson IPX_LOCK(ipxp); 20025652Sjhay ipx_input(m1, ipxp); 201139927Srwatson IPX_UNLOCK(ipxp); 202139927Srwatson } 20311819Sjulian } 204139926Srwatson IPX_LIST_UNLOCK(); 20511819Sjulian 20611819Sjulian ipx = mtod(m, struct ipx *); 20711819Sjulian len = ntohs(ipx->ipx_len); 20811819Sjulian /* 20911819Sjulian * Check that the amount of data in the buffers 21011819Sjulian * is as at least much as the IPX header would have us expect. 21111819Sjulian * Trim mbufs if longer than we expect. 21211819Sjulian * Drop packet if shorter than we expect. 21311819Sjulian */ 21411819Sjulian if (m->m_pkthdr.len < len) { 21511819Sjulian ipxstat.ipxs_tooshort++; 216139923Srwatson m_freem(m); 217139923Srwatson return; 21811819Sjulian } 21911819Sjulian if (m->m_pkthdr.len > len) { 22011819Sjulian if (m->m_len == m->m_pkthdr.len) { 22111819Sjulian m->m_len = len; 22211819Sjulian m->m_pkthdr.len = len; 22311819Sjulian } else 22411819Sjulian m_adj(m, len - m->m_pkthdr.len); 22511819Sjulian } 22650519Sjhay if (ipxcksum && ipx->ipx_sum != 0xffff) { 22750519Sjhay if (ipx->ipx_sum != ipx_cksum(m, len)) { 22811819Sjulian ipxstat.ipxs_badsum++; 229139923Srwatson m_freem(m); 230139923Srwatson return; 23111819Sjulian } 23211819Sjulian } 23325652Sjhay 23411819Sjulian /* 23525652Sjhay * Propagated (Netbios) packets (type 20) has to be handled 23625652Sjhay * different. :-( 23725652Sjhay */ 23825652Sjhay if (ipx->ipx_pt == IPXPROTO_NETBIOS) { 23925652Sjhay if (ipxnetbios) { 24025652Sjhay ipx_output_type20(m); 241111888Sjlemon return; 242139923Srwatson } else { 243139923Srwatson m_freem(m); 244139923Srwatson return; 245139923Srwatson } 24625652Sjhay } 24725652Sjhay 24825652Sjhay /* 24911819Sjulian * Is this a directed broadcast? 25011819Sjulian */ 25111819Sjulian if (ipx_hosteqnh(ipx_broadhost,ipx->ipx_dna.x_host)) { 25211819Sjulian if ((!ipx_neteq(ipx->ipx_dna, ipx->ipx_sna)) && 25311819Sjulian (!ipx_neteqnn(ipx->ipx_dna.x_net, ipx_broadnet)) && 25411819Sjulian (!ipx_neteqnn(ipx->ipx_sna.x_net, ipx_zeronet)) && 25511819Sjulian (!ipx_neteqnn(ipx->ipx_dna.x_net, ipx_zeronet)) ) { 25611819Sjulian /* 25725652Sjhay * If it is a broadcast to the net where it was 25825652Sjhay * received from, treat it as ours. 25925652Sjhay */ 260194608Srwatson IPX_IFADDR_RLOCK(); 261194905Srwatson TAILQ_FOREACH(ia, &ipx_ifaddrhead, ia_link) { 262194905Srwatson if ((ia->ia_ifa.ifa_ifp == m->m_pkthdr.rcvif) 263194905Srwatson && ipx_neteq(ia->ia_addr.sipx_addr, 264194905Srwatson ipx->ipx_dna)) { 265194608Srwatson IPX_IFADDR_RUNLOCK(); 26625652Sjhay goto ours; 267194608Srwatson } 268194905Srwatson } 269194608Srwatson IPX_IFADDR_RUNLOCK(); 27025652Sjhay 27125652Sjhay /* 27211819Sjulian * Look to see if I need to eat this packet. 27311819Sjulian * Algorithm is to forward all young packets 27411819Sjulian * and prematurely age any packets which will 27511819Sjulian * by physically broadcasted. 27611819Sjulian * Any very old packets eaten without forwarding 27711819Sjulian * would die anyway. 27811819Sjulian * 27911819Sjulian * Suggestion of Bill Nesheim, Cornell U. 28011819Sjulian */ 28111819Sjulian if (ipx->ipx_tc < IPX_MAXHOPS) { 28211819Sjulian ipx_forward(m); 283111888Sjlemon return; 28411819Sjulian } 28511819Sjulian } 28611819Sjulian /* 28711819Sjulian * Is this our packet? If not, forward. 28811819Sjulian */ 28925652Sjhay } else { 290194608Srwatson IPX_IFADDR_RLOCK(); 291194905Srwatson TAILQ_FOREACH(ia, &ipx_ifaddrhead, ia_link) { 29225652Sjhay if (ipx_hosteq(ipx->ipx_dna, ia->ia_addr.sipx_addr) && 29325652Sjhay (ipx_neteq(ipx->ipx_dna, ia->ia_addr.sipx_addr) || 29425652Sjhay ipx_neteqnn(ipx->ipx_dna.x_net, ipx_zeronet))) 29525652Sjhay break; 296194905Srwatson } 297194608Srwatson IPX_IFADDR_RUNLOCK(); 29825652Sjhay if (ia == NULL) { 29925652Sjhay ipx_forward(m); 300111888Sjlemon return; 30125652Sjhay } 30211819Sjulian } 30325652Sjhayours: 30411819Sjulian /* 30511819Sjulian * Locate pcb for datagram. 30611819Sjulian */ 307139926Srwatson IPX_LIST_LOCK(); 30811819Sjulian ipxp = ipx_pcblookup(&ipx->ipx_sna, ipx->ipx_dna.x_port, IPX_WILDCARD); 30911819Sjulian /* 31011819Sjulian * Switch out to protocol's input routine. 31111819Sjulian */ 31225652Sjhay if (ipxp != NULL) { 31325652Sjhay ipxstat.ipxs_delivered++; 31425652Sjhay if ((ipxp->ipxp_flags & IPXP_ALL_PACKETS) == 0) 31511819Sjulian switch (ipx->ipx_pt) { 316111888Sjlemon case IPXPROTO_SPX: 317139932Srwatson IPX_LOCK(ipxp); 318139932Srwatson /* Will release both locks. */ 319111888Sjlemon spx_input(m, ipxp); 320111888Sjlemon return; 32111819Sjulian } 322139927Srwatson IPX_LOCK(ipxp); 32311819Sjulian ipx_input(m, ipxp); 324139927Srwatson IPX_UNLOCK(ipxp); 32526965Sjhay } else 326139923Srwatson m_freem(m); 327139926Srwatson IPX_LIST_UNLOCK(); 32811819Sjulian} 32911819Sjulian 33011819Sjulianvoid 33112881Sbdeipx_ctlinput(cmd, arg_as_sa, dummy) 33211819Sjulian int cmd; 33312881Sbde struct sockaddr *arg_as_sa; /* XXX should be swapped with dummy */ 33412881Sbde void *dummy; 33511819Sjulian{ 33611819Sjulian 337157050Srwatson /* Currently, nothing. */ 33811819Sjulian} 33911819Sjulian 34011819Sjulian/* 34125652Sjhay * Forward a packet. If some error occurs drop the packet. IPX don't 34225652Sjhay * have a way to return errors to the sender. 34325652Sjhay */ 34425652Sjhay 34533181Seivindstatic struct route ipx_droute; 34633181Seivindstatic struct route ipx_sroute; 34711819Sjulian 34825652Sjhaystatic void 349169463Srwatsonipx_forward(struct mbuf *m) 35011819Sjulian{ 351169463Srwatson struct ipx *ipx = mtod(m, struct ipx *); 352169463Srwatson int error; 35311819Sjulian int agedelta = 1; 35411819Sjulian int flags = IPX_FORWARDING; 35511819Sjulian int ok_there = 0; 35611819Sjulian int ok_back = 0; 35711819Sjulian 35811819Sjulian if (ipxforwarding == 0) { 35911819Sjulian /* can't tell difference between net and host */ 36025652Sjhay ipxstat.ipxs_cantforward++; 36125652Sjhay m_freem(m); 36225652Sjhay goto cleanup; 36311819Sjulian } 36411819Sjulian ipx->ipx_tc++; 36511819Sjulian if (ipx->ipx_tc > IPX_MAXHOPS) { 36625652Sjhay ipxstat.ipxs_cantforward++; 36725652Sjhay m_freem(m); 36825652Sjhay goto cleanup; 36911819Sjulian } 37025652Sjhay 37125652Sjhay if ((ok_there = ipx_do_route(&ipx->ipx_dna,&ipx_droute)) == 0) { 37225652Sjhay ipxstat.ipxs_noroute++; 37325652Sjhay m_freem(m); 37425652Sjhay goto cleanup; 37511819Sjulian } 37611819Sjulian /* 37711819Sjulian * Here we think about forwarding broadcast packets, 37811819Sjulian * so we try to insure that it doesn't go back out 37911819Sjulian * on the interface it came in on. Also, if we 38011819Sjulian * are going to physically broadcast this, let us 38111819Sjulian * age the packet so we can eat it safely the second time around. 38211819Sjulian */ 38311819Sjulian if (ipx->ipx_dna.x_host.c_host[0] & 0x1) { 384194608Srwatson struct ipx_ifaddr *ia; 38511819Sjulian struct ifnet *ifp; 386194608Srwatson 387194608Srwatson IPX_IFADDR_RLOCK(); 388194608Srwatson ia = ipx_iaonnetof(&ipx->ipx_dna); 38925652Sjhay if (ia != NULL) { 39011819Sjulian /* I'm gonna hafta eat this packet */ 39111819Sjulian agedelta += IPX_MAXHOPS - ipx->ipx_tc; 39211819Sjulian ipx->ipx_tc = IPX_MAXHOPS; 39311819Sjulian } 394194608Srwatson IPX_IFADDR_RUNLOCK(); 39525652Sjhay if ((ok_back = ipx_do_route(&ipx->ipx_sna,&ipx_sroute)) == 0) { 39611819Sjulian /* error = ENETUNREACH; He'll never get it! */ 39725652Sjhay ipxstat.ipxs_noroute++; 39811819Sjulian m_freem(m); 39911819Sjulian goto cleanup; 40011819Sjulian } 40111819Sjulian if (ipx_droute.ro_rt && 40225652Sjhay (ifp = ipx_droute.ro_rt->rt_ifp) && 40311819Sjulian ipx_sroute.ro_rt && 40425652Sjhay (ifp != ipx_sroute.ro_rt->rt_ifp)) { 40511819Sjulian flags |= IPX_ALLOWBROADCAST; 40611819Sjulian } else { 40725652Sjhay ipxstat.ipxs_noroute++; 40825652Sjhay m_freem(m); 40925652Sjhay goto cleanup; 41011819Sjulian } 41111819Sjulian } 41250519Sjhay /* 41350519Sjhay * We don't need to recompute checksum because ipx_tc field 41450519Sjhay * is ignored by checksum calculation routine, however 41550519Sjhay * it may be desirable to reset checksum if ipxcksum == 0 41625652Sjhay */ 41750519Sjhay#if 0 41850519Sjhay if (!ipxcksum) 41911819Sjulian ipx->ipx_sum = 0xffff; 42050519Sjhay#endif 42111819Sjulian 42211819Sjulian error = ipx_outputfl(m, &ipx_droute, flags); 42325652Sjhay if (error == 0) { 42425652Sjhay ipxstat.ipxs_forward++; 42511819Sjulian 42625652Sjhay if (ipxprintfs) { 42725652Sjhay printf("forward: "); 42825652Sjhay ipx_printhost(&ipx->ipx_sna); 42925652Sjhay printf(" to "); 43025652Sjhay ipx_printhost(&ipx->ipx_dna); 43125652Sjhay printf(" hops %d\n", ipx->ipx_tc); 43225652Sjhay } 433154320Srwatson } 43411819Sjuliancleanup: 43511819Sjulian if (ok_there) 43611819Sjulian ipx_undo_route(&ipx_droute); 43711819Sjulian if (ok_back) 43811819Sjulian ipx_undo_route(&ipx_sroute); 43911819Sjulian} 44011819Sjulian 44125652Sjhaystatic int 442169463Srwatsonipx_do_route(struct ipx_addr *src, struct route *ro) 44311819Sjulian{ 44411819Sjulian struct sockaddr_ipx *dst; 44511819Sjulian 44625652Sjhay bzero((caddr_t)ro, sizeof(*ro)); 44711819Sjulian dst = (struct sockaddr_ipx *)&ro->ro_dst; 44811819Sjulian 44911819Sjulian dst->sipx_len = sizeof(*dst); 45011819Sjulian dst->sipx_family = AF_IPX; 45111819Sjulian dst->sipx_addr = *src; 45211819Sjulian dst->sipx_addr.x_port = 0; 453139556Srwatson rtalloc_ign(ro, 0); 45425652Sjhay if (ro->ro_rt == NULL || ro->ro_rt->rt_ifp == NULL) { 45511819Sjulian return (0); 45611819Sjulian } 457263478Sglebius counter_u64_add(ro->ro_rt->rt_pksent, 1); 45811819Sjulian return (1); 45911819Sjulian} 46011819Sjulian 46125652Sjhaystatic void 462169463Srwatsonipx_undo_route(struct route *ro) 46311819Sjulian{ 464169463Srwatson 46525652Sjhay if (ro->ro_rt != NULL) { 46625652Sjhay RTFREE(ro->ro_rt); 46725652Sjhay } 46811819Sjulian} 469