ipx.c revision 24204
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 *
3624204Sbde * $Id: ipx.c,v 1.7 1997/02/22 09:41:51 peter Exp $
3711819Sjulian */
3811819Sjulian
3911819Sjulian#include <sys/param.h>
4014546Sdg#include <sys/queue.h>
4111819Sjulian#include <sys/systm.h>
4211819Sjulian#include <sys/mbuf.h>
4324204Sbde#include <sys/sockio.h>
4411819Sjulian#include <sys/protosw.h>
4511819Sjulian#include <sys/errno.h>
4611819Sjulian#include <sys/socket.h>
4711819Sjulian#include <sys/socketvar.h>
4811819Sjulian
4911819Sjulian#include <net/if.h>
5011819Sjulian#include <net/route.h>
5111819Sjulian
5211819Sjulian#include <netipx/ipx.h>
5311819Sjulian#include <netipx/ipx_if.h>
5411819Sjulian
5511819Sjulian#ifdef IPX
5611819Sjulian
5711819Sjulianstruct ipx_ifaddr *ipx_ifaddr;
5811819Sjulianint ipx_interfaces;
5911819Sjulian
6011819Sjulian/*
6111819Sjulian * Generic internet control operations (ioctl's).
6211819Sjulian */
6311819Sjulian/* ARGSUSED */
6411819Sjulianint
6511819Sjulianipx_control(so, cmd, data, ifp)
6611819Sjulian	struct socket *so;
6711819Sjulian	int cmd;
6811819Sjulian	caddr_t data;
6911819Sjulian	register struct ifnet *ifp;
7011819Sjulian{
7111819Sjulian	register struct ifreq *ifr = (struct ifreq *)data;
7211819Sjulian	register struct ipx_aliasreq *ifra = (struct ipx_aliasreq *)data;
7311819Sjulian	register struct ipx_ifaddr *ia;
7411819Sjulian	struct ifaddr *ifa;
7511819Sjulian	struct ipx_ifaddr *oia;
7611819Sjulian	int dstIsNew, hostIsNew;
7711819Sjulian	int error = 0;
7811819Sjulian
7911819Sjulian	/*
8011819Sjulian	 * Find address for this interface, if it exists.
8111819Sjulian	 */
8211819Sjulian	if (ifp == 0)
8311819Sjulian		return (EADDRNOTAVAIL);
8411819Sjulian	for (ia = ipx_ifaddr; ia; ia = ia->ia_next)
8511819Sjulian		if (ia->ia_ifp == ifp)
8611819Sjulian			break;
8711819Sjulian
8811819Sjulian	switch (cmd) {
8911819Sjulian
9011819Sjulian	case SIOCGIFADDR:
9111819Sjulian		if (ia == (struct ipx_ifaddr *)0)
9211819Sjulian			return (EADDRNOTAVAIL);
9311819Sjulian		*(struct sockaddr_ipx *)&ifr->ifr_addr = ia->ia_addr;
9411819Sjulian		return (0);
9511819Sjulian
9611819Sjulian	case SIOCGIFBRDADDR:
9711819Sjulian		if (ia == (struct ipx_ifaddr *)0)
9811819Sjulian			return (EADDRNOTAVAIL);
9911819Sjulian		if ((ifp->if_flags & IFF_BROADCAST) == 0)
10011819Sjulian			return (EINVAL);
10111819Sjulian		*(struct sockaddr_ipx *)&ifr->ifr_dstaddr = ia->ia_broadaddr;
10211819Sjulian		return (0);
10311819Sjulian
10411819Sjulian	case SIOCGIFDSTADDR:
10511819Sjulian		if (ia == (struct ipx_ifaddr *)0)
10611819Sjulian			return (EADDRNOTAVAIL);
10711819Sjulian		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
10811819Sjulian			return (EINVAL);
10911819Sjulian		*(struct sockaddr_ipx *)&ifr->ifr_dstaddr = ia->ia_dstaddr;
11011819Sjulian		return (0);
11111819Sjulian	}
11211819Sjulian
11311819Sjulian	if ((so->so_state & SS_PRIV) == 0)
11411819Sjulian		return (EPERM);
11511819Sjulian
11611819Sjulian	switch (cmd) {
11711819Sjulian	case SIOCAIFADDR:
11811819Sjulian	case SIOCDIFADDR:
11911819Sjulian		if (ifra->ifra_addr.sipx_family == AF_IPX)
12011819Sjulian		    for (oia = ia; ia; ia = ia->ia_next) {
12111819Sjulian			if (ia->ia_ifp == ifp  &&
12211819Sjulian			    ipx_neteq(ia->ia_addr.sipx_addr,
12311819Sjulian				  ifra->ifra_addr.sipx_addr))
12411819Sjulian			    break;
12511819Sjulian		    }
12611819Sjulian		if (cmd == SIOCDIFADDR && ia == 0)
12711819Sjulian			return (EADDRNOTAVAIL);
12811819Sjulian		/* FALLTHROUGH */
12911819Sjulian
13011819Sjulian	case SIOCSIFADDR:
13111819Sjulian	case SIOCSIFDSTADDR:
13211819Sjulian		if (ia == (struct ipx_ifaddr *)0) {
13311819Sjulian			oia = (struct ipx_ifaddr *)
13411819Sjulian				malloc(sizeof *ia, M_IFADDR, M_WAITOK);
13511819Sjulian			if (oia == (struct ipx_ifaddr *)NULL)
13611819Sjulian				return (ENOBUFS);
13711819Sjulian			bzero((caddr_t)oia, sizeof(*oia));
13811819Sjulian			if ((ia = ipx_ifaddr)) {
13911819Sjulian				for ( ; ia->ia_next; ia = ia->ia_next)
14011819Sjulian					;
14111819Sjulian				ia->ia_next = oia;
14211819Sjulian			} else
14311819Sjulian				ipx_ifaddr = oia;
14411819Sjulian			ia = oia;
14520407Swollman			ifa = (struct ifaddr *)ia;
14620407Swollman			TAILQ_INSERT_TAIL(&ifp->if_addrhead, ifa, ifa_link);
14711819Sjulian			ia->ia_ifp = ifp;
14820407Swollman			ifa->ifa_addr = (struct sockaddr *)&ia->ia_addr;
14911819Sjulian
15020407Swollman			ifa->ifa_netmask = (struct sockaddr *)&ipx_netmask;
15111819Sjulian
15220407Swollman			ifa->ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr;
15311819Sjulian			if (ifp->if_flags & IFF_BROADCAST) {
15411819Sjulian				ia->ia_broadaddr.sipx_family = AF_IPX;
15511819Sjulian				ia->ia_broadaddr.sipx_len = sizeof(ia->ia_addr);
15611819Sjulian				ia->ia_broadaddr.sipx_addr.x_host = ipx_broadhost;
15711819Sjulian			}
15811819Sjulian			ipx_interfaces++;
15911819Sjulian		}
16011819Sjulian	}
16111819Sjulian
16211819Sjulian	switch (cmd) {
16311819Sjulian
16411819Sjulian	case SIOCSIFDSTADDR:
16511819Sjulian		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
16611819Sjulian			return (EINVAL);
16711819Sjulian		if (ia->ia_flags & IFA_ROUTE) {
16811819Sjulian			rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
16911819Sjulian			ia->ia_flags &= ~IFA_ROUTE;
17011819Sjulian		}
17111819Sjulian		if (ifp->if_ioctl) {
17211819Sjulian			error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, (void *)ia);
17311819Sjulian			if (error)
17411819Sjulian				return (error);
17511819Sjulian		}
17611819Sjulian		*(struct sockaddr *)&ia->ia_dstaddr = ifr->ifr_dstaddr;
17711819Sjulian		return (0);
17811819Sjulian
17911819Sjulian	case SIOCSIFADDR:
18011819Sjulian		return (ipx_ifinit(ifp, ia,
18111819Sjulian				(struct sockaddr_ipx *)&ifr->ifr_addr, 1));
18211819Sjulian
18311819Sjulian	case SIOCDIFADDR:
18411819Sjulian		ipx_ifscrub(ifp, ia);
18520407Swollman		ifa = (struct ifaddr *)ia;
18620407Swollman		TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link);
18711819Sjulian		oia = ia;
18811819Sjulian		if (oia == (ia = ipx_ifaddr)) {
18911819Sjulian			ipx_ifaddr = ia->ia_next;
19011819Sjulian		} else {
19111819Sjulian			while (ia->ia_next && (ia->ia_next != oia)) {
19211819Sjulian				ia = ia->ia_next;
19311819Sjulian			}
19411819Sjulian			if (ia->ia_next)
19511819Sjulian			    ia->ia_next = oia->ia_next;
19611819Sjulian			else
19711819Sjulian				printf("Didn't unlink ipxifadr from list\n");
19811819Sjulian		}
19911819Sjulian		IFAFREE((&oia->ia_ifa));
20011819Sjulian		if (0 == --ipx_interfaces) {
20111819Sjulian			/*
20211819Sjulian			 * We reset to virginity and start all over again
20311819Sjulian			 */
20411819Sjulian			ipx_thishost = ipx_zerohost;
20511819Sjulian		}
20611819Sjulian		return (0);
20711819Sjulian
20811819Sjulian	case SIOCAIFADDR:
20911819Sjulian		dstIsNew = 0; hostIsNew = 1;
21011819Sjulian		if (ia->ia_addr.sipx_family == AF_IPX) {
21111819Sjulian			if (ifra->ifra_addr.sipx_len == 0) {
21211819Sjulian				ifra->ifra_addr = ia->ia_addr;
21311819Sjulian				hostIsNew = 0;
21411819Sjulian			} else if (ipx_neteq(ifra->ifra_addr.sipx_addr,
21511819Sjulian					 ia->ia_addr.sipx_addr))
21611819Sjulian				hostIsNew = 0;
21711819Sjulian		}
21811819Sjulian		if ((ifp->if_flags & IFF_POINTOPOINT) &&
21911819Sjulian		    (ifra->ifra_dstaddr.sipx_family == AF_IPX)) {
22011819Sjulian			if (hostIsNew == 0)
22111819Sjulian				ipx_ifscrub(ifp, ia);
22211819Sjulian			ia->ia_dstaddr = ifra->ifra_dstaddr;
22311819Sjulian			dstIsNew  = 1;
22411819Sjulian		}
22511819Sjulian		if (ifra->ifra_addr.sipx_family == AF_IPX &&
22611819Sjulian					    (hostIsNew || dstIsNew))
22711819Sjulian			error = ipx_ifinit(ifp, ia, &ifra->ifra_addr, 0);
22811819Sjulian		return (error);
22911819Sjulian
23011819Sjulian	default:
23111819Sjulian		if (ifp->if_ioctl == 0)
23211819Sjulian			return (EOPNOTSUPP);
23311819Sjulian		return ((*ifp->if_ioctl)(ifp, cmd, data));
23411819Sjulian	}
23511819Sjulian}
23611819Sjulian
23711819Sjulian/*
23811819Sjulian* Delete any previous route for an old address.
23911819Sjulian*/
24011819Sjulianvoid
24111819Sjulianipx_ifscrub(ifp, ia)
24211819Sjulian	register struct ifnet *ifp;
24311819Sjulian	register struct ipx_ifaddr *ia;
24411819Sjulian{
24511819Sjulian	if (ia->ia_flags & IFA_ROUTE) {
24611819Sjulian		if (ifp->if_flags & IFF_POINTOPOINT) {
24711819Sjulian			rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
24811819Sjulian		} else
24911819Sjulian			rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0);
25011819Sjulian		ia->ia_flags &= ~IFA_ROUTE;
25111819Sjulian	}
25211819Sjulian}
25311819Sjulian/*
25411819Sjulian * Initialize an interface's internet address
25511819Sjulian * and routing table entry.
25611819Sjulian */
25711819Sjulianint
25811819Sjulianipx_ifinit(ifp, ia, sipx, scrub)
25911819Sjulian	register struct ifnet *ifp;
26011819Sjulian	register struct ipx_ifaddr *ia;
26111819Sjulian	register struct sockaddr_ipx *sipx;
26211819Sjulian	int scrub;
26311819Sjulian{
26411819Sjulian	struct sockaddr_ipx oldaddr;
26511819Sjulian	register union ipx_host *h = &ia->ia_addr.sipx_addr.x_host;
26611819Sjulian	int s = splimp(), error;
26711819Sjulian
26811819Sjulian	/*
26911819Sjulian	 * Set up new addresses.
27011819Sjulian	 */
27111819Sjulian	oldaddr = ia->ia_addr;
27211819Sjulian	ia->ia_addr = *sipx;
27311819Sjulian	/*
27411819Sjulian	 * The convention we shall adopt for naming is that
27511819Sjulian	 * a supplied address of zero means that "we don't care".
27611819Sjulian	 * if there is a single interface, use the address of that
27711819Sjulian	 * interface as our 6 byte host address.
27811819Sjulian	 * if there are multiple interfaces, use any address already
27911819Sjulian	 * used.
28011819Sjulian	 *
28111819Sjulian	 * Give the interface a chance to initialize
28211819Sjulian	 * if this is its first address,
28311819Sjulian	 * and to validate the address if necessary.
28411819Sjulian	 */
28511819Sjulian	if (ipx_hosteqnh(ipx_thishost, ipx_zerohost)) {
28611819Sjulian		if (ifp->if_ioctl &&
28711819Sjulian		     (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (void *)ia))) {
28811819Sjulian			ia->ia_addr = oldaddr;
28911819Sjulian			splx(s);
29011819Sjulian			return (error);
29111819Sjulian		}
29211819Sjulian		ipx_thishost = *h;
29311819Sjulian	} else if (ipx_hosteqnh(sipx->sipx_addr.x_host, ipx_zerohost)
29411819Sjulian	    || ipx_hosteqnh(sipx->sipx_addr.x_host, ipx_thishost)) {
29511819Sjulian		*h = ipx_thishost;
29611819Sjulian		if (ifp->if_ioctl &&
29711819Sjulian		     (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (void *)ia))) {
29811819Sjulian			ia->ia_addr = oldaddr;
29911819Sjulian			splx(s);
30011819Sjulian			return (error);
30111819Sjulian		}
30211819Sjulian		if (!ipx_hosteqnh(ipx_thishost,*h)) {
30311819Sjulian			ia->ia_addr = oldaddr;
30411819Sjulian			splx(s);
30511819Sjulian			return (EINVAL);
30611819Sjulian		}
30711819Sjulian	} else {
30811819Sjulian		ia->ia_addr = oldaddr;
30911819Sjulian		splx(s);
31011819Sjulian		return (EINVAL);
31111819Sjulian	}
31211819Sjulian	ia->ia_ifa.ifa_metric = ifp->if_metric;
31311819Sjulian	/*
31411819Sjulian	 * Add route for the network.
31511819Sjulian	 */
31611819Sjulian	if (scrub) {
31711819Sjulian		ia->ia_ifa.ifa_addr = (struct sockaddr *)&oldaddr;
31811819Sjulian		ipx_ifscrub(ifp, ia);
31911819Sjulian		ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
32011819Sjulian	}
32111819Sjulian	if (ifp->if_flags & IFF_POINTOPOINT)
32211819Sjulian		rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP);
32311819Sjulian	else {
32411819Sjulian		ia->ia_broadaddr.sipx_addr.x_net = ia->ia_addr.sipx_addr.x_net;
32511819Sjulian		rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_UP);
32611819Sjulian	}
32711819Sjulian	ia->ia_flags |= IFA_ROUTE;
32811819Sjulian	return (0);
32911819Sjulian}
33011819Sjulian
33111819Sjulian/*
33211819Sjulian * Return address info for specified internet network.
33311819Sjulian */
33411819Sjulianstruct ipx_ifaddr *
33511819Sjulianipx_iaonnetof(dst)
33611819Sjulian	register struct ipx_addr *dst;
33711819Sjulian{
33811819Sjulian	register struct ipx_ifaddr *ia;
33911819Sjulian	register struct ipx_addr *compare;
34011819Sjulian	register struct ifnet *ifp;
34111819Sjulian	struct ipx_ifaddr *ia_maybe = 0;
34211819Sjulian	union ipx_net net = dst->x_net;
34311819Sjulian
34411819Sjulian	for (ia = ipx_ifaddr; ia; ia = ia->ia_next) {
34511819Sjulian		if ((ifp = ia->ia_ifp)) {
34611819Sjulian			if (ifp->if_flags & IFF_POINTOPOINT) {
34711819Sjulian				compare = &satoipx_addr(ia->ia_dstaddr);
34811819Sjulian				if (ipx_hosteq(*dst, *compare))
34911819Sjulian					return (ia);
35011819Sjulian				if (ipx_neteqnn(net, ia->ia_addr.sipx_addr.x_net))
35111819Sjulian					ia_maybe = ia;
35211819Sjulian			} else {
35311819Sjulian				if (ipx_neteqnn(net, ia->ia_addr.sipx_addr.x_net))
35411819Sjulian					return (ia);
35511819Sjulian			}
35611819Sjulian		}
35711819Sjulian	}
35811819Sjulian	return (ia_maybe);
35911819Sjulian}
36011819Sjulian#endif
361