1 /*	$OpenBSD: ipx.c,v 1.12 2003/12/10 07:22:43 itojun Exp $	*/
2 
3 /*-
4  *
5  * Copyright (c) 1996 Michael Shalayeff
6  * Copyright (c) 1995, Mike Mitchell
7  * Copyright (c) 1984, 1985, 1986, 1987, 1993
8  *	The Regents of the University of California.  All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. Neither the name of the University nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  *
34  *	@(#)ipx.c
35  *
36  * from FreeBSD Id: ipx.c,v 1.4 1996/03/11 15:13:46 davidg Exp
37  */
38 
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/malloc.h>
42 #include <sys/ioctl.h>
43 #include <sys/protosw.h>
44 #include <sys/socket.h>
45 #include <sys/socketvar.h>
46 
47 #include <dev/rndvar.h>
48 
49 #include <net/if.h>
50 #include <net/route.h>
51 
52 #include <netipx/ipx.h>
53 #include <netipx/ipx_if.h>
54 
55 /*
56  * Generic internet control operations (ioctl's).
57  */
58 /* ARGSUSED */
59 int
ipx_control(so,cmd,data,ifp)60 ipx_control(so, cmd, data, ifp)
61 	struct socket *so;
62 	u_long	cmd;
63 	caddr_t	data;
64 	struct ifnet *ifp;
65 {
66 	struct ifreq *ifr = (struct ifreq *)data;
67 	struct ipx_aliasreq *ifra = (struct ipx_aliasreq *)data;
68 	struct ipx_ifaddr *ia;
69 	int dstIsNew, hostIsNew;
70 	int error = 0;
71 
72 	/*
73 	 * Find address for this interface, if it exists.
74 	 */
75 	if (ifp)
76 		for (ia = ipx_ifaddr.tqh_first; ia; ia = ia->ia_list.tqe_next)
77 			if (ia->ia_ifp == ifp)
78 				break;
79 
80 	switch (cmd) {
81 	case SIOCAIFADDR:
82 	case SIOCDIFADDR:
83 		if (ifra->ifra_addr.sipx_family == AF_IPX)
84 			for (; ia; ia = ia->ia_list.tqe_next) {
85 				if (ia->ia_ifp == ifp  &&
86 				    ipx_neteq(ia->ia_addr.sipx_addr,
87 					      ifra->ifra_addr.sipx_addr))
88 					break;
89 			}
90 		if (cmd == SIOCDIFADDR && ia == 0)
91 			return (EADDRNOTAVAIL);
92 		/* FALLTHROUGH */
93 
94 	case SIOCSIFADDR:
95 	case SIOCSIFDSTADDR:
96 		if ((so->so_state & SS_PRIV) == 0)
97 			return (EPERM);
98 
99 		if (ia == (struct ipx_ifaddr *)NULL) {
100 			ia = (struct ipx_ifaddr *)
101 				malloc(sizeof(*ia), M_IFADDR, M_WAITOK);
102 			bzero((caddr_t)ia, sizeof(*ia));
103 			TAILQ_INSERT_TAIL(&ifp->if_addrlist,
104 				(struct ifaddr *)ia, ifa_list);
105 			TAILQ_INSERT_TAIL(&ipx_ifaddr, ia, ia_list);
106 			ia->ia_ifp = ifp;
107 			ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
108 
109 			ia->ia_ifa.ifa_netmask =
110 				(struct sockaddr *)&ipx_netmask;
111 
112 			ia->ia_ifa.ifa_dstaddr =
113 				(struct sockaddr *)&ia->ia_dstaddr;
114 			if (ifp->if_flags & IFF_BROADCAST) {
115 				ia->ia_broadaddr.sipx_family = AF_IPX;
116 				ia->ia_broadaddr.sipx_len =
117 				    sizeof(ia->ia_addr);
118 				ia->ia_broadaddr.sipx_addr.ipx_host =
119 				    ipx_broadhost;
120 			}
121 		}
122 		break;
123 
124 	case SIOCSIFBRDADDR:
125 		if ((so->so_state & SS_PRIV) == 0)
126 			return (EPERM);
127 		/* FALLTHROUGH */
128 
129 	case SIOCGIFADDR:
130 	case SIOCGIFDSTADDR:
131 	case SIOCGIFBRDADDR:
132 		if (ia == (struct ipx_ifaddr *)NULL)
133 			return (EADDRNOTAVAIL);
134 		break;
135 	}
136 
137 	switch (cmd) {
138 
139 	case SIOCGIFADDR:
140 		*(struct sockaddr_ipx *)&ifr->ifr_addr = ia->ia_addr;
141 		return (0);
142 
143 	case SIOCGIFBRDADDR:
144 		if ((ifp->if_flags & IFF_BROADCAST) == 0)
145 			return (EINVAL);
146 		*(struct sockaddr_ipx *)&ifr->ifr_dstaddr = ia->ia_broadaddr;
147 		return (0);
148 
149 	case SIOCGIFDSTADDR:
150 		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
151 			return (EINVAL);
152 		*(struct sockaddr_ipx *)&ifr->ifr_dstaddr = ia->ia_dstaddr;
153 		return (0);
154 
155 	case SIOCSIFDSTADDR:
156 		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
157 			return (EINVAL);
158 		if (ia->ia_flags & IFA_ROUTE) {
159 			rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
160 			ia->ia_flags &= ~IFA_ROUTE;
161 		}
162 		if (ifp->if_ioctl) {
163 			error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR,
164 			    (void *)ia);
165 			if (error)
166 				return (error);
167 		}
168 		*(struct sockaddr *)&ia->ia_dstaddr = ifr->ifr_dstaddr;
169 		return (0);
170 
171 	case SIOCSIFADDR:
172 		return (ipx_ifinit(ifp, ia,
173 				(struct sockaddr_ipx *)&ifr->ifr_addr, 1));
174 
175 	case SIOCDIFADDR:
176 		ipx_ifscrub(ifp, ia);
177 		TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
178 		TAILQ_REMOVE(&ipx_ifaddr, ia, ia_list);
179 		IFAFREE((&ia->ia_ifa));
180 		return (0);
181 
182 	case SIOCAIFADDR:
183 		dstIsNew = 0; hostIsNew = 1;
184 		if (ia->ia_addr.sipx_family == AF_IPX) {
185 			if (ifra->ifra_addr.sipx_len == 0) {
186 				ifra->ifra_addr = ia->ia_addr;
187 				hostIsNew = 0;
188 			} else if (ipx_neteq(ifra->ifra_addr.sipx_addr,
189 					 ia->ia_addr.sipx_addr))
190 				hostIsNew = 0;
191 		}
192 		if ((ifp->if_flags & IFF_POINTOPOINT) &&
193 		    (ifra->ifra_dstaddr.sipx_family == AF_IPX)) {
194 			if (hostIsNew == 0)
195 				ipx_ifscrub(ifp, ia);
196 			ia->ia_dstaddr = ifra->ifra_dstaddr;
197 			dstIsNew  = 1;
198 		}
199 		if (ifra->ifra_addr.sipx_family == AF_IPX &&
200 					    (hostIsNew || dstIsNew))
201 			error = ipx_ifinit(ifp, ia, &ifra->ifra_addr, 0);
202 		return (error);
203 
204 	default:
205 		if (ifp->if_ioctl == 0)
206 			return (EOPNOTSUPP);
207 		return ((*ifp->if_ioctl)(ifp, cmd, data));
208 	}
209 }
210 
211 /*
212  * Delete any previous route for an old address.
213  */
214 void
ipx_ifscrub(ifp,ia)215 ipx_ifscrub(ifp, ia)
216 	struct ifnet *ifp;
217 	struct ipx_ifaddr *ia;
218 {
219 	if (ia->ia_flags & IFA_ROUTE) {
220 		if (ifp->if_flags & IFF_POINTOPOINT) {
221 			rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
222 		} else
223 			rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0);
224 		ia->ia_flags &= ~IFA_ROUTE;
225 	}
226 }
227 
228 /*
229  * Initialize an interface's IPX address
230  * and routing table entry.
231  */
232 int
ipx_ifinit(ifp,ia,sipx,scrub)233 ipx_ifinit(ifp, ia, sipx, scrub)
234 	struct ifnet *ifp;
235 	struct ipx_ifaddr *ia;
236 	struct sockaddr_ipx *sipx;
237 	int scrub;
238 {
239 	struct sockaddr_ipx oldaddr;
240 	int s = splimp(), error;
241 
242 	/*
243 	 * Set up new addresses.
244 	 */
245 	oldaddr = ia->ia_addr;
246 	ia->ia_addr = *sipx;
247 
248 	/*
249 	 * The convention we shall adopt for naming is that
250 	 * a supplied address of zero means that "we don't care".
251 	 * Use the MAC address of the interface. If it is an
252 	 * interface without a MAC address, like a serial line, the
253 	 * address must be supplied.
254 	 *
255 	 * Give the interface a chance to initialize
256 	 * if this is its first address,
257 	 * and to validate the address if necessary.
258 	 */
259 	if (ifp->if_ioctl != NULL &&
260 	    (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (void *)ia))) {
261 		ia->ia_addr = oldaddr;
262 		splx(s);
263 		return (error);
264 	}
265 	ia->ia_ifa.ifa_metric = ifp->if_metric;
266 	/*
267 	 * Add route for the network.
268 	 */
269 	if (scrub) {
270 		ia->ia_ifa.ifa_addr = (struct sockaddr *)&oldaddr;
271 		ipx_ifscrub(ifp, ia);
272 		ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
273 	}
274 	if (ifp->if_flags & IFF_POINTOPOINT)
275 		rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP);
276 	else {
277 		ia->ia_broadaddr.sipx_addr.ipx_net =
278 		    ia->ia_addr.sipx_addr.ipx_net;
279 		rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_UP);
280 	}
281 	ia->ia_flags |= IFA_ROUTE;
282 	rnd_lopool_addh(ia, sizeof(*ia));
283 	splx(s);
284 	return (0);
285 }
286 
287 /*
288  * Return address info for specified IPX network.
289  */
290 struct ipx_ifaddr *
ipx_iaonnetof(dst)291 ipx_iaonnetof(dst)
292 	struct ipx_addr *dst;
293 {
294 	struct ipx_ifaddr *ia;
295 	struct ipx_addr *compare;
296 	struct ifnet *ifp;
297 	struct ipx_ifaddr *ia_maybe = NULL;
298 	union ipx_net net = dst->ipx_net;
299 
300 	for (ia = ipx_ifaddr.tqh_first; ia; ia = ia->ia_list.tqe_next) {
301 		if ((ifp = ia->ia_ifp)) {
302 			if (ifp->if_flags & IFF_POINTOPOINT) {
303 				compare = &satoipx_addr(ia->ia_dstaddr);
304 				if (ipx_hosteq(*dst, *compare))
305 					return (ia);
306 				if (ipx_neteqnn(net,
307 				    ia->ia_addr.sipx_addr.ipx_net))
308 					ia_maybe = ia;
309 			} else {
310 				if (ipx_neteqnn(net,
311 				    ia->ia_addr.sipx_addr.ipx_net))
312 					return (ia);
313 			}
314 		}
315 	}
316 	return (ia_maybe);
317 }
318 
319 void
ipx_printhost(addr)320 ipx_printhost(addr)
321 register struct ipx_addr *addr;
322 {
323 	u_short port;
324 	struct ipx_addr work = *addr;
325 	char *p;
326 	u_char *q;
327 	char *net = "", *host = "";
328 	char cport[10], chost[15], cnet[15];
329 
330 	port = ntohs(work.ipx_port);
331 
332 	if (ipx_nullnet(work) && ipx_nullhost(work)) {
333 
334 		if (port)
335 			printf("*.%x", port);
336 		else
337 			printf("*.*");
338 
339 		return;
340 	}
341 
342 	if (ipx_wildnet(work))
343 		net = "any";
344 	else if (ipx_nullnet(work))
345 		net = "*";
346 	else {
347 		q = work.ipx_net.c_net;
348 		snprintf(cnet, sizeof(cnet), "%x%x%x%x",
349 			q[0], q[1], q[2], q[3]);
350 		for (p = cnet; *p == '0' && p < cnet + 8; p++)
351 			continue;
352 		net = p;
353 	}
354 
355 	if (ipx_wildhost(work))
356 		host = "any";
357 	else if (ipx_nullhost(work))
358 		host = "*";
359 	else {
360 		q = work.ipx_host.c_host;
361 		snprintf(chost, sizeof(chost), "%x%x%x%x%x%x",
362 			q[0], q[1], q[2], q[3], q[4], q[5]);
363 		for (p = chost; *p == '0' && p < chost + 12; p++)
364 			continue;
365 		host = p;
366 	}
367 
368 	if (port) {
369 		if (strcmp(host, "*") == 0) {
370 			host = "";
371 			snprintf(cport, sizeof(cport), "%x", port);
372 		} else
373 			snprintf(cport, sizeof(cport), ".%x", port);
374 	} else
375 		*cport = 0;
376 
377 	printf("%s.%s%s", net, host, cport);
378 }
379 
380