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