1 /* 2 * ng_gif.c 3 */ 4 5 /*- 6 * Copyright 2001 The Aerospace Corporation. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions, and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions, and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. The name of The Aerospace Corporation may not be used to endorse or 18 * promote products derived from this software. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AEROSPACE CORPORATION ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AEROSPACE CORPORATION BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * 33 * Copyright (c) 1996-2000 Whistle Communications, Inc. 34 * All rights reserved. 35 * 36 * Subject to the following obligations and disclaimer of warranty, use and 37 * redistribution of this software, in source or object code forms, with or 38 * without modifications are expressly permitted by Whistle Communications; 39 * provided, however, that: 40 * 1. Any and all reproductions of the source or object code must include the 41 * copyright notice above and the following disclaimer of warranties; and 42 * 2. No rights are granted, in any manner or form, to use Whistle 43 * Communications, Inc. trademarks, including the mark "WHISTLE 44 * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 45 * such appears in the above copyright notice or in the software. 46 * 47 * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 48 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 49 * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 50 * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 51 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 52 * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 53 * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 54 * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 55 * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 56 * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 57 * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 58 * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 59 * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 60 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 61 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 62 * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 63 * OF SUCH DAMAGE. 64 * 65 * $FreeBSD$ 66 */ 67 68 /* 69 * ng_gif(4) netgraph node type 70 */ 71 #include "opt_route.h" 72 73 #include <sys/param.h> 74 #include <sys/systm.h> 75 #include <sys/kernel.h> 76 #include <sys/malloc.h> 77 #include <sys/mbuf.h> 78 #include <sys/errno.h> 79 #include <sys/syslog.h> 80 #include <sys/socket.h> 81 #include <sys/vimage.h> 82 83 #include <net/if.h> 84 #include <net/route.h> 85 #include <net/if_types.h> 86 #include <net/if_var.h> 87 #include <net/if_gif.h> 88 #include <net/vnet.h> 89 90 #include <netgraph/ng_message.h> 91 #include <netgraph/netgraph.h> 92 #include <netgraph/ng_parse.h> 93 #include <netgraph/ng_gif.h> 94 95 #define IFP2NG(ifp) ((struct ng_node *)((struct gif_softc *)(ifp->if_softc))->gif_netgraph) 96 #define IFP2NG_SET(ifp, val) (((struct gif_softc *)(ifp->if_softc))->gif_netgraph = (val)) 97 98 /* Per-node private data */ 99 struct private { 100 struct ifnet *ifp; /* associated interface */ 101 hook_p lower; /* lower OR orphan hook connection */ 102 u_char lowerOrphan; /* whether lower is lower or orphan */ 103 }; 104 typedef struct private *priv_p; 105 106 /* Functional hooks called from if_gif.c */ 107 static void ng_gif_input(struct ifnet *ifp, struct mbuf **mp, int af); 108 static void ng_gif_input_orphan(struct ifnet *ifp, struct mbuf *m, int af); 109 static void ng_gif_attach(struct ifnet *ifp); 110 static void ng_gif_detach(struct ifnet *ifp); 111 112 /* Other functions */ 113 static void ng_gif_input2(node_p node, struct mbuf **mp, int af); 114 static int ng_gif_glue_af(struct mbuf **mp, int af); 115 static int ng_gif_rcv_lower(node_p node, struct mbuf *m); 116 117 /* Netgraph node methods */ 118 static ng_constructor_t ng_gif_constructor; 119 static ng_rcvmsg_t ng_gif_rcvmsg; 120 static ng_shutdown_t ng_gif_shutdown; 121 static ng_newhook_t ng_gif_newhook; 122 static ng_connect_t ng_gif_connect; 123 static ng_rcvdata_t ng_gif_rcvdata; 124 static ng_disconnect_t ng_gif_disconnect; 125 static int ng_gif_mod_event(module_t mod, int event, void *data); 126 127 /* List of commands and how to convert arguments to/from ASCII */ 128 static const struct ng_cmdlist ng_gif_cmdlist[] = { 129 { 130 NGM_GIF_COOKIE, 131 NGM_GIF_GET_IFNAME, 132 "getifname", 133 NULL, 134 &ng_parse_string_type 135 }, 136 { 137 NGM_GIF_COOKIE, 138 NGM_GIF_GET_IFINDEX, 139 "getifindex", 140 NULL, 141 &ng_parse_int32_type 142 }, 143 { 0 } 144 }; 145 146 static struct ng_type ng_gif_typestruct = { 147 .version = NG_ABI_VERSION, 148 .name = NG_GIF_NODE_TYPE, 149 .mod_event = ng_gif_mod_event, 150 .constructor = ng_gif_constructor, 151 .rcvmsg = ng_gif_rcvmsg, 152 .shutdown = ng_gif_shutdown, 153 .newhook = ng_gif_newhook, 154 .connect = ng_gif_connect, 155 .rcvdata = ng_gif_rcvdata, 156 .disconnect = ng_gif_disconnect, 157 .cmdlist = ng_gif_cmdlist, 158 }; 159 MODULE_DEPEND(ng_gif, if_gif, 1,1,1); 160 NETGRAPH_INIT(gif, &ng_gif_typestruct); 161 162 /****************************************************************** 163 GIF FUNCTION HOOKS 164 ******************************************************************/ 165 166 /* 167 * Handle a packet that has come in on an interface. We get to 168 * look at it here before any upper layer protocols do. 169 * 170 * NOTE: this function will get called at splimp() 171 */ 172 static void 173 ng_gif_input(struct ifnet *ifp, struct mbuf **mp, int af) 174 { 175 const node_p node = IFP2NG(ifp); 176 const priv_p priv = NG_NODE_PRIVATE(node); 177 178 /* If "lower" hook not connected, let packet continue */ 179 if (priv->lower == NULL || priv->lowerOrphan) 180 return; 181 ng_gif_input2(node, mp, af); 182 } 183 184 /* 185 * Handle a packet that has come in on an interface, and which 186 * does not match any of our known protocols (an ``orphan''). 187 * 188 * NOTE: this function will get called at splimp() 189 */ 190 static void 191 ng_gif_input_orphan(struct ifnet *ifp, struct mbuf *m, int af) 192 { 193 const node_p node = IFP2NG(ifp); 194 const priv_p priv = NG_NODE_PRIVATE(node); 195 196 /* If "orphan" hook not connected, let packet continue */ 197 if (priv->lower == NULL || !priv->lowerOrphan) { 198 m_freem(m); 199 return; 200 } 201 ng_gif_input2(node, &m, af); 202 if (m != NULL) 203 m_freem(m); 204 } 205 206 /* 207 * Handle a packet that has come in on a gif interface. 208 * Attach the address family to the mbuf for later use. 209 * 210 * NOTE: this function will get called at splimp() 211 */ 212 static void 213 ng_gif_input2(node_p node, struct mbuf **mp, int af) 214 { 215 const priv_p priv = NG_NODE_PRIVATE(node); 216 int error; 217 218 /* Glue address family on */ 219 if ((error = ng_gif_glue_af(mp, af)) != 0) 220 return; 221 222 /* Send out lower/orphan hook */ 223 NG_SEND_DATA_ONLY(error, priv->lower, *mp); 224 *mp = NULL; 225 } 226 227 /* 228 * A new gif interface has been attached. 229 * Create a new node for it, etc. 230 */ 231 static void 232 ng_gif_attach(struct ifnet *ifp) 233 { 234 priv_p priv; 235 node_p node; 236 237 /* Create node */ 238 KASSERT(!IFP2NG(ifp), ("%s: node already exists?", __func__)); 239 if (ng_make_node_common(&ng_gif_typestruct, &node) != 0) { 240 log(LOG_ERR, "%s: can't %s for %s\n", 241 __func__, "create node", ifp->if_xname); 242 return; 243 } 244 245 /* Allocate private data */ 246 priv = malloc(sizeof(*priv), M_NETGRAPH, M_NOWAIT | M_ZERO); 247 if (priv == NULL) { 248 log(LOG_ERR, "%s: can't %s for %s\n", 249 __func__, "allocate memory", ifp->if_xname); 250 NG_NODE_UNREF(node); 251 return; 252 } 253 NG_NODE_SET_PRIVATE(node, priv); 254 priv->ifp = ifp; 255 IFP2NG_SET(ifp, node); 256 257 /* Try to give the node the same name as the interface */ 258 if (ng_name_node(node, ifp->if_xname) != 0) { 259 log(LOG_WARNING, "%s: can't name node %s\n", 260 __func__, ifp->if_xname); 261 } 262 } 263 264 /* 265 * An interface is being detached. 266 * REALLY Destroy its node. 267 */ 268 static void 269 ng_gif_detach(struct ifnet *ifp) 270 { 271 const node_p node = IFP2NG(ifp); 272 priv_p priv; 273 274 if (node == NULL) /* no node (why not?), ignore */ 275 return; 276 priv = NG_NODE_PRIVATE(node); 277 NG_NODE_REALLY_DIE(node); /* Force real removal of node */ 278 /* 279 * We can't assume the ifnet is still around when we run shutdown 280 * So zap it now. XXX We HOPE that anything running at this time 281 * handles it (as it should in the non netgraph case). 282 */ 283 IFP2NG_SET(ifp, NULL); 284 priv->ifp = NULL; /* XXX race if interrupted an output packet */ 285 ng_rmnode_self(node); /* remove all netgraph parts */ 286 } 287 288 /* 289 * Optimization for gluing the address family onto 290 * the front of an incoming packet. 291 */ 292 static int 293 ng_gif_glue_af(struct mbuf **mp, int af) 294 { 295 struct mbuf *m = *mp; 296 int error = 0; 297 sa_family_t tmp_af; 298 299 tmp_af = (sa_family_t) af; 300 301 /* 302 * XXX: should try to bring back some of the optimizations from 303 * ng_ether.c 304 */ 305 306 /* 307 * Doing anything more is likely to get more 308 * expensive than it's worth.. 309 * it's probable that everything else is in one 310 * big lump. The next node will do an m_pullup() 311 * for exactly the amount of data it needs and 312 * hopefully everything after that will not 313 * need one. So let's just use M_PREPEND. 314 */ 315 M_PREPEND(m, sizeof (tmp_af), M_DONTWAIT); 316 if (m == NULL) { 317 error = ENOBUFS; 318 goto done; 319 } 320 321 #if 0 322 copy: 323 #endif 324 /* Copy header and return (possibly new) mbuf */ 325 *mtod(m, sa_family_t *) = tmp_af; 326 #if 0 327 bcopy((caddr_t)&tmp_af, mtod(m, sa_family_t *), sizeof(tmp_af)); 328 #endif 329 done: 330 *mp = m; 331 return error; 332 } 333 334 /****************************************************************** 335 NETGRAPH NODE METHODS 336 ******************************************************************/ 337 338 /* 339 * It is not possible or allowable to create a node of this type. 340 * Nodes get created when the interface is attached (or, when 341 * this node type's KLD is loaded). 342 */ 343 static int 344 ng_gif_constructor(node_p node) 345 { 346 return (EINVAL); 347 } 348 349 /* 350 * Check for attaching a new hook. 351 */ 352 static int 353 ng_gif_newhook(node_p node, hook_p hook, const char *name) 354 { 355 const priv_p priv = NG_NODE_PRIVATE(node); 356 u_char orphan = priv->lowerOrphan; 357 hook_p *hookptr; 358 359 /* Divert hook is an alias for lower */ 360 if (strcmp(name, NG_GIF_HOOK_DIVERT) == 0) 361 name = NG_GIF_HOOK_LOWER; 362 363 /* Which hook? */ 364 if (strcmp(name, NG_GIF_HOOK_LOWER) == 0) { 365 hookptr = &priv->lower; 366 orphan = 0; 367 } else if (strcmp(name, NG_GIF_HOOK_ORPHAN) == 0) { 368 hookptr = &priv->lower; 369 orphan = 1; 370 } else 371 return (EINVAL); 372 373 /* Check if already connected (shouldn't be, but doesn't hurt) */ 374 if (*hookptr != NULL) 375 return (EISCONN); 376 377 /* OK */ 378 *hookptr = hook; 379 priv->lowerOrphan = orphan; 380 return (0); 381 } 382 383 /* 384 * Hooks are attached, adjust to force queueing. 385 * We don't really care which hook it is. 386 * they should all be queuing for outgoing data. 387 */ 388 static int 389 ng_gif_connect(hook_p hook) 390 { 391 NG_HOOK_FORCE_QUEUE(NG_HOOK_PEER(hook)); 392 return (0); 393 } 394 395 /* 396 * Receive an incoming control message. 397 */ 398 static int 399 ng_gif_rcvmsg(node_p node, item_p item, hook_p lasthook) 400 { 401 const priv_p priv = NG_NODE_PRIVATE(node); 402 struct ng_mesg *resp = NULL; 403 int error = 0; 404 struct ng_mesg *msg; 405 406 NGI_GET_MSG(item, msg); 407 switch (msg->header.typecookie) { 408 case NGM_GIF_COOKIE: 409 switch (msg->header.cmd) { 410 case NGM_GIF_GET_IFNAME: 411 NG_MKRESPONSE(resp, msg, IFNAMSIZ, M_NOWAIT); 412 if (resp == NULL) { 413 error = ENOMEM; 414 break; 415 } 416 strlcpy(resp->data, priv->ifp->if_xname, IFNAMSIZ); 417 break; 418 case NGM_GIF_GET_IFINDEX: 419 NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT); 420 if (resp == NULL) { 421 error = ENOMEM; 422 break; 423 } 424 *((u_int32_t *)resp->data) = priv->ifp->if_index; 425 break; 426 default: 427 error = EINVAL; 428 break; 429 } 430 break; 431 default: 432 error = EINVAL; 433 break; 434 } 435 NG_RESPOND_MSG(error, node, item, resp); 436 NG_FREE_MSG(msg); 437 return (error); 438 } 439 440 /* 441 * Receive data on a hook. 442 */ 443 static int 444 ng_gif_rcvdata(hook_p hook, item_p item) 445 { 446 const node_p node = NG_HOOK_NODE(hook); 447 const priv_p priv = NG_NODE_PRIVATE(node); 448 struct mbuf *m; 449 450 NGI_GET_M(item, m); 451 NG_FREE_ITEM(item); 452 453 if (hook == priv->lower) 454 return ng_gif_rcv_lower(node, m); 455 panic("%s: weird hook", __func__); 456 } 457 458 /* 459 * Handle an mbuf received on the "lower" hook. 460 */ 461 static int 462 ng_gif_rcv_lower(node_p node, struct mbuf *m) 463 { 464 struct sockaddr dst; 465 const priv_p priv = NG_NODE_PRIVATE(node); 466 467 bzero(&dst, sizeof(dst)); 468 469 /* Make sure header is fully pulled up */ 470 if (m->m_pkthdr.len < sizeof(sa_family_t)) { 471 NG_FREE_M(m); 472 return (EINVAL); 473 } 474 if (m->m_len < sizeof(sa_family_t) 475 && (m = m_pullup(m, sizeof(sa_family_t))) == NULL) { 476 return (ENOBUFS); 477 } 478 479 dst.sa_family = *mtod(m, sa_family_t *); 480 m_adj(m, sizeof(sa_family_t)); 481 482 /* Send it on its way */ 483 /* 484 * XXX: gif_output only uses dst for the family and passes the 485 * fourth argument (rt) to in{,6}_gif_output which ignore it. 486 * If this changes ng_gif will probably break. 487 */ 488 return gif_output(priv->ifp, m, &dst, NULL); 489 } 490 491 /* 492 * Shutdown node. This resets the node but does not remove it 493 * unless the REALLY_DIE flag is set. 494 */ 495 static int 496 ng_gif_shutdown(node_p node) 497 { 498 const priv_p priv = NG_NODE_PRIVATE(node); 499 500 if (node->nd_flags & NGF_REALLY_DIE) { 501 /* 502 * WE came here because the gif interface is being destroyed, 503 * so stop being persistant. 504 * Actually undo all the things we did on creation. 505 * Assume the ifp has already been freed. 506 */ 507 NG_NODE_SET_PRIVATE(node, NULL); 508 free(priv, M_NETGRAPH); 509 NG_NODE_UNREF(node); /* free node itself */ 510 return (0); 511 } 512 NG_NODE_REVIVE(node); /* Signal ng_rmnode we are persisant */ 513 return (0); 514 } 515 516 /* 517 * Hook disconnection. 518 */ 519 static int 520 ng_gif_disconnect(hook_p hook) 521 { 522 const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 523 524 if (hook == priv->lower) { 525 priv->lower = NULL; 526 priv->lowerOrphan = 0; 527 } else 528 panic("%s: weird hook", __func__); 529 if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0) 530 && (NG_NODE_IS_VALID(NG_HOOK_NODE(hook)))) 531 ng_rmnode_self(NG_HOOK_NODE(hook)); /* reset node */ 532 533 return (0); 534 } 535 536 /****************************************************************** 537 INITIALIZATION 538 ******************************************************************/ 539 540 /* 541 * Handle loading and unloading for this node type. 542 */ 543 static int 544 ng_gif_mod_event(module_t mod, int event, void *data) 545 { 546 VNET_ITERATOR_DECL(vnet_iter); 547 struct ifnet *ifp; 548 int error = 0; 549 int s; 550 551 s = splnet(); 552 switch (event) { 553 case MOD_LOAD: 554 555 /* Register function hooks */ 556 if (ng_gif_attach_p != NULL) { 557 error = EEXIST; 558 break; 559 } 560 ng_gif_attach_p = ng_gif_attach; 561 ng_gif_detach_p = ng_gif_detach; 562 ng_gif_input_p = ng_gif_input; 563 ng_gif_input_orphan_p = ng_gif_input_orphan; 564 565 /* Create nodes for any already-existing gif interfaces */ 566 IFNET_RLOCK(); 567 VNET_LIST_RLOCK(); 568 VNET_FOREACH(vnet_iter) { 569 CURVNET_SET_QUIET(vnet_iter); /* XXX revisit quiet */ 570 INIT_VNET_NET(curvnet); 571 TAILQ_FOREACH(ifp, &V_ifnet, if_link) { 572 if (ifp->if_type == IFT_GIF) 573 ng_gif_attach(ifp); 574 } 575 CURVNET_RESTORE(); 576 } 577 VNET_LIST_RUNLOCK(); 578 IFNET_RUNLOCK(); 579 break; 580 581 case MOD_UNLOAD: 582 583 /* 584 * Note that the base code won't try to unload us until 585 * all nodes have been removed, and that can't happen 586 * until all gif interfaces are destroyed. In any 587 * case, we know there are no nodes left if the action 588 * is MOD_UNLOAD, so there's no need to detach any nodes. 589 * 590 * XXX: what about manual unloads?!? 591 */ 592 593 /* Unregister function hooks */ 594 ng_gif_attach_p = NULL; 595 ng_gif_detach_p = NULL; 596 ng_gif_input_p = NULL; 597 ng_gif_input_orphan_p = NULL; 598 break; 599 600 default: 601 error = EOPNOTSUPP; 602 break; 603 } 604 splx(s); 605 return (error); 606 } 607 608