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