Commit | Line | Data |
---|---|---|
8ae0e4b4 KM |
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 | * | |
e251991b | 6 | * @(#)in.c 6.14 (Berkeley) %G% |
8ae0e4b4 | 7 | */ |
8473bbab | 8 | |
20666ad3 | 9 | #include "param.h" |
65b95551 | 10 | #include "ioctl.h" |
20666ad3 JB |
11 | #include "mbuf.h" |
12 | #include "protosw.h" | |
13 | #include "socket.h" | |
14 | #include "socketvar.h" | |
65b95551 MK |
15 | #include "uio.h" |
16 | #include "dir.h" | |
17 | #include "user.h" | |
20666ad3 | 18 | #include "in_systm.h" |
6187f8f4 SL |
19 | #include "../net/if.h" |
20 | #include "../net/route.h" | |
8473bbab | 21 | #include "../net/af.h" |
65b95551 MK |
22 | #include "in.h" |
23 | #include "in_var.h" | |
8473bbab SL |
24 | |
25 | #ifdef INET | |
26 | inet_hash(sin, hp) | |
27 | register struct sockaddr_in *sin; | |
28 | struct afhash *hp; | |
29 | { | |
65b95551 | 30 | register u_long n; |
a8d3bf7f | 31 | |
65b95551 MK |
32 | n = in_netof(sin->sin_addr); |
33 | if (n) | |
34 | while ((n & 0xff) == 0) | |
35 | n >>= 8; | |
36 | hp->afh_nethash = n; | |
2c48b3f8 | 37 | hp->afh_hosthash = ntohl(sin->sin_addr.s_addr); |
8473bbab SL |
38 | } |
39 | ||
40 | inet_netmatch(sin1, sin2) | |
41 | struct sockaddr_in *sin1, *sin2; | |
42 | { | |
a8d3bf7f | 43 | |
6f117122 | 44 | return (in_netof(sin1->sin_addr) == in_netof(sin2->sin_addr)); |
8473bbab SL |
45 | } |
46 | ||
47 | /* | |
65b95551 | 48 | * Formulate an Internet address from network + host. |
8473bbab SL |
49 | */ |
50 | struct in_addr | |
65b95551 MK |
51 | in_makeaddr(net, host) |
52 | u_long net, host; | |
8473bbab | 53 | { |
65b95551 MK |
54 | register struct in_ifaddr *ia; |
55 | register u_long mask; | |
8473bbab SL |
56 | u_long addr; |
57 | ||
65b95551 MK |
58 | if (IN_CLASSA(net)) |
59 | mask = IN_CLASSA_HOST; | |
60 | else if (IN_CLASSB(net)) | |
61 | mask = IN_CLASSB_HOST; | |
8473bbab | 62 | else |
65b95551 MK |
63 | mask = IN_CLASSC_HOST; |
64 | for (ia = in_ifaddr; ia; ia = ia->ia_next) | |
65 | if ((ia->ia_netmask & net) == ia->ia_net) { | |
66 | mask = ~ia->ia_subnetmask; | |
67 | break; | |
68 | } | |
69 | addr = htonl(net | (host & mask)); | |
8473bbab SL |
70 | return (*(struct in_addr *)&addr); |
71 | } | |
72 | ||
73 | /* | |
a8d3bf7f | 74 | * Return the network number from an internet address. |
8473bbab | 75 | */ |
2dd77a90 | 76 | u_long |
8473bbab SL |
77 | in_netof(in) |
78 | struct in_addr in; | |
79 | { | |
2c48b3f8 | 80 | register u_long i = ntohl(in.s_addr); |
65b95551 MK |
81 | register u_long net; |
82 | register struct in_ifaddr *ia; | |
8473bbab | 83 | |
65b95551 MK |
84 | if (IN_CLASSA(i)) |
85 | net = i & IN_CLASSA_NET; | |
86 | else if (IN_CLASSB(i)) | |
87 | net = i & IN_CLASSB_NET; | |
88 | else | |
89 | net = i & IN_CLASSC_NET; | |
083b2954 MK |
90 | |
91 | /* | |
65b95551 | 92 | * Check whether network is a subnet; |
083b2954 MK |
93 | * if so, return subnet number. |
94 | */ | |
65b95551 | 95 | for (ia = in_ifaddr; ia; ia = ia->ia_next) |
2dd77a90 | 96 | if (net == ia->ia_net) |
65b95551 | 97 | return (i & ia->ia_subnetmask); |
083b2954 | 98 | return (net); |
8473bbab SL |
99 | } |
100 | ||
101 | /* | |
a8d3bf7f | 102 | * Return the host portion of an internet address. |
8473bbab | 103 | */ |
8011f5df | 104 | u_long |
8473bbab SL |
105 | in_lnaof(in) |
106 | struct in_addr in; | |
107 | { | |
2c48b3f8 | 108 | register u_long i = ntohl(in.s_addr); |
65b95551 MK |
109 | register u_long net, host; |
110 | register struct in_ifaddr *ia; | |
8473bbab | 111 | |
3adde5ac | 112 | if (IN_CLASSA(i)) { |
65b95551 MK |
113 | net = i & IN_CLASSA_NET; |
114 | host = i & IN_CLASSA_HOST; | |
3adde5ac | 115 | } else if (IN_CLASSB(i)) { |
65b95551 MK |
116 | net = i & IN_CLASSB_NET; |
117 | host = i & IN_CLASSB_HOST; | |
3adde5ac | 118 | } else { |
65b95551 MK |
119 | net = i & IN_CLASSC_NET; |
120 | host = i & IN_CLASSC_HOST; | |
3adde5ac | 121 | } |
3adde5ac | 122 | |
083b2954 | 123 | /* |
65b95551 | 124 | * Check whether network is a subnet; |
083b2954 MK |
125 | * if so, use the modified interpretation of `host'. |
126 | */ | |
65b95551 | 127 | for (ia = in_ifaddr; ia; ia = ia->ia_next) |
2dd77a90 | 128 | if (net == ia->ia_net) |
65b95551 | 129 | return (host &~ ia->ia_subnetmask); |
083b2954 | 130 | return (host); |
8473bbab SL |
131 | } |
132 | ||
8011f5df MK |
133 | #ifndef SUBNETSARELOCAL |
134 | #define SUBNETSARELOCAL 1 | |
135 | #endif | |
136 | int subnetsarelocal = SUBNETSARELOCAL; | |
99578149 | 137 | /* |
65b95551 | 138 | * Return 1 if an internet address is for a ``local'' host |
8011f5df MK |
139 | * (one to which we have a connection). If subnetsarelocal |
140 | * is true, this includes other subnets of the local net. | |
141 | * Otherwise, it includes only the directly-connected (sub)nets. | |
99578149 MK |
142 | */ |
143 | in_localaddr(in) | |
144 | struct in_addr in; | |
145 | { | |
146 | register u_long i = ntohl(in.s_addr); | |
147 | register u_long net; | |
65b95551 | 148 | register struct in_ifaddr *ia; |
99578149 MK |
149 | |
150 | if (IN_CLASSA(i)) | |
65b95551 | 151 | net = i & IN_CLASSA_NET; |
99578149 | 152 | else if (IN_CLASSB(i)) |
65b95551 | 153 | net = i & IN_CLASSB_NET; |
99578149 | 154 | else |
65b95551 MK |
155 | net = i & IN_CLASSC_NET; |
156 | ||
157 | for (ia = in_ifaddr; ia; ia = ia->ia_next) | |
8011f5df | 158 | if (net == subnetsarelocal ? ia->ia_net : ia->ia_subnet) |
65b95551 MK |
159 | return (1); |
160 | return (0); | |
161 | } | |
162 | ||
2dd77a90 MK |
163 | int in_interfaces; /* number of external internet interfaces */ |
164 | extern struct ifnet loif; | |
165 | ||
65b95551 MK |
166 | /* |
167 | * Generic internet control operations (ioctl's). | |
168 | * Ifp is 0 if not an interface-specific ioctl. | |
169 | */ | |
2dd77a90 | 170 | /* ARGSUSED */ |
65b95551 MK |
171 | in_control(so, cmd, data, ifp) |
172 | struct socket *so; | |
173 | int cmd; | |
174 | caddr_t data; | |
175 | register struct ifnet *ifp; | |
176 | { | |
177 | register struct ifreq *ifr = (struct ifreq *)data; | |
178 | register struct in_ifaddr *ia = 0; | |
4afb57fa | 179 | u_long tmp; |
65b95551 MK |
180 | struct ifaddr *ifa; |
181 | struct mbuf *m; | |
182 | int error; | |
183 | ||
184 | /* | |
185 | * Find address for this interface, if it exists. | |
186 | */ | |
187 | if (ifp) | |
188 | for (ia = in_ifaddr; ia; ia = ia->ia_next) | |
189 | if (ia->ia_ifp == ifp) | |
190 | break; | |
191 | ||
192 | switch (cmd) { | |
193 | ||
65b95551 | 194 | case SIOCSIFADDR: |
65b95551 | 195 | case SIOCSIFNETMASK: |
0977715b | 196 | case SIOCSIFDSTADDR: |
65b95551 MK |
197 | if (!suser()) |
198 | return (u.u_error); | |
199 | ||
200 | if (ifp == 0) | |
201 | panic("in_control"); | |
202 | if (ia == (struct in_ifaddr *)0) { | |
203 | m = m_getclr(M_WAIT, MT_IFADDR); | |
204 | if (m == (struct mbuf *)NULL) | |
205 | return (ENOBUFS); | |
206 | if (ia = in_ifaddr) { | |
207 | for ( ; ia->ia_next; ia = ia->ia_next) | |
208 | ; | |
209 | ia->ia_next = mtod(m, struct in_ifaddr *); | |
210 | } else | |
211 | in_ifaddr = mtod(m, struct in_ifaddr *); | |
212 | ia = mtod(m, struct in_ifaddr *); | |
213 | if (ifa = ifp->if_addrlist) { | |
214 | for ( ; ifa->ifa_next; ifa = ifa->ifa_next) | |
215 | ; | |
216 | ifa->ifa_next = (struct ifaddr *) ia; | |
217 | } else | |
218 | ifp->if_addrlist = (struct ifaddr *) ia; | |
219 | ia->ia_ifp = ifp; | |
220 | IA_SIN(ia)->sin_family = AF_INET; | |
2dd77a90 MK |
221 | if (ifp != &loif) |
222 | in_interfaces++; | |
99578149 | 223 | } |
65b95551 | 224 | break; |
b9ce6c7a MK |
225 | |
226 | case SIOCSIFBRDADDR: | |
b9ce6c7a MK |
227 | if (!suser()) |
228 | return (u.u_error); | |
229 | /* FALLTHROUGH */ | |
230 | ||
231 | default: | |
232 | if (ia == (struct in_ifaddr *)0) | |
233 | return (EADDRNOTAVAIL); | |
234 | break; | |
65b95551 MK |
235 | } |
236 | ||
237 | switch (cmd) { | |
238 | ||
239 | case SIOCGIFADDR: | |
240 | ifr->ifr_addr = ia->ia_addr; | |
241 | break; | |
242 | ||
243 | case SIOCGIFBRDADDR: | |
244 | if ((ifp->if_flags & IFF_BROADCAST) == 0) | |
245 | return (EINVAL); | |
246 | ifr->ifr_dstaddr = ia->ia_broadaddr; | |
247 | break; | |
248 | ||
249 | case SIOCGIFDSTADDR: | |
250 | if ((ifp->if_flags & IFF_POINTOPOINT) == 0) | |
251 | return (EINVAL); | |
252 | ifr->ifr_dstaddr = ia->ia_dstaddr; | |
253 | break; | |
254 | ||
255 | case SIOCGIFNETMASK: | |
256 | #define satosin(sa) ((struct sockaddr_in *)(sa)) | |
257 | satosin(&ifr->ifr_addr)->sin_family = AF_INET; | |
258 | satosin(&ifr->ifr_addr)->sin_addr.s_addr = htonl(ia->ia_subnetmask); | |
259 | break; | |
260 | ||
261 | case SIOCSIFDSTADDR: | |
262 | if ((ifp->if_flags & IFF_POINTOPOINT) == 0) | |
263 | return (EINVAL); | |
264 | if (ifp->if_ioctl && | |
2dd77a90 | 265 | (error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, ia))) |
65b95551 MK |
266 | return (error); |
267 | ia->ia_dstaddr = ifr->ifr_dstaddr; | |
268 | break; | |
269 | ||
270 | case SIOCSIFBRDADDR: | |
271 | if ((ifp->if_flags & IFF_BROADCAST) == 0) | |
272 | return (EINVAL); | |
273 | ia->ia_broadaddr = ifr->ifr_broadaddr; | |
4afb57fa MK |
274 | tmp = ntohl(satosin(&ia->ia_broadaddr)->sin_addr.s_addr); |
275 | if ((tmp &~ ia->ia_subnetmask) == ~ia->ia_subnetmask) | |
276 | tmp |= ~ia->ia_netmask; | |
277 | else if ((tmp &~ ia->ia_subnetmask) == 0) | |
278 | tmp &= ia->ia_netmask; | |
279 | ia->ia_netbroadcast.s_addr = htonl(tmp); | |
65b95551 MK |
280 | break; |
281 | ||
282 | case SIOCSIFADDR: | |
283 | return (in_ifinit(ifp, ia, &ifr->ifr_addr)); | |
65b95551 MK |
284 | |
285 | case SIOCSIFNETMASK: | |
286 | ia->ia_subnetmask = ntohl(satosin(&ifr->ifr_addr)->sin_addr.s_addr); | |
287 | break; | |
288 | ||
289 | default: | |
290 | if (ifp == 0 || ifp->if_ioctl == 0) | |
291 | return (EOPNOTSUPP); | |
292 | return ((*ifp->if_ioctl)(ifp, cmd, data)); | |
99578149 MK |
293 | } |
294 | return (0); | |
295 | } | |
296 | ||
8473bbab | 297 | /* |
65b95551 MK |
298 | * Initialize an interface's internet address |
299 | * and routing table entry. | |
8473bbab | 300 | */ |
65b95551 | 301 | in_ifinit(ifp, ia, sin) |
8473bbab | 302 | register struct ifnet *ifp; |
65b95551 MK |
303 | register struct in_ifaddr *ia; |
304 | struct sockaddr_in *sin; | |
305 | { | |
306 | register u_long i = ntohl(sin->sin_addr.s_addr); | |
b9ce6c7a | 307 | struct sockaddr_in tmpaddr; |
65b95551 MK |
308 | int s = splimp(), error; |
309 | ||
b9ce6c7a MK |
310 | tmpaddr = *(struct sockaddr_in *)&ia->ia_addr; |
311 | ia->ia_addr = *(struct sockaddr *)sin; | |
312 | ||
313 | /* | |
314 | * Give the interface a chance to initialize | |
315 | * if this is its first address, | |
316 | * and to validate the address if necessary. | |
317 | */ | |
318 | if (ifp->if_ioctl && (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, ia))) { | |
319 | splx(s); | |
320 | ia->ia_addr = *(struct sockaddr *)&tmpaddr; | |
321 | return (error); | |
322 | } | |
323 | ||
324 | bzero((caddr_t)&tmpaddr, sizeof (tmpaddr)); | |
325 | tmpaddr.sin_family = AF_INET; | |
65b95551 MK |
326 | /* |
327 | * Delete any previous route for an old address. | |
328 | */ | |
329 | if (ia->ia_flags & IFA_ROUTE) { | |
330 | if ((ifp->if_flags & IFF_POINTOPOINT) == 0) { | |
b9ce6c7a MK |
331 | tmpaddr.sin_addr = in_makeaddr(ia->ia_subnet, INADDR_ANY); |
332 | rtinit((struct sockaddr *)&tmpaddr, &ia->ia_addr, | |
aca5d587 | 333 | (int)SIOCDELRT, 0); |
65b95551 | 334 | } else |
aca5d587 KS |
335 | rtinit((struct sockaddr *)&ia->ia_dstaddr, &ia->ia_addr, |
336 | (int)SIOCDELRT, RTF_HOST); | |
65b95551 MK |
337 | ia->ia_flags &= ~IFA_ROUTE; |
338 | } | |
65b95551 MK |
339 | if (IN_CLASSA(i)) |
340 | ia->ia_netmask = IN_CLASSA_NET; | |
341 | else if (IN_CLASSB(i)) | |
342 | ia->ia_netmask = IN_CLASSB_NET; | |
343 | else | |
344 | ia->ia_netmask = IN_CLASSC_NET; | |
345 | ia->ia_net = i & ia->ia_netmask; | |
346 | /* | |
347 | * The subnet mask includes at least the standard network part, | |
348 | * but may already have been set to a larger value. | |
349 | */ | |
350 | ia->ia_subnetmask |= ia->ia_netmask; | |
351 | ia->ia_subnet = i & ia->ia_subnetmask; | |
352 | if (ifp->if_flags & IFF_BROADCAST) { | |
353 | ia->ia_broadaddr.sa_family = AF_INET; | |
354 | ((struct sockaddr_in *)(&ia->ia_broadaddr))->sin_addr = | |
355 | in_makeaddr(ia->ia_subnet, INADDR_BROADCAST); | |
4afb57fa MK |
356 | ia->ia_netbroadcast.s_addr = |
357 | htonl(ia->ia_net | (INADDR_BROADCAST &~ ia->ia_netmask)); | |
65b95551 | 358 | } |
65b95551 MK |
359 | splx(s); |
360 | /* | |
361 | * Add route for the network. | |
362 | */ | |
363 | if ((ifp->if_flags & IFF_POINTOPOINT) == 0) { | |
b9ce6c7a MK |
364 | tmpaddr.sin_addr = in_makeaddr(ia->ia_subnet, INADDR_ANY); |
365 | rtinit((struct sockaddr *)&tmpaddr, &ia->ia_addr, | |
aca5d587 | 366 | (int)SIOCADDRT, RTF_UP); |
65b95551 MK |
367 | } else |
368 | rtinit((struct sockaddr *)&ia->ia_dstaddr, &ia->ia_addr, | |
aca5d587 | 369 | (int)SIOCADDRT, RTF_HOST|RTF_UP); |
65b95551 | 370 | ia->ia_flags |= IFA_ROUTE; |
773256ba | 371 | return (0); |
65b95551 MK |
372 | } |
373 | ||
374 | /* | |
375 | * Return address info for specified internet network. | |
376 | */ | |
377 | struct in_ifaddr * | |
378 | in_iaonnetof(net) | |
379 | u_long net; | |
380 | { | |
381 | register struct in_ifaddr *ia; | |
382 | ||
383 | for (ia = in_ifaddr; ia; ia = ia->ia_next) | |
384 | if (ia->ia_subnet == net) | |
385 | return (ia); | |
386 | return ((struct in_ifaddr *)0); | |
387 | } | |
388 | ||
389 | /* | |
390 | * Return 1 if the address is a local broadcast address. | |
391 | */ | |
392 | in_broadcast(in) | |
393 | struct in_addr in; | |
8473bbab | 394 | { |
65b95551 MK |
395 | register struct in_ifaddr *ia; |
396 | ||
397 | /* | |
398 | * Look through the list of addresses for a match | |
399 | * with a broadcast address. | |
400 | */ | |
401 | for (ia = in_ifaddr; ia; ia = ia->ia_next) | |
402 | if (((struct sockaddr_in *)&ia->ia_broadaddr)->sin_addr.s_addr == | |
403 | in.s_addr && (ia->ia_ifp->if_flags & IFF_BROADCAST)) | |
404 | return (1); | |
405 | return (0); | |
8473bbab SL |
406 | } |
407 | #endif |