ipx.c revision 41514
111819Sjulian/*
211819Sjulian * Copyright (c) 1995, Mike Mitchell
311819Sjulian * Copyright (c) 1984, 1985, 1986, 1987, 1993
411819Sjulian *	The Regents of the University of California.  All rights reserved.
511819Sjulian *
611819Sjulian * Redistribution and use in source and binary forms, with or without
711819Sjulian * modification, are permitted provided that the following conditions
811819Sjulian * are met:
911819Sjulian * 1. Redistributions of source code must retain the above copyright
1011819Sjulian *    notice, this list of conditions and the following disclaimer.
1111819Sjulian * 2. Redistributions in binary form must reproduce the above copyright
1211819Sjulian *    notice, this list of conditions and the following disclaimer in the
1311819Sjulian *    documentation and/or other materials provided with the distribution.
1411819Sjulian * 3. All advertising materials mentioning features or use of this software
1511819Sjulian *    must display the following acknowledgement:
1611819Sjulian *	This product includes software developed by the University of
1711819Sjulian *	California, Berkeley and its contributors.
1811819Sjulian * 4. Neither the name of the University nor the names of its contributors
1911819Sjulian *    may be used to endorse or promote products derived from this software
2011819Sjulian *    without specific prior written permission.
2111819Sjulian *
2211819Sjulian * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2311819Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2411819Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2511819Sjulian * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2611819Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2711819Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2811819Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2911819Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3011819Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3111819Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3211819Sjulian * SUCH DAMAGE.
3311819Sjulian *
3412057Sjulian *	@(#)ipx.c
3512057Sjulian *
3641514Sarchie * $Id: ipx.c,v 1.12 1998/06/07 17:12:18 dfr Exp $
3711819Sjulian */
3811819Sjulian
3911819Sjulian#include <sys/param.h>
4011819Sjulian#include <sys/systm.h>
4126965Sjhay#include <sys/malloc.h>
4224204Sbde#include <sys/sockio.h>
4325345Sjhay#include <sys/proc.h>
4411819Sjulian#include <sys/socket.h>
4511819Sjulian
4611819Sjulian#include <net/if.h>
4711819Sjulian#include <net/route.h>
4811819Sjulian
4911819Sjulian#include <netipx/ipx.h>
5011819Sjulian#include <netipx/ipx_if.h>
5125652Sjhay#include <netipx/ipx_var.h>
5211819Sjulian
5311819Sjulianstruct ipx_ifaddr *ipx_ifaddr;
5411819Sjulian
5525652Sjhaystatic	void ipx_ifscrub(struct ifnet *ifp, struct ipx_ifaddr *ia);
5625652Sjhaystatic	int ipx_ifinit(struct ifnet *ifp, struct ipx_ifaddr *ia,
5725652Sjhay		       struct sockaddr_ipx *sipx, int scrub);
5825652Sjhay
5911819Sjulian/*
6011819Sjulian * Generic internet control operations (ioctl's).
6111819Sjulian */
6211819Sjulianint
6325345Sjhayipx_control(so, cmd, data, ifp, p)
6411819Sjulian	struct socket *so;
6536735Sdfr	u_long cmd;
6611819Sjulian	caddr_t data;
6711819Sjulian	register struct ifnet *ifp;
6825345Sjhay	struct proc *p;
6911819Sjulian{
7011819Sjulian	register struct ifreq *ifr = (struct ifreq *)data;
7111819Sjulian	register struct ipx_aliasreq *ifra = (struct ipx_aliasreq *)data;
7211819Sjulian	register struct ipx_ifaddr *ia;
7311819Sjulian	struct ifaddr *ifa;
7411819Sjulian	struct ipx_ifaddr *oia;
7511819Sjulian	int dstIsNew, hostIsNew;
7611819Sjulian	int error = 0;
7711819Sjulian
7811819Sjulian	/*
7911819Sjulian	 * Find address for this interface, if it exists.
8011819Sjulian	 */
8125652Sjhay	if (ifp == NULL)
8211819Sjulian		return (EADDRNOTAVAIL);
8325652Sjhay	for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next)
8411819Sjulian		if (ia->ia_ifp == ifp)
8511819Sjulian			break;
8611819Sjulian
8711819Sjulian	switch (cmd) {
8811819Sjulian
8911819Sjulian	case SIOCGIFADDR:
9025652Sjhay		if (ia == NULL)
9111819Sjulian			return (EADDRNOTAVAIL);
9211819Sjulian		*(struct sockaddr_ipx *)&ifr->ifr_addr = ia->ia_addr;
9311819Sjulian		return (0);
9411819Sjulian
9511819Sjulian	case SIOCGIFBRDADDR:
9625652Sjhay		if (ia == NULL)
9711819Sjulian			return (EADDRNOTAVAIL);
9811819Sjulian		if ((ifp->if_flags & IFF_BROADCAST) == 0)
9911819Sjulian			return (EINVAL);
10011819Sjulian		*(struct sockaddr_ipx *)&ifr->ifr_dstaddr = ia->ia_broadaddr;
10111819Sjulian		return (0);
10211819Sjulian
10311819Sjulian	case SIOCGIFDSTADDR:
10425652Sjhay		if (ia == NULL)
10511819Sjulian			return (EADDRNOTAVAIL);
10611819Sjulian		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
10711819Sjulian			return (EINVAL);
10811819Sjulian		*(struct sockaddr_ipx *)&ifr->ifr_dstaddr = ia->ia_dstaddr;
10911819Sjulian		return (0);
11011819Sjulian	}
11111819Sjulian
11225345Sjhay	if (p && (error = suser(p->p_ucred, &p->p_acflag)) != 0)
11325345Sjhay		return (error);
11411819Sjulian
11511819Sjulian	switch (cmd) {
11611819Sjulian	case SIOCAIFADDR:
11711819Sjulian	case SIOCDIFADDR:
11811819Sjulian		if (ifra->ifra_addr.sipx_family == AF_IPX)
11925652Sjhay		    for (oia = ia; ia != NULL; ia = ia->ia_next) {
12011819Sjulian			if (ia->ia_ifp == ifp  &&
12111819Sjulian			    ipx_neteq(ia->ia_addr.sipx_addr,
12211819Sjulian				  ifra->ifra_addr.sipx_addr))
12311819Sjulian			    break;
12411819Sjulian		    }
12525652Sjhay		if (cmd == SIOCDIFADDR && ia == NULL)
12611819Sjulian			return (EADDRNOTAVAIL);
12711819Sjulian		/* FALLTHROUGH */
12811819Sjulian
12911819Sjulian	case SIOCSIFADDR:
13011819Sjulian	case SIOCSIFDSTADDR:
13125652Sjhay		if (ia == NULL) {
13211819Sjulian			oia = (struct ipx_ifaddr *)
13325652Sjhay				malloc(sizeof(*ia), M_IFADDR, M_WAITOK);
13425652Sjhay			if (oia == NULL)
13511819Sjulian				return (ENOBUFS);
13611819Sjulian			bzero((caddr_t)oia, sizeof(*oia));
13725652Sjhay			if ((ia = ipx_ifaddr) != NULL) {
13825652Sjhay				for ( ; ia->ia_next != NULL; ia = ia->ia_next)
13911819Sjulian					;
14011819Sjulian				ia->ia_next = oia;
14111819Sjulian			} else
14211819Sjulian				ipx_ifaddr = oia;
14311819Sjulian			ia = oia;
14420407Swollman			ifa = (struct ifaddr *)ia;
14520407Swollman			TAILQ_INSERT_TAIL(&ifp->if_addrhead, ifa, ifa_link);
14611819Sjulian			ia->ia_ifp = ifp;
14720407Swollman			ifa->ifa_addr = (struct sockaddr *)&ia->ia_addr;
14811819Sjulian
14920407Swollman			ifa->ifa_netmask = (struct sockaddr *)&ipx_netmask;
15011819Sjulian
15120407Swollman			ifa->ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr;
15211819Sjulian			if (ifp->if_flags & IFF_BROADCAST) {
15311819Sjulian				ia->ia_broadaddr.sipx_family = AF_IPX;
15411819Sjulian				ia->ia_broadaddr.sipx_len = sizeof(ia->ia_addr);
15511819Sjulian				ia->ia_broadaddr.sipx_addr.x_host = ipx_broadhost;
15611819Sjulian			}
15711819Sjulian		}
15811819Sjulian	}
15911819Sjulian
16011819Sjulian	switch (cmd) {
16111819Sjulian
16211819Sjulian	case SIOCSIFDSTADDR:
16311819Sjulian		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
16411819Sjulian			return (EINVAL);
16511819Sjulian		if (ia->ia_flags & IFA_ROUTE) {
16611819Sjulian			rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
16711819Sjulian			ia->ia_flags &= ~IFA_ROUTE;
16811819Sjulian		}
16911819Sjulian		if (ifp->if_ioctl) {
17011819Sjulian			error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, (void *)ia);
17111819Sjulian			if (error)
17211819Sjulian				return (error);
17311819Sjulian		}
17411819Sjulian		*(struct sockaddr *)&ia->ia_dstaddr = ifr->ifr_dstaddr;
17511819Sjulian		return (0);
17611819Sjulian
17711819Sjulian	case SIOCSIFADDR:
17811819Sjulian		return (ipx_ifinit(ifp, ia,
17911819Sjulian				(struct sockaddr_ipx *)&ifr->ifr_addr, 1));
18011819Sjulian
18111819Sjulian	case SIOCDIFADDR:
18211819Sjulian		ipx_ifscrub(ifp, ia);
18320407Swollman		ifa = (struct ifaddr *)ia;
18420407Swollman		TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link);
18511819Sjulian		oia = ia;
18611819Sjulian		if (oia == (ia = ipx_ifaddr)) {
18711819Sjulian			ipx_ifaddr = ia->ia_next;
18811819Sjulian		} else {
18911819Sjulian			while (ia->ia_next && (ia->ia_next != oia)) {
19011819Sjulian				ia = ia->ia_next;
19111819Sjulian			}
19211819Sjulian			if (ia->ia_next)
19311819Sjulian			    ia->ia_next = oia->ia_next;
19411819Sjulian			else
19511819Sjulian				printf("Didn't unlink ipxifadr from list\n");
19611819Sjulian		}
19711819Sjulian		IFAFREE((&oia->ia_ifa));
19811819Sjulian		return (0);
19911819Sjulian
20011819Sjulian	case SIOCAIFADDR:
20125652Sjhay		dstIsNew = 0;
20225652Sjhay		hostIsNew = 1;
20311819Sjulian		if (ia->ia_addr.sipx_family == AF_IPX) {
20411819Sjulian			if (ifra->ifra_addr.sipx_len == 0) {
20511819Sjulian				ifra->ifra_addr = ia->ia_addr;
20611819Sjulian				hostIsNew = 0;
20711819Sjulian			} else if (ipx_neteq(ifra->ifra_addr.sipx_addr,
20811819Sjulian					 ia->ia_addr.sipx_addr))
20911819Sjulian				hostIsNew = 0;
21011819Sjulian		}
21111819Sjulian		if ((ifp->if_flags & IFF_POINTOPOINT) &&
21211819Sjulian		    (ifra->ifra_dstaddr.sipx_family == AF_IPX)) {
21311819Sjulian			if (hostIsNew == 0)
21411819Sjulian				ipx_ifscrub(ifp, ia);
21511819Sjulian			ia->ia_dstaddr = ifra->ifra_dstaddr;
21611819Sjulian			dstIsNew  = 1;
21711819Sjulian		}
21811819Sjulian		if (ifra->ifra_addr.sipx_family == AF_IPX &&
21911819Sjulian					    (hostIsNew || dstIsNew))
22011819Sjulian			error = ipx_ifinit(ifp, ia, &ifra->ifra_addr, 0);
22111819Sjulian		return (error);
22211819Sjulian
22311819Sjulian	default:
22425652Sjhay		if (ifp->if_ioctl == NULL)
22511819Sjulian			return (EOPNOTSUPP);
22611819Sjulian		return ((*ifp->if_ioctl)(ifp, cmd, data));
22711819Sjulian	}
22811819Sjulian}
22911819Sjulian
23011819Sjulian/*
23111819Sjulian* Delete any previous route for an old address.
23211819Sjulian*/
23325652Sjhaystatic void
23411819Sjulianipx_ifscrub(ifp, ia)
23511819Sjulian	register struct ifnet *ifp;
23611819Sjulian	register struct ipx_ifaddr *ia;
23711819Sjulian{
23811819Sjulian	if (ia->ia_flags & IFA_ROUTE) {
23911819Sjulian		if (ifp->if_flags & IFF_POINTOPOINT) {
24011819Sjulian			rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
24111819Sjulian		} else
24211819Sjulian			rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0);
24311819Sjulian		ia->ia_flags &= ~IFA_ROUTE;
24411819Sjulian	}
24511819Sjulian}
24611819Sjulian/*
24711819Sjulian * Initialize an interface's internet address
24811819Sjulian * and routing table entry.
24911819Sjulian */
25025652Sjhaystatic int
25111819Sjulianipx_ifinit(ifp, ia, sipx, scrub)
25211819Sjulian	register struct ifnet *ifp;
25311819Sjulian	register struct ipx_ifaddr *ia;
25411819Sjulian	register struct sockaddr_ipx *sipx;
25511819Sjulian	int scrub;
25611819Sjulian{
25711819Sjulian	struct sockaddr_ipx oldaddr;
25811819Sjulian	int s = splimp(), error;
25911819Sjulian
26011819Sjulian	/*
26111819Sjulian	 * Set up new addresses.
26211819Sjulian	 */
26311819Sjulian	oldaddr = ia->ia_addr;
26411819Sjulian	ia->ia_addr = *sipx;
26525652Sjhay
26611819Sjulian	/*
26711819Sjulian	 * The convention we shall adopt for naming is that
26811819Sjulian	 * a supplied address of zero means that "we don't care".
26925652Sjhay	 * Use the MAC address of the interface. If it is an
27025652Sjhay	 * interface without a MAC address, like a serial line, the
27125652Sjhay	 * address must be supplied.
27211819Sjulian	 *
27311819Sjulian	 * Give the interface a chance to initialize
27411819Sjulian	 * if this is its first address,
27511819Sjulian	 * and to validate the address if necessary.
27611819Sjulian	 */
27725652Sjhay	if (ifp->if_ioctl != NULL &&
27825652Sjhay	    (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (void *)ia))) {
27911819Sjulian		ia->ia_addr = oldaddr;
28011819Sjulian		splx(s);
28125652Sjhay		return (error);
28211819Sjulian	}
28325652Sjhay	splx(s);
28411819Sjulian	ia->ia_ifa.ifa_metric = ifp->if_metric;
28511819Sjulian	/*
28611819Sjulian	 * Add route for the network.
28711819Sjulian	 */
28811819Sjulian	if (scrub) {
28911819Sjulian		ia->ia_ifa.ifa_addr = (struct sockaddr *)&oldaddr;
29011819Sjulian		ipx_ifscrub(ifp, ia);
29111819Sjulian		ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
29211819Sjulian	}
29311819Sjulian	if (ifp->if_flags & IFF_POINTOPOINT)
29411819Sjulian		rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP);
29511819Sjulian	else {
29611819Sjulian		ia->ia_broadaddr.sipx_addr.x_net = ia->ia_addr.sipx_addr.x_net;
29711819Sjulian		rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_UP);
29811819Sjulian	}
29911819Sjulian	ia->ia_flags |= IFA_ROUTE;
30011819Sjulian	return (0);
30111819Sjulian}
30211819Sjulian
30311819Sjulian/*
30411819Sjulian * Return address info for specified internet network.
30511819Sjulian */
30611819Sjulianstruct ipx_ifaddr *
30711819Sjulianipx_iaonnetof(dst)
30811819Sjulian	register struct ipx_addr *dst;
30911819Sjulian{
31011819Sjulian	register struct ipx_ifaddr *ia;
31111819Sjulian	register struct ipx_addr *compare;
31211819Sjulian	register struct ifnet *ifp;
31325652Sjhay	struct ipx_ifaddr *ia_maybe = NULL;
31411819Sjulian	union ipx_net net = dst->x_net;
31511819Sjulian
31625652Sjhay	for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next) {
31725652Sjhay		if ((ifp = ia->ia_ifp) != NULL) {
31811819Sjulian			if (ifp->if_flags & IFF_POINTOPOINT) {
31911819Sjulian				compare = &satoipx_addr(ia->ia_dstaddr);
32011819Sjulian				if (ipx_hosteq(*dst, *compare))
32111819Sjulian					return (ia);
32211819Sjulian				if (ipx_neteqnn(net, ia->ia_addr.sipx_addr.x_net))
32311819Sjulian					ia_maybe = ia;
32411819Sjulian			} else {
32511819Sjulian				if (ipx_neteqnn(net, ia->ia_addr.sipx_addr.x_net))
32611819Sjulian					return (ia);
32711819Sjulian			}
32811819Sjulian		}
32911819Sjulian	}
33011819Sjulian	return (ia_maybe);
33111819Sjulian}
33226965Sjhay
33326965Sjhay
33426965Sjhayvoid
33526965Sjhayipx_printhost(addr)
33626965Sjhayregister struct ipx_addr *addr;
33726965Sjhay{
33826965Sjhay	u_short port;
33926965Sjhay	struct ipx_addr work = *addr;
34026965Sjhay	register char *p; register u_char *q;
34126965Sjhay	register char *net = "", *host = "";
34226965Sjhay	char cport[10], chost[15], cnet[15];
34326965Sjhay
34426965Sjhay	port = ntohs(work.x_port);
34526965Sjhay
34626965Sjhay	if (ipx_nullnet(work) && ipx_nullhost(work)) {
34726965Sjhay
34826965Sjhay		if (port)
34926965Sjhay			printf("*.%x", port);
35026965Sjhay		else
35126965Sjhay			printf("*.*");
35226965Sjhay
35326965Sjhay		return;
35426965Sjhay	}
35526965Sjhay
35626965Sjhay	if (ipx_wildnet(work))
35726965Sjhay		net = "any";
35826965Sjhay	else if (ipx_nullnet(work))
35926965Sjhay		net = "*";
36026965Sjhay	else {
36126965Sjhay		q = work.x_net.c_net;
36241514Sarchie		snprintf(cnet, sizeof(cnet), "%x%x%x%x",
36326965Sjhay			q[0], q[1], q[2], q[3]);
36426965Sjhay		for (p = cnet; *p == '0' && p < cnet + 8; p++)
36526965Sjhay			continue;
36626965Sjhay		net = p;
36726965Sjhay	}
36826965Sjhay
36926965Sjhay	if (ipx_wildhost(work))
37026965Sjhay		host = "any";
37126965Sjhay	else if (ipx_nullhost(work))
37226965Sjhay		host = "*";
37326965Sjhay	else {
37426965Sjhay		q = work.x_host.c_host;
37541514Sarchie		snprintf(chost, sizeof(chost), "%x%x%x%x%x%x",
37626965Sjhay			q[0], q[1], q[2], q[3], q[4], q[5]);
37726965Sjhay		for (p = chost; *p == '0' && p < chost + 12; p++)
37826965Sjhay			continue;
37926965Sjhay		host = p;
38026965Sjhay	}
38126965Sjhay
38226965Sjhay	if (port) {
38326965Sjhay		if (strcmp(host, "*") == 0) {
38426965Sjhay			host = "";
38541514Sarchie			snprintf(cport, sizeof(cport), "%x", port);
38626965Sjhay		} else
38741514Sarchie			snprintf(cport, sizeof(cport), ".%x", port);
38826965Sjhay	} else
38926965Sjhay		*cport = 0;
39026965Sjhay
39126965Sjhay	printf("%s.%s%s", net, host, cport);
39226965Sjhay}
393