new stats; change keepalives to use rcv_nxt instead of rcv_nxt-1
[unix-history] / usr / src / sys / netinet / in.c
CommitLineData
8ae0e4b4 1/*
0880b18e 2 * Copyright (c) 1982, 1986 Regents of the University of California.
8ae0e4b4
KM
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 *
d6c52d1d 6 * @(#)in.c 7.3 (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)
d117b1b7 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:
2c83bd95
MK
262 {
263 struct sockaddr oldaddr;
264
65b95551
MK
265 if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
266 return (EINVAL);
2c83bd95
MK
267 oldaddr = ia->ia_dstaddr;
268 ia->ia_dstaddr = ifr->ifr_dstaddr;
65b95551 269 if (ifp->if_ioctl &&
2c83bd95
MK
270 (error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, ia))) {
271 ia->ia_dstaddr = oldaddr;
65b95551 272 return (error);
2c83bd95
MK
273 }
274 if (ia->ia_flags & IFA_ROUTE) {
275 rtinit(&oldaddr, &ia->ia_addr, (int)SIOCDELRT,
276 RTF_HOST);
277 rtinit(&ia->ia_dstaddr, &ia->ia_addr, (int)SIOCADDRT,
278 RTF_HOST|RTF_UP);
279 }
280 }
65b95551
MK
281 break;
282
283 case SIOCSIFBRDADDR:
284 if ((ifp->if_flags & IFF_BROADCAST) == 0)
285 return (EINVAL);
286 ia->ia_broadaddr = ifr->ifr_broadaddr;
4afb57fa
MK
287 tmp = ntohl(satosin(&ia->ia_broadaddr)->sin_addr.s_addr);
288 if ((tmp &~ ia->ia_subnetmask) == ~ia->ia_subnetmask)
289 tmp |= ~ia->ia_netmask;
290 else if ((tmp &~ ia->ia_subnetmask) == 0)
291 tmp &= ia->ia_netmask;
292 ia->ia_netbroadcast.s_addr = htonl(tmp);
65b95551
MK
293 break;
294
295 case SIOCSIFADDR:
296 return (in_ifinit(ifp, ia, &ifr->ifr_addr));
65b95551
MK
297
298 case SIOCSIFNETMASK:
299 ia->ia_subnetmask = ntohl(satosin(&ifr->ifr_addr)->sin_addr.s_addr);
300 break;
301
302 default:
303 if (ifp == 0 || ifp->if_ioctl == 0)
304 return (EOPNOTSUPP);
305 return ((*ifp->if_ioctl)(ifp, cmd, data));
99578149
MK
306 }
307 return (0);
308}
309
8473bbab 310/*
65b95551
MK
311 * Initialize an interface's internet address
312 * and routing table entry.
8473bbab 313 */
65b95551 314in_ifinit(ifp, ia, sin)
8473bbab 315 register struct ifnet *ifp;
65b95551
MK
316 register struct in_ifaddr *ia;
317 struct sockaddr_in *sin;
318{
319 register u_long i = ntohl(sin->sin_addr.s_addr);
2c83bd95
MK
320 struct sockaddr oldaddr;
321 struct sockaddr_in netaddr;
65b95551
MK
322 int s = splimp(), error;
323
2c83bd95 324 oldaddr = ia->ia_addr;
b9ce6c7a
MK
325 ia->ia_addr = *(struct sockaddr *)sin;
326
327 /*
328 * Give the interface a chance to initialize
329 * if this is its first address,
330 * and to validate the address if necessary.
331 */
332 if (ifp->if_ioctl && (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, ia))) {
333 splx(s);
2c83bd95 334 ia->ia_addr = oldaddr;
b9ce6c7a
MK
335 return (error);
336 }
337
65b95551
MK
338 /*
339 * Delete any previous route for an old address.
340 */
2c83bd95
MK
341 bzero((caddr_t)&netaddr, sizeof (netaddr));
342 netaddr.sin_family = AF_INET;
65b95551 343 if (ia->ia_flags & IFA_ROUTE) {
2c83bd95
MK
344 if (ifp->if_flags & IFF_LOOPBACK)
345 rtinit(&oldaddr, &oldaddr, (int)SIOCDELRT, RTF_HOST);
346 else if (ifp->if_flags & IFF_POINTOPOINT)
347 rtinit(&ia->ia_dstaddr, &oldaddr, (int)SIOCDELRT,
348 RTF_HOST);
349 else {
350 netaddr.sin_addr = in_makeaddr(ia->ia_subnet,
351 INADDR_ANY);
352 rtinit((struct sockaddr *)&netaddr, &oldaddr,
aca5d587 353 (int)SIOCDELRT, 0);
2c83bd95 354 }
65b95551
MK
355 ia->ia_flags &= ~IFA_ROUTE;
356 }
65b95551
MK
357 if (IN_CLASSA(i))
358 ia->ia_netmask = IN_CLASSA_NET;
359 else if (IN_CLASSB(i))
360 ia->ia_netmask = IN_CLASSB_NET;
361 else
362 ia->ia_netmask = IN_CLASSC_NET;
363 ia->ia_net = i & ia->ia_netmask;
364 /*
365 * The subnet mask includes at least the standard network part,
366 * but may already have been set to a larger value.
367 */
368 ia->ia_subnetmask |= ia->ia_netmask;
369 ia->ia_subnet = i & ia->ia_subnetmask;
370 if (ifp->if_flags & IFF_BROADCAST) {
371 ia->ia_broadaddr.sa_family = AF_INET;
372 ((struct sockaddr_in *)(&ia->ia_broadaddr))->sin_addr =
373 in_makeaddr(ia->ia_subnet, INADDR_BROADCAST);
4afb57fa
MK
374 ia->ia_netbroadcast.s_addr =
375 htonl(ia->ia_net | (INADDR_BROADCAST &~ ia->ia_netmask));
65b95551 376 }
65b95551
MK
377 /*
378 * Add route for the network.
379 */
2c83bd95
MK
380 if (ifp->if_flags & IFF_LOOPBACK)
381 rtinit(&ia->ia_addr, &ia->ia_addr, (int)SIOCADDRT,
382 RTF_HOST|RTF_UP);
383 else if (ifp->if_flags & IFF_POINTOPOINT)
384 rtinit(&ia->ia_dstaddr, &ia->ia_addr, (int)SIOCADDRT,
385 RTF_HOST|RTF_UP);
386 else {
387 netaddr.sin_addr = in_makeaddr(ia->ia_subnet, INADDR_ANY);
388 rtinit((struct sockaddr *)&netaddr, &ia->ia_addr,
389 (int)SIOCADDRT, RTF_UP);
390 }
65b95551 391 ia->ia_flags |= IFA_ROUTE;
d6c52d1d 392 splx(s);
773256ba 393 return (0);
65b95551
MK
394}
395
396/*
397 * Return address info for specified internet network.
398 */
399struct in_ifaddr *
400in_iaonnetof(net)
401 u_long net;
402{
403 register struct in_ifaddr *ia;
404
405 for (ia = in_ifaddr; ia; ia = ia->ia_next)
406 if (ia->ia_subnet == net)
407 return (ia);
408 return ((struct in_ifaddr *)0);
409}
410
411/*
d6c52d1d 412 * Return 1 if the address might be a local broadcast address.
65b95551
MK
413 */
414in_broadcast(in)
415 struct in_addr in;
8473bbab 416{
65b95551 417 register struct in_ifaddr *ia;
d6c52d1d 418 u_long t;
65b95551
MK
419
420 /*
421 * Look through the list of addresses for a match
422 * with a broadcast address.
423 */
424 for (ia = in_ifaddr; ia; ia = ia->ia_next)
d6c52d1d
MK
425 if (ia->ia_ifp->if_flags & IFF_BROADCAST) {
426 if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr == in.s_addr)
65b95551 427 return (1);
d6c52d1d
MK
428 /*
429 * Check for old-style (host 0) broadcast.
430 */
431 if ((t = ntohl(in.s_addr)) == ia->ia_subnet || t == ia->ia_net)
432 return (1);
433 }
434 if (in.s_addr == INADDR_BROADCAST || in.s_addr == INADDR_ANY)
435 return (1);
65b95551 436 return (0);
8473bbab
SL
437}
438#endif