Annotation of sys/netinet/if_ether.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: if_ether.c,v 1.68 2007/03/25 16:43:22 claudio Exp $ */
! 2: /* $NetBSD: if_ether.c,v 1.31 1996/05/11 12:59:58 mycroft Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 1982, 1986, 1988, 1993
! 6: * The Regents of the University of California. All rights reserved.
! 7: *
! 8: * Redistribution and use in source and binary forms, with or without
! 9: * modification, are permitted provided that the following conditions
! 10: * are met:
! 11: * 1. Redistributions of source code must retain the above copyright
! 12: * notice, this list of conditions and the following disclaimer.
! 13: * 2. Redistributions in binary form must reproduce the above copyright
! 14: * notice, this list of conditions and the following disclaimer in the
! 15: * documentation and/or other materials provided with the distribution.
! 16: * 3. Neither the name of the University nor the names of its contributors
! 17: * may be used to endorse or promote products derived from this software
! 18: * without specific prior written permission.
! 19: *
! 20: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 21: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 22: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 23: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 24: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 25: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 26: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 27: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 28: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 29: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 30: * SUCH DAMAGE.
! 31: *
! 32: * @(#)if_ether.c 8.1 (Berkeley) 6/10/93
! 33: */
! 34:
! 35: /*
! 36: * Ethernet address resolution protocol.
! 37: * TODO:
! 38: * add "inuse/lock" bit (or ref. count) along with valid bit
! 39: */
! 40:
! 41: #ifdef INET
! 42: #include "carp.h"
! 43:
! 44: #include "bridge.h"
! 45:
! 46: #include <sys/param.h>
! 47: #include <sys/systm.h>
! 48: #include <sys/mbuf.h>
! 49: #include <sys/socket.h>
! 50: #include <sys/kernel.h>
! 51: #include <sys/syslog.h>
! 52: #include <sys/proc.h>
! 53:
! 54: #include <net/if.h>
! 55: #include <net/if_dl.h>
! 56: #include <net/route.h>
! 57: #include <net/if_fddi.h>
! 58: #include <net/if_types.h>
! 59:
! 60: #include <netinet/in.h>
! 61: #include <netinet/in_var.h>
! 62: #include <netinet/if_ether.h>
! 63: #if NCARP > 0
! 64: #include <netinet/ip_carp.h>
! 65: #endif
! 66:
! 67: #define SIN(s) ((struct sockaddr_in *)s)
! 68: #define SDL(s) ((struct sockaddr_dl *)s)
! 69: #define SRP(s) ((struct sockaddr_inarp *)s)
! 70:
! 71: /*
! 72: * ARP trailer negotiation. Trailer protocol is not IP specific,
! 73: * but ARP request/response use IP addresses.
! 74: */
! 75: #define ETHERTYPE_IPTRAILERS ETHERTYPE_TRAIL
! 76:
! 77: /* timer values */
! 78: int arpt_prune = (5*60*1); /* walk list every 5 minutes */
! 79: int arpt_keep = (20*60); /* once resolved, good for 20 more minutes */
! 80: int arpt_down = 20; /* once declared down, don't send for 20 secs */
! 81: #define rt_expire rt_rmx.rmx_expire
! 82:
! 83: void arptfree(struct llinfo_arp *);
! 84: void arptimer(void *);
! 85: struct llinfo_arp *arplookup(u_int32_t, int, int);
! 86: void in_arpinput(struct mbuf *);
! 87:
! 88: LIST_HEAD(, llinfo_arp) llinfo_arp;
! 89: struct ifqueue arpintrq = {0, 0, 0, 50};
! 90: int arp_inuse, arp_allocated, arp_intimer;
! 91: int arp_maxtries = 5;
! 92: int useloopback = 1; /* use loopback interface for local traffic */
! 93: int arpinit_done = 0;
! 94:
! 95: /* revarp state */
! 96: struct in_addr myip, srv_ip;
! 97: int myip_initialized = 0;
! 98: int revarp_in_progress = 0;
! 99: struct ifnet *myip_ifp = NULL;
! 100:
! 101: #ifdef DDB
! 102: #include <uvm/uvm_extern.h>
! 103:
! 104: void db_print_sa(struct sockaddr *);
! 105: void db_print_ifa(struct ifaddr *);
! 106: void db_print_llinfo(caddr_t);
! 107: int db_show_radix_node(struct radix_node *, void *);
! 108: #endif
! 109:
! 110: /*
! 111: * Timeout routine. Age arp_tab entries periodically.
! 112: */
! 113: /* ARGSUSED */
! 114: void
! 115: arptimer(arg)
! 116: void *arg;
! 117: {
! 118: struct timeout *to = (struct timeout *)arg;
! 119: int s;
! 120: struct llinfo_arp *la, *nla;
! 121:
! 122: s = splsoftnet();
! 123: timeout_add(to, arpt_prune * hz);
! 124: for (la = LIST_FIRST(&llinfo_arp); la != LIST_END(&llinfo_arp);
! 125: la = nla) {
! 126: struct rtentry *rt = la->la_rt;
! 127:
! 128: nla = LIST_NEXT(la, la_list);
! 129: if (rt->rt_expire && rt->rt_expire <= time_second)
! 130: arptfree(la); /* timer has expired; clear */
! 131: }
! 132: splx(s);
! 133: }
! 134:
! 135: /*
! 136: * Parallel to llc_rtrequest.
! 137: */
! 138: void
! 139: arp_rtrequest(req, rt, info)
! 140: int req;
! 141: struct rtentry *rt;
! 142: struct rt_addrinfo *info;
! 143: {
! 144: struct sockaddr *gate = rt->rt_gateway;
! 145: struct llinfo_arp *la = (struct llinfo_arp *)rt->rt_llinfo;
! 146: static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK};
! 147: struct in_ifaddr *ia;
! 148: struct ifaddr *ifa;
! 149:
! 150: if (!arpinit_done) {
! 151: static struct timeout arptimer_to;
! 152:
! 153: arpinit_done = 1;
! 154: /*
! 155: * We generate expiration times from time.tv_sec
! 156: * so avoid accidently creating permanent routes.
! 157: */
! 158: if (time_second == 0) {
! 159: time_second++;
! 160: }
! 161:
! 162: timeout_set(&arptimer_to, arptimer, &arptimer_to);
! 163: timeout_add(&arptimer_to, hz);
! 164: }
! 165:
! 166: if (rt->rt_flags & RTF_GATEWAY) {
! 167: if (req != RTM_ADD)
! 168: return;
! 169:
! 170: /*
! 171: * linklayers with particular link MTU limitation. it is a bit
! 172: * awkward to have FDDI handling here, we should split ARP from
! 173: * netinet/if_ether.c like NetBSD does.
! 174: */
! 175: switch (rt->rt_ifp->if_type) {
! 176: case IFT_FDDI:
! 177: if (rt->rt_ifp->if_mtu > FDDIIPMTU)
! 178: rt->rt_rmx.rmx_mtu = FDDIIPMTU;
! 179: break;
! 180: }
! 181:
! 182: return;
! 183: }
! 184:
! 185: switch (req) {
! 186:
! 187: case RTM_ADD:
! 188: /*
! 189: * XXX: If this is a manually added route to interface
! 190: * such as older version of routed or gated might provide,
! 191: * restore cloning bit.
! 192: */
! 193: if ((rt->rt_flags & RTF_HOST) == 0 &&
! 194: SIN(rt_mask(rt))->sin_addr.s_addr != 0xffffffff)
! 195: rt->rt_flags |= RTF_CLONING;
! 196: if (rt->rt_flags & RTF_CLONING) {
! 197: /*
! 198: * Case 1: This route should come from a route to iface.
! 199: */
! 200: rt_setgate(rt, rt_key(rt),
! 201: (struct sockaddr *)&null_sdl, 0);
! 202: gate = rt->rt_gateway;
! 203: SDL(gate)->sdl_type = rt->rt_ifp->if_type;
! 204: SDL(gate)->sdl_index = rt->rt_ifp->if_index;
! 205: /*
! 206: * Give this route an expiration time, even though
! 207: * it's a "permanent" route, so that routes cloned
! 208: * from it do not need their expiration time set.
! 209: */
! 210: rt->rt_expire = time_second;
! 211: /*
! 212: * linklayers with particular link MTU limitation.
! 213: */
! 214: switch (rt->rt_ifp->if_type) {
! 215: case IFT_FDDI:
! 216: if ((rt->rt_rmx.rmx_locks & RTV_MTU) == 0 &&
! 217: (rt->rt_rmx.rmx_mtu > FDDIIPMTU ||
! 218: (rt->rt_rmx.rmx_mtu == 0 &&
! 219: rt->rt_ifp->if_mtu > FDDIIPMTU)))
! 220: rt->rt_rmx.rmx_mtu = FDDIIPMTU;
! 221: break;
! 222: }
! 223: break;
! 224: }
! 225: /* Announce a new entry if requested. */
! 226: if (rt->rt_flags & RTF_ANNOUNCE)
! 227: arprequest(rt->rt_ifp,
! 228: &SIN(rt_key(rt))->sin_addr.s_addr,
! 229: &SIN(rt_key(rt))->sin_addr.s_addr,
! 230: (u_char *)LLADDR(SDL(gate)));
! 231: /*FALLTHROUGH*/
! 232: case RTM_RESOLVE:
! 233: if (gate->sa_family != AF_LINK ||
! 234: gate->sa_len < sizeof(null_sdl)) {
! 235: log(LOG_DEBUG, "arp_rtrequest: bad gateway value\n");
! 236: break;
! 237: }
! 238: SDL(gate)->sdl_type = rt->rt_ifp->if_type;
! 239: SDL(gate)->sdl_index = rt->rt_ifp->if_index;
! 240: if (la != 0)
! 241: break; /* This happens on a route change */
! 242: /*
! 243: * Case 2: This route may come from cloning, or a manual route
! 244: * add with a LL address.
! 245: */
! 246: R_Malloc(la, struct llinfo_arp *, sizeof(*la));
! 247: rt->rt_llinfo = (caddr_t)la;
! 248: if (la == 0) {
! 249: log(LOG_DEBUG, "arp_rtrequest: malloc failed\n");
! 250: break;
! 251: }
! 252: arp_inuse++, arp_allocated++;
! 253: Bzero(la, sizeof(*la));
! 254: la->la_rt = rt;
! 255: rt->rt_flags |= RTF_LLINFO;
! 256: LIST_INSERT_HEAD(&llinfo_arp, la, la_list);
! 257:
! 258: TAILQ_FOREACH(ia, &in_ifaddr, ia_list) {
! 259: if (ia->ia_ifp == rt->rt_ifp &&
! 260: SIN(rt_key(rt))->sin_addr.s_addr ==
! 261: (IA_SIN(ia))->sin_addr.s_addr)
! 262: break;
! 263: }
! 264: if (ia) {
! 265: /*
! 266: * This test used to be
! 267: * if (lo0ifp->if_flags & IFF_UP)
! 268: * It allowed local traffic to be forced through
! 269: * the hardware by configuring the loopback down.
! 270: * However, it causes problems during network
! 271: * configuration for boards that can't receive
! 272: * packets they send. It is now necessary to clear
! 273: * "useloopback" and remove the route to force
! 274: * traffic out to the hardware.
! 275: *
! 276: * In 4.4BSD, the above "if" statement checked
! 277: * rt->rt_ifa against rt_key(rt). It was changed
! 278: * to the current form so that we can provide a
! 279: * better support for multiple IPv4 addresses on a
! 280: * interface.
! 281: */
! 282: rt->rt_expire = 0;
! 283: Bcopy(((struct arpcom *)rt->rt_ifp)->ac_enaddr,
! 284: LLADDR(SDL(gate)),
! 285: SDL(gate)->sdl_alen = ETHER_ADDR_LEN);
! 286: if (useloopback)
! 287: rt->rt_ifp = lo0ifp;
! 288: /*
! 289: * make sure to set rt->rt_ifa to the interface
! 290: * address we are using, otherwise we will have trouble
! 291: * with source address selection.
! 292: */
! 293: ifa = &ia->ia_ifa;
! 294: if (ifa != rt->rt_ifa) {
! 295: IFAFREE(rt->rt_ifa);
! 296: ifa->ifa_refcnt++;
! 297: rt->rt_ifa = ifa;
! 298: }
! 299: }
! 300: break;
! 301:
! 302: case RTM_DELETE:
! 303: if (la == 0)
! 304: break;
! 305: arp_inuse--;
! 306: LIST_REMOVE(la, la_list);
! 307: rt->rt_llinfo = 0;
! 308: rt->rt_flags &= ~RTF_LLINFO;
! 309: if (la->la_hold)
! 310: m_freem(la->la_hold);
! 311: Free((caddr_t)la);
! 312: }
! 313: }
! 314:
! 315: /*
! 316: * Broadcast an ARP request. Caller specifies:
! 317: * - arp header source ip address
! 318: * - arp header target ip address
! 319: * - arp header source ethernet address
! 320: */
! 321: void
! 322: arprequest(ifp, sip, tip, enaddr)
! 323: struct ifnet *ifp;
! 324: u_int32_t *sip, *tip;
! 325: u_int8_t *enaddr;
! 326: {
! 327: struct mbuf *m;
! 328: struct ether_header *eh;
! 329: struct ether_arp *ea;
! 330: struct sockaddr sa;
! 331:
! 332: if ((m = m_gethdr(M_DONTWAIT, MT_DATA)) == NULL)
! 333: return;
! 334: m->m_len = sizeof(*ea);
! 335: m->m_pkthdr.len = sizeof(*ea);
! 336: MH_ALIGN(m, sizeof(*ea));
! 337: ea = mtod(m, struct ether_arp *);
! 338: eh = (struct ether_header *)sa.sa_data;
! 339: bzero((caddr_t)ea, sizeof (*ea));
! 340: bcopy((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost,
! 341: sizeof(eh->ether_dhost));
! 342: eh->ether_type = htons(ETHERTYPE_ARP); /* if_output will not swap */
! 343: ea->arp_hrd = htons(ARPHRD_ETHER);
! 344: ea->arp_pro = htons(ETHERTYPE_IP);
! 345: ea->arp_hln = sizeof(ea->arp_sha); /* hardware address length */
! 346: ea->arp_pln = sizeof(ea->arp_spa); /* protocol address length */
! 347: ea->arp_op = htons(ARPOP_REQUEST);
! 348: bcopy((caddr_t)enaddr, (caddr_t)eh->ether_shost,
! 349: sizeof(eh->ether_shost));
! 350: bcopy((caddr_t)enaddr, (caddr_t)ea->arp_sha, sizeof(ea->arp_sha));
! 351: bcopy((caddr_t)sip, (caddr_t)ea->arp_spa, sizeof(ea->arp_spa));
! 352: bcopy((caddr_t)tip, (caddr_t)ea->arp_tpa, sizeof(ea->arp_tpa));
! 353: sa.sa_family = pseudo_AF_HDRCMPLT;
! 354: sa.sa_len = sizeof(sa);
! 355: (*ifp->if_output)(ifp, m, &sa, (struct rtentry *)0);
! 356: }
! 357:
! 358: /*
! 359: * Resolve an IP address into an ethernet address. If success,
! 360: * desten is filled in. If there is no entry in arptab,
! 361: * set one up and broadcast a request for the IP address.
! 362: * Hold onto this mbuf and resend it once the address
! 363: * is finally resolved. A return value of 1 indicates
! 364: * that desten has been filled in and the packet should be sent
! 365: * normally; a 0 return indicates that the packet has been
! 366: * taken over here, either now or for later transmission.
! 367: */
! 368: int
! 369: arpresolve(ac, rt, m, dst, desten)
! 370: struct arpcom *ac;
! 371: struct rtentry *rt;
! 372: struct mbuf *m;
! 373: struct sockaddr *dst;
! 374: u_char *desten;
! 375: {
! 376: struct llinfo_arp *la;
! 377: struct sockaddr_dl *sdl;
! 378:
! 379: if (m->m_flags & M_BCAST) { /* broadcast */
! 380: bcopy((caddr_t)etherbroadcastaddr, (caddr_t)desten,
! 381: sizeof(etherbroadcastaddr));
! 382: return (1);
! 383: }
! 384: if (m->m_flags & M_MCAST) { /* multicast */
! 385: ETHER_MAP_IP_MULTICAST(&SIN(dst)->sin_addr, desten);
! 386: return (1);
! 387: }
! 388: if (rt) {
! 389: la = (struct llinfo_arp *)rt->rt_llinfo;
! 390: if (la == NULL)
! 391: log(LOG_DEBUG, "arpresolve: %s: route without link "
! 392: "local address\n", inet_ntoa(SIN(dst)->sin_addr));
! 393: } else {
! 394: if ((la = arplookup(SIN(dst)->sin_addr.s_addr, 1, 0)) != NULL)
! 395: rt = la->la_rt;
! 396: else
! 397: log(LOG_DEBUG,
! 398: "arpresolve: %s: can't allocate llinfo\n",
! 399: inet_ntoa(SIN(dst)->sin_addr));
! 400: }
! 401: if (la == 0 || rt == 0) {
! 402: m_freem(m);
! 403: return (0);
! 404: }
! 405: sdl = SDL(rt->rt_gateway);
! 406: /*
! 407: * Check the address family and length is valid, the address
! 408: * is resolved; otherwise, try to resolve.
! 409: */
! 410: if ((rt->rt_expire == 0 || rt->rt_expire > time_second) &&
! 411: sdl->sdl_family == AF_LINK && sdl->sdl_alen != 0) {
! 412: bcopy(LLADDR(sdl), desten, sdl->sdl_alen);
! 413: return 1;
! 414: }
! 415: if (((struct ifnet *)ac)->if_flags & IFF_NOARP)
! 416: return 0;
! 417:
! 418: /*
! 419: * There is an arptab entry, but no ethernet address
! 420: * response yet. Replace the held mbuf with this
! 421: * latest one.
! 422: */
! 423: if (la->la_hold)
! 424: m_freem(la->la_hold);
! 425: la->la_hold = m;
! 426: /*
! 427: * Re-send the ARP request when appropriate.
! 428: */
! 429: #ifdef DIAGNOSTIC
! 430: if (rt->rt_expire == 0) {
! 431: /* This should never happen. (Should it? -gwr) */
! 432: printf("arpresolve: unresolved and rt_expire == 0\n");
! 433: /* Set expiration time to now (expired). */
! 434: rt->rt_expire = time_second;
! 435: }
! 436: #endif
! 437: if (rt->rt_expire) {
! 438: rt->rt_flags &= ~RTF_REJECT;
! 439: if (la->la_asked == 0 || rt->rt_expire != time_second) {
! 440: rt->rt_expire = time_second;
! 441: if (la->la_asked++ < arp_maxtries)
! 442: arprequest(&ac->ac_if,
! 443: &(SIN(rt->rt_ifa->ifa_addr)->sin_addr.s_addr),
! 444: &(SIN(dst)->sin_addr.s_addr),
! 445: #if NCARP > 0
! 446: (rt->rt_ifp->if_type == IFT_CARP) ?
! 447: ((struct arpcom *) rt->rt_ifp->if_softc
! 448: )->ac_enaddr :
! 449: #endif
! 450: ac->ac_enaddr);
! 451: else {
! 452: rt->rt_flags |= RTF_REJECT;
! 453: rt->rt_expire += arpt_down;
! 454: la->la_asked = 0;
! 455: }
! 456: }
! 457: }
! 458: return (0);
! 459: }
! 460:
! 461: /*
! 462: * Common length and type checks are done here,
! 463: * then the protocol-specific routine is called.
! 464: */
! 465: void
! 466: arpintr()
! 467: {
! 468: struct mbuf *m;
! 469: struct arphdr *ar;
! 470: int s, len;
! 471:
! 472: while (arpintrq.ifq_head) {
! 473: s = splnet();
! 474: IF_DEQUEUE(&arpintrq, m);
! 475: splx(s);
! 476: if (m == 0 || (m->m_flags & M_PKTHDR) == 0)
! 477: panic("arpintr");
! 478:
! 479: len = sizeof(struct arphdr);
! 480: if (m->m_len < len && (m = m_pullup(m, len)) == NULL)
! 481: continue;
! 482:
! 483: ar = mtod(m, struct arphdr *);
! 484: if (ntohs(ar->ar_hrd) != ARPHRD_ETHER) {
! 485: m_freem(m);
! 486: continue;
! 487: }
! 488:
! 489: len += 2 * (ar->ar_hln + ar->ar_pln);
! 490: if (m->m_len < len && (m = m_pullup(m, len)) == NULL)
! 491: continue;
! 492:
! 493: switch (ntohs(ar->ar_pro)) {
! 494: case ETHERTYPE_IP:
! 495: case ETHERTYPE_IPTRAILERS:
! 496: in_arpinput(m);
! 497: continue;
! 498: }
! 499: m_freem(m);
! 500: }
! 501: }
! 502:
! 503: /*
! 504: * ARP for Internet protocols on Ethernet.
! 505: * Algorithm is that given in RFC 826.
! 506: * In addition, a sanity check is performed on the sender
! 507: * protocol address, to catch impersonators.
! 508: * We no longer handle negotiations for use of trailer protocol:
! 509: * Formerly, ARP replied for protocol type ETHERTYPE_TRAIL sent
! 510: * along with IP replies if we wanted trailers sent to us,
! 511: * and also sent them in response to IP replies.
! 512: * This allowed either end to announce the desire to receive
! 513: * trailer packets.
! 514: * We no longer reply to requests for ETHERTYPE_TRAIL protocol either,
! 515: * but formerly didn't normally send requests.
! 516: */
! 517: void
! 518: in_arpinput(m)
! 519: struct mbuf *m;
! 520: {
! 521: struct ether_arp *ea;
! 522: struct arpcom *ac = (struct arpcom *)m->m_pkthdr.rcvif;
! 523: struct ether_header *eh;
! 524: struct llinfo_arp *la = 0;
! 525: struct rtentry *rt;
! 526: struct in_ifaddr *ia;
! 527: #if NBRIDGE > 0
! 528: struct in_ifaddr *bridge_ia = NULL;
! 529: #endif
! 530: #if NCARP > 0
! 531: u_int32_t count = 0, index = 0;
! 532: #endif
! 533: struct sockaddr_dl *sdl;
! 534: struct sockaddr sa;
! 535: struct in_addr isaddr, itaddr, myaddr;
! 536: u_int8_t *enaddr = NULL;
! 537: int op;
! 538:
! 539: ea = mtod(m, struct ether_arp *);
! 540: op = ntohs(ea->arp_op);
! 541: if ((op != ARPOP_REQUEST) && (op != ARPOP_REPLY))
! 542: goto out;
! 543: #if notyet
! 544: if ((op == ARPOP_REPLY) && (m->m_flags & (M_BCAST|M_MCAST))) {
! 545: log(LOG_ERR,
! 546: "arp: received reply to broadcast or multicast address\n");
! 547: goto out;
! 548: }
! 549: #endif
! 550:
! 551: bcopy((caddr_t)ea->arp_tpa, (caddr_t)&itaddr, sizeof(itaddr));
! 552: bcopy((caddr_t)ea->arp_spa, (caddr_t)&isaddr, sizeof(isaddr));
! 553:
! 554: TAILQ_FOREACH(ia, &in_ifaddr, ia_list) {
! 555: if (itaddr.s_addr != ia->ia_addr.sin_addr.s_addr)
! 556: continue;
! 557:
! 558: #if NCARP > 0
! 559: if (ia->ia_ifp->if_type == IFT_CARP &&
! 560: ((ia->ia_ifp->if_flags & (IFF_UP|IFF_RUNNING)) ==
! 561: (IFF_UP|IFF_RUNNING))) {
! 562: index++;
! 563: if (ia->ia_ifp == m->m_pkthdr.rcvif &&
! 564: carp_iamatch(ia, ea->arp_sha,
! 565: &count, index))
! 566: break;
! 567: } else
! 568: #endif
! 569: if (ia->ia_ifp == m->m_pkthdr.rcvif)
! 570: break;
! 571: #if NBRIDGE > 0
! 572: /*
! 573: * If the interface we received the packet on
! 574: * is part of a bridge, check to see if we need
! 575: * to "bridge" the packet to ourselves at this
! 576: * layer. Note we still prefer a perfect match,
! 577: * but allow this weaker match if necessary.
! 578: */
! 579: if (m->m_pkthdr.rcvif->if_bridge != NULL) {
! 580: if (m->m_pkthdr.rcvif->if_bridge ==
! 581: ia->ia_ifp->if_bridge)
! 582: bridge_ia = ia;
! 583: #if NCARP > 0
! 584: else if (ia->ia_ifp->if_carpdev != NULL &&
! 585: m->m_pkthdr.rcvif->if_bridge ==
! 586: ia->ia_ifp->if_carpdev->if_bridge &&
! 587: carp_iamatch(ia, ea->arp_sha,
! 588: &count, index))
! 589: bridge_ia = ia;
! 590: #endif
! 591: }
! 592: #endif
! 593: }
! 594:
! 595: #if NBRIDGE > 0
! 596: if (ia == NULL && bridge_ia != NULL) {
! 597: ia = bridge_ia;
! 598: ac = (struct arpcom *)bridge_ia->ia_ifp;
! 599: }
! 600: #endif
! 601:
! 602: if (ia == NULL) {
! 603: TAILQ_FOREACH(ia, &in_ifaddr, ia_list) {
! 604: if (isaddr.s_addr != ia->ia_addr.sin_addr.s_addr)
! 605: continue;
! 606: if (ia->ia_ifp == m->m_pkthdr.rcvif)
! 607: break;
! 608: }
! 609: }
! 610:
! 611: if (ia == NULL && m->m_pkthdr.rcvif->if_type != IFT_CARP) {
! 612: struct ifaddr *ifa;
! 613:
! 614: TAILQ_FOREACH(ifa, &m->m_pkthdr.rcvif->if_addrlist, ifa_list) {
! 615: if (ifa->ifa_addr->sa_family == AF_INET)
! 616: break;
! 617: }
! 618: if (ifa)
! 619: ia = (struct in_ifaddr *)ifa;
! 620: }
! 621:
! 622: if (ia == NULL)
! 623: goto out;
! 624:
! 625: if (!enaddr)
! 626: enaddr = ac->ac_enaddr;
! 627: myaddr = ia->ia_addr.sin_addr;
! 628:
! 629: if (!bcmp((caddr_t)ea->arp_sha, enaddr, sizeof (ea->arp_sha)))
! 630: goto out; /* it's from me, ignore it. */
! 631: if (ETHER_IS_MULTICAST (&ea->arp_sha[0]))
! 632: if (!bcmp((caddr_t)ea->arp_sha, (caddr_t)etherbroadcastaddr,
! 633: sizeof (ea->arp_sha))) {
! 634: log(LOG_ERR, "arp: ether address is broadcast for "
! 635: "IP address %s!\n", inet_ntoa(isaddr));
! 636: goto out;
! 637: }
! 638: if (myaddr.s_addr && isaddr.s_addr == myaddr.s_addr) {
! 639: log(LOG_ERR,
! 640: "duplicate IP address %s sent from ethernet address %s\n",
! 641: inet_ntoa(isaddr), ether_sprintf(ea->arp_sha));
! 642: itaddr = myaddr;
! 643: goto reply;
! 644: }
! 645: la = arplookup(isaddr.s_addr, itaddr.s_addr == myaddr.s_addr, 0);
! 646: if (la && (rt = la->la_rt) && (sdl = SDL(rt->rt_gateway))) {
! 647: if (sdl->sdl_alen) {
! 648: if (bcmp(ea->arp_sha, LLADDR(sdl), sdl->sdl_alen)) {
! 649: if (rt->rt_flags & RTF_PERMANENT_ARP) {
! 650: log(LOG_WARNING,
! 651: "arp: attempt to overwrite permanent "
! 652: "entry for %s by %s on %s\n",
! 653: inet_ntoa(isaddr),
! 654: ether_sprintf(ea->arp_sha),
! 655: ac->ac_if.if_xname);
! 656: goto out;
! 657: } else if (rt->rt_ifp != &ac->ac_if) {
! 658: log(LOG_WARNING,
! 659: "arp: attempt to overwrite entry for %s "
! 660: "on %s by %s on %s\n",
! 661: inet_ntoa(isaddr), rt->rt_ifp->if_xname,
! 662: ether_sprintf(ea->arp_sha),
! 663: ac->ac_if.if_xname);
! 664: goto out;
! 665: } else {
! 666: log(LOG_INFO,
! 667: "arp info overwritten for %s by %s on %s\n",
! 668: inet_ntoa(isaddr),
! 669: ether_sprintf(ea->arp_sha),
! 670: ac->ac_if.if_xname);
! 671: rt->rt_expire = 1; /* no longer static */
! 672: }
! 673: }
! 674: } else if (rt->rt_ifp != &ac->ac_if && !(ac->ac_if.if_bridge &&
! 675: (rt->rt_ifp->if_bridge == ac->ac_if.if_bridge)) &&
! 676: !(rt->rt_ifp->if_type == IFT_CARP &&
! 677: rt->rt_ifp->if_carpdev == &ac->ac_if) &&
! 678: !(ac->ac_if.if_type == IFT_CARP &&
! 679: ac->ac_if.if_carpdev == rt->rt_ifp)) {
! 680: log(LOG_WARNING,
! 681: "arp: attempt to add entry for %s "
! 682: "on %s by %s on %s\n",
! 683: inet_ntoa(isaddr), rt->rt_ifp->if_xname,
! 684: ether_sprintf(ea->arp_sha),
! 685: ac->ac_if.if_xname);
! 686: goto out;
! 687: }
! 688: bcopy(ea->arp_sha, LLADDR(sdl),
! 689: sdl->sdl_alen = sizeof(ea->arp_sha));
! 690: if (rt->rt_expire)
! 691: rt->rt_expire = time_second + arpt_keep;
! 692: rt->rt_flags &= ~RTF_REJECT;
! 693: la->la_asked = 0;
! 694: if (la->la_hold) {
! 695: (*ac->ac_if.if_output)(&ac->ac_if, la->la_hold,
! 696: rt_key(rt), rt);
! 697: la->la_hold = 0;
! 698: }
! 699: }
! 700: reply:
! 701: if (op != ARPOP_REQUEST) {
! 702: out:
! 703: m_freem(m);
! 704: return;
! 705: }
! 706: if (itaddr.s_addr == myaddr.s_addr) {
! 707: /* I am the target */
! 708: bcopy(ea->arp_sha, ea->arp_tha, sizeof(ea->arp_sha));
! 709: bcopy(enaddr, ea->arp_sha, sizeof(ea->arp_sha));
! 710: } else {
! 711: la = arplookup(itaddr.s_addr, 0, SIN_PROXY);
! 712: if (la == 0)
! 713: goto out;
! 714: rt = la->la_rt;
! 715: if (rt->rt_ifp->if_type == IFT_CARP &&
! 716: m->m_pkthdr.rcvif->if_type != IFT_CARP)
! 717: goto out;
! 718: bcopy(ea->arp_sha, ea->arp_tha, sizeof(ea->arp_sha));
! 719: sdl = SDL(rt->rt_gateway);
! 720: bcopy(LLADDR(sdl), ea->arp_sha, sizeof(ea->arp_sha));
! 721: }
! 722:
! 723: bcopy(ea->arp_spa, ea->arp_tpa, sizeof(ea->arp_spa));
! 724: bcopy(&itaddr, ea->arp_spa, sizeof(ea->arp_spa));
! 725: ea->arp_op = htons(ARPOP_REPLY);
! 726: ea->arp_pro = htons(ETHERTYPE_IP); /* let's be sure! */
! 727: eh = (struct ether_header *)sa.sa_data;
! 728: bcopy(ea->arp_tha, eh->ether_dhost, sizeof(eh->ether_dhost));
! 729: #if NCARP > 0
! 730: if (ac->ac_if.if_type == IFT_CARP && ac->ac_if.if_flags & IFF_LINK1)
! 731: bcopy(((struct arpcom *)ac->ac_if.if_carpdev)->ac_enaddr,
! 732: eh->ether_shost, sizeof(eh->ether_shost));
! 733: else
! 734: #endif
! 735: bcopy(enaddr, eh->ether_shost, sizeof(eh->ether_shost));
! 736:
! 737: eh->ether_type = htons(ETHERTYPE_ARP);
! 738: sa.sa_family = pseudo_AF_HDRCMPLT;
! 739: sa.sa_len = sizeof(sa);
! 740: (*ac->ac_if.if_output)(&ac->ac_if, m, &sa, (struct rtentry *)0);
! 741: return;
! 742: }
! 743:
! 744: /*
! 745: * Free an arp entry.
! 746: */
! 747: void
! 748: arptfree(la)
! 749: struct llinfo_arp *la;
! 750: {
! 751: struct rtentry *rt = la->la_rt;
! 752: struct sockaddr_dl *sdl;
! 753:
! 754: if (rt == 0)
! 755: panic("arptfree");
! 756: if (rt->rt_refcnt > 0 && (sdl = SDL(rt->rt_gateway)) &&
! 757: sdl->sdl_family == AF_LINK) {
! 758: sdl->sdl_alen = 0;
! 759: la->la_asked = 0;
! 760: rt->rt_flags &= ~RTF_REJECT;
! 761: return;
! 762: }
! 763: rtrequest(RTM_DELETE, rt_key(rt), (struct sockaddr *)0, rt_mask(rt),
! 764: 0, (struct rtentry **)0, 0);
! 765: }
! 766:
! 767: /*
! 768: * Lookup or enter a new address in arptab.
! 769: */
! 770: struct llinfo_arp *
! 771: arplookup(addr, create, proxy)
! 772: u_int32_t addr;
! 773: int create, proxy;
! 774: {
! 775: struct rtentry *rt;
! 776: static struct sockaddr_inarp sin;
! 777:
! 778: sin.sin_len = sizeof(sin);
! 779: sin.sin_family = AF_INET;
! 780: sin.sin_addr.s_addr = addr;
! 781: sin.sin_other = proxy ? SIN_PROXY : 0;
! 782: rt = rtalloc1(sintosa(&sin), create, 0);
! 783: if (rt == 0)
! 784: return (0);
! 785: rt->rt_refcnt--;
! 786: if ((rt->rt_flags & RTF_GATEWAY) || (rt->rt_flags & RTF_LLINFO) == 0 ||
! 787: rt->rt_gateway->sa_family != AF_LINK) {
! 788: if (create) {
! 789: if (rt->rt_refcnt <= 0 &&
! 790: (rt->rt_flags & RTF_CLONED) != 0) {
! 791: rtrequest(RTM_DELETE,
! 792: (struct sockaddr *)rt_key(rt),
! 793: rt->rt_gateway, rt_mask(rt), rt->rt_flags,
! 794: 0, 0);
! 795: }
! 796: }
! 797: return (0);
! 798: }
! 799: return ((struct llinfo_arp *)rt->rt_llinfo);
! 800: }
! 801:
! 802: int
! 803: arpioctl(cmd, data)
! 804: u_long cmd;
! 805: caddr_t data;
! 806: {
! 807:
! 808: return (EOPNOTSUPP);
! 809: }
! 810:
! 811: void
! 812: arp_ifinit(ac, ifa)
! 813: struct arpcom *ac;
! 814: struct ifaddr *ifa;
! 815: {
! 816:
! 817: /* Warn the user if another station has this IP address. */
! 818: arprequest(&ac->ac_if,
! 819: &(IA_SIN(ifa)->sin_addr.s_addr),
! 820: &(IA_SIN(ifa)->sin_addr.s_addr),
! 821: ac->ac_enaddr);
! 822: ifa->ifa_rtrequest = arp_rtrequest;
! 823: ifa->ifa_flags |= RTF_CLONING;
! 824: }
! 825:
! 826: /*
! 827: * Called from Ethernet interrupt handlers
! 828: * when ether packet type ETHERTYPE_REVARP
! 829: * is received. Common length and type checks are done here,
! 830: * then the protocol-specific routine is called.
! 831: */
! 832: void
! 833: revarpinput(m)
! 834: struct mbuf *m;
! 835: {
! 836: struct arphdr *ar;
! 837:
! 838: if (m->m_len < sizeof(struct arphdr))
! 839: goto out;
! 840: ar = mtod(m, struct arphdr *);
! 841: if (ntohs(ar->ar_hrd) != ARPHRD_ETHER)
! 842: goto out;
! 843: if (m->m_len < sizeof(struct arphdr) + 2 * (ar->ar_hln + ar->ar_pln))
! 844: goto out;
! 845: switch (ntohs(ar->ar_pro)) {
! 846:
! 847: case ETHERTYPE_IP:
! 848: case ETHERTYPE_IPTRAILERS:
! 849: in_revarpinput(m);
! 850: return;
! 851:
! 852: default:
! 853: break;
! 854: }
! 855: out:
! 856: m_freem(m);
! 857: }
! 858:
! 859: /*
! 860: * RARP for Internet protocols on Ethernet.
! 861: * Algorithm is that given in RFC 903.
! 862: * We are only using for bootstrap purposes to get an ip address for one of
! 863: * our interfaces. Thus we support no user-interface.
! 864: *
! 865: * Since the contents of the RARP reply are specific to the interface that
! 866: * sent the request, this code must ensure that they are properly associated.
! 867: *
! 868: * Note: also supports ARP via RARP packets, per the RFC.
! 869: */
! 870: void
! 871: in_revarpinput(m)
! 872: struct mbuf *m;
! 873: {
! 874: struct ifnet *ifp;
! 875: struct ether_arp *ar;
! 876: int op;
! 877:
! 878: ar = mtod(m, struct ether_arp *);
! 879: op = ntohs(ar->arp_op);
! 880: switch (op) {
! 881: case ARPOP_REQUEST:
! 882: case ARPOP_REPLY: /* per RFC */
! 883: in_arpinput(m);
! 884: return;
! 885: case ARPOP_REVREPLY:
! 886: break;
! 887: case ARPOP_REVREQUEST: /* handled by rarpd(8) */
! 888: default:
! 889: goto out;
! 890: }
! 891: if (!revarp_in_progress)
! 892: goto out;
! 893: ifp = m->m_pkthdr.rcvif;
! 894: if (ifp != myip_ifp) /* !same interface */
! 895: goto out;
! 896: if (myip_initialized)
! 897: goto wake;
! 898: if (bcmp(ar->arp_tha, ((struct arpcom *)ifp)->ac_enaddr,
! 899: sizeof(ar->arp_tha)))
! 900: goto out;
! 901: bcopy((caddr_t)ar->arp_spa, (caddr_t)&srv_ip, sizeof(srv_ip));
! 902: bcopy((caddr_t)ar->arp_tpa, (caddr_t)&myip, sizeof(myip));
! 903: myip_initialized = 1;
! 904: wake: /* Do wakeup every time in case it was missed. */
! 905: wakeup((caddr_t)&myip);
! 906:
! 907: out:
! 908: m_freem(m);
! 909: }
! 910:
! 911: /*
! 912: * Send a RARP request for the ip address of the specified interface.
! 913: * The request should be RFC 903-compliant.
! 914: */
! 915: void
! 916: revarprequest(ifp)
! 917: struct ifnet *ifp;
! 918: {
! 919: struct sockaddr sa;
! 920: struct mbuf *m;
! 921: struct ether_header *eh;
! 922: struct ether_arp *ea;
! 923: struct arpcom *ac = (struct arpcom *)ifp;
! 924:
! 925: if ((m = m_gethdr(M_DONTWAIT, MT_DATA)) == NULL)
! 926: return;
! 927: m->m_len = sizeof(*ea);
! 928: m->m_pkthdr.len = sizeof(*ea);
! 929: MH_ALIGN(m, sizeof(*ea));
! 930: ea = mtod(m, struct ether_arp *);
! 931: eh = (struct ether_header *)sa.sa_data;
! 932: bzero((caddr_t)ea, sizeof(*ea));
! 933: bcopy((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost,
! 934: sizeof(eh->ether_dhost));
! 935: eh->ether_type = htons(ETHERTYPE_REVARP);
! 936: ea->arp_hrd = htons(ARPHRD_ETHER);
! 937: ea->arp_pro = htons(ETHERTYPE_IP);
! 938: ea->arp_hln = sizeof(ea->arp_sha); /* hardware address length */
! 939: ea->arp_pln = sizeof(ea->arp_spa); /* protocol address length */
! 940: ea->arp_op = htons(ARPOP_REVREQUEST);
! 941: bcopy((caddr_t)ac->ac_enaddr, (caddr_t)eh->ether_shost,
! 942: sizeof(ea->arp_tha));
! 943: bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->arp_sha,
! 944: sizeof(ea->arp_sha));
! 945: bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->arp_tha,
! 946: sizeof(ea->arp_tha));
! 947: sa.sa_family = pseudo_AF_HDRCMPLT;
! 948: sa.sa_len = sizeof(sa);
! 949: ifp->if_output(ifp, m, &sa, (struct rtentry *)0);
! 950: }
! 951:
! 952: /*
! 953: * RARP for the ip address of the specified interface, but also
! 954: * save the ip address of the server that sent the answer.
! 955: * Timeout if no response is received.
! 956: */
! 957: int
! 958: revarpwhoarewe(ifp, serv_in, clnt_in)
! 959: struct ifnet *ifp;
! 960: struct in_addr *serv_in;
! 961: struct in_addr *clnt_in;
! 962: {
! 963: int result, count = 20;
! 964:
! 965: if (myip_initialized)
! 966: return EIO;
! 967:
! 968: myip_ifp = ifp;
! 969: revarp_in_progress = 1;
! 970: while (count--) {
! 971: revarprequest(ifp);
! 972: result = tsleep((caddr_t)&myip, PSOCK, "revarp", hz/2);
! 973: if (result != EWOULDBLOCK)
! 974: break;
! 975: }
! 976: revarp_in_progress = 0;
! 977: if (!myip_initialized)
! 978: return ENETUNREACH;
! 979:
! 980: bcopy((caddr_t)&srv_ip, serv_in, sizeof(*serv_in));
! 981: bcopy((caddr_t)&myip, clnt_in, sizeof(*clnt_in));
! 982: return 0;
! 983: }
! 984:
! 985: /* For compatibility: only saves interface address. */
! 986: int
! 987: revarpwhoami(in, ifp)
! 988: struct in_addr *in;
! 989: struct ifnet *ifp;
! 990: {
! 991: struct in_addr server;
! 992: return (revarpwhoarewe(ifp, &server, in));
! 993: }
! 994:
! 995:
! 996: #ifdef DDB
! 997:
! 998: #include <machine/db_machdep.h>
! 999: #include <ddb/db_interface.h>
! 1000: #include <ddb/db_output.h>
! 1001:
! 1002: void
! 1003: db_print_sa(sa)
! 1004: struct sockaddr *sa;
! 1005: {
! 1006: int len;
! 1007: u_char *p;
! 1008:
! 1009: if (sa == 0) {
! 1010: db_printf("[NULL]");
! 1011: return;
! 1012: }
! 1013:
! 1014: p = (u_char *)sa;
! 1015: len = sa->sa_len;
! 1016: db_printf("[");
! 1017: while (len > 0) {
! 1018: db_printf("%d", *p);
! 1019: p++;
! 1020: len--;
! 1021: if (len)
! 1022: db_printf(",");
! 1023: }
! 1024: db_printf("]\n");
! 1025: }
! 1026:
! 1027: void
! 1028: db_print_ifa(ifa)
! 1029: struct ifaddr *ifa;
! 1030: {
! 1031: if (ifa == 0)
! 1032: return;
! 1033: db_printf(" ifa_addr=");
! 1034: db_print_sa(ifa->ifa_addr);
! 1035: db_printf(" ifa_dsta=");
! 1036: db_print_sa(ifa->ifa_dstaddr);
! 1037: db_printf(" ifa_mask=");
! 1038: db_print_sa(ifa->ifa_netmask);
! 1039: db_printf(" flags=0x%x, refcnt=%d, metric=%d\n",
! 1040: ifa->ifa_flags, ifa->ifa_refcnt, ifa->ifa_metric);
! 1041: }
! 1042:
! 1043: void
! 1044: db_print_llinfo(li)
! 1045: caddr_t li;
! 1046: {
! 1047: struct llinfo_arp *la;
! 1048:
! 1049: if (li == 0)
! 1050: return;
! 1051: la = (struct llinfo_arp *)li;
! 1052: db_printf(" la_rt=%p la_hold=%p, la_asked=0x%lx\n",
! 1053: la->la_rt, la->la_hold, la->la_asked);
! 1054: }
! 1055:
! 1056: /*
! 1057: * Function to pass to rn_walktree().
! 1058: * Return non-zero error to abort walk.
! 1059: */
! 1060: int
! 1061: db_show_radix_node(rn, w)
! 1062: struct radix_node *rn;
! 1063: void *w;
! 1064: {
! 1065: struct rtentry *rt = (struct rtentry *)rn;
! 1066:
! 1067: db_printf("rtentry=%p", rt);
! 1068:
! 1069: db_printf(" flags=0x%x refcnt=%d use=%ld expire=%ld\n",
! 1070: rt->rt_flags, rt->rt_refcnt, rt->rt_use, rt->rt_expire);
! 1071:
! 1072: db_printf(" key="); db_print_sa(rt_key(rt));
! 1073: db_printf(" mask="); db_print_sa(rt_mask(rt));
! 1074: db_printf(" gw="); db_print_sa(rt->rt_gateway);
! 1075:
! 1076: db_printf(" ifp=%p ", rt->rt_ifp);
! 1077: if (rt->rt_ifp)
! 1078: db_printf("(%s)", rt->rt_ifp->if_xname);
! 1079: else
! 1080: db_printf("(NULL)");
! 1081:
! 1082: db_printf(" ifa=%p\n", rt->rt_ifa);
! 1083: db_print_ifa(rt->rt_ifa);
! 1084:
! 1085: db_printf(" genmask="); db_print_sa(rt->rt_genmask);
! 1086:
! 1087: db_printf(" gwroute=%p llinfo=%p\n", rt->rt_gwroute, rt->rt_llinfo);
! 1088: db_print_llinfo(rt->rt_llinfo);
! 1089: return (0);
! 1090: }
! 1091:
! 1092: /*
! 1093: * Function to print all the route trees.
! 1094: * Use this from ddb: "call db_show_arptab"
! 1095: */
! 1096: int
! 1097: db_show_arptab()
! 1098: {
! 1099: struct radix_node_head *rnh;
! 1100: rnh = rt_gettable(AF_INET, 0);
! 1101: db_printf("Route tree for AF_INET\n");
! 1102: if (rnh == NULL) {
! 1103: db_printf(" (not initialized)\n");
! 1104: return (0);
! 1105: }
! 1106: rn_walktree(rnh, db_show_radix_node, NULL);
! 1107: return (0);
! 1108: }
! 1109: #endif
! 1110: #endif /* INET */
CVSweb