xref: /csrg-svn/sys/netns/ns.c (revision 24226)
1 /*
2  * Copyright (c) 1982 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.4 (Berkeley) 08/09/85
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 
38 	hp->afh_nethash = ns_netof(sns->sns_addr);
39 	hash = *s++; hash <<= 8; hash += *s++; hash <<= 8; hash += *s;
40 	hp->afh_hosthash =  hash;
41 }
42 
43 
44 ns_netmatch(sns1, sns2)
45 	struct sockaddr_ns *sns1, *sns2;
46 {
47 
48 	return (ns_netof(sns1->sns_addr) == ns_netof(sns2->sns_addr));
49 }
50 
51 /*
52  * Generic internet control operations (ioctl's).
53  */
54 /* ARGSUSED */
55 ns_control(so, cmd, data, ifp)
56 	struct socket *so;
57 	int cmd;
58 	caddr_t data;
59 	register struct ifnet *ifp;
60 {
61 	register struct ifreq *ifr = (struct ifreq *)data;
62 	register struct ns_ifaddr *ia;
63 	struct ifaddr *ifa;
64 	struct mbuf *m;
65 
66 	/*
67 	 * Find address for this interface, if it exists.
68 	 */
69 	if (ifp==0)
70 		return (EADDRNOTAVAIL);
71 	for (ia = ns_ifaddr; ia; ia = ia->ia_next)
72 		if (ia->ia_ifp == ifp)
73 			break;
74 
75 	switch (cmd) {
76 
77 	case SIOCGIFADDR:
78 		if (ia == (struct ns_ifaddr *)0)
79 			return (EADDRNOTAVAIL);
80 		ifr->ifr_addr = ia->ia_addr;
81 		return (0);
82 
83 
84 	case SIOCGIFBRDADDR:
85 		if (ia == (struct ns_ifaddr *)0)
86 			return (EADDRNOTAVAIL);
87 		if ((ifp->if_flags & IFF_BROADCAST) == 0)
88 			return (EINVAL);
89 		ifr->ifr_dstaddr = ia->ia_broadaddr;
90 		return (0);
91 
92 	case SIOCGIFDSTADDR:
93 		if (ia == (struct ns_ifaddr *)0)
94 			return (EADDRNOTAVAIL);
95 		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
96 			return (EINVAL);
97 		ifr->ifr_dstaddr = ia->ia_dstaddr;
98 		return (0);
99 	}
100 
101 	if (!suser())
102 		return (u.u_error);
103 
104 	switch (cmd) {
105 
106 	case SIOCSIFDSTADDR:
107 		return (EOPNOTSUPP);
108 
109 	case SIOCSIFADDR:
110 		if (ia == (struct ns_ifaddr *)0) {
111 			m = m_getclr(M_WAIT, MT_IFADDR);
112 			if (m == (struct mbuf *)NULL)
113 				return (ENOBUFS);
114 			if (ia = ns_ifaddr) {
115 				for ( ; ia->ia_next; ia = ia->ia_next)
116 					;
117 				ia->ia_next = mtod(m, struct ns_ifaddr *);
118 			} else
119 				ns_ifaddr = mtod(m, struct ns_ifaddr *);
120 			ia = mtod(m, struct ns_ifaddr *);
121 			if (ifa = ifp->if_addrlist) {
122 				for ( ; ifa->ifa_next; ifa = ifa->ifa_next)
123 					;
124 				ifa->ifa_next = (struct ifaddr *) ia;
125 			} else
126 				ifp->if_addrlist = (struct ifaddr *) ia;
127 			ia->ia_ifp = ifp;
128 			IA_SNS(ia)->sns_family = AF_NS;
129 		}
130 		return
131 		    (ns_ifinit(ifp, ia, (struct sockaddr_ns *)&ifr->ifr_addr));
132 
133 	default:
134 		if (ifp->if_ioctl == 0)
135 			return (EOPNOTSUPP);
136 		return ((*ifp->if_ioctl)(ifp, cmd, data));
137 	}
138 }
139 
140 /*
141  * Initialize an interface's internet address
142  * and routing table entry.
143  */
144 ns_ifinit(ifp, ia, sns)
145 	register struct ifnet *ifp;
146 	register struct ns_ifaddr *ia;
147 	struct sockaddr_ns *sns;
148 {
149 	struct sockaddr_ns netaddr;
150 	register union ns_host *h = &(IA_SNS(ia)->sns_addr.x_host);
151 	int s = splimp(), error;
152 
153 	/*
154 	 * The convention we shall adopt for naming is that
155 	 * a supplied address of zero means that "we don't care".
156 	 * if there is a single interface, use the address of that
157 	 * interface as our 6 byte host address.
158 	 * if there are multiple interfaces, use any address already
159 	 * used.
160 	 *
161 	 * If we have gotten into trouble and want to reset back to
162 	 * virginity, we recognize a request of the broadcast address.
163 	 */
164 	if (ns_hosteqnh(sns->sns_addr.x_host, ns_broadhost)) {
165 		ns_thishost = ns_zerohost;
166 		splx(s);
167 		return(EINVAL);
168 	}
169 
170 	/*
171 	 * Delete any previous route for an old address.
172 	 */
173 
174 	bzero((caddr_t)&netaddr, sizeof (netaddr));
175 	netaddr.sns_family = AF_NS;
176 	netaddr.sns_addr.x_host = ns_broadhost;
177 	netaddr.sns_addr.x_net = ia->ia_net;
178 	if (ia->ia_flags & IFA_ROUTE) {
179 		if ((ifp->if_flags & IFF_POINTOPOINT) == 0) {
180 		    rtinit((struct sockaddr *)&netaddr, &ia->ia_addr, -1);
181 		} else
182 		    rtinit((struct sockaddr *)&ia->ia_dstaddr, &ia->ia_addr, -1);
183 	}
184 
185 	/*
186 	 * Set up new addresses.
187 	 */
188 	ia->ia_addr = *(struct sockaddr *)sns;
189 	ia->ia_net = sns->sns_addr.x_net;
190 	netaddr.sns_addr.x_net = ia->ia_net;
191 	if (ifp->if_flags & IFF_BROADCAST) {
192 		ia->ia_broadaddr = * (struct sockaddr *) &netaddr;
193 	}
194 	/*
195 	 * Point to point links are a little touchier --
196 	 * We have to have an address of our own first,
197 	 * and will use the supplied address as that of the other end.
198 	 */
199 	if (ifp->if_flags & IFF_POINTOPOINT) {
200 		struct sockaddr_ns *sns2 = IA_SNS(ia);
201 		if (ns_hosteqnh(ns_zerohost,ns_thishost))
202 			return(EINVAL);
203 		ia->ia_dstaddr = ia->ia_addr;
204 		sns2->sns_addr.x_host = ns_thishost;
205 		sns->sns_addr.x_host = ns_thishost;
206 	}
207 	/*
208 	 * Give the interface a chance to initialize
209 	 * if this is its first address,
210 	 * and to validate the address if necessary.
211 	 */
212 
213 	if (ns_hosteqnh(ns_thishost, ns_zerohost)) {
214 		if (ifp->if_ioctl &&
215 		     (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, ia))) {
216 			splx(s);
217 			return (error);
218 		}
219 		ns_thishost = *h;
220 	} else if (ns_hosteqnh(sns->sns_addr.x_host, ns_zerohost)
221 	    || ns_hosteqnh(sns->sns_addr.x_host, ns_thishost)) {
222 		*h = ns_thishost;
223 		if (ifp->if_ioctl &&
224 		     (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, ia))) {
225 			splx(s);
226 			return (error);
227 		}
228 		if(!ns_hosteqnh(ns_thishost,*h)) {
229 			splx(s);
230 			return (EINVAL);
231 		}
232 	} else {
233 		splx(s);
234 		return(EINVAL);
235 	}
236 	/*
237 	 * Add route for the network.
238 	 */
239 	if ((ifp->if_flags & IFF_POINTOPOINT) == 0) {
240 		rtinit((struct sockaddr *)&netaddr, &ia->ia_addr, RTF_UP);
241 	} else
242 		rtinit((struct sockaddr *)&ia->ia_dstaddr, &ia->ia_addr,
243 			RTF_HOST|RTF_UP);
244 	ia->ia_flags |= IFA_ROUTE;
245 	return(0);
246 }
247 
248 /*
249  * Return address info for specified internet network.
250  */
251 struct ns_ifaddr *
252 ns_iaonnetof(net)
253 	union ns_net net;
254 {
255 	register struct ns_ifaddr *ia;
256 
257 #define	NtoL(x)	(*(long *)(&(x)))
258 	for (ia = ns_ifaddr; ia; ia = ia->ia_next)
259 		if (NtoL(ia->ia_net) == NtoL(net))
260 			return (ia);
261 	return ((struct ns_ifaddr *)0);
262 }
263 #endif
264