xref: /csrg-svn/sys/netns/ns.c (revision 37473)
1 /*
2  * Copyright (c) 1984, 1985, 1986, 1987 Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  *
17  *	@(#)ns.c	7.4 (Berkeley) 04/22/89
18  */
19 
20 #include "param.h"
21 #include "mbuf.h"
22 #include "ioctl.h"
23 #include "protosw.h"
24 #include "socket.h"
25 #include "socketvar.h"
26 #include "uio.h"
27 #include "dir.h"
28 #include "user.h"
29 
30 
31 #include "../net/if.h"
32 #include "../net/route.h"
33 #include "../net/af.h"
34 
35 #include "ns.h"
36 #include "ns_if.h"
37 
38 #ifdef NS
39 
40 struct ns_ifaddr *ns_ifaddr;
41 int ns_interfaces;
42 extern struct sockaddr_ns ns_netmask, ns_hostmask;
43 
44 /*
45  * Generic internet control operations (ioctl's).
46  */
47 /* ARGSUSED */
48 ns_control(so, cmd, data, ifp)
49 	struct socket *so;
50 	int cmd;
51 	caddr_t data;
52 	register struct ifnet *ifp;
53 {
54 	register struct ifreq *ifr = (struct ifreq *)data;
55 	register struct ns_aliasreq *ifra = (struct ns_aliasreq *)data;
56 	register struct ns_ifaddr *ia;
57 	struct ifaddr *ifa;
58 	struct ns_ifaddr *oia;
59 	struct mbuf *m;
60 	int dstIsNew, hostIsNew;
61 
62 	/*
63 	 * Find address for this interface, if it exists.
64 	 */
65 	if (ifp == 0)
66 		return (EADDRNOTAVAIL);
67 	for (ia = ns_ifaddr; ia; ia = ia->ia_next)
68 		if (ia->ia_ifp == ifp)
69 			break;
70 
71 	switch (cmd) {
72 
73 	case SIOCGIFADDR:
74 		if (ia == (struct ns_ifaddr *)0)
75 			return (EADDRNOTAVAIL);
76 		*(struct sockaddr_ns *)&ifr->ifr_addr = ia->ia_addr;
77 		return (0);
78 
79 
80 	case SIOCGIFBRDADDR:
81 		if (ia == (struct ns_ifaddr *)0)
82 			return (EADDRNOTAVAIL);
83 		if ((ifp->if_flags & IFF_BROADCAST) == 0)
84 			return (EINVAL);
85 		*(struct sockaddr_ns *)&ifr->ifr_dstaddr = ia->ia_broadaddr;
86 		return (0);
87 
88 	case SIOCGIFDSTADDR:
89 		if (ia == (struct ns_ifaddr *)0)
90 			return (EADDRNOTAVAIL);
91 		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
92 			return (EINVAL);
93 		*(struct sockaddr_ns *)&ifr->ifr_dstaddr = ia->ia_dstaddr;
94 		return (0);
95 	}
96 
97 	if (!suser())
98 		return (u.u_error);
99 
100 	switch (cmd) {
101 	case SIOCAIFADDR:
102 	case SIOCDIFADDR:
103 		if (ifra->ifra_addr.sns_family == AF_NS)
104 		    for (oia = ia; ia; ia = ia->ia_next) {
105 			if (ia->ia_ifp == ifp  &&
106 			    ns_neteq(ia->ia_addr.sns_addr,
107 				  ifra->ifra_addr.sns_addr))
108 			    break;
109 		    }
110 		if (cmd == SIOCDIFADDR && ia == 0)
111 			return (EADDRNOTAVAIL);
112 		/* FALLTHROUGH */
113 
114 	case SIOCSIFADDR:
115 	case SIOCSIFDSTADDR:
116 		if (ia == (struct ns_ifaddr *)0) {
117 			m = m_getclr(M_WAIT, MT_IFADDR);
118 			if (m == (struct mbuf *)NULL)
119 				return (ENOBUFS);
120 			if (ia = ns_ifaddr) {
121 				for ( ; ia->ia_next; ia = ia->ia_next)
122 					;
123 				ia->ia_next = mtod(m, struct ns_ifaddr *);
124 			} else
125 				ns_ifaddr = mtod(m, struct ns_ifaddr *);
126 			ia = mtod(m, struct ns_ifaddr *);
127 			if (ifa = ifp->if_addrlist) {
128 				for ( ; ifa->ifa_next; ifa = ifa->ifa_next)
129 					;
130 				ifa->ifa_next = (struct ifaddr *) ia;
131 			} else
132 				ifp->if_addrlist = (struct ifaddr *) ia;
133 			ia->ia_ifp = ifp;
134 			ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
135 
136 			ia->ia_ifa.ifa_netmask =
137 				(struct sockaddr *)&ns_netmask;
138 
139 			ia->ia_ifa.ifa_dstaddr =
140 				(struct sockaddr *)&ia->ia_dstaddr;
141 			if (ifp->if_flags & IFF_BROADCAST) {
142 				ia->ia_broadaddr.sns_family = AF_NS;
143 				ia->ia_broadaddr.sns_len = sizeof(ia->ia_addr);
144 				ia->ia_broadaddr.sns_addr.x_host = ns_broadhost;
145 			}
146 			ns_interfaces++;
147 		}
148 	}
149 
150 	switch (cmd) {
151 		int error;
152 
153 	case SIOCSIFDSTADDR:
154 		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
155 			return (EINVAL);
156 		if (ia->ia_flags & IFA_ROUTE) {
157 			rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
158 			ia->ia_flags &= ~IFA_ROUTE;
159 		}
160 		if (ifp->if_ioctl) {
161 			error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, ia);
162 			if (error)
163 				return (error);
164 		}
165 		*(struct sockaddr *)&ia->ia_dstaddr = ifr->ifr_dstaddr;
166 		return (0);
167 
168 	case SIOCSIFADDR:
169 		return (ns_ifinit(ifp, ia,
170 				(struct sockaddr_ns *)&ifr->ifr_addr, 1));
171 
172 	case SIOCDIFADDR:
173 		ns_ifscrub(ifp, ia);
174 		if ((ifa = ifp->if_addrlist) == (struct ifaddr *)ia)
175 			ifp->if_addrlist = ifa->ifa_next;
176 		else {
177 			while (ifa->ifa_next &&
178 			       (ifa->ifa_next != (struct ifaddr *)ia))
179 				    ifa = ifa->ifa_next;
180 			if (ifa->ifa_next)
181 			    ifa->ifa_next = ((struct ifaddr *)ia)->ifa_next;
182 			else
183 				printf("Couldn't unlink nsifaddr from ifp\n");
184 		}
185 		oia = ia;
186 		if (oia == (ia = ns_ifaddr)) {
187 			ns_ifaddr = ia->ia_next;
188 		} else {
189 			while (ia->ia_next && (ia->ia_next != oia)) {
190 				ia = ia->ia_next;
191 			}
192 			if (ia->ia_next)
193 			    ia->ia_next = oia->ia_next;
194 			else
195 				printf("Didn't unlink nsifadr from list\n");
196 		}
197 		(void) m_free(dtom(oia));
198 		if (0 == --ns_interfaces) {
199 			/*
200 			 * We reset to virginity and start all over again
201 			 */
202 			ns_thishost = ns_zerohost;
203 		}
204 		return (0);
205 
206 	case SIOCAIFADDR:
207 		dstIsNew = 0; hostIsNew = 1;
208 		if (ia->ia_addr.sns_family == AF_NS) {
209 			if (ifra->ifra_addr.sns_len == 0) {
210 				ifra->ifra_addr = ia->ia_addr;
211 				hostIsNew = 0;
212 			} else if (ns_neteq(ifra->ifra_addr.sns_addr,
213 					 ia->ia_addr.sns_addr))
214 				hostIsNew = 0;
215 		}
216 		if ((ifp->if_flags & IFF_POINTOPOINT) &&
217 		    (ifra->ifra_dstaddr.sns_family == AF_NS)) {
218 			if (hostIsNew == 0)
219 				ns_ifscrub(ifp, ia);
220 			ia->ia_dstaddr = ifra->ifra_dstaddr;
221 			dstIsNew  = 1;
222 		}
223 		if (ifra->ifra_addr.sns_family == AF_NS &&
224 					    (hostIsNew || dstIsNew))
225 			error = ns_ifinit(ifp, ia, &ifra->ifra_addr, 0);
226 		return (error);
227 
228 	default:
229 		if (ifp->if_ioctl == 0)
230 			return (EOPNOTSUPP);
231 		return ((*ifp->if_ioctl)(ifp, cmd, data));
232 	}
233 }
234 
235 /*
236 * Delete any previous route for an old address.
237 */
238 ns_ifscrub(ifp, ia)
239 	register struct ifnet *ifp;
240 	register struct ns_ifaddr *ia;
241 {
242 	if (ia->ia_flags & IFA_ROUTE) {
243 		if (ifp->if_flags & IFF_POINTOPOINT) {
244 			rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
245 		} else
246 			rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0);
247 		ia->ia_flags &= ~IFA_ROUTE;
248 	}
249 }
250 /*
251  * Initialize an interface's internet address
252  * and routing table entry.
253  */
254 ns_ifinit(ifp, ia, sns, scrub)
255 	register struct ifnet *ifp;
256 	register struct ns_ifaddr *ia;
257 	register struct sockaddr_ns *sns;
258 {
259 	struct sockaddr_ns oldaddr;
260 	register union ns_host *h = &ia->ia_addr.sns_addr.x_host;
261 	int s = splimp(), error;
262 
263 	/*
264 	 * Set up new addresses.
265 	 */
266 	oldaddr = ia->ia_addr;
267 	ia->ia_addr = *sns;
268 	/*
269 	 * The convention we shall adopt for naming is that
270 	 * a supplied address of zero means that "we don't care".
271 	 * if there is a single interface, use the address of that
272 	 * interface as our 6 byte host address.
273 	 * if there are multiple interfaces, use any address already
274 	 * used.
275 	 *
276 	 * Give the interface a chance to initialize
277 	 * if this is its first address,
278 	 * and to validate the address if necessary.
279 	 */
280 	if (ns_hosteqnh(ns_thishost, ns_zerohost)) {
281 		if (ifp->if_ioctl &&
282 		     (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, ia))) {
283 			ia->ia_addr = oldaddr;
284 			splx(s);
285 			return (error);
286 		}
287 		ns_thishost = *h;
288 	} else if (ns_hosteqnh(sns->sns_addr.x_host, ns_zerohost)
289 	    || ns_hosteqnh(sns->sns_addr.x_host, ns_thishost)) {
290 		*h = ns_thishost;
291 		if (ifp->if_ioctl &&
292 		     (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, ia))) {
293 			ia->ia_addr = oldaddr;
294 			splx(s);
295 			return (error);
296 		}
297 		if (!ns_hosteqnh(ns_thishost,*h)) {
298 			ia->ia_addr = oldaddr;
299 			splx(s);
300 			return (EINVAL);
301 		}
302 	} else {
303 		ia->ia_addr = oldaddr;
304 		splx(s);
305 		return (EINVAL);
306 	}
307 	/*
308 	 * Add route for the network.
309 	 */
310 	if (scrub) {
311 		ia->ia_ifa.ifa_addr = (struct sockaddr *)&oldaddr;
312 		ns_ifscrub(ifp, ia);
313 		ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
314 	}
315 	if (ifp->if_flags & IFF_POINTOPOINT)
316 		rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP);
317 	else {
318 		ia->ia_broadaddr.sns_addr.x_net = ia->ia_net;
319 		rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_UP);
320 	}
321 	ia->ia_flags |= IFA_ROUTE;
322 	return (0);
323 }
324 
325 /*
326  * Return address info for specified internet network.
327  */
328 struct ns_ifaddr *
329 ns_iaonnetof(dst)
330 	register struct ns_addr *dst;
331 {
332 	register struct ns_ifaddr *ia;
333 	register struct ns_addr *compare;
334 	register struct ifnet *ifp;
335 	struct ns_ifaddr *ia_maybe = 0;
336 	union ns_net net = dst->x_net;
337 
338 	for (ia = ns_ifaddr; ia; ia = ia->ia_next) {
339 		if (ifp = ia->ia_ifp) {
340 			if (ifp->if_flags & IFF_POINTOPOINT) {
341 				compare = &satons_addr(ia->ia_dstaddr);
342 				if (ns_hosteq(*dst, *compare))
343 					return (ia);
344 				if (ns_neteqnn(net, ia->ia_net))
345 					ia_maybe = ia;
346 			} else {
347 				if (ns_neteqnn(net, ia->ia_net))
348 					return (ia);
349 			}
350 		}
351 	}
352 	return (ia_maybe);
353 }
354 #endif
355