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$");
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