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