1139823Simp/*- 2157094Srwatson * Copyright (c) 1984, 1985, 1986, 1987, 1993 3157094Srwatson * The Regents of the University of California. 4194905Srwatson * Copyright (c) 2004-2009 Robert N. M. Watson 5157094Srwatson * 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_pcb.c 6311819Sjulian */ 6411819Sjulian 65116189Sobrien#include <sys/cdefs.h> 66116189Sobrien__FBSDID("$FreeBSD: releng/10.2/sys/netipx/ipx_pcb.c 194905 2009-06-24 20:57:50Z rwatson $"); 67116189Sobrien 6811819Sjulian#include <sys/param.h> 6911819Sjulian#include <sys/systm.h> 7029024Sbde#include <sys/malloc.h> 71164033Srwatson#include <sys/priv.h> 7211819Sjulian#include <sys/socket.h> 7311819Sjulian#include <sys/socketvar.h> 7411819Sjulian 7511819Sjulian#include <net/if.h> 7611819Sjulian#include <net/route.h> 7711819Sjulian 7811819Sjulian#include <netipx/ipx.h> 7911819Sjulian#include <netipx/ipx_if.h> 8011819Sjulian#include <netipx/ipx_pcb.h> 8125652Sjhay#include <netipx/ipx_var.h> 8211819Sjulian 8333181Seivindstatic struct ipx_addr zeroipx_addr; 84139584Srwatsonstatic u_short ipxpcb_lport_cache; 8511819Sjulian 8611819Sjulianint 87169463Srwatsonipx_pcballoc(struct socket *so, struct ipxpcbhead *head, struct thread *td) 8811819Sjulian{ 89169463Srwatson struct ipxpcb *ipxp; 9011819Sjulian 91157094Srwatson KASSERT(so->so_pcb == NULL, ("ipx_pcballoc: so_pcb != NULL")); 92139928Srwatson IPX_LIST_LOCK_ASSERT(); 93139928Srwatson 94184205Sdes ipxp = malloc(sizeof *ipxp, M_PCB, M_NOWAIT | M_ZERO); 9528270Swollman if (ipxp == NULL) 9611819Sjulian return (ENOBUFS); 97139925Srwatson IPX_LOCK_INIT(ipxp); 9811819Sjulian ipxp->ipxp_socket = so; 9950519Sjhay if (ipxcksum) 10050519Sjhay ipxp->ipxp_flags |= IPXP_CHECKSUM; 101139444Srwatson LIST_INSERT_HEAD(head, ipxp, ipxp_list); 10211819Sjulian so->so_pcb = (caddr_t)ipxp; 10311819Sjulian return (0); 10411819Sjulian} 105139584Srwatson 10611819Sjulianint 107169463Srwatsonipx_pcbbind(struct ipxpcb *ipxp, struct sockaddr *nam, struct thread *td) 10811819Sjulian{ 109169463Srwatson struct sockaddr_ipx *sipx; 11011819Sjulian u_short lport = 0; 11111819Sjulian 112139928Srwatson IPX_LIST_LOCK_ASSERT(); 113139928Srwatson IPX_LOCK_ASSERT(ipxp); 114139928Srwatson 11511819Sjulian if (ipxp->ipxp_lport || !ipx_nullhost(ipxp->ipxp_laddr)) 11611819Sjulian return (EINVAL); 11725652Sjhay if (nam == NULL) 11811819Sjulian goto noname; 11928270Swollman sipx = (struct sockaddr_ipx *)nam; 12011819Sjulian if (!ipx_nullhost(sipx->sipx_addr)) { 12111819Sjulian int tport = sipx->sipx_port; 12211819Sjulian 12311819Sjulian sipx->sipx_port = 0; /* yech... */ 124194622Srwatson if (ifa_ifwithaddr_check((struct sockaddr *)sipx) == 0) 12511819Sjulian return (EADDRNOTAVAIL); 12611819Sjulian sipx->sipx_port = tport; 12711819Sjulian } 12811819Sjulian lport = sipx->sipx_port; 12911819Sjulian if (lport) { 13011819Sjulian u_short aport = ntohs(lport); 13111819Sjulian 132164033Srwatson if (aport < IPXPORT_RESERVED && td != NULL && 133164033Srwatson priv_check(td, PRIV_NETIPX_RESERVEDPORT)) 134164033Srwatson return (EACCES); 13511819Sjulian if (ipx_pcblookup(&zeroipx_addr, lport, 0)) 13611819Sjulian return (EADDRINUSE); 13711819Sjulian } 13811819Sjulian ipxp->ipxp_laddr = sipx->sipx_addr; 13911819Sjuliannoname: 14011819Sjulian if (lport == 0) 14111819Sjulian do { 142139445Srwatson ipxpcb_lport_cache++; 143139445Srwatson if ((ipxpcb_lport_cache < IPXPORT_RESERVED) || 144139445Srwatson (ipxpcb_lport_cache >= IPXPORT_WELLKNOWN)) 145139445Srwatson ipxpcb_lport_cache = IPXPORT_RESERVED; 146139445Srwatson lport = htons(ipxpcb_lport_cache); 14711819Sjulian } while (ipx_pcblookup(&zeroipx_addr, lport, 0)); 14811819Sjulian ipxp->ipxp_lport = lport; 14911819Sjulian return (0); 15011819Sjulian} 15111819Sjulian 15211819Sjulian/* 15311819Sjulian * Connect from a socket to a specified address. 15411819Sjulian * Both address and port must be specified in argument sipx. 15511819Sjulian * If don't have a local address for this socket yet, 15611819Sjulian * then pick one. 15711819Sjulian */ 15811819Sjulianint 159169463Srwatsonipx_pcbconnect(struct ipxpcb *ipxp, struct sockaddr *nam, struct thread *td) 16011819Sjulian{ 161169463Srwatson struct sockaddr_ipx *sipx = (struct sockaddr_ipx *)nam; 162169463Srwatson struct ipx_addr *dst; 163169463Srwatson struct route *ro; 16411819Sjulian struct ifnet *ifp; 16511819Sjulian 166139928Srwatson IPX_LIST_LOCK_ASSERT(); 167139928Srwatson IPX_LOCK_ASSERT(ipxp); 168139928Srwatson 16911819Sjulian if (sipx->sipx_family != AF_IPX) 17011819Sjulian return (EAFNOSUPPORT); 17125652Sjhay if (sipx->sipx_port == 0 || ipx_nullhost(sipx->sipx_addr)) 17211819Sjulian return (EADDRNOTAVAIL); 17311819Sjulian /* 17411819Sjulian * If we haven't bound which network number to use as ours, 17511819Sjulian * we will use the number of the outgoing interface. 17611819Sjulian * This depends on having done a routing lookup, which 17711819Sjulian * we will probably have to do anyway, so we might 17811819Sjulian * as well do it now. On the other hand if we are 17911819Sjulian * sending to multiple destinations we may have already 18011819Sjulian * done the lookup, so see if we can use the route 18111819Sjulian * from before. In any case, we only 18211819Sjulian * chose a port number once, even if sending to multiple 18311819Sjulian * destinations. 18411819Sjulian */ 18511819Sjulian ro = &ipxp->ipxp_route; 18611819Sjulian dst = &satoipx_addr(ro->ro_dst); 18797658Stanimura if (ipxp->ipxp_socket->so_options & SO_DONTROUTE) 18811819Sjulian goto flush; 18911819Sjulian if (!ipx_neteq(ipxp->ipxp_lastdst, sipx->sipx_addr)) 19011819Sjulian goto flush; 19111819Sjulian if (!ipx_hosteq(ipxp->ipxp_lastdst, sipx->sipx_addr)) { 19225652Sjhay if (ro->ro_rt != NULL && !(ro->ro_rt->rt_flags & RTF_HOST)) { 19311819Sjulian /* can patch route to avoid rtalloc */ 19411819Sjulian *dst = sipx->sipx_addr; 19511819Sjulian } else { 19611819Sjulian flush: 19725652Sjhay if (ro->ro_rt != NULL) 19811819Sjulian RTFREE(ro->ro_rt); 19925652Sjhay ro->ro_rt = NULL; 20011819Sjulian } 20111819Sjulian }/* else cached route is ok; do nothing */ 20211819Sjulian ipxp->ipxp_lastdst = sipx->sipx_addr; 20311819Sjulian if ((ipxp->ipxp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/ 20425652Sjhay (ro->ro_rt == NULL || ro->ro_rt->rt_ifp == NULL)) { 20511819Sjulian /* No route yet, so try to acquire one */ 20611819Sjulian ro->ro_dst.sa_family = AF_IPX; 20711819Sjulian ro->ro_dst.sa_len = sizeof(ro->ro_dst); 20811819Sjulian *dst = sipx->sipx_addr; 20911819Sjulian dst->x_port = 0; 210139556Srwatson rtalloc_ign(ro, 0); 21197658Stanimura } 21211819Sjulian if (ipx_neteqnn(ipxp->ipxp_laddr.x_net, ipx_zeronet)) { 213194760Srwatson struct ipx_ifaddr *ia = NULL; 214194760Srwatson 215139584Srwatson /* 21611819Sjulian * If route is known or can be allocated now, 21711819Sjulian * our src addr is taken from the i/f, else punt. 21811819Sjulian */ 21911819Sjulian 22011819Sjulian /* 22111819Sjulian * If we found a route, use the address 22211819Sjulian * corresponding to the outgoing interface 22311819Sjulian */ 224194608Srwatson if (ro->ro_rt != NULL && (ifp = ro->ro_rt->rt_ifp) != NULL) { 225194608Srwatson IPX_IFADDR_RLOCK(); 226194905Srwatson TAILQ_FOREACH(ia, &ipx_ifaddrhead, ia_link) { 227194760Srwatson if (ia->ia_ifp == ifp) { 228194760Srwatson ifa_ref(&ia->ia_ifa); 22911819Sjulian break; 230194760Srwatson } 231194905Srwatson } 232194608Srwatson IPX_IFADDR_RUNLOCK(); 233194608Srwatson } 23425652Sjhay if (ia == NULL) { 23511819Sjulian u_short fport = sipx->sipx_addr.x_port; 23611819Sjulian sipx->sipx_addr.x_port = 0; 23711819Sjulian ia = (struct ipx_ifaddr *) 23811819Sjulian ifa_ifwithdstaddr((struct sockaddr *)sipx); 23911819Sjulian sipx->sipx_addr.x_port = fport; 240194760Srwatson if (ia == NULL) { 241194760Srwatson IPX_IFADDR_RLOCK(); 24211819Sjulian ia = ipx_iaonnetof(&sipx->sipx_addr); 243194760Srwatson if (ia != NULL) 244194760Srwatson ifa_ref(&ia->ia_ifa); 245194760Srwatson IPX_IFADDR_RUNLOCK(); 246194760Srwatson } 247194760Srwatson if (ia == NULL) { 248194760Srwatson IPX_IFADDR_RLOCK(); 249194905Srwatson ia = TAILQ_FIRST(&ipx_ifaddrhead); 250194760Srwatson if (ia != NULL) 251194760Srwatson ifa_ref(&ia->ia_ifa); 252194760Srwatson IPX_IFADDR_RUNLOCK(); 253194760Srwatson } 25425652Sjhay if (ia == NULL) 25511819Sjulian return (EADDRNOTAVAIL); 25611819Sjulian } 25711819Sjulian ipxp->ipxp_laddr.x_net = satoipx_addr(ia->ia_addr).x_net; 258194760Srwatson ifa_free(&ia->ia_ifa); 25911819Sjulian } 26025652Sjhay if (ipx_nullhost(ipxp->ipxp_laddr)) { 261194760Srwatson struct ipx_ifaddr *ia = NULL; 262139584Srwatson /* 26325652Sjhay * If route is known or can be allocated now, 26425652Sjhay * our src addr is taken from the i/f, else punt. 26525652Sjhay */ 26625652Sjhay 26725652Sjhay /* 26825652Sjhay * If we found a route, use the address 26925652Sjhay * corresponding to the outgoing interface 27025652Sjhay */ 271194608Srwatson if (ro->ro_rt != NULL && (ifp = ro->ro_rt->rt_ifp) != NULL) { 272194608Srwatson IPX_IFADDR_RLOCK(); 273194905Srwatson TAILQ_FOREACH(ia, &ipx_ifaddrhead, ia_link) { 274194760Srwatson if (ia->ia_ifp == ifp) { 275194760Srwatson ifa_ref(&ia->ia_ifa); 27625652Sjhay break; 277194760Srwatson } 278194905Srwatson } 279194608Srwatson IPX_IFADDR_RUNLOCK(); 280194608Srwatson } 28125652Sjhay if (ia == NULL) { 28225652Sjhay u_short fport = sipx->sipx_addr.x_port; 28325652Sjhay sipx->sipx_addr.x_port = 0; 28425652Sjhay ia = (struct ipx_ifaddr *) 28525652Sjhay ifa_ifwithdstaddr((struct sockaddr *)sipx); 28625652Sjhay sipx->sipx_addr.x_port = fport; 287194608Srwatson if (ia == NULL) { 288194608Srwatson IPX_IFADDR_RLOCK(); 28925652Sjhay ia = ipx_iaonnetof(&sipx->sipx_addr); 290194760Srwatson if (ia != NULL) 291194760Srwatson ifa_ref(&ia->ia_ifa); 292194608Srwatson IPX_IFADDR_RUNLOCK(); 293194608Srwatson } 294194608Srwatson if (ia == NULL) { 295194608Srwatson IPX_IFADDR_RLOCK(); 296194905Srwatson ia = TAILQ_FIRST(&ipx_ifaddrhead); 297194760Srwatson if (ia != NULL) 298194760Srwatson ifa_ref(&ia->ia_ifa); 299194608Srwatson IPX_IFADDR_RUNLOCK(); 300194608Srwatson } 30125652Sjhay if (ia == NULL) 30225652Sjhay return (EADDRNOTAVAIL); 30325652Sjhay } 30425652Sjhay ipxp->ipxp_laddr.x_host = satoipx_addr(ia->ia_addr).x_host; 305194760Srwatson ifa_free(&ia->ia_ifa); 30625652Sjhay } 30711819Sjulian if (ipx_pcblookup(&sipx->sipx_addr, ipxp->ipxp_lport, 0)) 30811819Sjulian return (EADDRINUSE); 30925652Sjhay if (ipxp->ipxp_lport == 0) 31083366Sjulian ipx_pcbbind(ipxp, (struct sockaddr *)NULL, td); 31125652Sjhay 31225652Sjhay /* XXX just leave it zero if we can't find a route */ 31325652Sjhay 31411819Sjulian ipxp->ipxp_faddr = sipx->sipx_addr; 31511819Sjulian /* Includes ipxp->ipxp_fport = sipx->sipx_port; */ 31611819Sjulian return (0); 31711819Sjulian} 31811819Sjulian 31911819Sjulianvoid 320169463Srwatsonipx_pcbdisconnect(struct ipxpcb *ipxp) 32111819Sjulian{ 32211819Sjulian 323139928Srwatson IPX_LIST_LOCK_ASSERT(); 324139928Srwatson IPX_LOCK_ASSERT(ipxp); 325139928Srwatson 32611819Sjulian ipxp->ipxp_faddr = zeroipx_addr; 32711819Sjulian} 32811819Sjulian 32911819Sjulianvoid 330169463Srwatsonipx_pcbdetach(struct ipxpcb *ipxp) 33111819Sjulian{ 33211819Sjulian struct socket *so = ipxp->ipxp_socket; 33311819Sjulian 334139928Srwatson IPX_LIST_LOCK_ASSERT(); 335139928Srwatson IPX_LOCK_ASSERT(ipxp); 336139928Srwatson 337139559Srwatson so->so_pcb = NULL; 338157128Srwatson ipxp->ipxp_socket = NULL; 339157128Srwatson} 340157128Srwatson 341157128Srwatsonvoid 342169463Srwatsonipx_pcbfree(struct ipxpcb *ipxp) 343157128Srwatson{ 344157128Srwatson 345157128Srwatson KASSERT(ipxp->ipxp_socket == NULL, 346157128Srwatson ("ipx_pcbfree: ipxp_socket != NULL")); 347157128Srwatson IPX_LIST_LOCK_ASSERT(); 348157128Srwatson IPX_LOCK_ASSERT(ipxp); 349157128Srwatson 35025652Sjhay if (ipxp->ipxp_route.ro_rt != NULL) 351139557Srwatson RTFREE(ipxp->ipxp_route.ro_rt); 352139444Srwatson LIST_REMOVE(ipxp, ipxp_list); 353139925Srwatson IPX_LOCK_DESTROY(ipxp); 354184205Sdes free(ipxp, M_PCB); 35511819Sjulian} 35611819Sjulian 35711819Sjulianvoid 358169463Srwatsonipx_getsockaddr(struct ipxpcb *ipxp, struct sockaddr **nam) 35911819Sjulian{ 36028270Swollman struct sockaddr_ipx *sipx, ssipx; 361139584Srwatson 36228270Swollman sipx = &ssipx; 36325652Sjhay bzero((caddr_t)sipx, sizeof(*sipx)); 36411819Sjulian sipx->sipx_len = sizeof(*sipx); 36511819Sjulian sipx->sipx_family = AF_IPX; 366139928Srwatson IPX_LOCK(ipxp); 36711819Sjulian sipx->sipx_addr = ipxp->ipxp_laddr; 368139928Srwatson IPX_UNLOCK(ipxp); 369139924Srwatson *nam = sodupsockaddr((struct sockaddr *)sipx, M_WAITOK); 37011819Sjulian} 37111819Sjulian 37211819Sjulianvoid 373169463Srwatsonipx_getpeeraddr(struct ipxpcb *ipxp, struct sockaddr **nam) 37411819Sjulian{ 37528270Swollman struct sockaddr_ipx *sipx, ssipx; 376139928Srwatson 37728270Swollman sipx = &ssipx; 378139587Srwatson bzero(sipx, sizeof(*sipx)); 37911819Sjulian sipx->sipx_len = sizeof(*sipx); 38011819Sjulian sipx->sipx_family = AF_IPX; 381139928Srwatson IPX_LOCK(ipxp); 38211819Sjulian sipx->sipx_addr = ipxp->ipxp_faddr; 383139928Srwatson IPX_UNLOCK(ipxp); 384139587Srwatson *nam = sodupsockaddr((struct sockaddr *)sipx, M_WAITOK); 38511819Sjulian} 38611819Sjulian 38711819Sjulianstruct ipxpcb * 388169463Srwatsonipx_pcblookup(struct ipx_addr *faddr, u_short lport, int wildp) 38911819Sjulian{ 390169463Srwatson struct ipxpcb *ipxp, *match = NULL; 39111819Sjulian int matchwild = 3, wildcard; 39211819Sjulian u_short fport; 39311819Sjulian 394139928Srwatson IPX_LIST_LOCK_ASSERT(); 395139928Srwatson 39611819Sjulian fport = faddr->x_port; 397139444Srwatson LIST_FOREACH(ipxp, &ipxpcb_list, ipxp_list) { 39811819Sjulian if (ipxp->ipxp_lport != lport) 39911819Sjulian continue; 40011819Sjulian wildcard = 0; 40111819Sjulian if (ipx_nullhost(ipxp->ipxp_faddr)) { 40211819Sjulian if (!ipx_nullhost(*faddr)) 40311819Sjulian wildcard++; 40411819Sjulian } else { 40511819Sjulian if (ipx_nullhost(*faddr)) 40611819Sjulian wildcard++; 40711819Sjulian else { 40811819Sjulian if (!ipx_hosteq(ipxp->ipxp_faddr, *faddr)) 40911819Sjulian continue; 41011819Sjulian if (ipxp->ipxp_fport != fport) { 41111819Sjulian if (ipxp->ipxp_fport != 0) 41211819Sjulian continue; 41311819Sjulian else 41411819Sjulian wildcard++; 41511819Sjulian } 41611819Sjulian } 41711819Sjulian } 41825652Sjhay if (wildcard && wildp == 0) 41911819Sjulian continue; 42011819Sjulian if (wildcard < matchwild) { 42111819Sjulian match = ipxp; 42211819Sjulian matchwild = wildcard; 42311819Sjulian if (wildcard == 0) 42411819Sjulian break; 42511819Sjulian } 42611819Sjulian } 42711819Sjulian return (match); 42811819Sjulian} 429