ipx.c revision 41617
1169689Skan/*
2169689Skan * Copyright (c) 1995, Mike Mitchell
3169689Skan * Copyright (c) 1984, 1985, 1986, 1987, 1993
4169689Skan *	The Regents of the University of California.  All rights reserved.
5169689Skan *
6169689Skan * Redistribution and use in source and binary forms, with or without
7169689Skan * modification, are permitted provided that the following conditions
8169689Skan * are met:
9169689Skan * 1. Redistributions of source code must retain the above copyright
10169689Skan *    notice, this list of conditions and the following disclaimer.
11169689Skan * 2. Redistributions in binary form must reproduce the above copyright
12169689Skan *    notice, this list of conditions and the following disclaimer in the
13169689Skan *    documentation and/or other materials provided with the distribution.
14169689Skan * 3. All advertising materials mentioning features or use of this software
15169689Skan *    must display the following acknowledgement:
16169689Skan *	This product includes software developed by the University of
17169689Skan *	California, Berkeley and its contributors.
18169689Skan * 4. Neither the name of the University nor the names of its contributors
19169689Skan *    may be used to endorse or promote products derived from this software
20169689Skan *    without specific prior written permission.
21169689Skan *
22169689Skan * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23169689Skan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24169689Skan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25169689Skan * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26169689Skan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27169689Skan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28169689Skan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29169689Skan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30169689Skan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31169689Skan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32169689Skan * SUCH DAMAGE.
33169689Skan *
34169689Skan *	@(#)ipx.c
35169689Skan *
36169689Skan * $Id: ipx.c,v 1.13 1998/12/04 22:54:54 archie Exp $
37169689Skan */
38169689Skan
39169689Skan#include <sys/param.h>
40169689Skan#include <sys/systm.h>
41169689Skan#include <sys/malloc.h>
42169689Skan#include <sys/sockio.h>
43169689Skan#include <sys/proc.h>
44169689Skan#include <sys/socket.h>
45169689Skan
46169689Skan#include <net/if.h>
47169689Skan#include <net/route.h>
48169689Skan
49169689Skan#include <netipx/ipx.h>
50169689Skan#include <netipx/ipx_if.h>
51169689Skan#include <netipx/ipx_var.h>
52169689Skan
53169689Skanstruct ipx_ifaddr *ipx_ifaddr;
54169689Skan
55169689Skanstatic	void ipx_ifscrub(struct ifnet *ifp, struct ipx_ifaddr *ia);
56169689Skanstatic	int ipx_ifinit(struct ifnet *ifp, struct ipx_ifaddr *ia,
57169689Skan		       struct sockaddr_ipx *sipx, int scrub);
58169689Skan
59169689Skan/*
60169689Skan * Generic internet control operations (ioctl's).
61169689Skan */
62169689Skanint
63169689Skanipx_control(so, cmd, data, ifp, p)
64169689Skan	struct socket *so;
65169689Skan	u_long cmd;
66169689Skan	caddr_t data;
67169689Skan	register struct ifnet *ifp;
68169689Skan	struct proc *p;
69169689Skan{
70169689Skan	register struct ifreq *ifr = (struct ifreq *)data;
71169689Skan	register struct ipx_aliasreq *ifra = (struct ipx_aliasreq *)data;
72169689Skan	register struct ipx_ifaddr *ia;
73169689Skan	struct ifaddr *ifa;
74169689Skan	struct ipx_ifaddr *oia;
75169689Skan	int dstIsNew, hostIsNew;
76169689Skan	int error = 0;
77169689Skan
78169689Skan	/*
79169689Skan	 * Find address for this interface, if it exists.
80169689Skan	 */
81169689Skan	if (ifp == NULL)
82169689Skan		return (EADDRNOTAVAIL);
83169689Skan	for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next)
84169689Skan		if (ia->ia_ifp == ifp)
85169689Skan			break;
86169689Skan
87169689Skan	switch (cmd) {
88169689Skan
89169689Skan	case SIOCGIFADDR:
90169689Skan		if (ia == NULL)
91169689Skan			return (EADDRNOTAVAIL);
92169689Skan		*(struct sockaddr_ipx *)&ifr->ifr_addr = ia->ia_addr;
93169689Skan		return (0);
94169689Skan
95169689Skan	case SIOCGIFBRDADDR:
96169689Skan		if (ia == NULL)
97169689Skan			return (EADDRNOTAVAIL);
98169689Skan		if ((ifp->if_flags & IFF_BROADCAST) == 0)
99169689Skan			return (EINVAL);
100169689Skan		*(struct sockaddr_ipx *)&ifr->ifr_dstaddr = ia->ia_broadaddr;
101169689Skan		return (0);
102169689Skan
103169689Skan	case SIOCGIFDSTADDR:
104169689Skan		if (ia == NULL)
105169689Skan			return (EADDRNOTAVAIL);
106169689Skan		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
107169689Skan			return (EINVAL);
108169689Skan		*(struct sockaddr_ipx *)&ifr->ifr_dstaddr = ia->ia_dstaddr;
109169689Skan		return (0);
110169689Skan	}
111169689Skan
112169689Skan	if (p && (error = suser(p->p_ucred, &p->p_acflag)) != 0)
113169689Skan		return (error);
114169689Skan
115169689Skan	switch (cmd) {
116169689Skan	case SIOCAIFADDR:
117169689Skan	case SIOCDIFADDR:
118169689Skan		if (ifra->ifra_addr.sipx_family == AF_IPX)
119169689Skan		    for (oia = ia; ia != NULL; ia = ia->ia_next) {
120169689Skan			if (ia->ia_ifp == ifp  &&
121169689Skan			    ipx_neteq(ia->ia_addr.sipx_addr,
122169689Skan				  ifra->ifra_addr.sipx_addr))
123169689Skan			    break;
124169689Skan		    }
125169689Skan		if (cmd == SIOCDIFADDR && ia == NULL)
126169689Skan			return (EADDRNOTAVAIL);
127169689Skan		/* FALLTHROUGH */
128169689Skan
129169689Skan	case SIOCSIFADDR:
130169689Skan	case SIOCSIFDSTADDR:
131169689Skan		if (ia == NULL) {
132169689Skan			oia = (struct ipx_ifaddr *)
133169689Skan				malloc(sizeof(*ia), M_IFADDR, M_WAITOK);
134169689Skan			if (oia == NULL)
135169689Skan				return (ENOBUFS);
136169689Skan			bzero((caddr_t)oia, sizeof(*oia));
137169689Skan			if ((ia = ipx_ifaddr) != NULL) {
138169689Skan				for ( ; ia->ia_next != NULL; ia = ia->ia_next)
139169689Skan					;
140169689Skan				ia->ia_next = oia;
141169689Skan			} else
142169689Skan				ipx_ifaddr = oia;
143169689Skan			ia = oia;
144169689Skan			ifa = (struct ifaddr *)ia;
145169689Skan			TAILQ_INSERT_TAIL(&ifp->if_addrhead, ifa, ifa_link);
146169689Skan			ia->ia_ifp = ifp;
147169689Skan			ifa->ifa_addr = (struct sockaddr *)&ia->ia_addr;
148169689Skan
149169689Skan			ifa->ifa_netmask = (struct sockaddr *)&ipx_netmask;
150169689Skan
151169689Skan			ifa->ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr;
152169689Skan			if (ifp->if_flags & IFF_BROADCAST) {
153169689Skan				ia->ia_broadaddr.sipx_family = AF_IPX;
154169689Skan				ia->ia_broadaddr.sipx_len = sizeof(ia->ia_addr);
155169689Skan				ia->ia_broadaddr.sipx_addr.x_host = ipx_broadhost;
156169689Skan			}
157169689Skan		}
158169689Skan	}
159169689Skan
160169689Skan	switch (cmd) {
161169689Skan
162169689Skan	case SIOCSIFDSTADDR:
163169689Skan		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
164169689Skan			return (EINVAL);
165169689Skan		if (ia->ia_flags & IFA_ROUTE) {
166169689Skan			rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
167169689Skan			ia->ia_flags &= ~IFA_ROUTE;
168169689Skan		}
169169689Skan		if (ifp->if_ioctl) {
170169689Skan			error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, (void *)ia);
171169689Skan			if (error)
172169689Skan				return (error);
173169689Skan		}
174169689Skan		*(struct sockaddr *)&ia->ia_dstaddr = ifr->ifr_dstaddr;
175169689Skan		return (0);
176169689Skan
177169689Skan	case SIOCSIFADDR:
178169689Skan		return (ipx_ifinit(ifp, ia,
179169689Skan				(struct sockaddr_ipx *)&ifr->ifr_addr, 1));
180169689Skan
181169689Skan	case SIOCDIFADDR:
182169689Skan		ipx_ifscrub(ifp, ia);
183169689Skan		ifa = (struct ifaddr *)ia;
184169689Skan		TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link);
185169689Skan		oia = ia;
186169689Skan		if (oia == (ia = ipx_ifaddr)) {
187169689Skan			ipx_ifaddr = ia->ia_next;
188169689Skan		} else {
189169689Skan			while (ia->ia_next && (ia->ia_next != oia)) {
190169689Skan				ia = ia->ia_next;
191169689Skan			}
192169689Skan			if (ia->ia_next)
193169689Skan			    ia->ia_next = oia->ia_next;
194169689Skan			else
195169689Skan				printf("Didn't unlink ipxifadr from list\n");
196169689Skan		}
197169689Skan		IFAFREE((&oia->ia_ifa));
198169689Skan		return (0);
199169689Skan
200169689Skan	case SIOCAIFADDR:
201169689Skan		dstIsNew = 0;
202169689Skan		hostIsNew = 1;
203169689Skan		if (ia->ia_addr.sipx_family == AF_IPX) {
204169689Skan			if (ifra->ifra_addr.sipx_len == 0) {
205169689Skan				ifra->ifra_addr = ia->ia_addr;
206169689Skan				hostIsNew = 0;
207169689Skan			} else if (ipx_neteq(ifra->ifra_addr.sipx_addr,
208169689Skan					 ia->ia_addr.sipx_addr))
209169689Skan				hostIsNew = 0;
210169689Skan		}
211169689Skan		if ((ifp->if_flags & IFF_POINTOPOINT) &&
212169689Skan		    (ifra->ifra_dstaddr.sipx_family == AF_IPX)) {
213169689Skan			if (hostIsNew == 0)
214169689Skan				ipx_ifscrub(ifp, ia);
215169689Skan			ia->ia_dstaddr = ifra->ifra_dstaddr;
216169689Skan			dstIsNew  = 1;
217169689Skan		}
218169689Skan		if (ifra->ifra_addr.sipx_family == AF_IPX &&
219169689Skan					    (hostIsNew || dstIsNew))
220169689Skan			error = ipx_ifinit(ifp, ia, &ifra->ifra_addr, 0);
221169689Skan		return (error);
222169689Skan
223169689Skan	default:
224169689Skan		if (ifp->if_ioctl == NULL)
225169689Skan			return (EOPNOTSUPP);
226169689Skan		return ((*ifp->if_ioctl)(ifp, cmd, data));
227169689Skan	}
228169689Skan}
229169689Skan
230169689Skan/*
231169689Skan* Delete any previous route for an old address.
232169689Skan*/
233169689Skanstatic void
234169689Skanipx_ifscrub(ifp, ia)
235169689Skan	register struct ifnet *ifp;
236169689Skan	register struct ipx_ifaddr *ia;
237169689Skan{
238169689Skan	if (ia->ia_flags & IFA_ROUTE) {
239169689Skan		if (ifp->if_flags & IFF_POINTOPOINT) {
240169689Skan			rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
241169689Skan		} else
242169689Skan			rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0);
243169689Skan		ia->ia_flags &= ~IFA_ROUTE;
244169689Skan	}
245169689Skan}
246169689Skan/*
247169689Skan * Initialize an interface's internet address
248169689Skan * and routing table entry.
249169689Skan */
250169689Skanstatic int
251169689Skanipx_ifinit(ifp, ia, sipx, scrub)
252169689Skan	register struct ifnet *ifp;
253169689Skan	register struct ipx_ifaddr *ia;
254169689Skan	register struct sockaddr_ipx *sipx;
255169689Skan	int scrub;
256169689Skan{
257169689Skan	struct sockaddr_ipx oldaddr;
258169689Skan	int s = splimp(), error;
259169689Skan
260169689Skan	/*
261169689Skan	 * Set up new addresses.
262169689Skan	 */
263169689Skan	oldaddr = ia->ia_addr;
264169689Skan	ia->ia_addr = *sipx;
265169689Skan
266169689Skan	/*
267169689Skan	 * The convention we shall adopt for naming is that
268169689Skan	 * a supplied address of zero means that "we don't care".
269169689Skan	 * Use the MAC address of the interface. If it is an
270169689Skan	 * interface without a MAC address, like a serial line, the
271169689Skan	 * address must be supplied.
272169689Skan	 *
273169689Skan	 * Give the interface a chance to initialize
274169689Skan	 * if this is its first address,
275169689Skan	 * and to validate the address if necessary.
276169689Skan	 */
277169689Skan	if (ifp->if_ioctl != NULL &&
278169689Skan	    (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (void *)ia))) {
279169689Skan		ia->ia_addr = oldaddr;
280169689Skan		splx(s);
281169689Skan		return (error);
282169689Skan	}
283169689Skan	splx(s);
284169689Skan	ia->ia_ifa.ifa_metric = ifp->if_metric;
285169689Skan	/*
286169689Skan	 * Add route for the network.
287169689Skan	 */
288169689Skan	if (scrub) {
289169689Skan		ia->ia_ifa.ifa_addr = (struct sockaddr *)&oldaddr;
290169689Skan		ipx_ifscrub(ifp, ia);
291169689Skan		ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
292169689Skan	}
293169689Skan	if (ifp->if_flags & IFF_POINTOPOINT)
294169689Skan		rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP);
295169689Skan	else {
296169689Skan		ia->ia_broadaddr.sipx_addr.x_net = ia->ia_addr.sipx_addr.x_net;
297169689Skan		rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_UP);
298169689Skan	}
299169689Skan	ia->ia_flags |= IFA_ROUTE;
300169689Skan	return (0);
301169689Skan}
302169689Skan
303169689Skan/*
304169689Skan * Return address info for specified internet network.
305169689Skan */
306169689Skanstruct ipx_ifaddr *
307169689Skanipx_iaonnetof(dst)
308169689Skan	register struct ipx_addr *dst;
309169689Skan{
310169689Skan	register struct ipx_ifaddr *ia;
311169689Skan	register struct ipx_addr *compare;
312169689Skan	register struct ifnet *ifp;
313169689Skan	struct ipx_ifaddr *ia_maybe = NULL;
314169689Skan	union ipx_net net = dst->x_net;
315169689Skan
316169689Skan	for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next) {
317169689Skan		if ((ifp = ia->ia_ifp) != NULL) {
318169689Skan			if (ifp->if_flags & IFF_POINTOPOINT) {
319169689Skan				compare = &satoipx_addr(ia->ia_dstaddr);
320169689Skan				if (ipx_hosteq(*dst, *compare))
321169689Skan					return (ia);
322169689Skan				if (ipx_neteqnn(net, ia->ia_addr.sipx_addr.x_net))
323169689Skan					ia_maybe = ia;
324169689Skan			} else {
325169689Skan				if (ipx_neteqnn(net, ia->ia_addr.sipx_addr.x_net))
326169689Skan					return (ia);
327169689Skan			}
328169689Skan		}
329169689Skan	}
330169689Skan	return (ia_maybe);
331169689Skan}
332169689Skan
333169689Skan
334169689Skanvoid
335169689Skanipx_printhost(addr)
336169689Skanregister struct ipx_addr *addr;
337169689Skan{
338169689Skan	u_short port;
339169689Skan	struct ipx_addr work = *addr;
340169689Skan	register char *p; register u_char *q;
341169689Skan	register char *net = "", *host = "";
342169689Skan	char cport[10], chost[15], cnet[15];
343169689Skan
344169689Skan	port = ntohs(work.x_port);
345169689Skan
346169689Skan	if (ipx_nullnet(work) && ipx_nullhost(work)) {
347169689Skan
348169689Skan		if (port)
349169689Skan			printf("*.%x", port);
350169689Skan		else
351169689Skan			printf("*.*");
352169689Skan
353169689Skan		return;
354169689Skan	}
355169689Skan
356169689Skan	if (ipx_wildnet(work))
357169689Skan		net = "any";
358169689Skan	else if (ipx_nullnet(work))
359169689Skan		net = "*";
360169689Skan	else {
361169689Skan		q = work.x_net.c_net;
362169689Skan		snprintf(cnet, sizeof(cnet), "%x%x%x%x",
363169689Skan			q[0], q[1], q[2], q[3]);
364169689Skan		for (p = cnet; *p == '0' && p < cnet + 8; p++)
365169689Skan			continue;
366169689Skan		net = p;
367169689Skan	}
368169689Skan
369169689Skan	if (ipx_wildhost(work))
370169689Skan		host = "any";
371169689Skan	else if (ipx_nullhost(work))
372169689Skan		host = "*";
373169689Skan	else {
374169689Skan		q = work.x_host.c_host;
375169689Skan		snprintf(chost, sizeof(chost), "%x%x%x%x%x%x",
376169689Skan			q[0], q[1], q[2], q[3], q[4], q[5]);
377169689Skan		for (p = chost; *p == '0' && p < chost + 12; p++)
378169689Skan			continue;
379169689Skan		host = p;
380169689Skan	}
381169689Skan
382169689Skan	if (port) {
383169689Skan		if (strcmp(host, "*") == 0) {
384169689Skan			host = "";
385169689Skan			snprintf(cport, sizeof(cport), "%x", port);
386169689Skan		} else
387169689Skan			snprintf(cport, sizeof(cport), ".%x", port);
388169689Skan	} else
389169689Skan		*cport = 0;
390169689Skan
391169689Skan	printf("%s.%s%s", net, host, cport);
392169689Skan}
393169689Skan