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