add stats for SNMP
[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 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.
2b6b6284 16 *
12e323a8 17 * @(#)in.c 7.12 (Berkeley) %G%
8ae0e4b4 18 */
8473bbab 19
20666ad3 20#include "param.h"
65b95551 21#include "ioctl.h"
20666ad3
JB
22#include "mbuf.h"
23#include "protosw.h"
24#include "socket.h"
25#include "socketvar.h"
65b95551 26#include "user.h"
20666ad3 27#include "in_systm.h"
6187f8f4
SL
28#include "../net/if.h"
29#include "../net/route.h"
8473bbab 30#include "../net/af.h"
65b95551
MK
31#include "in.h"
32#include "in_var.h"
8473bbab
SL
33
34#ifdef INET
8473bbab 35/*
65b95551 36 * Formulate an Internet address from network + host.
8473bbab
SL
37 */
38struct in_addr
65b95551
MK
39in_makeaddr(net, host)
40 u_long net, host;
8473bbab 41{
65b95551
MK
42 register struct in_ifaddr *ia;
43 register u_long mask;
8473bbab
SL
44 u_long addr;
45
65b95551
MK
46 if (IN_CLASSA(net))
47 mask = IN_CLASSA_HOST;
48 else if (IN_CLASSB(net))
49 mask = IN_CLASSB_HOST;
8473bbab 50 else
65b95551
MK
51 mask = IN_CLASSC_HOST;
52 for (ia = in_ifaddr; ia; ia = ia->ia_next)
53 if ((ia->ia_netmask & net) == ia->ia_net) {
54 mask = ~ia->ia_subnetmask;
55 break;
56 }
57 addr = htonl(net | (host & mask));
8473bbab
SL
58 return (*(struct in_addr *)&addr);
59}
60
61/*
a8d3bf7f 62 * Return the network number from an internet address.
8473bbab 63 */
2dd77a90 64u_long
8473bbab
SL
65in_netof(in)
66 struct in_addr in;
67{
2c48b3f8 68 register u_long i = ntohl(in.s_addr);
65b95551
MK
69 register u_long net;
70 register struct in_ifaddr *ia;
8473bbab 71
65b95551
MK
72 if (IN_CLASSA(i))
73 net = i & IN_CLASSA_NET;
74 else if (IN_CLASSB(i))
75 net = i & IN_CLASSB_NET;
b4f9e9c7 76 else if (IN_CLASSC(i))
65b95551 77 net = i & IN_CLASSC_NET;
b4f9e9c7
MK
78 else
79 return (0);
083b2954
MK
80
81 /*
65b95551 82 * Check whether network is a subnet;
083b2954
MK
83 * if so, return subnet number.
84 */
65b95551 85 for (ia = in_ifaddr; ia; ia = ia->ia_next)
2dd77a90 86 if (net == ia->ia_net)
65b95551 87 return (i & ia->ia_subnetmask);
083b2954 88 return (net);
8473bbab
SL
89}
90
b4dc7708
KS
91/*
92 * Compute and save network mask as sockaddr from an internet address.
93 */
94in_sockmaskof(in, sockmask)
95 struct in_addr in;
96 register struct sockaddr_in *sockmask;
97{
98 register u_long net;
99 register u_long mask;
100 {
101 register u_long i = ntohl(in.s_addr);
102
103 if (i == 0)
104 net = 0, mask = 0;
105 else if (IN_CLASSA(i))
106 net = i & IN_CLASSA_NET, mask = IN_CLASSA_NET;
107 else if (IN_CLASSB(i))
108 net = i & IN_CLASSB_NET, mask = IN_CLASSB_NET;
109 else if (IN_CLASSC(i))
110 net = i & IN_CLASSC_NET, mask = IN_CLASSC_NET;
111 else
112 net = i, mask = -1;
113 }
114 {
115 register struct in_ifaddr *ia;
116 /*
117 * Check whether network is a subnet;
118 * if so, return subnet number.
119 */
120 for (ia = in_ifaddr; ia; ia = ia->ia_next)
121 if (net == ia->ia_net)
122 mask = ia->ia_subnetmask;
123 }
124 {
125 register char *cp = (char *)&(sockmask->sin_port);
126 register char *cpbase = (char *)&(sockmask->sin_addr);
127
128 sockmask->sin_addr.s_addr = htonl(mask);
129 sockmask->sin_len = 0;
130 while (--cp >= cpbase)
131 if (*cp) {
132 sockmask->sin_len = 1 + cp - (caddr_t)sockmask;
133 break;
134 }
135 }
136}
137
8473bbab 138/*
a8d3bf7f 139 * Return the host portion of an internet address.
8473bbab 140 */
8011f5df 141u_long
8473bbab
SL
142in_lnaof(in)
143 struct in_addr in;
144{
2c48b3f8 145 register u_long i = ntohl(in.s_addr);
65b95551
MK
146 register u_long net, host;
147 register struct in_ifaddr *ia;
8473bbab 148
3adde5ac 149 if (IN_CLASSA(i)) {
65b95551
MK
150 net = i & IN_CLASSA_NET;
151 host = i & IN_CLASSA_HOST;
3adde5ac 152 } else if (IN_CLASSB(i)) {
65b95551
MK
153 net = i & IN_CLASSB_NET;
154 host = i & IN_CLASSB_HOST;
b4f9e9c7 155 } else if (IN_CLASSC(i)) {
65b95551
MK
156 net = i & IN_CLASSC_NET;
157 host = i & IN_CLASSC_HOST;
b4f9e9c7
MK
158 } else
159 return (i);
3adde5ac 160
083b2954 161 /*
65b95551 162 * Check whether network is a subnet;
083b2954
MK
163 * if so, use the modified interpretation of `host'.
164 */
65b95551 165 for (ia = in_ifaddr; ia; ia = ia->ia_next)
2dd77a90 166 if (net == ia->ia_net)
65b95551 167 return (host &~ ia->ia_subnetmask);
083b2954 168 return (host);
8473bbab
SL
169}
170
8011f5df
MK
171#ifndef SUBNETSARELOCAL
172#define SUBNETSARELOCAL 1
173#endif
174int subnetsarelocal = SUBNETSARELOCAL;
99578149 175/*
65b95551 176 * Return 1 if an internet address is for a ``local'' host
8011f5df
MK
177 * (one to which we have a connection). If subnetsarelocal
178 * is true, this includes other subnets of the local net.
179 * Otherwise, it includes only the directly-connected (sub)nets.
99578149
MK
180 */
181in_localaddr(in)
182 struct in_addr in;
183{
184 register u_long i = ntohl(in.s_addr);
65b95551 185 register struct in_ifaddr *ia;
99578149 186
16cae8d5
MK
187 if (subnetsarelocal) {
188 for (ia = in_ifaddr; ia; ia = ia->ia_next)
189 if ((i & ia->ia_netmask) == ia->ia_net)
190 return (1);
191 } else {
192 for (ia = in_ifaddr; ia; ia = ia->ia_next)
193 if ((i & ia->ia_subnetmask) == ia->ia_subnet)
194 return (1);
195 }
65b95551
MK
196 return (0);
197}
198
b4f9e9c7
MK
199/*
200 * Determine whether an IP address is in a reserved set of addresses
201 * that may not be forwarded, or whether datagrams to that destination
202 * may be forwarded.
203 */
204in_canforward(in)
205 struct in_addr in;
206{
207 register u_long i = ntohl(in.s_addr);
208 register u_long net;
209
210 if (IN_EXPERIMENTAL(i))
211 return (0);
212 if (IN_CLASSA(i)) {
213 net = i & IN_CLASSA_NET;
214 if (net == 0 || net == IN_LOOPBACKNET)
215 return (0);
216 }
217 return (1);
218}
219
2dd77a90
MK
220int in_interfaces; /* number of external internet interfaces */
221extern struct ifnet loif;
222
65b95551
MK
223/*
224 * Generic internet control operations (ioctl's).
225 * Ifp is 0 if not an interface-specific ioctl.
226 */
2dd77a90 227/* ARGSUSED */
65b95551
MK
228in_control(so, cmd, data, ifp)
229 struct socket *so;
230 int cmd;
231 caddr_t data;
232 register struct ifnet *ifp;
233{
234 register struct ifreq *ifr = (struct ifreq *)data;
235 register struct in_ifaddr *ia = 0;
b4dc7708
KS
236 register struct ifaddr *ifa;
237 struct in_ifaddr *oia;
238 struct in_aliasreq *ifra = (struct in_aliasreq *)data;
65b95551 239 struct mbuf *m;
b4dc7708
KS
240 struct sockaddr_in oldaddr;
241 int error, hostIsNew, maskIsNew;
242 u_long i;
65b95551
MK
243
244 /*
245 * Find address for this interface, if it exists.
246 */
247 if (ifp)
248 for (ia = in_ifaddr; ia; ia = ia->ia_next)
249 if (ia->ia_ifp == ifp)
250 break;
251
252 switch (cmd) {
253
b4dc7708
KS
254 case SIOCAIFADDR:
255 case SIOCDIFADDR:
256 if (ifra->ifra_addr.sin_family == AF_INET)
257 for (oia = ia; ia; ia = ia->ia_next) {
258 if (ia->ia_ifp == ifp &&
259 ia->ia_addr.sin_addr.s_addr ==
260 ifra->ifra_addr.sin_addr.s_addr)
261 break;
262 }
263 if (cmd == SIOCDIFADDR && ia == 0)
264 return (EADDRNOTAVAIL);
265 /* FALLTHROUGH */
65b95551 266 case SIOCSIFADDR:
65b95551 267 case SIOCSIFNETMASK:
0977715b 268 case SIOCSIFDSTADDR:
06c16dfa
KM
269 if (error = suser(u.u_cred, &u.u_acflag))
270 return (error);
65b95551
MK
271
272 if (ifp == 0)
273 panic("in_control");
274 if (ia == (struct in_ifaddr *)0) {
275 m = m_getclr(M_WAIT, MT_IFADDR);
276 if (m == (struct mbuf *)NULL)
277 return (ENOBUFS);
278 if (ia = in_ifaddr) {
279 for ( ; ia->ia_next; ia = ia->ia_next)
280 ;
281 ia->ia_next = mtod(m, struct in_ifaddr *);
282 } else
283 in_ifaddr = mtod(m, struct in_ifaddr *);
284 ia = mtod(m, struct in_ifaddr *);
285 if (ifa = ifp->if_addrlist) {
286 for ( ; ifa->ifa_next; ifa = ifa->ifa_next)
287 ;
288 ifa->ifa_next = (struct ifaddr *) ia;
289 } else
290 ifp->if_addrlist = (struct ifaddr *) ia;
b4dc7708
KS
291 ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
292 ia->ia_ifa.ifa_dstaddr
293 = (struct sockaddr *)&ia->ia_dstaddr;
294 ia->ia_ifa.ifa_netmask
295 = (struct sockaddr *)&ia->ia_sockmask;
296 ia->ia_sockmask.sin_len = 8;
297 if (ifp->if_flags & IFF_BROADCAST) {
298 ia->ia_broadaddr.sin_len = sizeof(ia->ia_addr);
299 ia->ia_broadaddr.sin_family = AF_INET;
300 }
65b95551 301 ia->ia_ifp = ifp;
2dd77a90
MK
302 if (ifp != &loif)
303 in_interfaces++;
99578149 304 }
65b95551 305 break;
b9ce6c7a
MK
306
307 case SIOCSIFBRDADDR:
06c16dfa
KM
308 if (error = suser(u.u_cred, &u.u_acflag))
309 return (error);
b9ce6c7a
MK
310 /* FALLTHROUGH */
311
312 default:
313 if (ia == (struct in_ifaddr *)0)
314 return (EADDRNOTAVAIL);
315 break;
65b95551 316 }
65b95551
MK
317 switch (cmd) {
318
319 case SIOCGIFADDR:
b4dc7708 320 *((struct sockaddr_in *)&ifr->ifr_addr) = ia->ia_addr;
65b95551
MK
321 break;
322
323 case SIOCGIFBRDADDR:
324 if ((ifp->if_flags & IFF_BROADCAST) == 0)
325 return (EINVAL);
b4dc7708 326 *((struct sockaddr_in *)&ifr->ifr_dstaddr) = ia->ia_broadaddr;
65b95551
MK
327 break;
328
329 case SIOCGIFDSTADDR:
330 if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
331 return (EINVAL);
b4dc7708 332 *((struct sockaddr_in *)&ifr->ifr_dstaddr) = ia->ia_dstaddr;
65b95551
MK
333 break;
334
335 case SIOCGIFNETMASK:
b4dc7708 336 *((struct sockaddr_in *)&ifr->ifr_addr) = ia->ia_sockmask;
65b95551
MK
337 break;
338
339 case SIOCSIFDSTADDR:
340 if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
341 return (EINVAL);
2c83bd95 342 oldaddr = ia->ia_dstaddr;
b4dc7708 343 ia->ia_dstaddr = *(struct sockaddr_in *)&ifr->ifr_dstaddr;
65b95551 344 if (ifp->if_ioctl &&
2c83bd95
MK
345 (error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, ia))) {
346 ia->ia_dstaddr = oldaddr;
65b95551 347 return (error);
2c83bd95
MK
348 }
349 if (ia->ia_flags & IFA_ROUTE) {
b4dc7708
KS
350 ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&oldaddr;
351 rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
352 ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&ia->ia_addr;
353 rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP);
2c83bd95 354 }
65b95551
MK
355 break;
356
357 case SIOCSIFBRDADDR:
358 if ((ifp->if_flags & IFF_BROADCAST) == 0)
359 return (EINVAL);
b4dc7708 360 ia->ia_broadaddr = *(struct sockaddr_in *)&ifr->ifr_broadaddr;
65b95551
MK
361 break;
362
363 case SIOCSIFADDR:
9340d736 364 return (in_ifinit(ifp, ia,
b4dc7708 365 (struct sockaddr_in *) &ifr->ifr_addr, 1));
65b95551
MK
366
367 case SIOCSIFNETMASK:
b4dc7708
KS
368 i = ifra->ifra_addr.sin_addr.s_addr;
369 ia->ia_subnetmask = ntohl(ia->ia_sockmask.sin_addr.s_addr = i);
370 break;
371
372 case SIOCAIFADDR:
373 maskIsNew = 0; hostIsNew = 1; error = u.u_error;
374 if (ia->ia_addr.sin_family == AF_INET) {
375 if (ifra->ifra_addr.sin_len == 0) {
376 ifra->ifra_addr = ia->ia_addr;
377 hostIsNew = 0;
378 } else if (ifra->ifra_addr.sin_addr.s_addr ==
379 ia->ia_addr.sin_addr.s_addr)
380 hostIsNew = 0;
381 }
382 if (ifra->ifra_mask.sin_len) {
383 in_ifscrub(ifp, ia);
384 ia->ia_sockmask = ifra->ifra_mask;
385 ia->ia_subnetmask =
386 ntohl(ia->ia_sockmask.sin_addr.s_addr);
387 maskIsNew = 1;
388 }
389 if ((ifp->if_flags & IFF_POINTOPOINT) &&
390 (ifra->ifra_dstaddr.sin_family == AF_INET)) {
391 in_ifscrub(ifp, ia);
392 ia->ia_dstaddr = ifra->ifra_dstaddr;
393 maskIsNew = 1; /* We lie; but the effect's the same */
394 }
395 if (ifra->ifra_addr.sin_family == AF_INET &&
396 (hostIsNew || maskIsNew))
397 error = in_ifinit(ifp, ia, &ifra->ifra_addr, 0);
398 if ((ifp->if_flags & IFF_BROADCAST) &&
399 (ifra->ifra_broadaddr.sin_family == AF_INET))
400 ia->ia_broadaddr = ifra->ifra_broadaddr;
401 return (error);
402
403 case SIOCDIFADDR:
404 in_ifscrub(ifp, ia);
405 if ((ifa = ifp->if_addrlist) == (struct ifaddr *)ia)
406 ifp->if_addrlist = ifa->ifa_next;
407 else {
408 while (ifa->ifa_next &&
409 (ifa->ifa_next != (struct ifaddr *)ia))
410 ifa = ifa->ifa_next;
411 if (ifa->ifa_next)
412 ifa->ifa_next = ((struct ifaddr *)ia)->ifa_next;
413 else
414 printf("Couldn't unlink inifaddr from ifp\n");
415 }
416 oia = ia;
417 if (oia == (ia = in_ifaddr)) {
418 in_ifaddr = ia->ia_next;
419 } else {
420 while (ia->ia_next && (ia->ia_next != oia)) {
421 ia = ia->ia_next;
422 }
423 if (ia->ia_next)
424 ia->ia_next = oia->ia_next;
425 else
426 printf("Didn't unlink inifadr from list\n");
427 }
428 (void) m_free(dtom(oia));
65b95551
MK
429 break;
430
431 default:
432 if (ifp == 0 || ifp->if_ioctl == 0)
433 return (EOPNOTSUPP);
434 return ((*ifp->if_ioctl)(ifp, cmd, data));
99578149
MK
435 }
436 return (0);
437}
438
b4dc7708
KS
439/*
440 * Delete any existing route for an interface.
441 */
442in_ifscrub(ifp, ia)
443 register struct ifnet *ifp;
444 register struct in_ifaddr *ia;
445{
446
447 if ((ia->ia_flags & IFA_ROUTE) == 0)
448 return;
449 if (ifp->if_flags & (IFF_LOOPBACK|IFF_POINTOPOINT))
450 rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
451 else
452 rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0);
453 ia->ia_flags &= ~IFA_ROUTE;
454}
455
8473bbab 456/*
65b95551
MK
457 * Initialize an interface's internet address
458 * and routing table entry.
8473bbab 459 */
b4dc7708 460in_ifinit(ifp, ia, sin, scrub)
8473bbab 461 register struct ifnet *ifp;
65b95551
MK
462 register struct in_ifaddr *ia;
463 struct sockaddr_in *sin;
464{
465 register u_long i = ntohl(sin->sin_addr.s_addr);
b4dc7708 466 struct sockaddr_in oldaddr;
65b95551
MK
467 int s = splimp(), error;
468
2c83bd95 469 oldaddr = ia->ia_addr;
b4dc7708 470 ia->ia_addr = *sin;
b9ce6c7a
MK
471 /*
472 * Give the interface a chance to initialize
473 * if this is its first address,
474 * and to validate the address if necessary.
475 */
476 if (ifp->if_ioctl && (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, ia))) {
477 splx(s);
2c83bd95 478 ia->ia_addr = oldaddr;
b9ce6c7a
MK
479 return (error);
480 }
b4dc7708
KS
481 if (scrub) {
482 ia->ia_ifa.ifa_addr = (struct sockaddr *)&oldaddr;
483 in_ifscrub(ifp, ia);
484 ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
65b95551 485 }
65b95551
MK
486 if (IN_CLASSA(i))
487 ia->ia_netmask = IN_CLASSA_NET;
488 else if (IN_CLASSB(i))
489 ia->ia_netmask = IN_CLASSB_NET;
490 else
491 ia->ia_netmask = IN_CLASSC_NET;
492 ia->ia_net = i & ia->ia_netmask;
493 /*
494 * The subnet mask includes at least the standard network part,
495 * but may already have been set to a larger value.
496 */
497 ia->ia_subnetmask |= ia->ia_netmask;
498 ia->ia_subnet = i & ia->ia_subnetmask;
b4dc7708 499 ia->ia_sockmask.sin_addr.s_addr = htonl(ia->ia_subnetmask);
65b95551 500 if (ifp->if_flags & IFF_BROADCAST) {
b4dc7708 501 ia->ia_broadaddr.sin_addr =
65b95551 502 in_makeaddr(ia->ia_subnet, INADDR_BROADCAST);
4afb57fa
MK
503 ia->ia_netbroadcast.s_addr =
504 htonl(ia->ia_net | (INADDR_BROADCAST &~ ia->ia_netmask));
65b95551 505 }
65b95551
MK
506 /*
507 * Add route for the network.
508 */
b4dc7708
KS
509 if (ifp->if_flags & IFF_LOOPBACK) {
510 ia->ia_ifa.ifa_dstaddr = ia->ia_ifa.ifa_addr;
511 rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP);
512 } else if (ifp->if_flags & IFF_POINTOPOINT &&
513 ia->ia_dstaddr.sin_family == AF_INET)
514 rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP);
2c83bd95 515 else {
b4dc7708 516 rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_UP);
2c83bd95 517 }
65b95551 518 ia->ia_flags |= IFA_ROUTE;
d6c52d1d 519 splx(s);
773256ba 520 return (0);
65b95551
MK
521}
522
523/*
524 * Return address info for specified internet network.
525 */
526struct in_ifaddr *
527in_iaonnetof(net)
528 u_long net;
529{
530 register struct in_ifaddr *ia;
531
532 for (ia = in_ifaddr; ia; ia = ia->ia_next)
533 if (ia->ia_subnet == net)
534 return (ia);
535 return ((struct in_ifaddr *)0);
536}
537
538/*
d6c52d1d 539 * Return 1 if the address might be a local broadcast address.
65b95551
MK
540 */
541in_broadcast(in)
542 struct in_addr in;
8473bbab 543{
65b95551 544 register struct in_ifaddr *ia;
d6c52d1d 545 u_long t;
65b95551
MK
546
547 /*
548 * Look through the list of addresses for a match
549 * with a broadcast address.
550 */
551 for (ia = in_ifaddr; ia; ia = ia->ia_next)
d6c52d1d 552 if (ia->ia_ifp->if_flags & IFF_BROADCAST) {
b4dc7708 553 if (ia->ia_broadaddr.sin_addr.s_addr == in.s_addr)
65b95551 554 return (1);
d6c52d1d
MK
555 /*
556 * Check for old-style (host 0) broadcast.
557 */
558 if ((t = ntohl(in.s_addr)) == ia->ia_subnet || t == ia->ia_net)
559 return (1);
560 }
561 if (in.s_addr == INADDR_BROADCAST || in.s_addr == INADDR_ANY)
562 return (1);
65b95551 563 return (0);
8473bbab
SL
564}
565#endif