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