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