1 /* 2 * Copyright (c) 1982, 1986 Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are permitted 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. 16 * 17 * @(#)in.c 7.9 (Berkeley) 06/29/88 18 */ 19 20 #include "param.h" 21 #include "ioctl.h" 22 #include "mbuf.h" 23 #include "protosw.h" 24 #include "socket.h" 25 #include "socketvar.h" 26 #include "uio.h" 27 #include "dir.h" 28 #include "user.h" 29 #include "in_systm.h" 30 #include "../net/if.h" 31 #include "../net/route.h" 32 #include "../net/af.h" 33 #include "in.h" 34 #include "in_var.h" 35 36 #ifdef INET 37 inet_hash(sin, hp) 38 register struct sockaddr_in *sin; 39 struct afhash *hp; 40 { 41 register u_long n; 42 43 n = in_netof(sin->sin_addr); 44 if (n) 45 while ((n & 0xff) == 0) 46 n >>= 8; 47 hp->afh_nethash = n; 48 hp->afh_hosthash = ntohl(sin->sin_addr.s_addr); 49 } 50 51 inet_netmatch(sin1, sin2) 52 struct sockaddr_in *sin1, *sin2; 53 { 54 55 return (in_netof(sin1->sin_addr) == in_netof(sin2->sin_addr)); 56 } 57 58 /* 59 * Formulate an Internet address from network + host. 60 */ 61 struct in_addr 62 in_makeaddr(net, host) 63 u_long net, host; 64 { 65 register struct in_ifaddr *ia; 66 register u_long mask; 67 u_long addr; 68 69 if (IN_CLASSA(net)) 70 mask = IN_CLASSA_HOST; 71 else if (IN_CLASSB(net)) 72 mask = IN_CLASSB_HOST; 73 else 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)); 81 return (*(struct in_addr *)&addr); 82 } 83 84 /* 85 * Return the network number from an internet address. 86 */ 87 u_long 88 in_netof(in) 89 struct in_addr in; 90 { 91 register u_long i = ntohl(in.s_addr); 92 register u_long net; 93 register struct in_ifaddr *ia; 94 95 if (IN_CLASSA(i)) 96 net = i & IN_CLASSA_NET; 97 else if (IN_CLASSB(i)) 98 net = i & IN_CLASSB_NET; 99 else if (IN_CLASSC(i)) 100 net = i & IN_CLASSC_NET; 101 else 102 return (0); 103 104 /* 105 * Check whether network is a subnet; 106 * if so, return subnet number. 107 */ 108 for (ia = in_ifaddr; ia; ia = ia->ia_next) 109 if (net == ia->ia_net) 110 return (i & ia->ia_subnetmask); 111 return (net); 112 } 113 114 /* 115 * Return the host portion of an internet address. 116 */ 117 u_long 118 in_lnaof(in) 119 struct in_addr in; 120 { 121 register u_long i = ntohl(in.s_addr); 122 register u_long net, host; 123 register struct in_ifaddr *ia; 124 125 if (IN_CLASSA(i)) { 126 net = i & IN_CLASSA_NET; 127 host = i & IN_CLASSA_HOST; 128 } else if (IN_CLASSB(i)) { 129 net = i & IN_CLASSB_NET; 130 host = i & IN_CLASSB_HOST; 131 } else if (IN_CLASSC(i)) { 132 net = i & IN_CLASSC_NET; 133 host = i & IN_CLASSC_HOST; 134 } else 135 return (i); 136 137 /* 138 * Check whether network is a subnet; 139 * if so, use the modified interpretation of `host'. 140 */ 141 for (ia = in_ifaddr; ia; ia = ia->ia_next) 142 if (net == ia->ia_net) 143 return (host &~ ia->ia_subnetmask); 144 return (host); 145 } 146 147 #ifndef SUBNETSARELOCAL 148 #define SUBNETSARELOCAL 1 149 #endif 150 int subnetsarelocal = SUBNETSARELOCAL; 151 /* 152 * Return 1 if an internet address is for a ``local'' host 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. 156 */ 157 in_localaddr(in) 158 struct in_addr in; 159 { 160 register u_long i = ntohl(in.s_addr); 161 register struct in_ifaddr *ia; 162 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 } 172 return (0); 173 } 174 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 */ 180 in_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 196 int in_interfaces; /* number of external internet interfaces */ 197 extern struct ifnet loif; 198 199 /* 200 * Generic internet control operations (ioctl's). 201 * Ifp is 0 if not an interface-specific ioctl. 202 */ 203 /* ARGSUSED */ 204 in_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 226 case SIOCSIFADDR: 227 case SIOCSIFNETMASK: 228 case SIOCSIFDSTADDR: 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; 253 if (ifp != &loif) 254 in_interfaces++; 255 } 256 break; 257 258 case SIOCSIFBRDADDR: 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; 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: 294 { 295 struct sockaddr oldaddr; 296 297 if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 298 return (EINVAL); 299 oldaddr = ia->ia_dstaddr; 300 ia->ia_dstaddr = ifr->ifr_dstaddr; 301 if (ifp->if_ioctl && 302 (error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, ia))) { 303 ia->ia_dstaddr = oldaddr; 304 return (error); 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 } 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: 322 return (in_ifinit(ifp, ia, 323 (struct sockaddr_in *) &ifr->ifr_addr)); 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)); 333 } 334 return (0); 335 } 336 337 /* 338 * Initialize an interface's internet address 339 * and routing table entry. 340 */ 341 in_ifinit(ifp, ia, sin) 342 register struct ifnet *ifp; 343 register struct in_ifaddr *ia; 344 struct sockaddr_in *sin; 345 { 346 register u_long i = ntohl(sin->sin_addr.s_addr); 347 struct sockaddr oldaddr; 348 struct sockaddr_in netaddr; 349 int s = splimp(), error; 350 351 oldaddr = ia->ia_addr; 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); 361 ia->ia_addr = oldaddr; 362 return (error); 363 } 364 365 /* 366 * Delete any previous route for an old address. 367 */ 368 bzero((caddr_t)&netaddr, sizeof (netaddr)); 369 netaddr.sin_family = AF_INET; 370 if (ia->ia_flags & IFA_ROUTE) { 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, 380 (int)SIOCDELRT, 0); 381 } 382 ia->ia_flags &= ~IFA_ROUTE; 383 } 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); 401 ia->ia_netbroadcast.s_addr = 402 htonl(ia->ia_net | (INADDR_BROADCAST &~ ia->ia_netmask)); 403 } 404 /* 405 * Add route for the network. 406 */ 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 } 418 ia->ia_flags |= IFA_ROUTE; 419 splx(s); 420 return (0); 421 } 422 423 /* 424 * Return address info for specified internet network. 425 */ 426 struct in_ifaddr * 427 in_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 /* 439 * Return 1 if the address might be a local broadcast address. 440 */ 441 in_broadcast(in) 442 struct in_addr in; 443 { 444 register struct in_ifaddr *ia; 445 u_long t; 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) 452 if (ia->ia_ifp->if_flags & IFF_BROADCAST) { 453 if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr == in.s_addr) 454 return (1); 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); 463 return (0); 464 } 465 #endif 466