Commit | Line | Data |
---|---|---|
8ae0e4b4 | 1 | /* |
240edf1f KS |
2 | * Copyright (c) 1984, 1985, 1986, 1987 Regents of the University of California. |
3 | * All rights reserved. | |
8ae0e4b4 | 4 | * |
240edf1f | 5 | * Redistribution and use in source and binary forms are permitted |
616d42db KB |
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. | |
240edf1f | 16 | * |
4dcdd98e | 17 | * @(#)ns.c 7.4 (Berkeley) %G% |
8ae0e4b4 | 18 | */ |
de9bc7de KS |
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; | |
4dcdd98e KS |
41 | int ns_interfaces; |
42 | extern struct sockaddr_ns ns_netmask, ns_hostmask; | |
de9bc7de KS |
43 | |
44 | /* | |
45 | * Generic internet control operations (ioctl's). | |
46 | */ | |
f97be0c9 | 47 | /* ARGSUSED */ |
de9bc7de KS |
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; | |
4dcdd98e | 55 | register struct ns_aliasreq *ifra = (struct ns_aliasreq *)data; |
de9bc7de KS |
56 | register struct ns_ifaddr *ia; |
57 | struct ifaddr *ifa; | |
4dcdd98e | 58 | struct ns_ifaddr *oia; |
de9bc7de | 59 | struct mbuf *m; |
4dcdd98e | 60 | int dstIsNew, hostIsNew; |
de9bc7de | 61 | |
de9bc7de KS |
62 | /* |
63 | * Find address for this interface, if it exists. | |
64 | */ | |
8b659320 | 65 | if (ifp == 0) |
4353fa68 | 66 | return (EADDRNOTAVAIL); |
de9bc7de KS |
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: | |
4353fa68 KS |
74 | if (ia == (struct ns_ifaddr *)0) |
75 | return (EADDRNOTAVAIL); | |
4dcdd98e | 76 | *(struct sockaddr_ns *)&ifr->ifr_addr = ia->ia_addr; |
4353fa68 KS |
77 | return (0); |
78 | ||
79 | ||
de9bc7de | 80 | case SIOCGIFBRDADDR: |
4353fa68 KS |
81 | if (ia == (struct ns_ifaddr *)0) |
82 | return (EADDRNOTAVAIL); | |
83 | if ((ifp->if_flags & IFF_BROADCAST) == 0) | |
84 | return (EINVAL); | |
4dcdd98e | 85 | *(struct sockaddr_ns *)&ifr->ifr_dstaddr = ia->ia_broadaddr; |
4353fa68 KS |
86 | return (0); |
87 | ||
de9bc7de KS |
88 | case SIOCGIFDSTADDR: |
89 | if (ia == (struct ns_ifaddr *)0) | |
90 | return (EADDRNOTAVAIL); | |
4353fa68 KS |
91 | if ((ifp->if_flags & IFF_POINTOPOINT) == 0) |
92 | return (EINVAL); | |
4dcdd98e | 93 | *(struct sockaddr_ns *)&ifr->ifr_dstaddr = ia->ia_dstaddr; |
4353fa68 KS |
94 | return (0); |
95 | } | |
96 | ||
97 | if (!suser()) | |
98 | return (u.u_error); | |
99 | ||
100 | switch (cmd) { | |
4dcdd98e KS |
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 */ | |
de9bc7de | 113 | |
de9bc7de | 114 | case SIOCSIFADDR: |
8b659320 | 115 | case SIOCSIFDSTADDR: |
de9bc7de KS |
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; | |
4dcdd98e KS |
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++; | |
de9bc7de | 147 | } |
8b659320 KS |
148 | } |
149 | ||
150 | switch (cmd) { | |
4dcdd98e | 151 | int error; |
8b659320 KS |
152 | |
153 | case SIOCSIFDSTADDR: | |
154 | if ((ifp->if_flags & IFF_POINTOPOINT) == 0) | |
155 | return (EINVAL); | |
156 | if (ia->ia_flags & IFA_ROUTE) { | |
4dcdd98e | 157 | rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST); |
8b659320 KS |
158 | ia->ia_flags &= ~IFA_ROUTE; |
159 | } | |
160 | if (ifp->if_ioctl) { | |
4dcdd98e | 161 | error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, ia); |
8b659320 KS |
162 | if (error) |
163 | return (error); | |
164 | } | |
4dcdd98e | 165 | *(struct sockaddr *)&ia->ia_dstaddr = ifr->ifr_dstaddr; |
8b659320 KS |
166 | return (0); |
167 | ||
168 | case SIOCSIFADDR: | |
4dcdd98e KS |
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); | |
de9bc7de KS |
227 | |
228 | default: | |
229 | if (ifp->if_ioctl == 0) | |
230 | return (EOPNOTSUPP); | |
231 | return ((*ifp->if_ioctl)(ifp, cmd, data)); | |
232 | } | |
de9bc7de KS |
233 | } |
234 | ||
4dcdd98e KS |
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 | } | |
de9bc7de KS |
250 | /* |
251 | * Initialize an interface's internet address | |
252 | * and routing table entry. | |
253 | */ | |
4dcdd98e | 254 | ns_ifinit(ifp, ia, sns, scrub) |
de9bc7de KS |
255 | register struct ifnet *ifp; |
256 | register struct ns_ifaddr *ia; | |
4dcdd98e | 257 | register struct sockaddr_ns *sns; |
de9bc7de | 258 | { |
4dcdd98e KS |
259 | struct sockaddr_ns oldaddr; |
260 | register union ns_host *h = &ia->ia_addr.sns_addr.x_host; | |
de9bc7de KS |
261 | int s = splimp(), error; |
262 | ||
4dcdd98e KS |
263 | /* |
264 | * Set up new addresses. | |
265 | */ | |
266 | oldaddr = ia->ia_addr; | |
267 | ia->ia_addr = *sns; | |
de9bc7de KS |
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 | * | |
de9bc7de KS |
276 | * Give the interface a chance to initialize |
277 | * if this is its first address, | |
278 | * and to validate the address if necessary. | |
279 | */ | |
de9bc7de KS |
280 | if (ns_hosteqnh(ns_thishost, ns_zerohost)) { |
281 | if (ifp->if_ioctl && | |
282 | (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, ia))) { | |
4dcdd98e | 283 | ia->ia_addr = oldaddr; |
de9bc7de KS |
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))) { | |
4dcdd98e | 293 | ia->ia_addr = oldaddr; |
de9bc7de KS |
294 | splx(s); |
295 | return (error); | |
296 | } | |
8b659320 | 297 | if (!ns_hosteqnh(ns_thishost,*h)) { |
4dcdd98e | 298 | ia->ia_addr = oldaddr; |
de9bc7de KS |
299 | splx(s); |
300 | return (EINVAL); | |
301 | } | |
302 | } else { | |
4dcdd98e | 303 | ia->ia_addr = oldaddr; |
de9bc7de | 304 | splx(s); |
8b659320 | 305 | return (EINVAL); |
de9bc7de KS |
306 | } |
307 | /* | |
308 | * Add route for the network. | |
309 | */ | |
4dcdd98e KS |
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 | } | |
8b659320 | 315 | if (ifp->if_flags & IFF_POINTOPOINT) |
4dcdd98e KS |
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 | } | |
de9bc7de | 321 | ia->ia_flags |= IFA_ROUTE; |
8b659320 | 322 | return (0); |
de9bc7de KS |
323 | } |
324 | ||
325 | /* | |
326 | * Return address info for specified internet network. | |
327 | */ | |
328 | struct ns_ifaddr * | |
46aa06a9 KS |
329 | ns_iaonnetof(dst) |
330 | register struct ns_addr *dst; | |
de9bc7de KS |
331 | { |
332 | register struct ns_ifaddr *ia; | |
46aa06a9 | 333 | register struct ns_addr *compare; |
8b659320 KS |
334 | register struct ifnet *ifp; |
335 | struct ns_ifaddr *ia_maybe = 0; | |
f1e269d4 | 336 | union ns_net net = dst->x_net; |
de9bc7de | 337 | |
46aa06a9 | 338 | for (ia = ns_ifaddr; ia; ia = ia->ia_next) { |
8b659320 KS |
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); | |
f1e269d4 | 344 | if (ns_neteqnn(net, ia->ia_net)) |
8b659320 KS |
345 | ia_maybe = ia; |
346 | } else { | |
f1e269d4 | 347 | if (ns_neteqnn(net, ia->ia_net)) |
46aa06a9 KS |
348 | return (ia); |
349 | } | |
350 | } | |
351 | } | |
352 | return (ia_maybe); | |
de9bc7de KS |
353 | } |
354 | #endif |