ipx.c revision 14546
194575Sdes/*
294575Sdes * Copyright (c) 1995, Mike Mitchell
394575Sdes * Copyright (c) 1984, 1985, 1986, 1987, 1993
494575Sdes *	The Regents of the University of California.  All rights reserved.
594575Sdes *
694575Sdes * Redistribution and use in source and binary forms, with or without
794575Sdes * modification, are permitted provided that the following conditions
894575Sdes * are met:
994575Sdes * 1. Redistributions of source code must retain the above copyright
1094575Sdes *    notice, this list of conditions and the following disclaimer.
1194575Sdes * 2. Redistributions in binary form must reproduce the above copyright
1294575Sdes *    notice, this list of conditions and the following disclaimer in the
1394575Sdes *    documentation and/or other materials provided with the distribution.
1494575Sdes * 3. All advertising materials mentioning features or use of this software
1594575Sdes *    must display the following acknowledgement:
1694575Sdes *	This product includes software developed by the University of
1794575Sdes *	California, Berkeley and its contributors.
1894575Sdes * 4. Neither the name of the University nor the names of its contributors
1994575Sdes *    may be used to endorse or promote products derived from this software
2094575Sdes *    without specific prior written permission.
2194575Sdes *
2294575Sdes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2394575Sdes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2494575Sdes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2594575Sdes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2694575Sdes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2794575Sdes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2894575Sdes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2994575Sdes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3094575Sdes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3194575Sdes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3294575Sdes * SUCH DAMAGE.
3394575Sdes *
3494575Sdes *	@(#)ipx.c
3594575Sdes *
3694575Sdes * $Id: ipx.c,v 1.3 1995/11/04 09:02:34 julian Exp $
3794575Sdes */
3894575Sdes
3994575Sdes#include <sys/param.h>
4094575Sdes#include <sys/queue.h>
4194575Sdes#include <sys/systm.h>
4294575Sdes#include <sys/mbuf.h>
4394575Sdes#include <sys/ioctl.h>
4494575Sdes#include <sys/protosw.h>
4594575Sdes#include <sys/errno.h>
4694575Sdes#include <sys/socket.h>
4794575Sdes#include <sys/socketvar.h>
4894575Sdes
4994575Sdes#include <net/if.h>
5094575Sdes#include <net/route.h>
5194575Sdes
5294575Sdes#include <netipx/ipx.h>
5394575Sdes#include <netipx/ipx_if.h>
5494575Sdes
5594575Sdes#ifdef IPX
5694575Sdes
5794575Sdesstruct ipx_ifaddr *ipx_ifaddr;
5894575Sdesint ipx_interfaces;
5994575Sdes
6094575Sdes/*
6194575Sdes * Generic internet control operations (ioctl's).
6294575Sdes */
63/* ARGSUSED */
64int
65ipx_control(so, cmd, data, ifp)
66	struct socket *so;
67	int cmd;
68	caddr_t data;
69	register struct ifnet *ifp;
70{
71	register struct ifreq *ifr = (struct ifreq *)data;
72	register struct ipx_aliasreq *ifra = (struct ipx_aliasreq *)data;
73	register struct ipx_ifaddr *ia;
74	struct ifaddr *ifa;
75	struct ipx_ifaddr *oia;
76	int dstIsNew, hostIsNew;
77	int error = 0;
78
79	/*
80	 * Find address for this interface, if it exists.
81	 */
82	if (ifp == 0)
83		return (EADDRNOTAVAIL);
84	for (ia = ipx_ifaddr; ia; ia = ia->ia_next)
85		if (ia->ia_ifp == ifp)
86			break;
87
88	switch (cmd) {
89
90	case SIOCGIFADDR:
91		if (ia == (struct ipx_ifaddr *)0)
92			return (EADDRNOTAVAIL);
93		*(struct sockaddr_ipx *)&ifr->ifr_addr = ia->ia_addr;
94		return (0);
95
96	case SIOCGIFBRDADDR:
97		if (ia == (struct ipx_ifaddr *)0)
98			return (EADDRNOTAVAIL);
99		if ((ifp->if_flags & IFF_BROADCAST) == 0)
100			return (EINVAL);
101		*(struct sockaddr_ipx *)&ifr->ifr_dstaddr = ia->ia_broadaddr;
102		return (0);
103
104	case SIOCGIFDSTADDR:
105		if (ia == (struct ipx_ifaddr *)0)
106			return (EADDRNOTAVAIL);
107		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
108			return (EINVAL);
109		*(struct sockaddr_ipx *)&ifr->ifr_dstaddr = ia->ia_dstaddr;
110		return (0);
111	}
112
113	if ((so->so_state & SS_PRIV) == 0)
114		return (EPERM);
115
116	switch (cmd) {
117	case SIOCAIFADDR:
118	case SIOCDIFADDR:
119		if (ifra->ifra_addr.sipx_family == AF_IPX)
120		    for (oia = ia; ia; ia = ia->ia_next) {
121			if (ia->ia_ifp == ifp  &&
122			    ipx_neteq(ia->ia_addr.sipx_addr,
123				  ifra->ifra_addr.sipx_addr))
124			    break;
125		    }
126		if (cmd == SIOCDIFADDR && ia == 0)
127			return (EADDRNOTAVAIL);
128		/* FALLTHROUGH */
129
130	case SIOCSIFADDR:
131	case SIOCSIFDSTADDR:
132		if (ia == (struct ipx_ifaddr *)0) {
133			oia = (struct ipx_ifaddr *)
134				malloc(sizeof *ia, M_IFADDR, M_WAITOK);
135			if (oia == (struct ipx_ifaddr *)NULL)
136				return (ENOBUFS);
137			bzero((caddr_t)oia, sizeof(*oia));
138			if ((ia = ipx_ifaddr)) {
139				for ( ; ia->ia_next; ia = ia->ia_next)
140					;
141				ia->ia_next = oia;
142			} else
143				ipx_ifaddr = oia;
144			ia = oia;
145			if ((ifa = ifp->if_addrlist)) {
146				for ( ; ifa->ifa_next; ifa = ifa->ifa_next)
147					;
148				ifa->ifa_next = (struct ifaddr *) ia;
149			} else
150				ifp->if_addrlist = (struct ifaddr *) ia;
151			ia->ia_ifp = ifp;
152			ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
153
154			ia->ia_ifa.ifa_netmask =
155				(struct sockaddr *)&ipx_netmask;
156
157			ia->ia_ifa.ifa_dstaddr =
158				(struct sockaddr *)&ia->ia_dstaddr;
159			if (ifp->if_flags & IFF_BROADCAST) {
160				ia->ia_broadaddr.sipx_family = AF_IPX;
161				ia->ia_broadaddr.sipx_len = sizeof(ia->ia_addr);
162				ia->ia_broadaddr.sipx_addr.x_host = ipx_broadhost;
163			}
164			ipx_interfaces++;
165		}
166	}
167
168	switch (cmd) {
169
170	case SIOCSIFDSTADDR:
171		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
172			return (EINVAL);
173		if (ia->ia_flags & IFA_ROUTE) {
174			rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
175			ia->ia_flags &= ~IFA_ROUTE;
176		}
177		if (ifp->if_ioctl) {
178			error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, (void *)ia);
179			if (error)
180				return (error);
181		}
182		*(struct sockaddr *)&ia->ia_dstaddr = ifr->ifr_dstaddr;
183		return (0);
184
185	case SIOCSIFADDR:
186		return (ipx_ifinit(ifp, ia,
187				(struct sockaddr_ipx *)&ifr->ifr_addr, 1));
188
189	case SIOCDIFADDR:
190		ipx_ifscrub(ifp, ia);
191		if ((ifa = ifp->if_addrlist) == (struct ifaddr *)ia)
192			ifp->if_addrlist = ifa->ifa_next;
193		else {
194			while (ifa->ifa_next &&
195			       (ifa->ifa_next != (struct ifaddr *)ia))
196				    ifa = ifa->ifa_next;
197			if (ifa->ifa_next)
198			    ifa->ifa_next = ((struct ifaddr *)ia)->ifa_next;
199			else
200				printf("Couldn't unlink ipxifaddr from ifp\n");
201		}
202		oia = ia;
203		if (oia == (ia = ipx_ifaddr)) {
204			ipx_ifaddr = ia->ia_next;
205		} else {
206			while (ia->ia_next && (ia->ia_next != oia)) {
207				ia = ia->ia_next;
208			}
209			if (ia->ia_next)
210			    ia->ia_next = oia->ia_next;
211			else
212				printf("Didn't unlink ipxifadr from list\n");
213		}
214		IFAFREE((&oia->ia_ifa));
215		if (0 == --ipx_interfaces) {
216			/*
217			 * We reset to virginity and start all over again
218			 */
219			ipx_thishost = ipx_zerohost;
220		}
221		return (0);
222
223	case SIOCAIFADDR:
224		dstIsNew = 0; hostIsNew = 1;
225		if (ia->ia_addr.sipx_family == AF_IPX) {
226			if (ifra->ifra_addr.sipx_len == 0) {
227				ifra->ifra_addr = ia->ia_addr;
228				hostIsNew = 0;
229			} else if (ipx_neteq(ifra->ifra_addr.sipx_addr,
230					 ia->ia_addr.sipx_addr))
231				hostIsNew = 0;
232		}
233		if ((ifp->if_flags & IFF_POINTOPOINT) &&
234		    (ifra->ifra_dstaddr.sipx_family == AF_IPX)) {
235			if (hostIsNew == 0)
236				ipx_ifscrub(ifp, ia);
237			ia->ia_dstaddr = ifra->ifra_dstaddr;
238			dstIsNew  = 1;
239		}
240		if (ifra->ifra_addr.sipx_family == AF_IPX &&
241					    (hostIsNew || dstIsNew))
242			error = ipx_ifinit(ifp, ia, &ifra->ifra_addr, 0);
243		return (error);
244
245	default:
246		if (ifp->if_ioctl == 0)
247			return (EOPNOTSUPP);
248		return ((*ifp->if_ioctl)(ifp, cmd, data));
249	}
250}
251
252/*
253* Delete any previous route for an old address.
254*/
255void
256ipx_ifscrub(ifp, ia)
257	register struct ifnet *ifp;
258	register struct ipx_ifaddr *ia;
259{
260	if (ia->ia_flags & IFA_ROUTE) {
261		if (ifp->if_flags & IFF_POINTOPOINT) {
262			rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
263		} else
264			rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0);
265		ia->ia_flags &= ~IFA_ROUTE;
266	}
267}
268/*
269 * Initialize an interface's internet address
270 * and routing table entry.
271 */
272int
273ipx_ifinit(ifp, ia, sipx, scrub)
274	register struct ifnet *ifp;
275	register struct ipx_ifaddr *ia;
276	register struct sockaddr_ipx *sipx;
277	int scrub;
278{
279	struct sockaddr_ipx oldaddr;
280	register union ipx_host *h = &ia->ia_addr.sipx_addr.x_host;
281	int s = splimp(), error;
282
283	/*
284	 * Set up new addresses.
285	 */
286	oldaddr = ia->ia_addr;
287	ia->ia_addr = *sipx;
288	/*
289	 * The convention we shall adopt for naming is that
290	 * a supplied address of zero means that "we don't care".
291	 * if there is a single interface, use the address of that
292	 * interface as our 6 byte host address.
293	 * if there are multiple interfaces, use any address already
294	 * used.
295	 *
296	 * Give the interface a chance to initialize
297	 * if this is its first address,
298	 * and to validate the address if necessary.
299	 */
300	if (ipx_hosteqnh(ipx_thishost, ipx_zerohost)) {
301		if (ifp->if_ioctl &&
302		     (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (void *)ia))) {
303			ia->ia_addr = oldaddr;
304			splx(s);
305			return (error);
306		}
307		ipx_thishost = *h;
308	} else if (ipx_hosteqnh(sipx->sipx_addr.x_host, ipx_zerohost)
309	    || ipx_hosteqnh(sipx->sipx_addr.x_host, ipx_thishost)) {
310		*h = ipx_thishost;
311		if (ifp->if_ioctl &&
312		     (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (void *)ia))) {
313			ia->ia_addr = oldaddr;
314			splx(s);
315			return (error);
316		}
317		if (!ipx_hosteqnh(ipx_thishost,*h)) {
318			ia->ia_addr = oldaddr;
319			splx(s);
320			return (EINVAL);
321		}
322	} else {
323		ia->ia_addr = oldaddr;
324		splx(s);
325		return (EINVAL);
326	}
327	ia->ia_ifa.ifa_metric = ifp->if_metric;
328	/*
329	 * Add route for the network.
330	 */
331	if (scrub) {
332		ia->ia_ifa.ifa_addr = (struct sockaddr *)&oldaddr;
333		ipx_ifscrub(ifp, ia);
334		ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
335	}
336	if (ifp->if_flags & IFF_POINTOPOINT)
337		rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP);
338	else {
339		ia->ia_broadaddr.sipx_addr.x_net = ia->ia_addr.sipx_addr.x_net;
340		rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_UP);
341	}
342	ia->ia_flags |= IFA_ROUTE;
343	return (0);
344}
345
346/*
347 * Return address info for specified internet network.
348 */
349struct ipx_ifaddr *
350ipx_iaonnetof(dst)
351	register struct ipx_addr *dst;
352{
353	register struct ipx_ifaddr *ia;
354	register struct ipx_addr *compare;
355	register struct ifnet *ifp;
356	struct ipx_ifaddr *ia_maybe = 0;
357	union ipx_net net = dst->x_net;
358
359	for (ia = ipx_ifaddr; ia; ia = ia->ia_next) {
360		if ((ifp = ia->ia_ifp)) {
361			if (ifp->if_flags & IFF_POINTOPOINT) {
362				compare = &satoipx_addr(ia->ia_dstaddr);
363				if (ipx_hosteq(*dst, *compare))
364					return (ia);
365				if (ipx_neteqnn(net, ia->ia_addr.sipx_addr.x_net))
366					ia_maybe = ia;
367			} else {
368				if (ipx_neteqnn(net, ia->ia_addr.sipx_addr.x_net))
369					return (ia);
370			}
371		}
372	}
373	return (ia_maybe);
374}
375#endif
376