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