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