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.7 (Berkeley) 04/03/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, &ifr->ifr_addr)); 318 319 case SIOCSIFNETMASK: 320 ia->ia_subnetmask = ntohl(satosin(&ifr->ifr_addr)->sin_addr.s_addr); 321 break; 322 323 default: 324 if (ifp == 0 || ifp->if_ioctl == 0) 325 return (EOPNOTSUPP); 326 return ((*ifp->if_ioctl)(ifp, cmd, data)); 327 } 328 return (0); 329 } 330 331 /* 332 * Initialize an interface's internet address 333 * and routing table entry. 334 */ 335 in_ifinit(ifp, ia, sin) 336 register struct ifnet *ifp; 337 register struct in_ifaddr *ia; 338 struct sockaddr_in *sin; 339 { 340 register u_long i = ntohl(sin->sin_addr.s_addr); 341 struct sockaddr oldaddr; 342 struct sockaddr_in netaddr; 343 int s = splimp(), error; 344 345 oldaddr = ia->ia_addr; 346 ia->ia_addr = *(struct sockaddr *)sin; 347 348 /* 349 * Give the interface a chance to initialize 350 * if this is its first address, 351 * and to validate the address if necessary. 352 */ 353 if (ifp->if_ioctl && (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, ia))) { 354 splx(s); 355 ia->ia_addr = oldaddr; 356 return (error); 357 } 358 359 /* 360 * Delete any previous route for an old address. 361 */ 362 bzero((caddr_t)&netaddr, sizeof (netaddr)); 363 netaddr.sin_family = AF_INET; 364 if (ia->ia_flags & IFA_ROUTE) { 365 if (ifp->if_flags & IFF_LOOPBACK) 366 rtinit(&oldaddr, &oldaddr, (int)SIOCDELRT, RTF_HOST); 367 else if (ifp->if_flags & IFF_POINTOPOINT) 368 rtinit(&ia->ia_dstaddr, &oldaddr, (int)SIOCDELRT, 369 RTF_HOST); 370 else { 371 netaddr.sin_addr = in_makeaddr(ia->ia_subnet, 372 INADDR_ANY); 373 rtinit((struct sockaddr *)&netaddr, &oldaddr, 374 (int)SIOCDELRT, 0); 375 } 376 ia->ia_flags &= ~IFA_ROUTE; 377 } 378 if (IN_CLASSA(i)) 379 ia->ia_netmask = IN_CLASSA_NET; 380 else if (IN_CLASSB(i)) 381 ia->ia_netmask = IN_CLASSB_NET; 382 else 383 ia->ia_netmask = IN_CLASSC_NET; 384 ia->ia_net = i & ia->ia_netmask; 385 /* 386 * The subnet mask includes at least the standard network part, 387 * but may already have been set to a larger value. 388 */ 389 ia->ia_subnetmask |= ia->ia_netmask; 390 ia->ia_subnet = i & ia->ia_subnetmask; 391 if (ifp->if_flags & IFF_BROADCAST) { 392 ia->ia_broadaddr.sa_family = AF_INET; 393 ((struct sockaddr_in *)(&ia->ia_broadaddr))->sin_addr = 394 in_makeaddr(ia->ia_subnet, INADDR_BROADCAST); 395 ia->ia_netbroadcast.s_addr = 396 htonl(ia->ia_net | (INADDR_BROADCAST &~ ia->ia_netmask)); 397 } 398 /* 399 * Add route for the network. 400 */ 401 if (ifp->if_flags & IFF_LOOPBACK) 402 rtinit(&ia->ia_addr, &ia->ia_addr, (int)SIOCADDRT, 403 RTF_HOST|RTF_UP); 404 else if (ifp->if_flags & IFF_POINTOPOINT) 405 rtinit(&ia->ia_dstaddr, &ia->ia_addr, (int)SIOCADDRT, 406 RTF_HOST|RTF_UP); 407 else { 408 netaddr.sin_addr = in_makeaddr(ia->ia_subnet, INADDR_ANY); 409 rtinit((struct sockaddr *)&netaddr, &ia->ia_addr, 410 (int)SIOCADDRT, RTF_UP); 411 } 412 ia->ia_flags |= IFA_ROUTE; 413 splx(s); 414 return (0); 415 } 416 417 /* 418 * Return address info for specified internet network. 419 */ 420 struct in_ifaddr * 421 in_iaonnetof(net) 422 u_long net; 423 { 424 register struct in_ifaddr *ia; 425 426 for (ia = in_ifaddr; ia; ia = ia->ia_next) 427 if (ia->ia_subnet == net) 428 return (ia); 429 return ((struct in_ifaddr *)0); 430 } 431 432 /* 433 * Return 1 if the address might be a local broadcast address. 434 */ 435 in_broadcast(in) 436 struct in_addr in; 437 { 438 register struct in_ifaddr *ia; 439 u_long t; 440 441 /* 442 * Look through the list of addresses for a match 443 * with a broadcast address. 444 */ 445 for (ia = in_ifaddr; ia; ia = ia->ia_next) 446 if (ia->ia_ifp->if_flags & IFF_BROADCAST) { 447 if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr == in.s_addr) 448 return (1); 449 /* 450 * Check for old-style (host 0) broadcast. 451 */ 452 if ((t = ntohl(in.s_addr)) == ia->ia_subnet || t == ia->ia_net) 453 return (1); 454 } 455 if (in.s_addr == INADDR_BROADCAST || in.s_addr == INADDR_ANY) 456 return (1); 457 return (0); 458 } 459 #endif 460