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 BPF_MTAP(ifp, m); 329 330 /* Copy length before the mbuf gets invalidated */ 331 len = m->m_pkthdr.len; 332 333 /* 334 * Send packet; if hook is not connected, mbuf will get 335 * freed. 336 */ 337 NG_SEND_DATA_ONLY(error, priv->ether, m); 338 339 /* Update stats */ 340 if (error == 0) { 341 ifp->if_obytes += len; 342 ifp->if_opackets++; 343 } 344 ifp->if_flags &= ~IFF_OACTIVE; 345 return; 346 } 347 348 /* 349 * This routine is called to deliver a packet out the interface. 350 * We simply queue the netgraph version to be called when netgraph locking 351 * allows it to happen. 352 * Until we know what the rest of the networking code is doing for 353 * locking, we don't know how we will interact with it. 354 * Take comfort from the fact that the ifnet struct is part of our 355 * private info and can't go away while we are queued. 356 * [Though we don't know it is still there now....] 357 * it is possible we don't gain anything from this because 358 * we would like to get the mbuf and queue it as data 359 * somehow, but we can't and if we did would we solve anything? 360 */ 361 static void 362 ng_eiface_start(struct ifnet *ifp) 363 { 364 365 const priv_p priv = (priv_p) ifp->if_softc; 366 367 ng_send_fn(priv->node, NULL, &ng_eiface_start2, ifp, 0); 368 } 369 370 #ifdef DEBUG 371 /* 372 * Display an ioctl to the virtual interface 373 */ 374 375 static void 376 ng_eiface_print_ioctl(struct ifnet *ifp, int command, caddr_t data){ 377 char *str; 378 379 switch (command & IOC_DIRMASK) 380 { 381 case IOC_VOID: 382 str = "IO"; 383 break; 384 case IOC_OUT: 385 str = "IOR"; 386 break; 387 case IOC_IN: 388 str = "IOW"; 389 break; 390 case IOC_INOUT: 391 str = "IORW"; 392 break; 393 default: 394 str = "IO??"; 395 } 396 log(LOG_DEBUG, "%s%d: %s('%c', %d, char[%d])\n", 397 ifp->if_name, ifp->if_unit, 398 str, 399 IOCGROUP(command), 400 command & 0xff, 401 IOCPARM_LEN(command)); 402 } 403 #endif /* DEBUG */ 404 405 /************************************************************************ 406 NETGRAPH NODE STUFF 407 ************************************************************************/ 408 409 /* 410 * Constructor for a node 411 */ 412 static int 413 ng_eiface_constructor(node_p node) 414 { 415 struct ifnet *ifp; 416 priv_p priv; 417 int error = 0; 418 419 /* Allocate node and interface private structures */ 420 MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH, 0); 421 if (priv == NULL) { 422 return (ENOMEM); 423 } 424 bzero(priv, sizeof(*priv)); 425 426 ifp = &(priv->arpcom.ac_if); 427 428 /* Link them together */ 429 ifp->if_softc = priv; 430 priv->ifp = ifp; 431 432 /* Get an interface unit number */ 433 if ((error = ng_eiface_get_unit(&priv->unit)) != 0) { 434 FREE(priv, M_NETGRAPH); 435 return (error); 436 } 437 438 /* Link together node and private info */ 439 NG_NODE_SET_PRIVATE(node, priv); 440 priv->node = node; 441 442 /* Initialize interface structure */ 443 ifp->if_name = ng_eiface_ifname; 444 ifp->if_unit = priv->unit; 445 ifp->if_init = ng_eiface_init; 446 ifp->if_output = ether_output; 447 ifp->if_start = ng_eiface_start; 448 ifp->if_ioctl = ng_eiface_ioctl; 449 ifp->if_watchdog = NULL; 450 ifp->if_snd.ifq_maxlen = IFQ_MAXLEN; 451 ifp->if_flags = (IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST); 452 453 /* 454 * Give this node name * bzero(ifname, sizeof(ifname)); 455 * sprintf(ifname, "if%s%d", ifp->if_name, ifp->if_unit); (void) 456 * ng_name_node(node, ifname); 457 */ 458 459 /* Attach the interface */ 460 ether_ifattach(ifp, priv->arpcom.ac_enaddr); 461 462 /* Done */ 463 return (0); 464 } 465 466 /* 467 * Give our ok for a hook to be added 468 */ 469 static int 470 ng_eiface_newhook(node_p node, hook_p hook, const char *name) 471 { 472 priv_p priv = NG_NODE_PRIVATE(node); 473 474 if (strcmp(name, NG_EIFACE_HOOK_ETHER)) 475 return (EPFNOSUPPORT); 476 if (priv->ether != NULL) 477 return (EISCONN); 478 priv->ether = hook; 479 NG_HOOK_SET_PRIVATE(hook, &priv->ether); 480 481 return (0); 482 } 483 484 /* 485 * Receive a control message 486 */ 487 static int 488 ng_eiface_rcvmsg(node_p node, item_p item, hook_p lasthook) 489 { 490 priv_p priv = NG_NODE_PRIVATE(node); 491 struct ifnet *const ifp = priv->ifp; 492 struct ng_mesg *resp = NULL; 493 int error = 0; 494 struct ng_mesg *msg; 495 496 NGI_GET_MSG(item, msg); 497 switch (msg->header.typecookie) { 498 case NGM_EIFACE_COOKIE: 499 switch (msg->header.cmd) { 500 case NGM_EIFACE_SET: 501 { 502 struct ng_eiface_par *eaddr; 503 struct ifaddr *ifa; 504 struct sockaddr_dl *sdl; 505 506 if (msg->header.arglen != sizeof(struct ng_eiface_par)){ 507 error = EINVAL; 508 break; 509 } 510 eaddr = (struct ng_eiface_par *)(msg->data); 511 512 priv->arpcom.ac_enaddr[0] = eaddr->oct0; 513 priv->arpcom.ac_enaddr[1] = eaddr->oct1; 514 priv->arpcom.ac_enaddr[2] = eaddr->oct2; 515 priv->arpcom.ac_enaddr[3] = eaddr->oct3; 516 priv->arpcom.ac_enaddr[4] = eaddr->oct4; 517 priv->arpcom.ac_enaddr[5] = eaddr->oct5; 518 519 /* And put it in the ifaddr list */ 520 #define IFP2AC(IFP) ((struct arpcom *)IFP) 521 TAILQ_FOREACH(ifa, &(ifp->if_addrhead), ifa_link) { 522 sdl = (struct sockaddr_dl *)ifa->ifa_addr; 523 if (sdl->sdl_type == IFT_ETHER) { 524 bcopy((IFP2AC(ifp))->ac_enaddr, 525 LLADDR(sdl), ifp->if_addrlen); 526 break; 527 } 528 } 529 break; 530 } 531 532 case NGM_EIFACE_GET_IFNAME: 533 { 534 struct ng_eiface_ifname *arg; 535 536 NG_MKRESPONSE(resp, msg, sizeof(*arg), M_NOWAIT); 537 if (resp == NULL) { 538 error = ENOMEM; 539 break; 540 } 541 arg = (struct ng_eiface_ifname *)resp->data; 542 sprintf(arg->ngif_name, 543 "%s%d", ifp->if_name, ifp->if_unit); 544 break; 545 } 546 547 case NGM_EIFACE_GET_IFADDRS: 548 { 549 struct ifaddr *ifa; 550 caddr_t ptr; 551 int buflen; 552 553 #define SA_SIZE(s) ((s)->sa_len<sizeof(*(s))? sizeof(*(s)):(s)->sa_len) 554 555 /* Determine size of response and allocate it */ 556 buflen = 0; 557 TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) 558 buflen += SA_SIZE(ifa->ifa_addr); 559 NG_MKRESPONSE(resp, msg, buflen, M_NOWAIT); 560 if (resp == NULL) { 561 error = ENOMEM; 562 break; 563 } 564 /* Add addresses */ 565 ptr = resp->data; 566 TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 567 const int len = SA_SIZE(ifa->ifa_addr); 568 569 if (buflen < len) { 570 log(LOG_ERR, "%s%d: len changed?\n", 571 ifp->if_name, ifp->if_unit); 572 break; 573 } 574 bcopy(ifa->ifa_addr, ptr, len); 575 ptr += len; 576 buflen -= len; 577 } 578 break; 579 #undef SA_SIZE 580 } 581 582 default: 583 error = EINVAL; 584 break; 585 } /* end of inner switch() */ 586 break; 587 default: 588 error = EINVAL; 589 break; 590 } 591 NG_RESPOND_MSG(error, node, item, resp); 592 NG_FREE_MSG(msg); 593 return (error); 594 } 595 596 /* 597 * Recive data from a hook. Pass the packet to the ether_input routine. 598 */ 599 static int 600 ng_eiface_rcvdata(hook_p hook, item_p item) 601 { 602 priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 603 struct ifnet *const ifp = priv->ifp; 604 struct mbuf *m; 605 606 NGI_GET_M(item, m); 607 /* Meta-data ends its life here... */ 608 NG_FREE_ITEM(item); 609 610 if (m == NULL) 611 { 612 printf("ng_eiface: mbuf is null.\n"); 613 return (EINVAL); 614 } 615 if (!(ifp->if_flags & IFF_UP)) { 616 return (ENETDOWN); 617 } 618 619 /* Note receiving interface */ 620 m->m_pkthdr.rcvif = ifp; 621 622 /* Update interface stats */ 623 ifp->if_ipackets++; 624 625 (*ifp->if_input)(ifp, m); 626 627 /* Done */ 628 return (0); 629 } 630 631 /* 632 * the node. 633 */ 634 static int 635 ng_eiface_rmnode(node_p node) 636 { 637 priv_p priv = NG_NODE_PRIVATE(node); 638 struct ifnet *const ifp = priv->ifp; 639 640 ether_ifdetach(ifp); 641 ng_eiface_free_unit(priv->unit); 642 FREE(priv, M_NETGRAPH); 643 NG_NODE_SET_PRIVATE(node, NULL); 644 NG_NODE_UNREF(node); 645 return (0); 646 } 647 648 649 /* 650 * This is called once we've already connected a new hook to the other node. 651 * It gives us a chance to balk at the last minute. 652 */ 653 static int 654 ng_eiface_connect(hook_p hook) 655 { 656 /* be really amiable and just say "YUP that's OK by me! " */ 657 return (0); 658 } 659 660 /* 661 * Hook disconnection 662 */ 663 static int 664 ng_eiface_disconnect(hook_p hook) 665 { 666 priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 667 668 priv->ether = NULL; 669 return (0); 670 } 671