longer TTL's
[unix-history] / usr / src / sys / netinet / in.c
CommitLineData
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
26inet_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
40inet_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 */
50struct in_addr
65b95551
MK
51in_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 76u_long
8473bbab
SL
77in_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 104u_long
8473bbab
SL
105in_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
136int 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 */
143in_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
163int in_interfaces; /* number of external internet interfaces */
164extern 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
171in_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 301in_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 */
377struct in_ifaddr *
378in_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 */
392in_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