1/* 2 * Copyright (c) 1982, 1986, 1991, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright --- 17 unchanged lines hidden (view full) --- 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * @(#)in.c 8.4 (Berkeley) 1/9/95 |
34 * $FreeBSD: head/sys/netinet/in.c 55009 1999-12-22 19:13:38Z shin $ |
35 */ 36 37#include <sys/param.h> 38#include <sys/systm.h> 39#include <sys/sockio.h> 40#include <sys/malloc.h> 41#include <sys/proc.h> 42#include <sys/socket.h> 43#include <sys/kernel.h> 44#include <sys/sysctl.h> 45 46#include <net/if.h> |
47#include <net/if_types.h> |
48#include <net/route.h> 49 50#include <netinet/in.h> 51#include <netinet/in_var.h> 52 53#include <netinet/igmp_var.h> 54 |
55#include "gif.h" 56#if NGIF > 0 57#include <net/if_gif.h> 58#endif 59 |
60static MALLOC_DEFINE(M_IPMADDR, "in_multi", "internet multicast address"); 61 |
62static int in_mask2len __P((struct in_addr *)); 63static void in_len2mask __P((struct in_addr *, int)); 64static int in_lifaddr_ioctl __P((struct socket *, u_long, caddr_t, 65 struct ifnet *, struct proc *)); 66 |
67static void in_socktrim __P((struct sockaddr_in *)); 68static int in_ifinit __P((struct ifnet *, 69 struct in_ifaddr *, struct sockaddr_in *, int)); 70 71static int subnetsarelocal = 0; 72SYSCTL_INT(_net_inet_ip, OID_AUTO, subnets_are_local, CTLFLAG_RW, 73 &subnetsarelocal, 0, ""); 74 --- 61 unchanged lines hidden (view full) --- 136 ap->sin_len = 0; 137 while (--cp >= cplim) 138 if (*cp) { 139 (ap)->sin_len = cp - (char *) (ap) + 1; 140 break; 141 } 142} 143 |
144static int 145in_mask2len(mask) 146 struct in_addr *mask; 147{ 148 int x, y; 149 u_char *p; 150 151 p = (u_char *)mask; 152 for (x = 0; x < sizeof(*mask); x++) { 153 if (p[x] != 0xff) 154 break; 155 } 156 y = 0; 157 if (x < sizeof(*mask)) { 158 for (y = 0; y < 8; y++) { 159 if ((p[x] & (0x80 >> y)) == 0) 160 break; 161 } 162 } 163 return x * 8 + y; 164} 165 166static void 167in_len2mask(mask, len) 168 struct in_addr *mask; 169 int len; 170{ 171 int i; 172 u_char *p; 173 174 p = (u_char *)mask; 175 bzero(mask, sizeof(*mask)); 176 for (i = 0; i < len / 8; i++) 177 p[i] = 0xff; 178 if (len % 8) 179 p[i] = (0xff00 >> (len % 8)) & 0xff; 180} 181 |
182static int in_interfaces; /* number of external internet interfaces */ 183 184/* 185 * Generic internet control operations (ioctl's). 186 * Ifp is 0 if not an interface-specific ioctl. 187 */ 188/* ARGSUSED */ 189int --- 8 unchanged lines hidden (view full) --- 198 register struct in_ifaddr *ia = 0, *iap; 199 register struct ifaddr *ifa; 200 struct in_ifaddr *oia; 201 struct in_aliasreq *ifra = (struct in_aliasreq *)data; 202 struct sockaddr_in oldaddr; 203 int error, hostIsNew, maskIsNew, s; 204 u_long i; 205 |
206#if NGIF > 0 207 if (ifp && ifp->if_type == IFT_GIF) { 208 switch (cmd) { 209 case SIOCSIFPHYADDR: 210 if (p && 211 (error = suser(p)) != 0) 212 return(error); 213 case SIOCGIFPSRCADDR: 214 case SIOCGIFPDSTADDR: 215 return gif_ioctl(ifp, cmd, data); 216 } 217 } 218#endif 219 220 switch (cmd) { 221 case SIOCALIFADDR: 222 case SIOCDLIFADDR: 223 if (p && (error = suser(p)) != 0) 224 return error; 225 /*fall through*/ 226 case SIOCGLIFADDR: 227 if (!ifp) 228 return EINVAL; 229 return in_lifaddr_ioctl(so, cmd, data, ifp, p); 230 } 231 |
232 /* 233 * Find address for this interface, if it exists. 234 * 235 * If an alias address was specified, find that one instead of 236 * the first one on the interface. 237 */ 238 if (ifp) 239 for (iap = in_ifaddrhead.tqh_first; iap; --- 194 unchanged lines hidden (view full) --- 434 if (ifp == 0 || ifp->if_ioctl == 0) 435 return (EOPNOTSUPP); 436 return ((*ifp->if_ioctl)(ifp, cmd, data)); 437 } 438 return (0); 439} 440 441/* |
442 * SIOC[GAD]LIFADDR. 443 * SIOCGLIFADDR: get first address. (?!?) 444 * SIOCGLIFADDR with IFLR_PREFIX: 445 * get first address that matches the specified prefix. 446 * SIOCALIFADDR: add the specified address. 447 * SIOCALIFADDR with IFLR_PREFIX: 448 * EINVAL since we can't deduce hostid part of the address. 449 * SIOCDLIFADDR: delete the specified address. 450 * SIOCDLIFADDR with IFLR_PREFIX: 451 * delete the first address that matches the specified prefix. 452 * return values: 453 * EINVAL on invalid parameters 454 * EADDRNOTAVAIL on prefix match failed/specified address not found 455 * other values may be returned from in_ioctl() 456 */ 457static int 458in_lifaddr_ioctl(so, cmd, data, ifp, p) 459 struct socket *so; 460 u_long cmd; 461 caddr_t data; 462 struct ifnet *ifp; 463 struct proc *p; 464{ 465 struct if_laddrreq *iflr = (struct if_laddrreq *)data; 466 struct ifaddr *ifa; 467 468 /* sanity checks */ 469 if (!data || !ifp) { 470 panic("invalid argument to in_lifaddr_ioctl"); 471 /*NOTRECHED*/ 472 } 473 474 switch (cmd) { 475 case SIOCGLIFADDR: 476 /* address must be specified on GET with IFLR_PREFIX */ 477 if ((iflr->flags & IFLR_PREFIX) == 0) 478 break; 479 /*FALLTHROUGH*/ 480 case SIOCALIFADDR: 481 case SIOCDLIFADDR: 482 /* address must be specified on ADD and DELETE */ 483 if (iflr->addr.__ss_family != AF_INET) 484 return EINVAL; 485 if (iflr->addr.__ss_len != sizeof(struct sockaddr_in)) 486 return EINVAL; 487 /* XXX need improvement */ 488 if (iflr->dstaddr.__ss_family 489 && iflr->dstaddr.__ss_family != AF_INET) 490 return EINVAL; 491 if (iflr->dstaddr.__ss_family 492 && iflr->dstaddr.__ss_len != sizeof(struct sockaddr_in)) 493 return EINVAL; 494 break; 495 default: /*shouldn't happen*/ 496 return EOPNOTSUPP; 497 } 498 if (sizeof(struct in_addr) * 8 < iflr->prefixlen) 499 return EINVAL; 500 501 switch (cmd) { 502 case SIOCALIFADDR: 503 { 504 struct in_aliasreq ifra; 505 506 if (iflr->flags & IFLR_PREFIX) 507 return EINVAL; 508 509 /* copy args to in_aliasreq, perform ioctl(SIOCAIFADDR_IN6). */ 510 bzero(&ifra, sizeof(ifra)); 511 bcopy(iflr->iflr_name, ifra.ifra_name, 512 sizeof(ifra.ifra_name)); 513 514 bcopy(&iflr->addr, &ifra.ifra_addr, iflr->addr.__ss_len); 515 516 if (iflr->dstaddr.__ss_family) { /*XXX*/ 517 bcopy(&iflr->dstaddr, &ifra.ifra_dstaddr, 518 iflr->dstaddr.__ss_len); 519 } 520 521 ifra.ifra_mask.sin_family = AF_INET; 522 ifra.ifra_mask.sin_len = sizeof(struct sockaddr_in); 523 in_len2mask(&ifra.ifra_mask.sin_addr, iflr->prefixlen); 524 525 return in_control(so, SIOCAIFADDR, (caddr_t)&ifra, ifp, p); 526 } 527 case SIOCGLIFADDR: 528 case SIOCDLIFADDR: 529 { 530 struct in_ifaddr *ia; 531 struct in_addr mask, candidate, match; 532 struct sockaddr_in *sin; 533 int cmp; 534 535 bzero(&mask, sizeof(mask)); 536 if (iflr->flags & IFLR_PREFIX) { 537 /* lookup a prefix rather than address. */ 538 in_len2mask(&mask, iflr->prefixlen); 539 540 sin = (struct sockaddr_in *)&iflr->addr; 541 match.s_addr = sin->sin_addr.s_addr; 542 match.s_addr &= mask.s_addr; 543 544 /* if you set extra bits, that's wrong */ 545 if (match.s_addr != sin->sin_addr.s_addr) 546 return EINVAL; 547 548 cmp = 1; 549 } else { 550 if (cmd == SIOCGLIFADDR) { 551 /* on getting an address, take the 1st match */ 552 cmp = 0; /*XXX*/ 553 } else { 554 /* on deleting an address, do exact match */ 555 in_len2mask(&mask, 32); 556 sin = (struct sockaddr_in *)&iflr->addr; 557 match.s_addr = sin->sin_addr.s_addr; 558 559 cmp = 1; 560 } 561 } 562 563 TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 564 if (ifa->ifa_addr->sa_family != AF_INET6) 565 continue; 566 if (!cmp) 567 break; 568 candidate.s_addr = ((struct sockaddr_in *)&ifa->ifa_addr)->sin_addr.s_addr; 569 candidate.s_addr &= mask.s_addr; 570 if (candidate.s_addr == match.s_addr) 571 break; 572 } 573 if (!ifa) 574 return EADDRNOTAVAIL; 575 ia = (struct in_ifaddr *)ifa; 576 577 if (cmd == SIOCGLIFADDR) { 578 /* fill in the if_laddrreq structure */ 579 bcopy(&ia->ia_addr, &iflr->addr, ia->ia_addr.sin_len); 580 581 if ((ifp->if_flags & IFF_POINTOPOINT) != 0) { 582 bcopy(&ia->ia_dstaddr, &iflr->dstaddr, 583 ia->ia_dstaddr.sin_len); 584 } else 585 bzero(&iflr->dstaddr, sizeof(iflr->dstaddr)); 586 587 iflr->prefixlen = 588 in_mask2len(&ia->ia_sockmask.sin_addr); 589 590 iflr->flags = 0; /*XXX*/ 591 592 return 0; 593 } else { 594 struct in_aliasreq ifra; 595 596 /* fill in_aliasreq and do ioctl(SIOCDIFADDR_IN6) */ 597 bzero(&ifra, sizeof(ifra)); 598 bcopy(iflr->iflr_name, ifra.ifra_name, 599 sizeof(ifra.ifra_name)); 600 601 bcopy(&ia->ia_addr, &ifra.ifra_addr, 602 ia->ia_addr.sin_len); 603 if ((ifp->if_flags & IFF_POINTOPOINT) != 0) { 604 bcopy(&ia->ia_dstaddr, &ifra.ifra_dstaddr, 605 ia->ia_dstaddr.sin_len); 606 } 607 bcopy(&ia->ia_sockmask, &ifra.ifra_dstaddr, 608 ia->ia_sockmask.sin_len); 609 610 return in_control(so, SIOCDIFADDR, (caddr_t)&ifra, 611 ifp, p); 612 } 613 } 614 } 615 616 return EOPNOTSUPP; /*just for safety*/ 617} 618 619/* |
620 * Delete any existing route for an interface. 621 */ 622void 623in_ifscrub(ifp, ia) 624 register struct ifnet *ifp; 625 register struct in_ifaddr *ia; 626{ 627 --- 226 unchanged lines hidden --- |