if_ef.c revision 69781
1/*- 2 * Copyright (c) 1999, 2000 Boris Popov 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD: head/sys/net/if_ef.c 69781 2000-12-08 21:51:06Z dwmalone $ 27 */ 28 29#include "opt_inet.h" 30#include "opt_ipx.h" 31#include "opt_ef.h" 32 33#include <sys/param.h> 34#include <sys/systm.h> 35#include <sys/sockio.h> 36#include <sys/malloc.h> 37#include <sys/mbuf.h> 38#include <sys/socket.h> 39#include <sys/syslog.h> 40#include <sys/kernel.h> 41#include <sys/module.h> 42 43#include <net/ethernet.h> 44#include <net/if_llc.h> 45#include <net/if.h> 46#include <net/if_arp.h> 47#include <net/if_dl.h> 48#include <net/if_types.h> 49#include <net/netisr.h> 50#include <net/route.h> 51#include <net/bpf.h> 52 53#ifdef INET 54#include <netinet/in.h> 55#include <netinet/in_var.h> 56#include <netinet/if_ether.h> 57#endif 58 59#ifdef IPX 60#include <netipx/ipx.h> 61#include <netipx/ipx_if.h> 62#endif 63 64/* internal frame types */ 65#define ETHER_FT_EII 0 /* Ethernet_II - default */ 66#define ETHER_FT_8023 1 /* 802.3 (Novell) */ 67#define ETHER_FT_8022 2 /* 802.2 */ 68#define ETHER_FT_SNAP 3 /* SNAP */ 69#define EF_NFT 4 /* total number of frame types */ 70 71#ifdef EF_DEBUG 72#define EFDEBUG(format, args...) printf("%s: "format, __FUNCTION__ ,## args) 73#else 74#define EFDEBUG(format, args...) 75#endif 76 77#define EFERROR(format, args...) printf("%s: "format, __FUNCTION__ ,## args) 78 79struct efnet { 80 struct arpcom ef_ac; 81 struct ifnet * ef_ifp; 82}; 83 84struct ef_link { 85 SLIST_ENTRY(ef_link) el_next; 86 struct ifnet *el_ifp; /* raw device for this clones */ 87 struct efnet *el_units[EF_NFT]; /* our clones */ 88}; 89 90static SLIST_HEAD(ef_link_head, ef_link) efdev = {NULL}; 91static int efcount; 92 93extern int (*ef_inputp)(struct ifnet*, struct ether_header *eh, struct mbuf *m); 94extern int (*ef_outputp)(struct ifnet *ifp, struct mbuf **mp, 95 struct sockaddr *dst, short *tp, int *hlen); 96 97/* 98static void ef_reset (struct ifnet *); 99*/ 100static int ef_attach(struct efnet *sc); 101static int ef_detach(struct efnet *sc); 102static void ef_init(void *); 103static int ef_ioctl(struct ifnet *, u_long, caddr_t); 104static void ef_start(struct ifnet *); 105static int ef_input(struct ifnet*, struct ether_header *, struct mbuf *); 106static int ef_output(struct ifnet *ifp, struct mbuf **mp, 107 struct sockaddr *dst, short *tp, int *hlen); 108 109static int ef_load(void); 110static int ef_unload(void); 111 112/* 113 * Install the interface, most of structure initialization done in ef_clone() 114 */ 115static int 116ef_attach(struct efnet *sc) 117{ 118 struct ifnet *ifp = (struct ifnet*)&sc->ef_ac.ac_if; 119 struct ifaddr *ifa1, *ifa2; 120 struct sockaddr_dl *sdl1, *sdl2; 121 122 ifp->if_output = ether_output; 123 ifp->if_start = ef_start; 124 ifp->if_watchdog = NULL; 125 ifp->if_init = ef_init; 126 ifp->if_snd.ifq_maxlen = IFQ_MAXLEN; 127 ifp->if_flags = (IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST); 128 /* 129 * Attach the interface 130 */ 131 ether_ifattach(ifp, ETHER_BPF_SUPPORTED); 132 133 ifp->if_resolvemulti = 0; 134 ifp->if_type = IFT_XETHER; 135 ifp->if_flags |= IFF_RUNNING; 136 137 ifa1 = ifnet_addrs[ifp->if_index - 1]; 138 ifa2 = ifnet_addrs[sc->ef_ifp->if_index - 1]; 139 sdl1 = (struct sockaddr_dl *)ifa1->ifa_addr; 140 sdl2 = (struct sockaddr_dl *)ifa2->ifa_addr; 141 sdl1->sdl_type = IFT_ETHER; 142 sdl1->sdl_alen = ETHER_ADDR_LEN; 143 bcopy(LLADDR(sdl2), LLADDR(sdl1), ETHER_ADDR_LEN); 144 bcopy(LLADDR(sdl2), sc->ef_ac.ac_enaddr, ETHER_ADDR_LEN); 145 146 EFDEBUG("%s%d: attached\n", ifp->if_name, ifp->if_unit); 147 return 1; 148} 149 150/* 151 * This is for _testing_only_, just removes interface from interfaces list 152 */ 153static int 154ef_detach(struct efnet *sc) 155{ 156 struct ifnet *ifp = (struct ifnet*)&sc->ef_ac.ac_if; 157 int s; 158 159 s = splimp(); 160 161 if (ifp->if_flags & IFF_UP) { 162 if_down(ifp); 163 if (ifp->if_flags & IFF_RUNNING) { 164 /* find internet addresses and delete routes */ 165 register struct ifaddr *ifa; 166 for (ifa = ifp->if_addrhead.tqh_first; ifa; 167 ifa = ifa->ifa_link.tqe_next) { 168 rtinit(ifa, (int)RTM_DELETE, 0); 169 } 170 } 171 } 172 173 TAILQ_REMOVE(&ifnet, ifp, if_link); 174 splx(s); 175 return 0; 176} 177 178static void 179ef_init(void *foo) { 180 return; 181} 182 183static int 184ef_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 185{ 186/* struct ef_link *sc = (struct ef_link*)ifp->if_softc;*/ 187 struct ifaddr *ifa = (struct ifaddr*)data; 188 int s, error; 189 190 EFDEBUG("IOCTL %ld for %s%d\n", cmd, ifp->if_name, ifp->if_unit); 191 error = 0; 192 s = splimp(); 193 switch (cmd) { 194 case SIOCSIFADDR: 195 if (ifp->if_unit == ETHER_FT_8023 && 196 ifa->ifa_addr->sa_family != AF_IPX) { 197 error = EAFNOSUPPORT; 198 break; 199 } 200 ifp->if_flags |= IFF_UP; 201 /* FALL THROUGH */ 202 case SIOCGIFADDR: 203 case SIOCSIFMTU: 204 error = ether_ioctl(ifp, cmd, data); 205 break; 206 case SIOCSIFFLAGS: 207 error = 0; 208 break; 209 default: 210 error = EINVAL; 211 } 212 splx(s); 213 return error; 214} 215 216/* 217 * Currently packet prepared in the ether_output(), but this can be a better 218 * place. 219 */ 220static void 221ef_start(struct ifnet *ifp) 222{ 223 struct efnet *sc = (struct efnet*)ifp->if_softc; 224 struct ifnet *p; 225 struct mbuf *m; 226 227 ifp->if_flags |= IFF_OACTIVE; 228 p = sc->ef_ifp; 229 230 EFDEBUG("\n"); 231 for (;;) { 232 IF_DEQUEUE(&ifp->if_snd, m); 233 if (m == 0) 234 break; 235 if (ifp->if_bpf) 236 bpf_mtap(ifp, m); 237 if (! IF_HANDOFF(&p->if_snd, m, NULL)) { 238 ifp->if_oerrors++; 239 continue; 240 } 241 ifp->if_opackets++; 242 } 243 ifp->if_flags &= ~IFF_OACTIVE; 244 return; 245} 246 247/* 248 * Inline functions do not put additional overhead to procedure call or 249 * parameter passing but simplify the code 250 */ 251static int __inline 252ef_inputEII(struct mbuf *m, struct ether_header *eh, struct llc* l, 253 u_short ether_type, struct ifqueue **inq) 254{ 255 switch(ether_type) { 256#ifdef IPX 257 case ETHERTYPE_IPX: 258 schednetisr(NETISR_IPX); 259 *inq = &ipxintrq; 260 break; 261#endif 262#ifdef INET 263 case ETHERTYPE_IP: 264 if (ipflow_fastforward(m)) 265 return 1; 266 schednetisr(NETISR_IP); 267 *inq = &ipintrq; 268 break; 269 270 case ETHERTYPE_ARP: 271 schednetisr(NETISR_ARP); 272 *inq = &arpintrq; 273 break; 274#endif 275 default: 276 return EPROTONOSUPPORT; 277 } 278 return 0; 279} 280 281static int __inline 282ef_inputSNAP(struct mbuf *m, struct ether_header *eh, struct llc* l, 283 u_short ether_type, struct ifqueue **inq) 284{ 285 switch(ether_type) { 286#ifdef IPX 287 case ETHERTYPE_IPX: 288 m_adj(m, 8); 289 schednetisr(NETISR_IPX); 290 *inq = &ipxintrq; 291 break; 292#endif 293 default: 294 return EPROTONOSUPPORT; 295 } 296 return 0; 297} 298 299static int __inline 300ef_input8022(struct mbuf *m, struct ether_header *eh, struct llc* l, 301 u_short ether_type, struct ifqueue **inq) 302{ 303 switch(ether_type) { 304#ifdef IPX 305 case 0xe0: 306 m_adj(m, 3); 307 schednetisr(NETISR_IPX); 308 *inq = &ipxintrq; 309 break; 310#endif 311 default: 312 return EPROTONOSUPPORT; 313 } 314 return 0; 315} 316/* 317 * Called from ether_input() 318 */ 319static int 320ef_input(struct ifnet *ifp, struct ether_header *eh, struct mbuf *m) 321{ 322 u_short ether_type; 323 int s, ft = -1; 324 struct ifqueue *inq; 325 struct efnet *efp; 326 struct ifnet *eifp; 327 struct llc *l; 328 struct ef_link *efl; 329 330 ether_type = ntohs(eh->ether_type); 331 if (ether_type < ETHERMTU) { 332 l = mtod(m, struct llc*); 333 if (l->llc_dsap == 0xff && l->llc_ssap == 0xff) { 334 /* 335 * Novell's "802.3" frame 336 */ 337 ft = ETHER_FT_8023; 338 } else if (l->llc_dsap == 0xaa && l->llc_ssap == 0xaa) { 339 /* 340 * 802.2/SNAP 341 */ 342 ft = ETHER_FT_SNAP; 343 ether_type = ntohs(l->llc_un.type_snap.ether_type); 344 } else if (l->llc_dsap == l->llc_ssap) { 345 /* 346 * 802.3/802.2 347 */ 348 ft = ETHER_FT_8022; 349 ether_type = l->llc_ssap; 350 } 351 } else 352 ft = ETHER_FT_EII; 353 354 if (ft == -1) { 355 EFDEBUG("Unrecognised ether_type %x\n", ether_type); 356 return EPROTONOSUPPORT; 357 } 358 359 /* 360 * Check if interface configured for the given frame 361 */ 362 efp = NULL; 363 SLIST_FOREACH(efl, &efdev, el_next) { 364 if (efl->el_ifp == ifp) { 365 efp = efl->el_units[ft]; 366 break; 367 } 368 } 369 if (efp == NULL) { 370 EFDEBUG("Can't find if for %d\n", ft); 371 return EPROTONOSUPPORT; 372 } 373 eifp = &efp->ef_ac.ac_if; 374 if ((eifp->if_flags & IFF_UP) == 0) 375 return EPROTONOSUPPORT; 376 eifp->if_ibytes += m->m_pkthdr.len + sizeof (*eh); 377 m->m_pkthdr.rcvif = eifp; 378 379 if (eifp->if_bpf) { 380 struct mbuf m0; 381 m0.m_next = m; 382 m0.m_len = sizeof(struct ether_header); 383 m0.m_data = (char *)eh; 384 bpf_mtap(eifp, &m0); 385 } 386 /* 387 * Now we ready to adjust mbufs and pass them to protocol intr's 388 */ 389 inq = NULL; 390 switch(ft) { 391 case ETHER_FT_EII: 392 if (ef_inputEII(m, eh, l, ether_type, &inq) != 0) 393 return EPROTONOSUPPORT; 394 break; 395#ifdef IPX 396 case ETHER_FT_8023: /* only IPX can be here */ 397 schednetisr(NETISR_IPX); 398 inq = &ipxintrq; 399 break; 400#endif 401 case ETHER_FT_SNAP: 402 if (ef_inputSNAP(m, eh, l, ether_type, &inq) != 0) 403 return EPROTONOSUPPORT; 404 break; 405 case ETHER_FT_8022: 406 if (ef_input8022(m, eh, l, ether_type, &inq) != 0) 407 return EPROTONOSUPPORT; 408 break; 409 } 410 411 if (inq == NULL) { 412 EFDEBUG("No support for frame %d and proto %04x\n", 413 ft, ether_type); 414 return EPROTONOSUPPORT; 415 } 416 (void) IF_HANDOFF(inq, m, NULL); 417 return 0; 418} 419 420static int 421ef_output(struct ifnet *ifp, struct mbuf **mp, struct sockaddr *dst, short *tp, 422 int *hlen) 423{ 424 struct mbuf *m = *mp; 425 u_char *cp; 426 short type; 427 428 if (ifp->if_type != IFT_XETHER) 429 return ENETDOWN; 430 switch (ifp->if_unit) { 431 case ETHER_FT_EII: 432#ifdef IPX 433 type = htons(ETHERTYPE_IPX); 434#else 435 return EPFNOSUPPORT; 436#endif 437 break; 438 case ETHER_FT_8023: 439 type = htons(m->m_pkthdr.len); 440 break; 441 case ETHER_FT_8022: 442 M_PREPEND(m, ETHER_HDR_LEN + 3, M_WAIT); 443 if (m == NULL) { 444 *mp = NULL; 445 return ENOBUFS; 446 } 447 /* 448 * Ensure that ethernet header and next three bytes 449 * will fit into single mbuf 450 */ 451 m = m_pullup(m, ETHER_HDR_LEN + 3); 452 if (m == NULL) { 453 *mp = NULL; 454 return ENOBUFS; 455 } 456 m_adj(m, ETHER_HDR_LEN); 457 type = htons(m->m_pkthdr.len); 458 cp = mtod(m, u_char *); 459 *cp++ = 0xE0; 460 *cp++ = 0xE0; 461 *cp++ = 0x03; 462 *hlen += 3; 463 break; 464 case ETHER_FT_SNAP: 465 M_PREPEND(m, 8, M_WAIT); 466 if (m == NULL) { 467 *mp = NULL; 468 return ENOBUFS; 469 } 470 type = htons(m->m_pkthdr.len); 471 cp = mtod(m, u_char *); 472 bcopy("\xAA\xAA\x03\x00\x00\x00\x81\x37", cp, 8); 473 *hlen += 8; 474 break; 475 default: 476 return EPFNOSUPPORT; 477 } 478 *mp = m; 479 *tp = type; 480 return 0; 481} 482 483/* 484 * Create clone from the given interface 485 */ 486static int 487ef_clone(struct ef_link *efl, int ft) 488{ 489 struct efnet *efp; 490 struct ifnet *eifp; 491 struct ifnet *ifp = efl->el_ifp; 492 char cbuf[IFNAMSIZ], *ifname; 493 int ifnlen; 494 495 efp = (struct efnet*)malloc(sizeof(struct efnet), M_IFADDR, 496 M_WAITOK | M_ZERO); 497 if (efp == NULL) 498 return ENOMEM; 499 efp->ef_ifp = ifp; 500 eifp = &efp->ef_ac.ac_if; 501 ifnlen = 1 + snprintf(cbuf, sizeof(cbuf), "%s%df", ifp->if_name, 502 ifp->if_unit); 503 ifname = (char*)malloc(ifnlen, M_IFADDR, M_WAITOK); 504 eifp->if_name = strcpy(ifname, cbuf); 505 eifp->if_unit = ft; 506 eifp->if_softc = efp; 507 if (ifp->if_ioctl) 508 eifp->if_ioctl = ef_ioctl; 509 efl->el_units[ft] = efp; 510 return 0; 511} 512 513static int 514ef_load(void) 515{ 516 struct ifnet *ifp; 517 struct efnet *efp; 518 struct ef_link *efl = NULL; 519 int error = 0, d; 520 521 for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_link.tqe_next) { 522 if (ifp->if_type != IFT_ETHER) continue; 523 EFDEBUG("Found interface %s%d\n", ifp->if_name, ifp->if_unit); 524 efl = (struct ef_link*)malloc(sizeof(struct ef_link), 525 M_IFADDR, M_WAITOK); 526 if (efl == NULL) { 527 error = ENOMEM; 528 break; 529 } 530 bzero(efl, sizeof(*efl)); 531 532 efl->el_ifp = ifp; 533#ifdef ETHER_II 534 error = ef_clone(efl, ETHER_FT_EII); 535 if (error) break; 536#endif 537#ifdef ETHER_8023 538 error = ef_clone(efl, ETHER_FT_8023); 539 if (error) break; 540#endif 541#ifdef ETHER_8022 542 error = ef_clone(efl, ETHER_FT_8022); 543 if (error) break; 544#endif 545#ifdef ETHER_SNAP 546 error = ef_clone(efl, ETHER_FT_SNAP); 547 if (error) break; 548#endif 549 efcount++; 550 SLIST_INSERT_HEAD(&efdev, efl, el_next); 551 } 552 if (error) { 553 if (efl) 554 SLIST_INSERT_HEAD(&efdev, efl, el_next); 555 SLIST_FOREACH(efl, &efdev, el_next) { 556 for (d = 0; d < EF_NFT; d++) 557 if (efl->el_units[d]) 558 free(efl->el_units[d], M_IFADDR); 559 free(efl, M_IFADDR); 560 } 561 return error; 562 } 563 SLIST_FOREACH(efl, &efdev, el_next) { 564 for (d = 0; d < EF_NFT; d++) { 565 efp = efl->el_units[d]; 566 if (efp) 567 ef_attach(efp); 568 } 569 } 570 ef_inputp = ef_input; 571 ef_outputp = ef_output; 572 EFDEBUG("Loaded\n"); 573 return 0; 574} 575 576static int 577ef_unload(void) 578{ 579 struct efnet *efp; 580 struct ef_link *efl; 581 int d; 582 583 ef_inputp = NULL; 584 ef_outputp = NULL; 585 SLIST_FOREACH(efl, &efdev, el_next) { 586 for (d = 0; d < EF_NFT; d++) { 587 efp = efl->el_units[d]; 588 if (efp) { 589 ef_detach(efp); 590 } 591 } 592 } 593 EFDEBUG("Unloaded\n"); 594 return 0; 595} 596 597static int 598if_ef_modevent(module_t mod, int type, void *data) 599{ 600 switch ((modeventtype_t)type) { 601 case MOD_LOAD: 602 return ef_load(); 603 case MOD_UNLOAD: 604 return ef_unload(); 605 default: 606 break; 607 } 608 return 0; 609} 610 611static moduledata_t if_ef_mod = { 612 "if_ef", if_ef_modevent, NULL 613}; 614 615DECLARE_MODULE(if_ef, if_ef_mod, SI_SUB_PSEUDO, SI_ORDER_MIDDLE); 616