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