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