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