1 /*- 2 * 3 * Copyright (c) 1999-2001, Vitaly V Belekhov 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice unmodified, this list of conditions, and the following 11 * disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 * $FreeBSD$ 29 */ 30 31 32 #include <sys/param.h> 33 #include <sys/systm.h> 34 #include <sys/errno.h> 35 #include <sys/kernel.h> 36 #include <sys/malloc.h> 37 #include <sys/mbuf.h> 38 #include <sys/errno.h> 39 #include <sys/sockio.h> 40 #include <sys/socket.h> 41 #include <sys/syslog.h> 42 43 #include <net/if.h> 44 #include <net/if_dl.h> 45 #include <net/if_types.h> 46 #include <net/netisr.h> 47 48 #include <netinet/in.h> 49 #include <netinet/if_ether.h> 50 51 #include <netgraph/ng_message.h> 52 #include <netgraph/netgraph.h> 53 #include <netgraph/ng_parse.h> 54 #include <netgraph/ng_eiface.h> 55 56 #include <net/bpf.h> 57 #include <net/ethernet.h> 58 #include <net/if_arp.h> 59 60 static const struct ng_parse_struct_field ng_eiface_par_fields[] 61 = NG_EIFACE_PAR_FIELDS; 62 63 static const struct ng_parse_type ng_eiface_par_type = { 64 &ng_parse_struct_type, 65 &ng_eiface_par_fields 66 }; 67 68 static const struct ng_cmdlist ng_eiface_cmdlist[] = { 69 { 70 NGM_EIFACE_COOKIE, 71 NGM_EIFACE_SET, 72 "set", 73 &ng_eiface_par_type, 74 NULL 75 }, 76 { 0 } 77 }; 78 79 80 /* Node private data */ 81 struct ng_eiface_private { 82 struct ifnet *ifp; /* This interface */ 83 int unit; /* Interface unit number */ 84 struct arpcom arpcom; /* per-interface network data */ 85 node_p node; /* Our netgraph node */ 86 hook_p ether; /* Hook for ethernet stream */ 87 }; 88 typedef struct ng_eiface_private *priv_p; 89 90 /* Interface methods */ 91 static void ng_eiface_init(void *xsc); 92 static void ng_eiface_start(struct ifnet *ifp); 93 static int ng_eiface_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data); 94 #ifdef DEBUG 95 static void ng_eiface_print_ioctl(struct ifnet *ifp, int cmd, caddr_t data); 96 #endif 97 98 /* Netgraph methods */ 99 static ng_constructor_t ng_eiface_constructor; 100 static ng_rcvmsg_t ng_eiface_rcvmsg; 101 static ng_shutdown_t ng_eiface_rmnode; 102 static ng_newhook_t ng_eiface_newhook; 103 static ng_rcvdata_t ng_eiface_rcvdata; 104 static ng_connect_t ng_eiface_connect; 105 static ng_disconnect_t ng_eiface_disconnect; 106 107 /* Node type descriptor */ 108 static struct ng_type typestruct = { 109 NG_ABI_VERSION, 110 NG_EIFACE_NODE_TYPE, 111 NULL, 112 ng_eiface_constructor, 113 ng_eiface_rcvmsg, 114 ng_eiface_rmnode, 115 ng_eiface_newhook, 116 NULL, 117 ng_eiface_connect, 118 ng_eiface_rcvdata, 119 ng_eiface_disconnect, 120 ng_eiface_cmdlist 121 }; 122 NETGRAPH_INIT(eiface, &typestruct); 123 124 static char ng_eiface_ifname[] = NG_EIFACE_EIFACE_NAME; 125 126 /* We keep a bitmap indicating which unit numbers are free. 127 One means the unit number is free, zero means it's taken. */ 128 static int *ng_eiface_units = NULL; 129 static int ng_eiface_units_len = 0; 130 static int ng_units_in_use = 0; 131 132 #define UNITS_BITSPERWORD (sizeof(*ng_eiface_units) * NBBY) 133 134 135 /************************************************************************ 136 HELPER STUFF 137 ************************************************************************/ 138 /* 139 * Find the first free unit number for a new interface. 140 * Increase the size of the unit bitmap as necessary. 141 */ 142 static __inline__ int 143 ng_eiface_get_unit(int *unit) 144 { 145 int index, bit; 146 147 for (index = 0; index < ng_eiface_units_len 148 && ng_eiface_units[index] == 0; index++); 149 if (index == ng_eiface_units_len) { /* extend array */ 150 int i, *newarray, newlen; 151 152 newlen = (2 * ng_eiface_units_len) + 4; 153 MALLOC(newarray, int *, newlen * sizeof(*ng_eiface_units), 154 M_NETGRAPH, M_NOWAIT); 155 if (newarray == NULL) 156 return (ENOMEM); 157 bcopy(ng_eiface_units, newarray, 158 ng_eiface_units_len * sizeof(*ng_eiface_units)); 159 for (i = ng_eiface_units_len; i < newlen; i++) 160 newarray[i] = ~0; 161 if (ng_eiface_units != NULL) 162 FREE(ng_eiface_units, M_NETGRAPH); 163 ng_eiface_units = newarray; 164 ng_eiface_units_len = newlen; 165 } 166 bit = ffs(ng_eiface_units[index]) - 1; 167 KASSERT(bit >= 0 && bit <= UNITS_BITSPERWORD - 1, 168 ("%s: word=%d bit=%d", __func__, ng_eiface_units[index], bit)); 169 ng_eiface_units[index] &= ~(1 << bit); 170 *unit = (index * UNITS_BITSPERWORD) + bit; 171 ng_units_in_use++; 172 return (0); 173 } 174 175 /* 176 * Free a no longer needed unit number. 177 */ 178 static __inline__ void 179 ng_eiface_free_unit(int unit) 180 { 181 int index, bit; 182 183 index = unit / UNITS_BITSPERWORD; 184 bit = unit % UNITS_BITSPERWORD; 185 KASSERT(index < ng_eiface_units_len, 186 ("%s: unit=%d len=%d", __func__, unit, ng_eiface_units_len)); 187 KASSERT((ng_eiface_units[index] & (1 << bit)) == 0, 188 ("%s: unit=%d is free", __func__, unit)); 189 ng_eiface_units[index] |= (1 << bit); 190 /* 191 * XXX We could think about reducing the size of ng_eiface_units[] 192 * XXX here if the last portion is all ones 193 * XXX At least free it if no more units. 194 * Needed if we are to eventually be able to unload. 195 */ 196 ng_units_in_use--; 197 if (ng_units_in_use == 0) { /* XXX make SMP safe */ 198 FREE(ng_eiface_units, M_NETGRAPH); 199 ng_eiface_units_len = 0; 200 ng_eiface_units = NULL; 201 } 202 } 203 204 /************************************************************************ 205 INTERFACE STUFF 206 ************************************************************************/ 207 208 /* 209 * Process an ioctl for the virtual interface 210 */ 211 static int 212 ng_eiface_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 213 { 214 struct ifreq *const ifr = (struct ifreq *)data; 215 int s, error = 0; 216 217 #ifdef DEBUG 218 ng_eiface_print_ioctl(ifp, command, data); 219 #endif 220 s = splimp(); 221 switch (command) 222 { 223 /* These two are mostly handled at a higher layer */ 224 case SIOCSIFADDR: 225 error = ether_ioctl(ifp, command, data); 226 break; 227 case SIOCGIFADDR: 228 break; 229 230 /* Set flags */ 231 case SIOCSIFFLAGS: 232 /* 233 * If the interface is marked up and stopped, then 234 * start it. If it is marked down and running, 235 * then stop it. 236 */ 237 if (ifr->ifr_flags & IFF_UP) { 238 if (!(ifp->if_flags & IFF_RUNNING)) { 239 ifp->if_flags &= ~(IFF_OACTIVE); 240 ifp->if_flags |= IFF_RUNNING; 241 } 242 } else { 243 if (ifp->if_flags & IFF_RUNNING) 244 ifp->if_flags 245 &= ~(IFF_RUNNING | IFF_OACTIVE); 246 } 247 break; 248 249 /* Set the interface MTU */ 250 case SIOCSIFMTU: 251 if (ifr->ifr_mtu > NG_EIFACE_MTU_MAX 252 || ifr->ifr_mtu < NG_EIFACE_MTU_MIN) 253 error = EINVAL; 254 else 255 ifp->if_mtu = ifr->ifr_mtu; 256 break; 257 258 /* Stuff that's not supported */ 259 case SIOCADDMULTI: 260 case SIOCDELMULTI: 261 error = 0; 262 break; 263 case SIOCSIFPHYS: 264 error = EOPNOTSUPP; 265 break; 266 267 default: 268 error = EINVAL; 269 break; 270 } 271 (void)splx(s); 272 return (error); 273 } 274 275 static void 276 ng_eiface_init(void *xsc) 277 { 278 priv_p sc = xsc; 279 struct ifnet *ifp = sc->ifp; 280 int s; 281 282 s = splimp(); 283 284 ifp->if_flags |= IFF_RUNNING; 285 ifp->if_flags &= ~IFF_OACTIVE; 286 287 splx(s); 288 } 289 290 /* 291 * We simply relay the packet to the ether hook, if it is connected. 292 * We have been throughthe netgraph locking an are guaranteed to 293 * be the only code running in this node at this time. 294 */ 295 static void 296 ng_eiface_start2(node_p node, hook_p hook, void *arg1, int arg2) 297 { 298 struct ifnet *ifp = arg1; 299 const priv_p priv = (priv_p) ifp->if_softc; 300 int len, error = 0; 301 struct mbuf *m; 302 303 /* Check interface flags */ 304 if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) != (IFF_UP | IFF_RUNNING)) 305 return; 306 307 /* Don't do anything if output is active */ 308 if (ifp->if_flags & IFF_OACTIVE) 309 return; 310 311 ifp->if_flags |= IFF_OACTIVE; 312 313 /* 314 * Grab a packet to transmit. 315 */ 316 IF_DEQUEUE(&ifp->if_snd, m); 317 318 /* If there's nothing to send, return. */ 319 if (m == NULL) { 320 ifp->if_flags &= ~IFF_OACTIVE; 321 return; 322 } 323 324 /* Berkeley packet filter 325 * Pass packet to bpf if there is a listener. 326 * XXX is this safe? locking? 327 */ 328 if (ifp->if_bpf) 329 bpf_mtap(ifp, m); 330 331 /* Copy length before the mbuf gets invalidated */ 332 len = m->m_pkthdr.len; 333 334 /* 335 * Send packet; if hook is not connected, mbuf will get 336 * freed. 337 */ 338 NG_SEND_DATA_ONLY(error, priv->ether, m); 339 340 /* Update stats */ 341 if (error == 0) { 342 ifp->if_obytes += len; 343 ifp->if_opackets++; 344 } 345 ifp->if_flags &= ~IFF_OACTIVE; 346 return; 347 } 348 349 /* 350 * This routine is called to deliver a packet out the interface. 351 * We simply queue the netgraph version to be called when netgraph locking 352 * allows it to happen. 353 * Until we know what the rest of the networking code is doing for 354 * locking, we don't know how we will interact with it. 355 * Take comfort from the fact that the ifnet struct is part of our 356 * private info and can't go away while we are queued. 357 * [Though we don't know it is still there now....] 358 * it is possible we don't gain anything from this because 359 * we would like to get the mbuf and queue it as data 360 * somehow, but we can't and if we did would we solve anything? 361 */ 362 static void 363 ng_eiface_start(struct ifnet *ifp) 364 { 365 366 const priv_p priv = (priv_p) ifp->if_softc; 367 368 ng_send_fn(priv->node, NULL, &ng_eiface_start2, ifp, 0); 369 } 370 371 #ifdef DEBUG 372 /* 373 * Display an ioctl to the virtual interface 374 */ 375 376 static void 377 ng_eiface_print_ioctl(struct ifnet *ifp, int command, caddr_t data){ 378 char *str; 379 380 switch (command & IOC_DIRMASK) 381 { 382 case IOC_VOID: 383 str = "IO"; 384 break; 385 case IOC_OUT: 386 str = "IOR"; 387 break; 388 case IOC_IN: 389 str = "IOW"; 390 break; 391 case IOC_INOUT: 392 str = "IORW"; 393 break; 394 default: 395 str = "IO??"; 396 } 397 log(LOG_DEBUG, "%s%d: %s('%c', %d, char[%d])\n", 398 ifp->if_name, ifp->if_unit, 399 str, 400 IOCGROUP(command), 401 command & 0xff, 402 IOCPARM_LEN(command)); 403 } 404 #endif /* DEBUG */ 405 406 /************************************************************************ 407 NETGRAPH NODE STUFF 408 ************************************************************************/ 409 410 /* 411 * Constructor for a node 412 */ 413 static int 414 ng_eiface_constructor(node_p node) 415 { 416 struct ifnet *ifp; 417 priv_p priv; 418 int error = 0; 419 420 /* Allocate node and interface private structures */ 421 MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH, M_WAITOK); 422 if (priv == NULL) { 423 return (ENOMEM); 424 } 425 bzero(priv, sizeof(*priv)); 426 427 ifp = &(priv->arpcom.ac_if); 428 429 /* Link them together */ 430 ifp->if_softc = priv; 431 priv->ifp = ifp; 432 433 /* Get an interface unit number */ 434 if ((error = ng_eiface_get_unit(&priv->unit)) != 0) { 435 FREE(priv, M_NETGRAPH); 436 return (error); 437 } 438 439 /* Link together node and private info */ 440 NG_NODE_SET_PRIVATE(node, priv); 441 priv->node = node; 442 443 /* Initialize interface structure */ 444 ifp->if_name = ng_eiface_ifname; 445 ifp->if_unit = priv->unit; 446 ifp->if_init = ng_eiface_init; 447 ifp->if_output = ether_output; 448 ifp->if_start = ng_eiface_start; 449 ifp->if_ioctl = ng_eiface_ioctl; 450 ifp->if_watchdog = NULL; 451 ifp->if_snd.ifq_maxlen = IFQ_MAXLEN; 452 ifp->if_flags = (IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST); 453 454 /* 455 * Give this node name * bzero(ifname, sizeof(ifname)); 456 * sprintf(ifname, "if%s%d", ifp->if_name, ifp->if_unit); (void) 457 * ng_name_node(node, ifname); 458 */ 459 460 /* Attach the interface */ 461 ether_ifattach(ifp, ETHER_BPF_SUPPORTED); 462 463 /* Done */ 464 return (0); 465 } 466 467 /* 468 * Give our ok for a hook to be added 469 */ 470 static int 471 ng_eiface_newhook(node_p node, hook_p hook, const char *name) 472 { 473 priv_p priv = NG_NODE_PRIVATE(node); 474 475 if (strcmp(name, NG_EIFACE_HOOK_ETHER)) 476 return (EPFNOSUPPORT); 477 if (priv->ether != NULL) 478 return (EISCONN); 479 priv->ether = hook; 480 NG_HOOK_SET_PRIVATE(hook, &priv->ether); 481 482 return (0); 483 } 484 485 /* 486 * Receive a control message 487 */ 488 static int 489 ng_eiface_rcvmsg(node_p node, item_p item, hook_p lasthook) 490 { 491 priv_p priv = NG_NODE_PRIVATE(node); 492 struct ifnet *const ifp = priv->ifp; 493 struct ng_mesg *resp = NULL; 494 int error = 0; 495 struct ng_mesg *msg; 496 497 NGI_GET_MSG(item, msg); 498 switch (msg->header.typecookie) { 499 case NGM_EIFACE_COOKIE: 500 switch (msg->header.cmd) { 501 case NGM_EIFACE_SET: 502 { 503 struct ng_eiface_par *eaddr; 504 struct ifaddr *ifa; 505 struct sockaddr_dl *sdl; 506 507 if (msg->header.arglen != sizeof(struct ng_eiface_par)){ 508 error = EINVAL; 509 break; 510 } 511 eaddr = (struct ng_eiface_par *)(msg->data); 512 513 priv->arpcom.ac_enaddr[0] = eaddr->oct0; 514 priv->arpcom.ac_enaddr[1] = eaddr->oct1; 515 priv->arpcom.ac_enaddr[2] = eaddr->oct2; 516 priv->arpcom.ac_enaddr[3] = eaddr->oct3; 517 priv->arpcom.ac_enaddr[4] = eaddr->oct4; 518 priv->arpcom.ac_enaddr[5] = eaddr->oct5; 519 520 /* And put it in the ifaddr list */ 521 #define IFP2AC(IFP) ((struct arpcom *)IFP) 522 TAILQ_FOREACH(ifa, &(ifp->if_addrhead), ifa_link) { 523 sdl = (struct sockaddr_dl *)ifa->ifa_addr; 524 if (sdl->sdl_type == IFT_ETHER) { 525 bcopy((IFP2AC(ifp))->ac_enaddr, 526 LLADDR(sdl), ifp->if_addrlen); 527 break; 528 } 529 } 530 break; 531 } 532 533 case NGM_EIFACE_GET_IFNAME: 534 { 535 struct ng_eiface_ifname *arg; 536 537 NG_MKRESPONSE(resp, msg, sizeof(*arg), M_NOWAIT); 538 if (resp == NULL) { 539 error = ENOMEM; 540 break; 541 } 542 arg = (struct ng_eiface_ifname *)resp->data; 543 sprintf(arg->ngif_name, 544 "%s%d", ifp->if_name, ifp->if_unit); 545 break; 546 } 547 548 case NGM_EIFACE_GET_IFADDRS: 549 { 550 struct ifaddr *ifa; 551 caddr_t ptr; 552 int buflen; 553 554 #define SA_SIZE(s) ((s)->sa_len<sizeof(*(s))? sizeof(*(s)):(s)->sa_len) 555 556 /* Determine size of response and allocate it */ 557 buflen = 0; 558 TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) 559 buflen += SA_SIZE(ifa->ifa_addr); 560 NG_MKRESPONSE(resp, msg, buflen, M_NOWAIT); 561 if (resp == NULL) { 562 error = ENOMEM; 563 break; 564 } 565 /* Add addresses */ 566 ptr = resp->data; 567 TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 568 const int len = SA_SIZE(ifa->ifa_addr); 569 570 if (buflen < len) { 571 log(LOG_ERR, "%s%d: len changed?\n", 572 ifp->if_name, ifp->if_unit); 573 break; 574 } 575 bcopy(ifa->ifa_addr, ptr, len); 576 ptr += len; 577 buflen -= len; 578 } 579 break; 580 #undef SA_SIZE 581 } 582 583 default: 584 error = EINVAL; 585 break; 586 } /* end of inner switch() */ 587 break; 588 default: 589 error = EINVAL; 590 break; 591 } 592 NG_RESPOND_MSG(error, node, item, resp); 593 NG_FREE_MSG(msg); 594 return (error); 595 } 596 597 /* 598 * Recive data from a hook. Pass the packet to the ether_input routine. 599 */ 600 static int 601 ng_eiface_rcvdata(hook_p hook, item_p item) 602 { 603 priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 604 struct ifnet *const ifp = priv->ifp; 605 int s, error = 0; 606 struct ether_header *eh; 607 u_short ether_type; 608 struct mbuf *m; 609 610 NGI_GET_M(item, m); 611 /* Meta-data ends its life here... */ 612 NG_FREE_ITEM(item); 613 614 if (m == NULL) 615 { 616 printf("ng_eiface: mbuf is null.\n"); 617 return (EINVAL); 618 } 619 if (!(ifp->if_flags & IFF_UP)) { 620 return (ENETDOWN); 621 } 622 623 /* Note receiving interface */ 624 m->m_pkthdr.rcvif = ifp; 625 626 /* Update interface stats */ 627 ifp->if_ipackets++; 628 629 eh = mtod(m, struct ether_header *); 630 ether_type = ntohs(eh->ether_type); 631 632 s = splimp(); 633 m->m_pkthdr.len -= sizeof(*eh); 634 m->m_len -= sizeof(*eh); 635 if (m->m_len) { 636 m->m_data += sizeof(*eh); 637 } else { 638 if (ether_type == ETHERTYPE_ARP) { 639 m->m_len = m->m_next->m_len; 640 m->m_data = m->m_next->m_data; 641 } 642 } 643 splx(s); 644 645 ether_input(ifp, eh, m); 646 647 /* Done */ 648 return (error); 649 } 650 651 /* 652 * the node. 653 */ 654 static int 655 ng_eiface_rmnode(node_p node) 656 { 657 priv_p priv = NG_NODE_PRIVATE(node); 658 struct ifnet *const ifp = priv->ifp; 659 660 ether_ifdetach(ifp, ETHER_BPF_SUPPORTED); 661 ng_eiface_free_unit(priv->unit); 662 FREE(priv, M_NETGRAPH); 663 NG_NODE_SET_PRIVATE(node, NULL); 664 NG_NODE_UNREF(node); 665 return (0); 666 } 667 668 669 /* 670 * This is called once we've already connected a new hook to the other node. 671 * It gives us a chance to balk at the last minute. 672 */ 673 static int 674 ng_eiface_connect(hook_p hook) 675 { 676 /* be really amiable and just say "YUP that's OK by me! " */ 677 return (0); 678 } 679 680 /* 681 * Hook disconnection 682 */ 683 static int 684 ng_eiface_disconnect(hook_p hook) 685 { 686 priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 687 688 priv->ether = NULL; 689 return (0); 690 } 691