ipx.c revision 194610
1139823Simp/*-
211819Sjulian * Copyright (c) 1984, 1985, 1986, 1987, 1993
3194610Srwatson *	The Regents of the University of California.
4194610Srwatson * Copyright (c) 2009 Robert N. M. Watson
5194610Srwatson * 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 *
33165899Srwatson * Redistribution and use in source and binary forms, with or without
34165899Srwatson * modification, are permitted provided that the following conditions
35165899Srwatson * are met:
36165899Srwatson * 1. Redistributions of source code must retain the above copyright
37165899Srwatson *    notice, this list of conditions and the following disclaimer.
38165899Srwatson * 2. Redistributions in binary form must reproduce the above copyright
39165899Srwatson *    notice, this list of conditions and the following disclaimer in the
40165899Srwatson *    documentation and/or other materials provided with the distribution.
4111819Sjulian * 3. All advertising materials mentioning features or use of this software
4211819Sjulian *    must display the following acknowledgement:
4311819Sjulian *	This product includes software developed by the University of
4411819Sjulian *	California, Berkeley and its contributors.
4511819Sjulian * 4. Neither the name of the University nor the names of its contributors
4611819Sjulian *    may be used to endorse or promote products derived from this software
4711819Sjulian *    without specific prior written permission.
4811819Sjulian *
4911819Sjulian * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
5011819Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
5111819Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
5211819Sjulian * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
5311819Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
5411819Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
5511819Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
5611819Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
5711819Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
5811819Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
5911819Sjulian * SUCH DAMAGE.
60139584Srwatson *
6112057Sjulian *	@(#)ipx.c
6211819Sjulian */
6311819Sjulian
64116189Sobrien#include <sys/cdefs.h>
65116189Sobrien__FBSDID("$FreeBSD: head/sys/netipx/ipx.c 194610 2009-06-21 21:42:29Z rwatson $");
66116189Sobrien
6711819Sjulian#include <sys/param.h>
68134445Srwatson#include <sys/kernel.h>
6911819Sjulian#include <sys/systm.h>
70194608Srwatson#include <sys/lock.h>
7126965Sjhay#include <sys/malloc.h>
72170689Srwatson#include <sys/priv.h>
73194608Srwatson#include <sys/rwlock.h>
7424204Sbde#include <sys/sockio.h>
7511819Sjulian#include <sys/socket.h>
7611819Sjulian
7711819Sjulian#include <net/if.h>
7811819Sjulian#include <net/route.h>
7911819Sjulian
8011819Sjulian#include <netipx/ipx.h>
8111819Sjulian#include <netipx/ipx_if.h>
8225652Sjhay#include <netipx/ipx_var.h>
8311819Sjulian
84134445Srwatson/*
85194608Srwatson * The IPX-layer address list is protected by ipx_ifaddr_rw.
86134445Srwatson */
87194608Srwatsonstruct rwlock		 ipx_ifaddr_rw;
88194608Srwatsonstruct ipx_ifaddr	*ipx_ifaddr;
8911819Sjulian
90194595Srwatsonstatic void	ipx_ifscrub(struct ifnet *ifp, struct ipx_ifaddr *ia);
91194595Srwatsonstatic int	ipx_ifinit(struct ifnet *ifp, struct ipx_ifaddr *ia,
92194595Srwatson		    struct sockaddr_ipx *sipx, int scrub);
9325652Sjhay
9411819Sjulian/*
9511819Sjulian * Generic internet control operations (ioctl's).
9611819Sjulian */
9711819Sjulianint
98169463Srwatsonipx_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp,
99169463Srwatson    struct thread *td)
10011819Sjulian{
101169463Srwatson	struct ifreq *ifr = (struct ifreq *)data;
102169463Srwatson	struct ipx_aliasreq *ifra = (struct ipx_aliasreq *)data;
103169463Srwatson	struct ipx_ifaddr *ia;
10411819Sjulian	struct ifaddr *ifa;
10511819Sjulian	struct ipx_ifaddr *oia;
10611819Sjulian	int dstIsNew, hostIsNew;
107183113Sattilio	int error = 0, priv;
10811819Sjulian
10911819Sjulian	/*
11011819Sjulian	 * Find address for this interface, if it exists.
11111819Sjulian	 */
11225652Sjhay	if (ifp == NULL)
11311819Sjulian		return (EADDRNOTAVAIL);
114194610Srwatson
115194610Srwatson	IPX_IFADDR_WLOCK();
11625652Sjhay	for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next)
11711819Sjulian		if (ia->ia_ifp == ifp)
11811819Sjulian			break;
11911819Sjulian
12011819Sjulian	switch (cmd) {
12111819Sjulian	case SIOCGIFADDR:
122194610Srwatson		if (ia == NULL) {
123194610Srwatson			error = EADDRNOTAVAIL;
124194610Srwatson			goto out;
125194610Srwatson		}
12611819Sjulian		*(struct sockaddr_ipx *)&ifr->ifr_addr = ia->ia_addr;
127194610Srwatson		goto out;
12811819Sjulian
12911819Sjulian	case SIOCGIFBRDADDR:
130194610Srwatson		if (ia == NULL) {
131194610Srwatson			error = EADDRNOTAVAIL;
132194610Srwatson			goto out;
133194610Srwatson		}
134194610Srwatson		if ((ifp->if_flags & IFF_BROADCAST) == 0) {
135194610Srwatson			error = EINVAL;
136194610Srwatson			goto out;
137194610Srwatson		}
13811819Sjulian		*(struct sockaddr_ipx *)&ifr->ifr_dstaddr = ia->ia_broadaddr;
139194610Srwatson		goto out;
14011819Sjulian
14111819Sjulian	case SIOCGIFDSTADDR:
142194610Srwatson		if (ia == NULL) {
143194610Srwatson			error = EADDRNOTAVAIL;
144194610Srwatson			goto out;
145194610Srwatson		}
146194610Srwatson		if ((ifp->if_flags & IFF_POINTOPOINT) == 0) {
147194610Srwatson			error = EINVAL;
148194610Srwatson			goto out;
149194610Srwatson		}
15011819Sjulian		*(struct sockaddr_ipx *)&ifr->ifr_dstaddr = ia->ia_dstaddr;
151194610Srwatson		goto out;
15211819Sjulian	}
15311819Sjulian
15411819Sjulian	switch (cmd) {
15511819Sjulian	case SIOCAIFADDR:
15611819Sjulian	case SIOCDIFADDR:
157183113Sattilio		priv = (cmd == SIOCAIFADDR) ? PRIV_NET_ADDIFADDR :
158183113Sattilio		    PRIV_NET_DELIFADDR;
159183113Sattilio		if (td && (error = priv_check(td, priv)) != 0)
160194610Srwatson			goto out;
16111819Sjulian		if (ifra->ifra_addr.sipx_family == AF_IPX)
16225652Sjhay		    for (oia = ia; ia != NULL; ia = ia->ia_next) {
16311819Sjulian			if (ia->ia_ifp == ifp  &&
16411819Sjulian			    ipx_neteq(ia->ia_addr.sipx_addr,
16511819Sjulian				  ifra->ifra_addr.sipx_addr))
16611819Sjulian			    break;
16711819Sjulian		    }
168194610Srwatson		if (cmd == SIOCDIFADDR && ia == NULL) {
169194610Srwatson			error = EADDRNOTAVAIL;
170194610Srwatson			goto out;
171194610Srwatson		}
17211819Sjulian		/* FALLTHROUGH */
17311819Sjulian
17411819Sjulian	case SIOCSIFADDR:
17511819Sjulian	case SIOCSIFDSTADDR:
176183113Sattilio		if (td && (error = priv_check(td, PRIV_NET_SETLLADDR)) != 0)
177194610Srwatson			goto out;
17825652Sjhay		if (ia == NULL) {
17911819Sjulian			oia = (struct ipx_ifaddr *)
18069781Sdwmalone				malloc(sizeof(*ia), M_IFADDR,
181194610Srwatson				M_NOWAIT | M_ZERO);
182194610Srwatson			if (oia == NULL) {
183194610Srwatson				error = ENOBUFS;
184194610Srwatson				goto out;
185194610Srwatson			}
18625652Sjhay			if ((ia = ipx_ifaddr) != NULL) {
18725652Sjhay				for ( ; ia->ia_next != NULL; ia = ia->ia_next)
18811819Sjulian					;
18911819Sjulian				ia->ia_next = oia;
19011819Sjulian			} else
19111819Sjulian				ipx_ifaddr = oia;
19211819Sjulian			ia = oia;
19320407Swollman			ifa = (struct ifaddr *)ia;
194194602Srwatson			ifa_init(ifa);
19511819Sjulian			ia->ia_ifp = ifp;
19620407Swollman			ifa->ifa_addr = (struct sockaddr *)&ia->ia_addr;
19720407Swollman			ifa->ifa_netmask = (struct sockaddr *)&ipx_netmask;
19820407Swollman			ifa->ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr;
19911819Sjulian			if (ifp->if_flags & IFF_BROADCAST) {
20011819Sjulian				ia->ia_broadaddr.sipx_family = AF_IPX;
201194595Srwatson				ia->ia_broadaddr.sipx_len =
202194595Srwatson				    sizeof(ia->ia_addr);
203194595Srwatson				ia->ia_broadaddr.sipx_addr.x_host =
204194595Srwatson				    ipx_broadhost;
20511819Sjulian			}
206194606Srwatson			IF_ADDR_LOCK(ifp);
207194606Srwatson			TAILQ_INSERT_TAIL(&ifp->if_addrhead, ifa, ifa_link);
208194606Srwatson			IF_ADDR_UNLOCK(ifp);
20911819Sjulian		}
210183113Sattilio		break;
211194595Srwatson
212183113Sattilio	default:
213183113Sattilio		if (td && (error = priv_check(td, PRIV_NET_HWIOCTL)) != 0)
214194610Srwatson			goto out;
21511819Sjulian	}
21611819Sjulian
21711819Sjulian	switch (cmd) {
21811819Sjulian	case SIOCSIFDSTADDR:
219194610Srwatson		if ((ifp->if_flags & IFF_POINTOPOINT) == 0) {
220194610Srwatson			error = EINVAL;
221194610Srwatson			goto out;
222194610Srwatson		}
22311819Sjulian		if (ia->ia_flags & IFA_ROUTE) {
22411819Sjulian			rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
22511819Sjulian			ia->ia_flags &= ~IFA_ROUTE;
22611819Sjulian		}
227194610Srwatson		ifa_ref(&ia->ia_ifa);
228194610Srwatson		IPX_IFADDR_WUNLOCK();
22911819Sjulian		if (ifp->if_ioctl) {
230194595Srwatson			error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR,
231194595Srwatson			    (void *)ia);
232194610Srwatson			if (error) {
233194610Srwatson				ifa_free(&ia->ia_ifa);
23411819Sjulian				return (error);
235194610Srwatson			}
23611819Sjulian		}
23711819Sjulian		*(struct sockaddr *)&ia->ia_dstaddr = ifr->ifr_dstaddr;
238194610Srwatson		ifa_free(&ia->ia_ifa);
23911819Sjulian		return (0);
24011819Sjulian
24111819Sjulian	case SIOCSIFADDR:
242194610Srwatson		ifa_ref(&ia->ia_ifa);
243194610Srwatson		IPX_IFADDR_WUNLOCK();
244194610Srwatson		error = ipx_ifinit(ifp, ia,
245194610Srwatson		    (struct sockaddr_ipx *)&ifr->ifr_addr, 1);
246194610Srwatson		ifa_free(&ia->ia_ifa);
247194610Srwatson		return (error);
24811819Sjulian
24911819Sjulian	case SIOCDIFADDR:
250194610Srwatson		/* XXXRW: Potential race here while ipx_ifaddr_rw is dropped. */
251194610Srwatson		ifa_ref(&ia->ia_ifa);
252194610Srwatson		IPX_IFADDR_WUNLOCK();
25311819Sjulian		ipx_ifscrub(ifp, ia);
254194610Srwatson		IPX_IFADDR_WLOCK();
255194610Srwatson		ifa_free(&ia->ia_ifa);
25620407Swollman		ifa = (struct ifaddr *)ia;
257194606Srwatson		IF_ADDR_LOCK(ifp);
25820407Swollman		TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link);
259194606Srwatson		IF_ADDR_UNLOCK(ifp);
26011819Sjulian		oia = ia;
26111819Sjulian		if (oia == (ia = ipx_ifaddr)) {
26211819Sjulian			ipx_ifaddr = ia->ia_next;
26311819Sjulian		} else {
26411819Sjulian			while (ia->ia_next && (ia->ia_next != oia)) {
26511819Sjulian				ia = ia->ia_next;
26611819Sjulian			}
26711819Sjulian			if (ia->ia_next)
26811819Sjulian			    ia->ia_next = oia->ia_next;
26911819Sjulian			else
27011819Sjulian				printf("Didn't unlink ipxifadr from list\n");
27111819Sjulian		}
272194602Srwatson		ifa_free(&oia->ia_ifa);
273194610Srwatson		IPX_IFADDR_WUNLOCK();
27411819Sjulian		return (0);
275139584Srwatson
27611819Sjulian	case SIOCAIFADDR:
27725652Sjhay		dstIsNew = 0;
27825652Sjhay		hostIsNew = 1;
27911819Sjulian		if (ia->ia_addr.sipx_family == AF_IPX) {
28011819Sjulian			if (ifra->ifra_addr.sipx_len == 0) {
28111819Sjulian				ifra->ifra_addr = ia->ia_addr;
28211819Sjulian				hostIsNew = 0;
28311819Sjulian			} else if (ipx_neteq(ifra->ifra_addr.sipx_addr,
28411819Sjulian					 ia->ia_addr.sipx_addr))
28511819Sjulian				hostIsNew = 0;
28611819Sjulian		}
287194610Srwatson		ifa_ref(&ia->ia_ifa);
288194610Srwatson		IPX_IFADDR_WUNLOCK();
28911819Sjulian		if ((ifp->if_flags & IFF_POINTOPOINT) &&
29011819Sjulian		    (ifra->ifra_dstaddr.sipx_family == AF_IPX)) {
29111819Sjulian			if (hostIsNew == 0)
29211819Sjulian				ipx_ifscrub(ifp, ia);
29311819Sjulian			ia->ia_dstaddr = ifra->ifra_dstaddr;
29411819Sjulian			dstIsNew  = 1;
29511819Sjulian		}
29611819Sjulian		if (ifra->ifra_addr.sipx_family == AF_IPX &&
29711819Sjulian					    (hostIsNew || dstIsNew))
29811819Sjulian			error = ipx_ifinit(ifp, ia, &ifra->ifra_addr, 0);
299194610Srwatson		ifa_free(&ia->ia_ifa);
30011819Sjulian		return (error);
30111819Sjulian
30211819Sjulian	default:
303194610Srwatson		IPX_IFADDR_WUNLOCK();
30425652Sjhay		if (ifp->if_ioctl == NULL)
30511819Sjulian			return (EOPNOTSUPP);
30611819Sjulian		return ((*ifp->if_ioctl)(ifp, cmd, data));
30711819Sjulian	}
308194610Srwatson
309194610Srwatsonout:
310194610Srwatson	IPX_IFADDR_WUNLOCK();
311194610Srwatson	return (error);
31211819Sjulian}
31311819Sjulian
31411819Sjulian/*
315194595Srwatson * Delete any previous route for an old address.
316194595Srwatson */
31725652Sjhaystatic void
318169463Srwatsonipx_ifscrub(struct ifnet *ifp, struct ipx_ifaddr *ia)
31911819Sjulian{
320169463Srwatson
32111819Sjulian	if (ia->ia_flags & IFA_ROUTE) {
32211819Sjulian		if (ifp->if_flags & IFF_POINTOPOINT) {
32311819Sjulian			rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
32411819Sjulian		} else
32511819Sjulian			rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0);
32611819Sjulian		ia->ia_flags &= ~IFA_ROUTE;
32711819Sjulian	}
32811819Sjulian}
329194595Srwatson
33011819Sjulian/*
331194595Srwatson * Initialize an interface's internet address and routing table entry.
33211819Sjulian */
33325652Sjhaystatic int
334169463Srwatsonipx_ifinit(struct ifnet *ifp, struct ipx_ifaddr *ia,
335169463Srwatson    struct sockaddr_ipx *sipx, int scrub)
33611819Sjulian{
33711819Sjulian	struct sockaddr_ipx oldaddr;
33811819Sjulian	int s = splimp(), error;
33911819Sjulian
34011819Sjulian	/*
34111819Sjulian	 * Set up new addresses.
34211819Sjulian	 */
34311819Sjulian	oldaddr = ia->ia_addr;
34411819Sjulian	ia->ia_addr = *sipx;
34525652Sjhay
34611819Sjulian	/*
347194595Srwatson	 * The convention we shall adopt for naming is that a supplied
348194595Srwatson	 * address of zero means that "we don't care".  Use the MAC address
349194595Srwatson	 * of the interface.  If it is an interface without a MAC address,
350194595Srwatson	 * like a serial line, the address must be supplied.
35111819Sjulian	 *
352194595Srwatson	 * Give the interface a chance to initialize if this is its first
353194595Srwatson	 * address, and to validate the address if necessary.
35411819Sjulian	 */
35525652Sjhay	if (ifp->if_ioctl != NULL &&
35625652Sjhay	    (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (void *)ia))) {
35711819Sjulian		ia->ia_addr = oldaddr;
35811819Sjulian		splx(s);
35925652Sjhay		return (error);
36011819Sjulian	}
36125652Sjhay	splx(s);
36211819Sjulian	ia->ia_ifa.ifa_metric = ifp->if_metric;
363194595Srwatson
36411819Sjulian	/*
36511819Sjulian	 * Add route for the network.
36611819Sjulian	 */
36711819Sjulian	if (scrub) {
36811819Sjulian		ia->ia_ifa.ifa_addr = (struct sockaddr *)&oldaddr;
36911819Sjulian		ipx_ifscrub(ifp, ia);
37011819Sjulian		ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
37111819Sjulian	}
37211819Sjulian	if (ifp->if_flags & IFF_POINTOPOINT)
37311819Sjulian		rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP);
37411819Sjulian	else {
37511819Sjulian		ia->ia_broadaddr.sipx_addr.x_net = ia->ia_addr.sipx_addr.x_net;
37611819Sjulian		rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_UP);
37711819Sjulian	}
37811819Sjulian	ia->ia_flags |= IFA_ROUTE;
37911819Sjulian	return (0);
38011819Sjulian}
38111819Sjulian
38211819Sjulian/*
38311819Sjulian * Return address info for specified internet network.
38411819Sjulian */
38511819Sjulianstruct ipx_ifaddr *
386169463Srwatsonipx_iaonnetof(struct ipx_addr *dst)
38711819Sjulian{
388169463Srwatson	struct ipx_ifaddr *ia;
389169463Srwatson	struct ipx_addr *compare;
390169463Srwatson	struct ifnet *ifp;
39125652Sjhay	struct ipx_ifaddr *ia_maybe = NULL;
39211819Sjulian	union ipx_net net = dst->x_net;
39311819Sjulian
394194608Srwatson	IPX_IFADDR_LOCK_ASSERT();
395194608Srwatson
39625652Sjhay	for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next) {
39725652Sjhay		if ((ifp = ia->ia_ifp) != NULL) {
39811819Sjulian			if (ifp->if_flags & IFF_POINTOPOINT) {
39911819Sjulian				compare = &satoipx_addr(ia->ia_dstaddr);
40011819Sjulian				if (ipx_hosteq(*dst, *compare))
40111819Sjulian					return (ia);
402194595Srwatson				if (ipx_neteqnn(net,
403194595Srwatson				    ia->ia_addr.sipx_addr.x_net))
40411819Sjulian					ia_maybe = ia;
40511819Sjulian			} else {
406194595Srwatson				if (ipx_neteqnn(net,
407194595Srwatson				    ia->ia_addr.sipx_addr.x_net))
40811819Sjulian					return (ia);
40911819Sjulian			}
41011819Sjulian		}
41111819Sjulian	}
41211819Sjulian	return (ia_maybe);
41311819Sjulian}
41426965Sjhay
41526965Sjhayvoid
416169463Srwatsonipx_printhost(struct ipx_addr *addr)
41726965Sjhay{
41826965Sjhay	u_short port;
41926965Sjhay	struct ipx_addr work = *addr;
420169463Srwatson	char *p; u_char *q;
421169463Srwatson	char *net = "", *host = "";
42226965Sjhay	char cport[10], chost[15], cnet[15];
42326965Sjhay
42426965Sjhay	port = ntohs(work.x_port);
42526965Sjhay
42626965Sjhay	if (ipx_nullnet(work) && ipx_nullhost(work)) {
42726965Sjhay		if (port)
42826965Sjhay			printf("*.%x", port);
42926965Sjhay		else
43026965Sjhay			printf("*.*");
43126965Sjhay
43226965Sjhay		return;
43326965Sjhay	}
43426965Sjhay
43526965Sjhay	if (ipx_wildnet(work))
43626965Sjhay		net = "any";
43726965Sjhay	else if (ipx_nullnet(work))
43826965Sjhay		net = "*";
43926965Sjhay	else {
44026965Sjhay		q = work.x_net.c_net;
44141514Sarchie		snprintf(cnet, sizeof(cnet), "%x%x%x%x",
44226965Sjhay			q[0], q[1], q[2], q[3]);
44326965Sjhay		for (p = cnet; *p == '0' && p < cnet + 8; p++)
44426965Sjhay			continue;
44526965Sjhay		net = p;
44626965Sjhay	}
44726965Sjhay
44826965Sjhay	if (ipx_wildhost(work))
44926965Sjhay		host = "any";
45026965Sjhay	else if (ipx_nullhost(work))
45126965Sjhay		host = "*";
45226965Sjhay	else {
45326965Sjhay		q = work.x_host.c_host;
45441514Sarchie		snprintf(chost, sizeof(chost), "%x%x%x%x%x%x",
45526965Sjhay			q[0], q[1], q[2], q[3], q[4], q[5]);
45626965Sjhay		for (p = chost; *p == '0' && p < chost + 12; p++)
45726965Sjhay			continue;
45826965Sjhay		host = p;
45926965Sjhay	}
46026965Sjhay
46126965Sjhay	if (port) {
46226965Sjhay		if (strcmp(host, "*") == 0) {
46326965Sjhay			host = "";
46441514Sarchie			snprintf(cport, sizeof(cport), "%x", port);
46526965Sjhay		} else
46641514Sarchie			snprintf(cport, sizeof(cport), ".%x", port);
46726965Sjhay	} else
46826965Sjhay		*cport = 0;
46926965Sjhay
47026965Sjhay	printf("%s.%s%s", net, host, cport);
47126965Sjhay}
472