xref: /csrg-svn/sys/netns/ns.c (revision 26055)
1 /*
2  * Copyright (c) 1984, 1985 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  *
6  *	@(#)ns.c	6.7 (Berkeley) 02/03/86
7  */
8 
9 #include "param.h"
10 #include "mbuf.h"
11 #include "ioctl.h"
12 #include "protosw.h"
13 #include "socket.h"
14 #include "socketvar.h"
15 #include "uio.h"
16 #include "dir.h"
17 #include "user.h"
18 
19 
20 #include "../net/if.h"
21 #include "../net/route.h"
22 #include "../net/af.h"
23 
24 #include "ns.h"
25 #include "ns_if.h"
26 
27 #ifdef NS
28 
29 struct ns_ifaddr *ns_ifaddr;
30 
31 ns_hash(sns, hp)
32 	register struct sockaddr_ns *sns;
33 	struct afhash *hp;
34 {
35 	register long hash = 0;
36 	register u_short *s =  sns->sns_addr.x_host.s_host;
37 	union {
38 		union ns_net	net_e;
39 		long		long_e;
40 	} net;
41 
42 	net.net_e = sns->sns_addr.x_net;
43 	hp->afh_nethash = net.long_e;
44 	hash = *s++; hash <<= 8; hash += *s++; hash <<= 8; hash += *s;
45 	hp->afh_hosthash =  hash;
46 }
47 
48 
49 ns_netmatch(sns1, sns2)
50 	struct sockaddr_ns *sns1, *sns2;
51 {
52 
53 	return (ns_neteq(sns1->sns_addr, sns2->sns_addr));
54 }
55 
56 /*
57  * Generic internet control operations (ioctl's).
58  */
59 /* ARGSUSED */
60 ns_control(so, cmd, data, ifp)
61 	struct socket *so;
62 	int cmd;
63 	caddr_t data;
64 	register struct ifnet *ifp;
65 {
66 	register struct ifreq *ifr = (struct ifreq *)data;
67 	register struct ns_ifaddr *ia;
68 	struct ifaddr *ifa;
69 	struct mbuf *m;
70 
71 	/*
72 	 * Find address for this interface, if it exists.
73 	 */
74 	if (ifp == 0)
75 		return (EADDRNOTAVAIL);
76 	for (ia = ns_ifaddr; ia; ia = ia->ia_next)
77 		if (ia->ia_ifp == ifp)
78 			break;
79 
80 	switch (cmd) {
81 
82 	case SIOCGIFADDR:
83 		if (ia == (struct ns_ifaddr *)0)
84 			return (EADDRNOTAVAIL);
85 		ifr->ifr_addr = ia->ia_addr;
86 		return (0);
87 
88 
89 	case SIOCGIFBRDADDR:
90 		if (ia == (struct ns_ifaddr *)0)
91 			return (EADDRNOTAVAIL);
92 		if ((ifp->if_flags & IFF_BROADCAST) == 0)
93 			return (EINVAL);
94 		ifr->ifr_dstaddr = ia->ia_broadaddr;
95 		return (0);
96 
97 	case SIOCGIFDSTADDR:
98 		if (ia == (struct ns_ifaddr *)0)
99 			return (EADDRNOTAVAIL);
100 		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
101 			return (EINVAL);
102 		ifr->ifr_dstaddr = ia->ia_dstaddr;
103 		return (0);
104 	}
105 
106 	if (!suser())
107 		return (u.u_error);
108 
109 	switch (cmd) {
110 
111 	case SIOCSIFADDR:
112 	case SIOCSIFDSTADDR:
113 		if (ia == (struct ns_ifaddr *)0) {
114 			m = m_getclr(M_WAIT, MT_IFADDR);
115 			if (m == (struct mbuf *)NULL)
116 				return (ENOBUFS);
117 			if (ia = ns_ifaddr) {
118 				for ( ; ia->ia_next; ia = ia->ia_next)
119 					;
120 				ia->ia_next = mtod(m, struct ns_ifaddr *);
121 			} else
122 				ns_ifaddr = mtod(m, struct ns_ifaddr *);
123 			ia = mtod(m, struct ns_ifaddr *);
124 			if (ifa = ifp->if_addrlist) {
125 				for ( ; ifa->ifa_next; ifa = ifa->ifa_next)
126 					;
127 				ifa->ifa_next = (struct ifaddr *) ia;
128 			} else
129 				ifp->if_addrlist = (struct ifaddr *) ia;
130 			ia->ia_ifp = ifp;
131 			IA_SNS(ia)->sns_family = AF_NS;
132 		}
133 	}
134 
135 	switch (cmd) {
136 
137 	case SIOCSIFDSTADDR:
138 		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
139 			return (EINVAL);
140 		if (ia->ia_flags & IFA_ROUTE) {
141 			rtinit(&ia->ia_dstaddr, &ia->ia_addr,
142 				(int)SIOCDELRT, RTF_HOST);
143 			ia->ia_flags &= ~IFA_ROUTE;
144 		}
145 		if (ifp->if_ioctl) {
146 			int error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, ia);
147 			if (error)
148 				return (error);
149 		}
150 		ia->ia_dstaddr = ifr->ifr_dstaddr;
151 		return (0);
152 
153 	case SIOCSIFADDR:
154 		return
155 		    (ns_ifinit(ifp, ia, (struct sockaddr_ns *)&ifr->ifr_addr));
156 
157 	default:
158 		if (ifp->if_ioctl == 0)
159 			return (EOPNOTSUPP);
160 		return ((*ifp->if_ioctl)(ifp, cmd, data));
161 	}
162 }
163 
164 /*
165  * Initialize an interface's internet address
166  * and routing table entry.
167  */
168 ns_ifinit(ifp, ia, sns)
169 	register struct ifnet *ifp;
170 	register struct ns_ifaddr *ia;
171 	struct sockaddr_ns *sns;
172 {
173 	struct sockaddr_ns netaddr;
174 	register union ns_host *h = &(IA_SNS(ia)->sns_addr.x_host);
175 	int s = splimp(), error;
176 
177 	/*
178 	 * The convention we shall adopt for naming is that
179 	 * a supplied address of zero means that "we don't care".
180 	 * if there is a single interface, use the address of that
181 	 * interface as our 6 byte host address.
182 	 * if there are multiple interfaces, use any address already
183 	 * used.
184 	 *
185 	 * If we have gotten into trouble and want to reset back to
186 	 * virginity, we recognize a request of the broadcast address.
187 	 */
188 	if (ns_hosteqnh(sns->sns_addr.x_host, ns_broadhost)) {
189 		ns_thishost = ns_zerohost;
190 		splx(s);
191 		return (0);
192 	}
193 
194 	/*
195 	 * Delete any previous route for an old address.
196 	 */
197 	bzero((caddr_t)&netaddr, sizeof (netaddr));
198 	netaddr.sns_family = AF_NS;
199 	netaddr.sns_addr.x_host = ns_broadhost;
200 	netaddr.sns_addr.x_net = ia->ia_net;
201 	if (ia->ia_flags & IFA_ROUTE) {
202 		if ((ifp->if_flags & IFF_POINTOPOINT) == 0) {
203 		    rtinit((struct sockaddr *)&netaddr, &ia->ia_addr,
204 				    (int)SIOCDELRT, 0);
205 		} else
206 		    rtinit(&ia->ia_dstaddr, &ia->ia_addr,
207 				    (int)SIOCDELRT, RTF_HOST);
208 	}
209 
210 	/*
211 	 * Set up new addresses.
212 	 */
213 	ia->ia_addr = *(struct sockaddr *)sns;
214 	ia->ia_net = sns->sns_addr.x_net;
215 	netaddr.sns_addr.x_net = ia->ia_net;
216 	if (ifp->if_flags & IFF_BROADCAST) {
217 		ia->ia_broadaddr = * (struct sockaddr *) &netaddr;
218 	}
219 
220 	/*
221 	 * Give the interface a chance to initialize
222 	 * if this is its first address,
223 	 * and to validate the address if necessary.
224 	 */
225 	if (ns_hosteqnh(ns_thishost, ns_zerohost)) {
226 		if (ifp->if_ioctl &&
227 		     (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, ia))) {
228 			splx(s);
229 			return (error);
230 		}
231 		ns_thishost = *h;
232 	} else if (ns_hosteqnh(sns->sns_addr.x_host, ns_zerohost)
233 	    || ns_hosteqnh(sns->sns_addr.x_host, ns_thishost)) {
234 		*h = ns_thishost;
235 		if (ifp->if_ioctl &&
236 		     (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, ia))) {
237 			splx(s);
238 			return (error);
239 		}
240 		if (!ns_hosteqnh(ns_thishost,*h)) {
241 			splx(s);
242 			return (EINVAL);
243 		}
244 	} else {
245 		splx(s);
246 		return (EINVAL);
247 	}
248 
249 	/*
250 	 * Add route for the network.
251 	 */
252 	if (ifp->if_flags & IFF_POINTOPOINT)
253 		rtinit(&ia->ia_dstaddr, &ia->ia_addr, (int)SIOCADDRT,
254 			RTF_HOST|RTF_UP);
255 	else
256 		rtinit(&ia->ia_broadaddr, &ia->ia_addr, (int)SIOCADDRT,
257 			RTF_UP);
258 	ia->ia_flags |= IFA_ROUTE;
259 	return (0);
260 }
261 
262 /*
263  * Return address info for specified internet network.
264  */
265 struct ns_ifaddr *
266 ns_iaonnetof(dst)
267 	register struct ns_addr *dst;
268 {
269 	register struct ns_ifaddr *ia;
270 	register struct ns_addr *compare;
271 	register struct ifnet *ifp;
272 	struct ns_ifaddr *ia_maybe = 0;
273 	union ns_net net = dst->x_net;
274 
275 	for (ia = ns_ifaddr; ia; ia = ia->ia_next) {
276 		if (ifp = ia->ia_ifp) {
277 			if (ifp->if_flags & IFF_POINTOPOINT) {
278 				compare = &satons_addr(ia->ia_dstaddr);
279 				if (ns_hosteq(*dst, *compare))
280 					return (ia);
281 				if (ns_neteqnn(net, ia->ia_net))
282 					ia_maybe = ia;
283 			} else {
284 				if (ns_neteqnn(net, ia->ia_net))
285 					return (ia);
286 			}
287 		}
288 	}
289 	return (ia_maybe);
290 }
291 #endif
292