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