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 | * | |
6 | * @(#)in.c 6.8 (Berkeley) %G% | |
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 SL |
75 | */ |
76 | in_netof(in) | |
77 | struct in_addr in; | |
78 | { | |
2c48b3f8 | 79 | register u_long i = ntohl(in.s_addr); |
65b95551 MK |
80 | register u_long net; |
81 | register struct in_ifaddr *ia; | |
8473bbab | 82 | |
65b95551 MK |
83 | if (IN_CLASSA(i)) |
84 | net = i & IN_CLASSA_NET; | |
85 | else if (IN_CLASSB(i)) | |
86 | net = i & IN_CLASSB_NET; | |
87 | else | |
88 | net = i & IN_CLASSC_NET; | |
083b2954 MK |
89 | |
90 | /* | |
65b95551 | 91 | * Check whether network is a subnet; |
083b2954 MK |
92 | * if so, return subnet number. |
93 | */ | |
65b95551 MK |
94 | for (ia = in_ifaddr; ia; ia = ia->ia_next) |
95 | if ((ia->ia_netmask & net) == ia->ia_net) | |
96 | return (i & ia->ia_subnetmask); | |
083b2954 | 97 | return (net); |
8473bbab SL |
98 | } |
99 | ||
100 | /* | |
a8d3bf7f | 101 | * Return the host portion of an internet address. |
8473bbab SL |
102 | */ |
103 | in_lnaof(in) | |
104 | struct in_addr in; | |
105 | { | |
2c48b3f8 | 106 | register u_long i = ntohl(in.s_addr); |
65b95551 MK |
107 | register u_long net, host; |
108 | register struct in_ifaddr *ia; | |
8473bbab | 109 | |
3adde5ac | 110 | if (IN_CLASSA(i)) { |
65b95551 MK |
111 | net = i & IN_CLASSA_NET; |
112 | host = i & IN_CLASSA_HOST; | |
3adde5ac | 113 | } else if (IN_CLASSB(i)) { |
65b95551 MK |
114 | net = i & IN_CLASSB_NET; |
115 | host = i & IN_CLASSB_HOST; | |
3adde5ac | 116 | } else { |
65b95551 MK |
117 | net = i & IN_CLASSC_NET; |
118 | host = i & IN_CLASSC_HOST; | |
3adde5ac | 119 | } |
3adde5ac | 120 | |
083b2954 | 121 | /* |
65b95551 | 122 | * Check whether network is a subnet; |
083b2954 MK |
123 | * if so, use the modified interpretation of `host'. |
124 | */ | |
65b95551 MK |
125 | for (ia = in_ifaddr; ia; ia = ia->ia_next) |
126 | if ((ia->ia_netmask & net) == ia->ia_net) | |
127 | return (host &~ ia->ia_subnetmask); | |
083b2954 | 128 | return (host); |
8473bbab SL |
129 | } |
130 | ||
99578149 | 131 | /* |
65b95551 MK |
132 | * Return 1 if an internet address is for a ``local'' host |
133 | * (one to which we have a connection). | |
99578149 MK |
134 | */ |
135 | in_localaddr(in) | |
136 | struct in_addr in; | |
137 | { | |
138 | register u_long i = ntohl(in.s_addr); | |
139 | register u_long net; | |
65b95551 | 140 | register struct in_ifaddr *ia; |
99578149 MK |
141 | |
142 | if (IN_CLASSA(i)) | |
65b95551 | 143 | net = i & IN_CLASSA_NET; |
99578149 | 144 | else if (IN_CLASSB(i)) |
65b95551 | 145 | net = i & IN_CLASSB_NET; |
99578149 | 146 | else |
65b95551 MK |
147 | net = i & IN_CLASSC_NET; |
148 | ||
149 | for (ia = in_ifaddr; ia; ia = ia->ia_next) | |
150 | if ((ia->ia_netmask & net) == ia->ia_net) | |
151 | return (1); | |
152 | return (0); | |
153 | } | |
154 | ||
155 | /* | |
156 | * Generic internet control operations (ioctl's). | |
157 | * Ifp is 0 if not an interface-specific ioctl. | |
158 | */ | |
159 | in_control(so, cmd, data, ifp) | |
160 | struct socket *so; | |
161 | int cmd; | |
162 | caddr_t data; | |
163 | register struct ifnet *ifp; | |
164 | { | |
165 | register struct ifreq *ifr = (struct ifreq *)data; | |
166 | register struct in_ifaddr *ia = 0; | |
167 | struct ifaddr *ifa; | |
168 | struct mbuf *m; | |
169 | int error; | |
170 | ||
171 | /* | |
172 | * Find address for this interface, if it exists. | |
173 | */ | |
174 | if (ifp) | |
175 | for (ia = in_ifaddr; ia; ia = ia->ia_next) | |
176 | if (ia->ia_ifp == ifp) | |
177 | break; | |
178 | ||
179 | switch (cmd) { | |
180 | ||
181 | case SIOCGIFADDR: | |
182 | case SIOCGIFBRDADDR: | |
183 | case SIOCGIFDSTADDR: | |
184 | case SIOCGIFNETMASK: | |
185 | if (ia == (struct in_ifaddr *)0) | |
186 | return (EADDRNOTAVAIL); | |
187 | break; | |
188 | ||
189 | case SIOCSIFADDR: | |
190 | case SIOCSIFDSTADDR: | |
191 | case SIOCSIFBRDADDR: | |
192 | case SIOCSIFNETMASK: | |
193 | if (!suser()) | |
194 | return (u.u_error); | |
195 | ||
196 | if (ifp == 0) | |
197 | panic("in_control"); | |
198 | if (ia == (struct in_ifaddr *)0) { | |
199 | m = m_getclr(M_WAIT, MT_IFADDR); | |
200 | if (m == (struct mbuf *)NULL) | |
201 | return (ENOBUFS); | |
202 | if (ia = in_ifaddr) { | |
203 | for ( ; ia->ia_next; ia = ia->ia_next) | |
204 | ; | |
205 | ia->ia_next = mtod(m, struct in_ifaddr *); | |
206 | } else | |
207 | in_ifaddr = mtod(m, struct in_ifaddr *); | |
208 | ia = mtod(m, struct in_ifaddr *); | |
209 | if (ifa = ifp->if_addrlist) { | |
210 | for ( ; ifa->ifa_next; ifa = ifa->ifa_next) | |
211 | ; | |
212 | ifa->ifa_next = (struct ifaddr *) ia; | |
213 | } else | |
214 | ifp->if_addrlist = (struct ifaddr *) ia; | |
215 | ia->ia_ifp = ifp; | |
216 | IA_SIN(ia)->sin_family = AF_INET; | |
99578149 | 217 | } |
65b95551 MK |
218 | break; |
219 | } | |
220 | ||
221 | switch (cmd) { | |
222 | ||
223 | case SIOCGIFADDR: | |
224 | ifr->ifr_addr = ia->ia_addr; | |
225 | break; | |
226 | ||
227 | case SIOCGIFBRDADDR: | |
228 | if ((ifp->if_flags & IFF_BROADCAST) == 0) | |
229 | return (EINVAL); | |
230 | ifr->ifr_dstaddr = ia->ia_broadaddr; | |
231 | break; | |
232 | ||
233 | case SIOCGIFDSTADDR: | |
234 | if ((ifp->if_flags & IFF_POINTOPOINT) == 0) | |
235 | return (EINVAL); | |
236 | ifr->ifr_dstaddr = ia->ia_dstaddr; | |
237 | break; | |
238 | ||
239 | case SIOCGIFNETMASK: | |
240 | #define satosin(sa) ((struct sockaddr_in *)(sa)) | |
241 | satosin(&ifr->ifr_addr)->sin_family = AF_INET; | |
242 | satosin(&ifr->ifr_addr)->sin_addr.s_addr = htonl(ia->ia_subnetmask); | |
243 | break; | |
244 | ||
245 | case SIOCSIFDSTADDR: | |
246 | if ((ifp->if_flags & IFF_POINTOPOINT) == 0) | |
247 | return (EINVAL); | |
248 | if (ifp->if_ioctl && | |
249 | (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, ia))) | |
250 | return (error); | |
251 | ia->ia_dstaddr = ifr->ifr_dstaddr; | |
252 | break; | |
253 | ||
254 | case SIOCSIFBRDADDR: | |
255 | if ((ifp->if_flags & IFF_BROADCAST) == 0) | |
256 | return (EINVAL); | |
257 | ia->ia_broadaddr = ifr->ifr_broadaddr; | |
258 | break; | |
259 | ||
260 | case SIOCSIFADDR: | |
261 | return (in_ifinit(ifp, ia, &ifr->ifr_addr)); | |
262 | break; | |
263 | ||
264 | case SIOCSIFNETMASK: | |
265 | ia->ia_subnetmask = ntohl(satosin(&ifr->ifr_addr)->sin_addr.s_addr); | |
266 | break; | |
267 | ||
268 | default: | |
269 | if (ifp == 0 || ifp->if_ioctl == 0) | |
270 | return (EOPNOTSUPP); | |
271 | return ((*ifp->if_ioctl)(ifp, cmd, data)); | |
99578149 MK |
272 | } |
273 | return (0); | |
274 | } | |
275 | ||
8473bbab | 276 | /* |
65b95551 MK |
277 | * Initialize an interface's internet address |
278 | * and routing table entry. | |
8473bbab | 279 | */ |
65b95551 | 280 | in_ifinit(ifp, ia, sin) |
8473bbab | 281 | register struct ifnet *ifp; |
65b95551 MK |
282 | register struct in_ifaddr *ia; |
283 | struct sockaddr_in *sin; | |
284 | { | |
285 | register u_long i = ntohl(sin->sin_addr.s_addr); | |
286 | struct sockaddr_in netaddr; | |
287 | int s = splimp(), error; | |
288 | ||
289 | bzero((caddr_t)&netaddr, sizeof (netaddr)); | |
290 | netaddr.sin_family = AF_INET; | |
291 | /* | |
292 | * Delete any previous route for an old address. | |
293 | */ | |
294 | if (ia->ia_flags & IFA_ROUTE) { | |
295 | if ((ifp->if_flags & IFF_POINTOPOINT) == 0) { | |
296 | netaddr.sin_addr = in_makeaddr(ia->ia_subnet, INADDR_ANY); | |
297 | rtinit((struct sockaddr *)&netaddr, &ia->ia_addr, -1); | |
298 | } else | |
299 | rtinit((struct sockaddr *)&ia->ia_dstaddr, &ia->ia_addr, -1); | |
300 | ia->ia_flags &= ~IFA_ROUTE; | |
301 | } | |
302 | ia->ia_addr = *(struct sockaddr *)sin; | |
303 | if (IN_CLASSA(i)) | |
304 | ia->ia_netmask = IN_CLASSA_NET; | |
305 | else if (IN_CLASSB(i)) | |
306 | ia->ia_netmask = IN_CLASSB_NET; | |
307 | else | |
308 | ia->ia_netmask = IN_CLASSC_NET; | |
309 | ia->ia_net = i & ia->ia_netmask; | |
310 | /* | |
311 | * The subnet mask includes at least the standard network part, | |
312 | * but may already have been set to a larger value. | |
313 | */ | |
314 | ia->ia_subnetmask |= ia->ia_netmask; | |
315 | ia->ia_subnet = i & ia->ia_subnetmask; | |
316 | if (ifp->if_flags & IFF_BROADCAST) { | |
317 | ia->ia_broadaddr.sa_family = AF_INET; | |
318 | ((struct sockaddr_in *)(&ia->ia_broadaddr))->sin_addr = | |
319 | in_makeaddr(ia->ia_subnet, INADDR_BROADCAST); | |
320 | } | |
321 | ||
322 | /* | |
323 | * Give the interface a chance to initialize | |
324 | * if this is its first address, | |
325 | * and to validate the address if necessary. | |
326 | */ | |
327 | if (ifp->if_ioctl && (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, ia))) { | |
328 | splx(s); | |
329 | bzero((caddr_t)&ia->ia_addr, sizeof(ia->ia_addr)); | |
330 | return (error); | |
331 | } | |
332 | splx(s); | |
333 | /* | |
334 | * Add route for the network. | |
335 | */ | |
336 | if ((ifp->if_flags & IFF_POINTOPOINT) == 0) { | |
337 | netaddr.sin_addr = in_makeaddr(ia->ia_subnet, INADDR_ANY); | |
338 | rtinit((struct sockaddr *)&netaddr, &ia->ia_addr, RTF_UP); | |
339 | } else | |
340 | rtinit((struct sockaddr *)&ia->ia_dstaddr, &ia->ia_addr, | |
341 | RTF_HOST|RTF_UP); | |
342 | ia->ia_flags |= IFA_ROUTE; | |
773256ba | 343 | return (0); |
65b95551 MK |
344 | } |
345 | ||
346 | /* | |
347 | * Return address info for specified internet network. | |
348 | */ | |
349 | struct in_ifaddr * | |
350 | in_iaonnetof(net) | |
351 | u_long net; | |
352 | { | |
353 | register struct in_ifaddr *ia; | |
354 | ||
355 | for (ia = in_ifaddr; ia; ia = ia->ia_next) | |
356 | if (ia->ia_subnet == net) | |
357 | return (ia); | |
358 | return ((struct in_ifaddr *)0); | |
359 | } | |
360 | ||
361 | /* | |
362 | * Return 1 if the address is a local broadcast address. | |
363 | */ | |
364 | in_broadcast(in) | |
365 | struct in_addr in; | |
8473bbab | 366 | { |
65b95551 MK |
367 | register struct in_ifaddr *ia; |
368 | ||
369 | /* | |
370 | * Look through the list of addresses for a match | |
371 | * with a broadcast address. | |
372 | */ | |
373 | for (ia = in_ifaddr; ia; ia = ia->ia_next) | |
374 | if (((struct sockaddr_in *)&ia->ia_broadaddr)->sin_addr.s_addr == | |
375 | in.s_addr && (ia->ia_ifp->if_flags & IFF_BROADCAST)) | |
376 | return (1); | |
377 | return (0); | |
8473bbab SL |
378 | } |
379 | #endif |