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