1 /* 2 * Copyright (c) 1982, 1989, 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 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 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 * @(#)if_ethersubr.c 8.1 (Berkeley) 6/10/93 34 * $Id: if_ethersubr.c,v 1.9 1995/06/11 19:31:39 rgrimes Exp $ 35 */ 36 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/kernel.h> 40 #include <sys/malloc.h> 41 #include <sys/mbuf.h> 42 #include <sys/protosw.h> 43 #include <sys/socket.h> 44 #include <sys/ioctl.h> 45 #include <sys/errno.h> 46 #include <sys/syslog.h> 47 48 #include <machine/cpu.h> 49 50 #include <net/if.h> 51 #include <net/netisr.h> 52 #include <net/route.h> 53 #include <net/if_llc.h> 54 #include <net/if_dl.h> 55 #include <net/if_types.h> 56 57 #ifdef INET 58 #include <netinet/in.h> 59 #include <netinet/in_var.h> 60 #endif 61 #include <netinet/if_ether.h> 62 63 #ifdef IPX 64 #include <netipx/ipx.h> 65 #include <netipx/ipx_if.h> 66 #endif 67 68 #ifdef NS 69 #include <netns/ns.h> 70 #include <netns/ns_if.h> 71 #endif 72 73 #ifdef ISO 74 #include <netiso/argo_debug.h> 75 #include <netiso/iso.h> 76 #include <netiso/iso_var.h> 77 #include <netiso/iso_snpac.h> 78 #endif 79 80 #ifdef LLC 81 #include <netccitt/dll.h> 82 #include <netccitt/llc_var.h> 83 #endif 84 85 #if defined(LLC) && defined(CCITT) 86 extern struct ifqueue pkintrq; 87 #endif 88 89 u_char etherbroadcastaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 90 #define senderr(e) { error = (e); goto bad;} 91 92 /* 93 * Ethernet output routine. 94 * Encapsulate a packet of type family for the local net. 95 * Use trailer local net encapsulation if enough data in first 96 * packet leaves a multiple of 512 bytes of data in remainder. 97 * Assumes that ifp is actually pointer to arpcom structure. 98 */ 99 int 100 ether_output(ifp, m0, dst, rt0) 101 register struct ifnet *ifp; 102 struct mbuf *m0; 103 struct sockaddr *dst; 104 struct rtentry *rt0; 105 { 106 short type; 107 int s, error = 0; 108 u_char edst[6]; 109 register struct mbuf *m = m0; 110 register struct rtentry *rt; 111 struct mbuf *mcopy = (struct mbuf *)0; 112 register struct ether_header *eh; 113 int off, len = m->m_pkthdr.len; 114 struct arpcom *ac = (struct arpcom *)ifp; 115 116 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) 117 senderr(ENETDOWN); 118 ifp->if_lastchange = time; 119 if (rt = rt0) { 120 if ((rt->rt_flags & RTF_UP) == 0) { 121 if (rt0 = rt = rtalloc1(dst, 1, 0UL)) 122 rt->rt_refcnt--; 123 else 124 senderr(EHOSTUNREACH); 125 } 126 if (rt->rt_flags & RTF_GATEWAY) { 127 if (rt->rt_gwroute == 0) 128 goto lookup; 129 if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) { 130 rtfree(rt); rt = rt0; 131 lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1, 132 0UL); 133 if ((rt = rt->rt_gwroute) == 0) 134 senderr(EHOSTUNREACH); 135 } 136 } 137 if (rt->rt_flags & RTF_REJECT) 138 if (rt->rt_rmx.rmx_expire == 0 || 139 time.tv_sec < rt->rt_rmx.rmx_expire) 140 senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH); 141 } 142 switch (dst->sa_family) { 143 144 #ifdef INET 145 case AF_INET: 146 if (!arpresolve(ac, rt, m, dst, edst, rt0)) 147 return (0); /* if not yet resolved */ 148 /* If broadcasting on a simplex interface, loopback a copy */ 149 if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX)) 150 mcopy = m_copy(m, 0, (int)M_COPYALL); 151 off = m->m_pkthdr.len - m->m_len; 152 type = ETHERTYPE_IP; 153 break; 154 #endif 155 #ifdef IPX 156 case AF_IPX: 157 type = ETHERTYPE_IPX; 158 bcopy((caddr_t)&(((struct sockaddr_ipx *)dst)->sipx_addr.x_host), 159 (caddr_t)edst, sizeof (edst)); 160 if (!bcmp((caddr_t)edst, (caddr_t)&ipx_thishost, sizeof(edst))) 161 return (looutput(ifp, m, dst, rt)); 162 /* If broadcasting on a simplex interface, loopback a copy */ 163 if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX)) 164 mcopy = m_copy(m, 0, (int)M_COPYALL); 165 break; 166 #endif 167 #ifdef NS 168 case AF_NS: 169 type = ETHERTYPE_NS; 170 bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host), 171 (caddr_t)edst, sizeof (edst)); 172 if (!bcmp((caddr_t)edst, (caddr_t)&ns_thishost, sizeof(edst))) 173 return (looutput(ifp, m, dst, rt)); 174 /* If broadcasting on a simplex interface, loopback a copy */ 175 if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX)) 176 mcopy = m_copy(m, 0, (int)M_COPYALL); 177 break; 178 #endif 179 #ifdef ISO 180 case AF_ISO: { 181 int snpalen; 182 struct llc *l; 183 register struct sockaddr_dl *sdl; 184 185 if (rt && (sdl = (struct sockaddr_dl *)rt->rt_gateway) && 186 sdl->sdl_family == AF_LINK && sdl->sdl_alen > 0) { 187 bcopy(LLADDR(sdl), (caddr_t)edst, sizeof(edst)); 188 } else if (error = 189 iso_snparesolve(ifp, (struct sockaddr_iso *)dst, 190 (char *)edst, &snpalen)) 191 goto bad; /* Not Resolved */ 192 /* If broadcasting on a simplex interface, loopback a copy */ 193 if (*edst & 1) 194 m->m_flags |= (M_BCAST|M_MCAST); 195 if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX) && 196 (mcopy = m_copy(m, 0, (int)M_COPYALL))) { 197 M_PREPEND(mcopy, sizeof (*eh), M_DONTWAIT); 198 if (mcopy) { 199 eh = mtod(mcopy, struct ether_header *); 200 bcopy((caddr_t)edst, 201 (caddr_t)eh->ether_dhost, sizeof (edst)); 202 bcopy((caddr_t)ac->ac_enaddr, 203 (caddr_t)eh->ether_shost, sizeof (edst)); 204 } 205 } 206 M_PREPEND(m, 3, M_DONTWAIT); 207 if (m == NULL) 208 return (0); 209 type = m->m_pkthdr.len; 210 l = mtod(m, struct llc *); 211 l->llc_dsap = l->llc_ssap = LLC_ISO_LSAP; 212 l->llc_control = LLC_UI; 213 len += 3; 214 IFDEBUG(D_ETHER) 215 int i; 216 printf("unoutput: sending pkt to: "); 217 for (i=0; i<6; i++) 218 printf("%x ", edst[i] & 0xff); 219 printf("\n"); 220 ENDDEBUG 221 } break; 222 #endif /* ISO */ 223 #ifdef LLC 224 /* case AF_NSAP: */ 225 case AF_CCITT: { 226 register struct sockaddr_dl *sdl = 227 (struct sockaddr_dl *) rt -> rt_gateway; 228 229 if (sdl && sdl->sdl_family == AF_LINK 230 && sdl->sdl_alen > 0) { 231 bcopy(LLADDR(sdl), (char *)edst, 232 sizeof(edst)); 233 } else goto bad; /* Not a link interface ? Funny ... */ 234 if ((ifp->if_flags & IFF_SIMPLEX) && (*edst & 1) && 235 (mcopy = m_copy(m, 0, (int)M_COPYALL))) { 236 M_PREPEND(mcopy, sizeof (*eh), M_DONTWAIT); 237 if (mcopy) { 238 eh = mtod(mcopy, struct ether_header *); 239 bcopy((caddr_t)edst, 240 (caddr_t)eh->ether_dhost, sizeof (edst)); 241 bcopy((caddr_t)ac->ac_enaddr, 242 (caddr_t)eh->ether_shost, sizeof (edst)); 243 } 244 } 245 type = m->m_pkthdr.len; 246 #ifdef LLC_DEBUG 247 { 248 int i; 249 register struct llc *l = mtod(m, struct llc *); 250 251 printf("ether_output: sending LLC2 pkt to: "); 252 for (i=0; i<6; i++) 253 printf("%x ", edst[i] & 0xff); 254 printf(" len 0x%x dsap 0x%x ssap 0x%x control 0x%x\n", 255 type & 0xff, l->llc_dsap & 0xff, l->llc_ssap &0xff, 256 l->llc_control & 0xff); 257 258 } 259 #endif /* LLC_DEBUG */ 260 } break; 261 #endif /* LLC */ 262 263 case AF_UNSPEC: 264 eh = (struct ether_header *)dst->sa_data; 265 (void)memcpy(edst, eh->ether_dhost, sizeof (edst)); 266 type = eh->ether_type; 267 break; 268 269 default: 270 printf("%s%d: can't handle af%d\n", ifp->if_name, ifp->if_unit, 271 dst->sa_family); 272 senderr(EAFNOSUPPORT); 273 } 274 275 276 if (mcopy) 277 (void) looutput(ifp, mcopy, dst, rt); 278 /* 279 * Add local net header. If no space in first mbuf, 280 * allocate another. 281 */ 282 M_PREPEND(m, sizeof (struct ether_header), M_DONTWAIT); 283 if (m == 0) 284 senderr(ENOBUFS); 285 eh = mtod(m, struct ether_header *); 286 type = htons((u_short)type); 287 (void)memcpy(&eh->ether_type, &type, 288 sizeof(eh->ether_type)); 289 (void)memcpy(eh->ether_dhost, edst, sizeof (edst)); 290 (void)memcpy(eh->ether_shost, ac->ac_enaddr, 291 sizeof(eh->ether_shost)); 292 s = splimp(); 293 /* 294 * Queue message on interface, and start output if interface 295 * not yet active. 296 */ 297 if (IF_QFULL(&ifp->if_snd)) { 298 IF_DROP(&ifp->if_snd); 299 splx(s); 300 senderr(ENOBUFS); 301 } 302 IF_ENQUEUE(&ifp->if_snd, m); 303 if ((ifp->if_flags & IFF_OACTIVE) == 0) 304 (*ifp->if_start)(ifp); 305 splx(s); 306 ifp->if_obytes += len + sizeof (struct ether_header); 307 if (m->m_flags & M_MCAST) 308 ifp->if_omcasts++; 309 return (error); 310 311 bad: 312 if (m) 313 m_freem(m); 314 return (error); 315 } 316 317 /* 318 * Process a received Ethernet packet; 319 * the packet is in the mbuf chain m without 320 * the ether header, which is provided separately. 321 */ 322 void 323 ether_input(ifp, eh, m) 324 struct ifnet *ifp; 325 register struct ether_header *eh; 326 struct mbuf *m; 327 { 328 register struct ifqueue *inq; 329 register struct llc *l; 330 struct arpcom *ac = (struct arpcom *)ifp; 331 u_short ether_type; 332 int s; 333 334 if ((ifp->if_flags & IFF_UP) == 0) { 335 m_freem(m); 336 return; 337 } 338 ifp->if_lastchange = time; 339 ifp->if_ibytes += m->m_pkthdr.len + sizeof (*eh); 340 if (bcmp((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost, 341 sizeof(etherbroadcastaddr)) == 0) 342 m->m_flags |= M_BCAST; 343 else if (eh->ether_dhost[0] & 1) 344 m->m_flags |= M_MCAST; 345 if (m->m_flags & (M_BCAST|M_MCAST)) 346 ifp->if_imcasts++; 347 348 ether_type = ntohs(eh->ether_type); 349 350 switch (ether_type) { 351 #ifdef INET 352 case ETHERTYPE_IP: 353 schednetisr(NETISR_IP); 354 inq = &ipintrq; 355 break; 356 357 case ETHERTYPE_ARP: 358 schednetisr(NETISR_ARP); 359 inq = &arpintrq; 360 break; 361 #endif 362 #ifdef IPX 363 case ETHERTYPE_IPX: 364 schednetisr(NETISR_IPX); 365 inq = &ipxintrq; 366 break; 367 #endif 368 #ifdef NS 369 case ETHERTYPE_NS: 370 schednetisr(NETISR_NS); 371 inq = &nsintrq; 372 break; 373 #endif 374 default: 375 #if defined (ISO) || defined (LLC) 376 if (ether_type > ETHERMTU) 377 goto dropanyway; 378 l = mtod(m, struct llc *); 379 switch (l->llc_dsap) { 380 #ifdef ISO 381 case LLC_ISO_LSAP: 382 switch (l->llc_control) { 383 case LLC_UI: 384 /* LLC_UI_P forbidden in class 1 service */ 385 if ((l->llc_dsap == LLC_ISO_LSAP) && 386 (l->llc_ssap == LLC_ISO_LSAP)) { 387 /* LSAP for ISO */ 388 if (m->m_pkthdr.len > ether_type) 389 m_adj(m, ether_type - m->m_pkthdr.len); 390 m->m_data += 3; /* XXX */ 391 m->m_len -= 3; /* XXX */ 392 m->m_pkthdr.len -= 3; /* XXX */ 393 M_PREPEND(m, sizeof *eh, M_DONTWAIT); 394 if (m == 0) 395 return; 396 *mtod(m, struct ether_header *) = *eh; 397 IFDEBUG(D_ETHER) 398 printf("clnp packet"); 399 ENDDEBUG 400 schednetisr(NETISR_ISO); 401 inq = &clnlintrq; 402 break; 403 } 404 goto dropanyway; 405 406 case LLC_XID: 407 case LLC_XID_P: 408 if(m->m_len < 6) 409 goto dropanyway; 410 l->llc_window = 0; 411 l->llc_fid = 9; 412 l->llc_class = 1; 413 l->llc_dsap = l->llc_ssap = 0; 414 /* Fall through to */ 415 case LLC_TEST: 416 case LLC_TEST_P: 417 { 418 struct sockaddr sa; 419 register struct ether_header *eh2; 420 int i; 421 u_char c = l->llc_dsap; 422 423 l->llc_dsap = l->llc_ssap; 424 l->llc_ssap = c; 425 if (m->m_flags & (M_BCAST | M_MCAST)) 426 bcopy((caddr_t)ac->ac_enaddr, 427 (caddr_t)eh->ether_dhost, 6); 428 sa.sa_family = AF_UNSPEC; 429 sa.sa_len = sizeof(sa); 430 eh2 = (struct ether_header *)sa.sa_data; 431 for (i = 0; i < 6; i++) { 432 eh2->ether_shost[i] = c = eh->ether_dhost[i]; 433 eh2->ether_dhost[i] = 434 eh->ether_dhost[i] = eh->ether_shost[i]; 435 eh->ether_shost[i] = c; 436 } 437 ifp->if_output(ifp, m, &sa, NULL); 438 return; 439 } 440 default: 441 m_freem(m); 442 return; 443 } 444 break; 445 #endif /* ISO */ 446 #ifdef LLC 447 case LLC_X25_LSAP: 448 { 449 if (m->m_pkthdr.len > ether_type) 450 m_adj(m, ether_type - m->m_pkthdr.len); 451 M_PREPEND(m, sizeof(struct sdl_hdr) , M_DONTWAIT); 452 if (m == 0) 453 return; 454 if ( !sdl_sethdrif(ifp, eh->ether_shost, LLC_X25_LSAP, 455 eh->ether_dhost, LLC_X25_LSAP, 6, 456 mtod(m, struct sdl_hdr *))) 457 panic("ETHER cons addr failure"); 458 mtod(m, struct sdl_hdr *)->sdlhdr_len = ether_type; 459 #ifdef LLC_DEBUG 460 printf("llc packet\n"); 461 #endif /* LLC_DEBUG */ 462 schednetisr(NETISR_CCITT); 463 inq = &llcintrq; 464 break; 465 } 466 #endif /* LLC */ 467 dropanyway: 468 default: 469 m_freem(m); 470 return; 471 } 472 #else /* ISO || LLC */ 473 m_freem(m); 474 return; 475 #endif /* ISO || LLC */ 476 } 477 478 s = splimp(); 479 if (IF_QFULL(inq)) { 480 IF_DROP(inq); 481 m_freem(m); 482 } else 483 IF_ENQUEUE(inq, m); 484 splx(s); 485 } 486 487 /* 488 * Convert Ethernet address to printable (loggable) representation. 489 */ 490 static char digits[] = "0123456789abcdef"; 491 char * 492 ether_sprintf(ap) 493 register u_char *ap; 494 { 495 register i; 496 static char etherbuf[18]; 497 register char *cp = etherbuf; 498 499 for (i = 0; i < 6; i++) { 500 *cp++ = digits[*ap >> 4]; 501 *cp++ = digits[*ap++ & 0xf]; 502 *cp++ = ':'; 503 } 504 *--cp = 0; 505 return (etherbuf); 506 } 507 508 /* 509 * Perform common duties while attaching to interface list 510 */ 511 void 512 ether_ifattach(ifp) 513 register struct ifnet *ifp; 514 { 515 register struct ifaddr *ifa; 516 register struct sockaddr_dl *sdl; 517 518 ifp->if_type = IFT_ETHER; 519 ifp->if_addrlen = 6; 520 ifp->if_hdrlen = 14; 521 ifp->if_mtu = ETHERMTU; 522 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) 523 if ((sdl = (struct sockaddr_dl *)ifa->ifa_addr) && 524 sdl->sdl_family == AF_LINK) { 525 sdl->sdl_type = IFT_ETHER; 526 sdl->sdl_alen = ifp->if_addrlen; 527 bcopy((caddr_t)((struct arpcom *)ifp)->ac_enaddr, 528 LLADDR(sdl), ifp->if_addrlen); 529 break; 530 } 531 } 532 533 u_char ether_ipmulticast_min[6] = { 0x01, 0x00, 0x5e, 0x00, 0x00, 0x00 }; 534 u_char ether_ipmulticast_max[6] = { 0x01, 0x00, 0x5e, 0x7f, 0xff, 0xff }; 535 /* 536 * Add an Ethernet multicast address or range of addresses to the list for a 537 * given interface. 538 */ 539 int 540 ether_addmulti(ifr, ac) 541 struct ifreq *ifr; 542 register struct arpcom *ac; 543 { 544 register struct ether_multi *enm; 545 struct sockaddr_in *sin; 546 u_char addrlo[6]; 547 u_char addrhi[6]; 548 int set_allmulti = 0; 549 int s = splimp(); 550 551 switch (ifr->ifr_addr.sa_family) { 552 553 case AF_UNSPEC: 554 bcopy(ifr->ifr_addr.sa_data, addrlo, 6); 555 bcopy(addrlo, addrhi, 6); 556 break; 557 558 #ifdef INET 559 case AF_INET: 560 sin = (struct sockaddr_in *)&(ifr->ifr_addr); 561 if (sin->sin_addr.s_addr == INADDR_ANY) { 562 /* 563 * An IP address of INADDR_ANY means listen to all 564 * of the Ethernet multicast addresses used for IP. 565 * (This is for the sake of IP multicast routers.) 566 */ 567 bcopy(ether_ipmulticast_min, addrlo, 6); 568 bcopy(ether_ipmulticast_max, addrhi, 6); 569 set_allmulti = 1; 570 } 571 else { 572 ETHER_MAP_IP_MULTICAST(&sin->sin_addr, addrlo); 573 bcopy(addrlo, addrhi, 6); 574 } 575 break; 576 #endif 577 578 default: 579 splx(s); 580 return (EAFNOSUPPORT); 581 } 582 583 /* 584 * Verify that we have valid Ethernet multicast addresses. 585 */ 586 if ((addrlo[0] & 0x01) != 1 || (addrhi[0] & 0x01) != 1) { 587 splx(s); 588 return (EINVAL); 589 } 590 /* 591 * See if the address range is already in the list. 592 */ 593 ETHER_LOOKUP_MULTI(addrlo, addrhi, ac, enm); 594 if (enm != NULL) { 595 /* 596 * Found it; just increment the reference count. 597 */ 598 ++enm->enm_refcount; 599 splx(s); 600 return (0); 601 } 602 /* 603 * New address or range; malloc a new multicast record 604 * and link it into the interface's multicast list. 605 */ 606 enm = (struct ether_multi *)malloc(sizeof(*enm), M_IFMADDR, M_NOWAIT); 607 if (enm == NULL) { 608 splx(s); 609 return (ENOBUFS); 610 } 611 bcopy(addrlo, enm->enm_addrlo, 6); 612 bcopy(addrhi, enm->enm_addrhi, 6); 613 enm->enm_ac = ac; 614 enm->enm_refcount = 1; 615 enm->enm_next = ac->ac_multiaddrs; 616 ac->ac_multiaddrs = enm; 617 ac->ac_multicnt++; 618 splx(s); 619 if (set_allmulti) 620 ac->ac_if.if_flags |= IFF_ALLMULTI; 621 622 /* 623 * Return ENETRESET to inform the driver that the list has changed 624 * and its reception filter should be adjusted accordingly. 625 */ 626 return (ENETRESET); 627 } 628 629 /* 630 * Delete a multicast address record. 631 */ 632 int 633 ether_delmulti(ifr, ac) 634 struct ifreq *ifr; 635 register struct arpcom *ac; 636 { 637 register struct ether_multi *enm; 638 register struct ether_multi **p; 639 struct sockaddr_in *sin; 640 u_char addrlo[6]; 641 u_char addrhi[6]; 642 int unset_allmulti = 0; 643 int s = splimp(); 644 645 switch (ifr->ifr_addr.sa_family) { 646 647 case AF_UNSPEC: 648 bcopy(ifr->ifr_addr.sa_data, addrlo, 6); 649 bcopy(addrlo, addrhi, 6); 650 break; 651 652 #ifdef INET 653 case AF_INET: 654 sin = (struct sockaddr_in *)&(ifr->ifr_addr); 655 if (sin->sin_addr.s_addr == INADDR_ANY) { 656 /* 657 * An IP address of INADDR_ANY means stop listening 658 * to the range of Ethernet multicast addresses used 659 * for IP. 660 */ 661 bcopy(ether_ipmulticast_min, addrlo, 6); 662 bcopy(ether_ipmulticast_max, addrhi, 6); 663 unset_allmulti = 1; 664 } 665 else { 666 ETHER_MAP_IP_MULTICAST(&sin->sin_addr, addrlo); 667 bcopy(addrlo, addrhi, 6); 668 } 669 break; 670 #endif 671 672 default: 673 splx(s); 674 return (EAFNOSUPPORT); 675 } 676 677 /* 678 * Look up the address in our list. 679 */ 680 ETHER_LOOKUP_MULTI(addrlo, addrhi, ac, enm); 681 if (enm == NULL) { 682 splx(s); 683 return (ENXIO); 684 } 685 if (--enm->enm_refcount != 0) { 686 /* 687 * Still some claims to this record. 688 */ 689 splx(s); 690 return (0); 691 } 692 /* 693 * No remaining claims to this record; unlink and free it. 694 */ 695 for (p = &enm->enm_ac->ac_multiaddrs; 696 *p != enm; 697 p = &(*p)->enm_next) 698 continue; 699 *p = (*p)->enm_next; 700 free(enm, M_IFMADDR); 701 ac->ac_multicnt--; 702 splx(s); 703 if (unset_allmulti) 704 ac->ac_if.if_flags &= ~IFF_ALLMULTI; 705 706 /* 707 * Return ENETRESET to inform the driver that the list has changed 708 * and its reception filter should be adjusted accordingly. 709 */ 710 return (ENETRESET); 711 } 712