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