1 /* $NetBSD: if_ethersubr.c,v 1.26 1997/10/02 19:41:59 is 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 <net/if_ether.h> 59 60 #include <netinet/in.h> 61 #ifdef INET 62 #include <netinet/in_var.h> 63 #endif 64 #include <netinet/if_inarp.h> 65 66 #ifdef NS 67 #include <netns/ns.h> 68 #include <netns/ns_if.h> 69 #endif 70 71 #ifdef ISO 72 #include <netiso/argo_debug.h> 73 #include <netiso/iso.h> 74 #include <netiso/iso_var.h> 75 #include <netiso/iso_snpac.h> 76 #endif 77 78 #ifdef LLC 79 #include <netccitt/dll.h> 80 #include <netccitt/llc_var.h> 81 #endif 82 83 #if defined(LLC) && defined(CCITT) 84 extern struct ifqueue pkintrq; 85 #endif 86 87 #ifdef NETATALK 88 #include <netatalk/at.h> 89 #include <netatalk/at_var.h> 90 #include <netatalk/at_extern.h> 91 92 #define llc_snap_org_code llc_un.type_snap.org_code 93 #define llc_snap_ether_type llc_un.type_snap.ether_type 94 95 extern u_char at_org_code[3]; 96 extern u_char aarp_org_code[3]; 97 #endif /* NETATALK */ 98 99 u_char etherbroadcastaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 100 #define senderr(e) { error = (e); goto bad;} 101 102 #define SIN(x) ((struct sockaddr_in *)x) 103 104 /* 105 * Ethernet output routine. 106 * Encapsulate a packet of type family for the local net. 107 * Assumes that ifp is actually pointer to ethercom structure. 108 */ 109 int 110 ether_output(ifp, m0, dst, rt0) 111 register struct ifnet *ifp; 112 struct mbuf *m0; 113 struct sockaddr *dst; 114 struct rtentry *rt0; 115 { 116 u_int16_t etype; 117 int s, error = 0; 118 u_char edst[6]; 119 register struct mbuf *m = m0; 120 register struct rtentry *rt; 121 struct mbuf *mcopy = (struct mbuf *)0; 122 register struct ether_header *eh; 123 #ifdef INET 124 struct arphdr *ah; 125 #endif /* INET */ 126 #ifdef NETATALK 127 struct at_ifaddr *aa; 128 #endif /* NETATALK */ 129 130 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) 131 senderr(ENETDOWN); 132 ifp->if_lastchange = time; 133 if ((rt = rt0) != NULL) { 134 if ((rt->rt_flags & RTF_UP) == 0) { 135 if ((rt0 = rt = rtalloc1(dst, 1)) != NULL) 136 rt->rt_refcnt--; 137 else 138 senderr(EHOSTUNREACH); 139 } 140 if (rt->rt_flags & RTF_GATEWAY) { 141 if (rt->rt_gwroute == 0) 142 goto lookup; 143 if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) { 144 rtfree(rt); rt = rt0; 145 lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1); 146 if ((rt = rt->rt_gwroute) == 0) 147 senderr(EHOSTUNREACH); 148 } 149 } 150 if (rt->rt_flags & RTF_REJECT) 151 if (rt->rt_rmx.rmx_expire == 0 || 152 time.tv_sec < rt->rt_rmx.rmx_expire) 153 senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH); 154 } 155 switch (dst->sa_family) { 156 157 #ifdef INET 158 case AF_INET: 159 if (m->m_flags & M_BCAST) 160 bcopy((caddr_t)etherbroadcastaddr, (caddr_t)edst, 161 sizeof(edst)); 162 163 else if (m->m_flags & M_MCAST) { 164 ETHER_MAP_IP_MULTICAST(&SIN(dst)->sin_addr, 165 (caddr_t)edst) 166 167 } else if (!arpresolve(ifp, rt, m, dst, edst)) 168 return (0); /* if not yet resolved */ 169 /* If broadcasting on a simplex interface, loopback a copy */ 170 if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX)) 171 mcopy = m_copy(m, 0, (int)M_COPYALL); 172 etype = htons(ETHERTYPE_IP); 173 break; 174 175 case AF_ARP: 176 ah = mtod(m, struct arphdr *); 177 if (m->m_flags & M_BCAST) 178 bcopy((caddr_t)etherbroadcastaddr, (caddr_t)edst, 179 sizeof(edst)); 180 else 181 bcopy((caddr_t)ar_tha(ah), 182 (caddr_t)edst, sizeof(edst)); 183 184 ah->ar_hrd = htons(ARPHRD_ETHER); 185 186 switch(ntohs(ah->ar_op)) { 187 case ARPOP_REVREQUEST: 188 case ARPOP_REVREPLY: 189 etype = htons(ETHERTYPE_REVARP); 190 break; 191 192 case ARPOP_REQUEST: 193 case ARPOP_REPLY: 194 default: 195 etype = htons(ETHERTYPE_ARP); 196 } 197 198 break; 199 #endif 200 #ifdef NETATALK 201 case AF_APPLETALK: 202 if (!aarpresolve(ifp, m, (struct sockaddr_at *)dst, edst)) { 203 #ifdef NETATALKDEBUG 204 printf("aarpresolv failed\n"); 205 #endif /* NETATALKDEBUG */ 206 return (0); 207 } 208 /* 209 * ifaddr is the first thing in at_ifaddr 210 */ 211 aa = (struct at_ifaddr *) at_ifawithnet( 212 (struct sockaddr_at *)dst, ifp); 213 if (aa == NULL) 214 goto bad; 215 216 /* 217 * In the phase 2 case, we need to prepend an mbuf for the 218 * llc header. Since we must preserve the value of m, 219 * which is passed to us by value, we m_copy() the first 220 * mbuf, and use it for our llc header. 221 */ 222 if (aa->aa_flags & AFA_PHASE2) { 223 struct llc llc; 224 225 M_PREPEND(m, sizeof(struct llc), M_WAIT); 226 llc.llc_dsap = llc.llc_ssap = LLC_SNAP_LSAP; 227 llc.llc_control = LLC_UI; 228 bcopy(at_org_code, llc.llc_snap_org_code, 229 sizeof(llc.llc_snap_org_code)); 230 llc.llc_snap_ether_type = htons(ETHERTYPE_AT); 231 bcopy(&llc, mtod(m, caddr_t), sizeof(struct llc)); 232 etype = htons(m->m_pkthdr.len); 233 } else { 234 etype = htons(ETHERTYPE_AT); 235 } 236 break; 237 #endif /* NETATALK */ 238 #ifdef NS 239 case AF_NS: 240 etype = htons(ETHERTYPE_NS); 241 bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host), 242 (caddr_t)edst, sizeof (edst)); 243 if (!bcmp((caddr_t)edst, (caddr_t)&ns_thishost, sizeof(edst))) 244 return (looutput(ifp, m, dst, rt)); 245 /* If broadcasting on a simplex interface, loopback a copy */ 246 if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX)) 247 mcopy = m_copy(m, 0, (int)M_COPYALL); 248 break; 249 #endif 250 #ifdef ISO 251 case AF_ISO: { 252 int snpalen; 253 struct llc *l; 254 register struct sockaddr_dl *sdl; 255 256 if (rt && (sdl = (struct sockaddr_dl *)rt->rt_gateway) && 257 sdl->sdl_family == AF_LINK && sdl->sdl_alen > 0) { 258 bcopy(LLADDR(sdl), (caddr_t)edst, sizeof(edst)); 259 } else { 260 error = iso_snparesolve(ifp, (struct sockaddr_iso *)dst, 261 (char *)edst, &snpalen); 262 if (error) 263 goto bad; /* Not Resolved */ 264 } 265 /* If broadcasting on a simplex interface, loopback a copy */ 266 if (*edst & 1) 267 m->m_flags |= (M_BCAST|M_MCAST); 268 if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX) && 269 (mcopy = m_copy(m, 0, (int)M_COPYALL))) { 270 M_PREPEND(mcopy, sizeof (*eh), M_DONTWAIT); 271 if (mcopy) { 272 eh = mtod(mcopy, struct ether_header *); 273 bcopy((caddr_t)edst, 274 (caddr_t)eh->ether_dhost, sizeof (edst)); 275 bcopy(LLADDR(ifp->if_sadl), 276 (caddr_t)eh->ether_shost, sizeof (edst)); 277 } 278 } 279 M_PREPEND(m, 3, M_DONTWAIT); 280 if (m == NULL) 281 return (0); 282 etype = htons(m->m_pkthdr.len); 283 l = mtod(m, struct llc *); 284 l->llc_dsap = l->llc_ssap = LLC_ISO_LSAP; 285 l->llc_control = LLC_UI; 286 #ifdef ARGO_DEBUG 287 if (argo_debug[D_ETHER]) { 288 int i; 289 printf("unoutput: sending pkt to: "); 290 for (i=0; i<6; i++) 291 printf("%x ", edst[i] & 0xff); 292 printf("\n"); 293 } 294 #endif 295 } break; 296 #endif /* ISO */ 297 #ifdef LLC 298 /* case AF_NSAP: */ 299 case AF_CCITT: { 300 register struct sockaddr_dl *sdl = 301 (struct sockaddr_dl *) rt -> rt_gateway; 302 303 if (sdl && sdl->sdl_family == AF_LINK 304 && sdl->sdl_alen > 0) { 305 bcopy(LLADDR(sdl), (char *)edst, 306 sizeof(edst)); 307 } else goto bad; /* Not a link interface ? Funny ... */ 308 if ((ifp->if_flags & IFF_SIMPLEX) && (*edst & 1) && 309 (mcopy = m_copy(m, 0, (int)M_COPYALL))) { 310 M_PREPEND(mcopy, sizeof (*eh), M_DONTWAIT); 311 if (mcopy) { 312 eh = mtod(mcopy, struct ether_header *); 313 bcopy((caddr_t)edst, 314 (caddr_t)eh->ether_dhost, sizeof (edst)); 315 bcopy(LLADDR(ifp->if_sadl), 316 (caddr_t)eh->ether_shost, sizeof (edst)); 317 } 318 } 319 etype = htons(m->m_pkthdr.len); 320 #ifdef LLC_DEBUG 321 { 322 int i; 323 register struct llc *l = mtod(m, struct llc *); 324 325 printf("ether_output: sending LLC2 pkt to: "); 326 for (i=0; i<6; i++) 327 printf("%x ", edst[i] & 0xff); 328 printf(" len 0x%x dsap 0x%x ssap 0x%x control 0x%x\n", 329 m->m_pkthdr.len, l->llc_dsap & 0xff, l->llc_ssap &0xff, 330 l->llc_control & 0xff); 331 332 } 333 #endif /* LLC_DEBUG */ 334 } break; 335 #endif /* LLC */ 336 337 case AF_UNSPEC: 338 eh = (struct ether_header *)dst->sa_data; 339 bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, sizeof (edst)); 340 /* AF_UNSPEC doesn't swap the byte order of the ether_type. */ 341 etype = eh->ether_type; 342 break; 343 344 default: 345 printf("%s: can't handle af%d\n", ifp->if_xname, 346 dst->sa_family); 347 senderr(EAFNOSUPPORT); 348 } 349 350 if (mcopy) 351 (void) looutput(ifp, mcopy, dst, rt); 352 353 /* 354 * Add local net header. If no space in first mbuf, 355 * allocate another. 356 */ 357 M_PREPEND(m, sizeof (struct ether_header), M_DONTWAIT); 358 if (m == 0) 359 senderr(ENOBUFS); 360 eh = mtod(m, struct ether_header *); 361 bcopy((caddr_t)&etype,(caddr_t)&eh->ether_type, 362 sizeof(eh->ether_type)); 363 bcopy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof (edst)); 364 bcopy(LLADDR(ifp->if_sadl), (caddr_t)eh->ether_shost, 365 sizeof(eh->ether_shost)); 366 s = splimp(); 367 /* 368 * Queue message on interface, and start output if interface 369 * not yet active. 370 */ 371 if (IF_QFULL(&ifp->if_snd)) { 372 IF_DROP(&ifp->if_snd); 373 splx(s); 374 senderr(ENOBUFS); 375 } 376 ifp->if_obytes += m->m_pkthdr.len; 377 IF_ENQUEUE(&ifp->if_snd, m); 378 if ((ifp->if_flags & IFF_OACTIVE) == 0) 379 (*ifp->if_start)(ifp); 380 splx(s); 381 if (m->m_flags & M_MCAST) 382 ifp->if_omcasts++; 383 return (error); 384 385 bad: 386 if (m) 387 m_freem(m); 388 return (error); 389 } 390 391 /* 392 * Process a received Ethernet packet; 393 * the packet is in the mbuf chain m without 394 * the ether header, which is provided separately. 395 */ 396 void 397 ether_input(ifp, eh, m) 398 struct ifnet *ifp; 399 register struct ether_header *eh; 400 struct mbuf *m; 401 { 402 register struct ifqueue *inq; 403 u_int16_t etype; 404 int s; 405 #if defined (ISO) || defined (LLC) || defined(NETATALK) 406 register struct llc *l; 407 #endif 408 409 if ((ifp->if_flags & IFF_UP) == 0) { 410 m_freem(m); 411 return; 412 } 413 ifp->if_lastchange = time; 414 ifp->if_ibytes += m->m_pkthdr.len + sizeof (*eh); 415 if (eh->ether_dhost[0] & 1) { 416 if (bcmp((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost, 417 sizeof(etherbroadcastaddr)) == 0) 418 m->m_flags |= M_BCAST; 419 else 420 m->m_flags |= M_MCAST; 421 } 422 if (m->m_flags & (M_BCAST|M_MCAST)) 423 ifp->if_imcasts++; 424 425 etype = ntohs(eh->ether_type); 426 switch (etype) { 427 #ifdef INET 428 case ETHERTYPE_IP: 429 schednetisr(NETISR_IP); 430 inq = &ipintrq; 431 break; 432 433 case ETHERTYPE_ARP: 434 schednetisr(NETISR_ARP); 435 inq = &arpintrq; 436 break; 437 438 case ETHERTYPE_REVARP: 439 revarpinput(m); /* XXX queue? */ 440 return; 441 #endif 442 #ifdef NS 443 case ETHERTYPE_NS: 444 schednetisr(NETISR_NS); 445 inq = &nsintrq; 446 break; 447 448 #endif 449 #ifdef NETATALK 450 case ETHERTYPE_AT: 451 schednetisr(NETISR_ATALK); 452 inq = &atintrq1; 453 break; 454 case ETHERTYPE_AARP: 455 /* probably this should be done with a NETISR as well */ 456 aarpinput(ifp, m); /* XXX */ 457 return; 458 #endif /* NETATALK */ 459 default: 460 #if defined (ISO) || defined (LLC) || defined (NETATALK) 461 if (etype > ETHERMTU) 462 goto dropanyway; 463 l = mtod(m, struct llc *); 464 switch (l->llc_dsap) { 465 #ifdef NETATALK 466 case LLC_SNAP_LSAP: 467 switch (l->llc_control) { 468 case LLC_UI: 469 if (l->llc_ssap != LLC_SNAP_LSAP) { 470 goto dropanyway; 471 } 472 473 if (Bcmp(&(l->llc_snap_org_code)[0], 474 at_org_code, sizeof(at_org_code)) == 0 && 475 ntohs(l->llc_snap_ether_type) == 476 ETHERTYPE_AT) { 477 inq = &atintrq2; 478 m_adj(m, sizeof(struct llc)); 479 schednetisr(NETISR_ATALK); 480 break; 481 } 482 483 if (Bcmp(&(l->llc_snap_org_code)[0], 484 aarp_org_code, 485 sizeof(aarp_org_code)) == 0 && 486 ntohs(l->llc_snap_ether_type) == 487 ETHERTYPE_AARP) { 488 m_adj( m, sizeof(struct llc)); 489 aarpinput(ifp, m); /* XXX */ 490 return; 491 } 492 493 default: 494 goto dropanyway; 495 } 496 break; 497 #endif /* NETATALK */ 498 #ifdef ISO 499 case LLC_ISO_LSAP: 500 switch (l->llc_control) { 501 case LLC_UI: 502 /* LLC_UI_P forbidden in class 1 service */ 503 if ((l->llc_dsap == LLC_ISO_LSAP) && 504 (l->llc_ssap == LLC_ISO_LSAP)) { 505 /* LSAP for ISO */ 506 if (m->m_pkthdr.len > etype) 507 m_adj(m, etype - m->m_pkthdr.len); 508 m->m_data += 3; /* XXX */ 509 m->m_len -= 3; /* XXX */ 510 m->m_pkthdr.len -= 3; /* XXX */ 511 M_PREPEND(m, sizeof *eh, M_DONTWAIT); 512 if (m == 0) 513 return; 514 *mtod(m, struct ether_header *) = *eh; 515 #ifdef ARGO_DEBUG 516 if (argo_debug[D_ETHER]) 517 printf("clnp packet"); 518 #endif 519 schednetisr(NETISR_ISO); 520 inq = &clnlintrq; 521 break; 522 } 523 goto dropanyway; 524 525 case LLC_XID: 526 case LLC_XID_P: 527 if(m->m_len < 6) 528 goto dropanyway; 529 l->llc_window = 0; 530 l->llc_fid = 9; 531 l->llc_class = 1; 532 l->llc_dsap = l->llc_ssap = 0; 533 /* Fall through to */ 534 case LLC_TEST: 535 case LLC_TEST_P: 536 { 537 struct sockaddr sa; 538 register struct ether_header *eh2; 539 int i; 540 u_char c = l->llc_dsap; 541 542 l->llc_dsap = l->llc_ssap; 543 l->llc_ssap = c; 544 if (m->m_flags & (M_BCAST | M_MCAST)) 545 bcopy(LLADDR(ifp->if_sadl), 546 (caddr_t)eh->ether_dhost, 6); 547 sa.sa_family = AF_UNSPEC; 548 sa.sa_len = sizeof(sa); 549 eh2 = (struct ether_header *)sa.sa_data; 550 for (i = 0; i < 6; i++) { 551 eh2->ether_shost[i] = c = 552 eh->ether_dhost[i]; 553 eh2->ether_dhost[i] = 554 eh->ether_dhost[i] = 555 eh->ether_shost[i]; 556 eh->ether_shost[i] = c; 557 } 558 ifp->if_output(ifp, m, &sa, NULL); 559 return; 560 } 561 default: 562 m_freem(m); 563 return; 564 } 565 break; 566 #endif /* ISO */ 567 #ifdef LLC 568 case LLC_X25_LSAP: 569 { 570 if (m->m_pkthdr.len > etype) 571 m_adj(m, etype - m->m_pkthdr.len); 572 M_PREPEND(m, sizeof(struct sdl_hdr) , M_DONTWAIT); 573 if (m == 0) 574 return; 575 if ( !sdl_sethdrif(ifp, eh->ether_shost, LLC_X25_LSAP, 576 eh->ether_dhost, LLC_X25_LSAP, 6, 577 mtod(m, struct sdl_hdr *))) 578 panic("ETHER cons addr failure"); 579 mtod(m, struct sdl_hdr *)->sdlhdr_len = etype; 580 #ifdef LLC_DEBUG 581 printf("llc packet\n"); 582 #endif /* LLC_DEBUG */ 583 schednetisr(NETISR_CCITT); 584 inq = &llcintrq; 585 break; 586 } 587 #endif /* LLC */ 588 dropanyway: 589 default: 590 m_freem(m); 591 return; 592 } 593 #else /* ISO || LLC || NETATALK*/ 594 m_freem(m); 595 return; 596 #endif /* ISO || LLC || NETATALK*/ 597 } 598 599 s = splimp(); 600 if (IF_QFULL(inq)) { 601 IF_DROP(inq); 602 m_freem(m); 603 } else 604 IF_ENQUEUE(inq, m); 605 splx(s); 606 } 607 608 /* 609 * Convert Ethernet address to printable (loggable) representation. 610 */ 611 static char digits[] = "0123456789abcdef"; 612 char * 613 ether_sprintf(ap) 614 register u_char *ap; 615 { 616 register i; 617 static char etherbuf[18]; 618 register char *cp = etherbuf; 619 620 for (i = 0; i < 6; i++) { 621 *cp++ = digits[*ap >> 4]; 622 *cp++ = digits[*ap++ & 0xf]; 623 *cp++ = ':'; 624 } 625 *--cp = 0; 626 return (etherbuf); 627 } 628 629 /* 630 * Perform common duties while attaching to interface list 631 */ 632 void 633 ether_ifattach(ifp, lla) 634 register struct ifnet *ifp; 635 u_int8_t * lla; 636 { 637 register struct sockaddr_dl *sdl; 638 639 ifp->if_type = IFT_ETHER; 640 ifp->if_addrlen = 6; 641 ifp->if_hdrlen = 14; 642 ifp->if_mtu = ETHERMTU; 643 ifp->if_output = ether_output; 644 if ((sdl = ifp->if_sadl) && 645 sdl->sdl_family == AF_LINK) { 646 sdl->sdl_type = IFT_ETHER; 647 sdl->sdl_alen = ifp->if_addrlen; 648 bcopy((caddr_t)lla, LLADDR(sdl), ifp->if_addrlen); 649 } 650 LIST_INIT(&((struct ethercom *)ifp)->ec_multiaddrs); 651 ifp->if_broadcastaddr = etherbroadcastaddr; 652 } 653 654 u_char ether_ipmulticast_min[6] = { 0x01, 0x00, 0x5e, 0x00, 0x00, 0x00 }; 655 u_char ether_ipmulticast_max[6] = { 0x01, 0x00, 0x5e, 0x7f, 0xff, 0xff }; 656 /* 657 * Add an Ethernet multicast address or range of addresses to the list for a 658 * given interface. 659 */ 660 int 661 ether_addmulti(ifr, ec) 662 struct ifreq *ifr; 663 register struct ethercom *ec; 664 { 665 register struct ether_multi *enm; 666 #ifdef INET 667 struct sockaddr_in *sin; 668 #endif /* INET */ 669 u_char addrlo[6]; 670 u_char addrhi[6]; 671 int s = splimp(); 672 673 switch (ifr->ifr_addr.sa_family) { 674 675 case AF_UNSPEC: 676 bcopy(ifr->ifr_addr.sa_data, addrlo, 6); 677 bcopy(addrlo, addrhi, 6); 678 break; 679 680 #ifdef INET 681 case AF_INET: 682 sin = (struct sockaddr_in *)&(ifr->ifr_addr); 683 if (sin->sin_addr.s_addr == INADDR_ANY) { 684 /* 685 * An IP address of INADDR_ANY means listen to all 686 * of the Ethernet multicast addresses used for IP. 687 * (This is for the sake of IP multicast routers.) 688 */ 689 bcopy(ether_ipmulticast_min, addrlo, 6); 690 bcopy(ether_ipmulticast_max, addrhi, 6); 691 } 692 else { 693 ETHER_MAP_IP_MULTICAST(&sin->sin_addr, addrlo); 694 bcopy(addrlo, addrhi, 6); 695 } 696 break; 697 #endif 698 699 default: 700 splx(s); 701 return (EAFNOSUPPORT); 702 } 703 704 /* 705 * Verify that we have valid Ethernet multicast addresses. 706 */ 707 if ((addrlo[0] & 0x01) != 1 || (addrhi[0] & 0x01) != 1) { 708 splx(s); 709 return (EINVAL); 710 } 711 /* 712 * See if the address range is already in the list. 713 */ 714 ETHER_LOOKUP_MULTI(addrlo, addrhi, ec, enm); 715 if (enm != NULL) { 716 /* 717 * Found it; just increment the reference count. 718 */ 719 ++enm->enm_refcount; 720 splx(s); 721 return (0); 722 } 723 /* 724 * New address or range; malloc a new multicast record 725 * and link it into the interface's multicast list. 726 */ 727 enm = (struct ether_multi *)malloc(sizeof(*enm), M_IFMADDR, M_NOWAIT); 728 if (enm == NULL) { 729 splx(s); 730 return (ENOBUFS); 731 } 732 bcopy(addrlo, enm->enm_addrlo, 6); 733 bcopy(addrhi, enm->enm_addrhi, 6); 734 enm->enm_ec = ec; 735 enm->enm_refcount = 1; 736 LIST_INSERT_HEAD(&ec->ec_multiaddrs, enm, enm_list); 737 ec->ec_multicnt++; 738 splx(s); 739 /* 740 * Return ENETRESET to inform the driver that the list has changed 741 * and its reception filter should be adjusted accordingly. 742 */ 743 return (ENETRESET); 744 } 745 746 /* 747 * Delete a multicast address record. 748 */ 749 int 750 ether_delmulti(ifr, ec) 751 struct ifreq *ifr; 752 register struct ethercom *ec; 753 { 754 register struct ether_multi *enm; 755 #ifdef INET 756 struct sockaddr_in *sin; 757 #endif /* INET */ 758 u_char addrlo[6]; 759 u_char addrhi[6]; 760 int s = splimp(); 761 762 switch (ifr->ifr_addr.sa_family) { 763 764 case AF_UNSPEC: 765 bcopy(ifr->ifr_addr.sa_data, addrlo, 6); 766 bcopy(addrlo, addrhi, 6); 767 break; 768 769 #ifdef INET 770 case AF_INET: 771 sin = (struct sockaddr_in *)&(ifr->ifr_addr); 772 if (sin->sin_addr.s_addr == INADDR_ANY) { 773 /* 774 * An IP address of INADDR_ANY means stop listening 775 * to the range of Ethernet multicast addresses used 776 * for IP. 777 */ 778 bcopy(ether_ipmulticast_min, addrlo, 6); 779 bcopy(ether_ipmulticast_max, addrhi, 6); 780 } 781 else { 782 ETHER_MAP_IP_MULTICAST(&sin->sin_addr, addrlo); 783 bcopy(addrlo, addrhi, 6); 784 } 785 break; 786 #endif 787 788 default: 789 splx(s); 790 return (EAFNOSUPPORT); 791 } 792 793 /* 794 * Look up the address in our list. 795 */ 796 ETHER_LOOKUP_MULTI(addrlo, addrhi, ec, enm); 797 if (enm == NULL) { 798 splx(s); 799 return (ENXIO); 800 } 801 if (--enm->enm_refcount != 0) { 802 /* 803 * Still some claims to this record. 804 */ 805 splx(s); 806 return (0); 807 } 808 /* 809 * No remaining claims to this record; unlink and free it. 810 */ 811 LIST_REMOVE(enm, enm_list); 812 free(enm, M_IFMADDR); 813 ec->ec_multicnt--; 814 splx(s); 815 /* 816 * Return ENETRESET to inform the driver that the list has changed 817 * and its reception filter should be adjusted accordingly. 818 */ 819 return (ENETRESET); 820 } 821