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 <sys/param.h> 72 #include <sys/systm.h> 73 #include <sys/kernel.h> 74 #include <sys/malloc.h> 75 #include <sys/mbuf.h> 76 #include <sys/errno.h> 77 #include <sys/syslog.h> 78 #include <sys/socket.h> 79 80 #include <net/if.h> 81 #include <net/route.h> 82 #include <net/if_types.h> 83 #include <net/if_var.h> 84 #include <net/if_gif.h> 85 #include <net/vnet.h> 86 87 #include <netgraph/ng_message.h> 88 #include <netgraph/netgraph.h> 89 #include <netgraph/ng_parse.h> 90 #include <netgraph/ng_gif.h> 91 92 #define IFP2NG(ifp) ((struct ng_node *)((struct gif_softc *)(ifp->if_softc))->gif_netgraph) 93 #define IFP2NG_SET(ifp, val) (((struct gif_softc *)(ifp->if_softc))->gif_netgraph = (val)) 94 95 /* Per-node private data */ 96 struct private { 97 struct ifnet *ifp; /* associated interface */ 98 hook_p lower; /* lower OR orphan hook connection */ 99 u_char lowerOrphan; /* whether lower is lower or orphan */ 100 }; 101 typedef struct private *priv_p; 102 103 /* Functional hooks called from if_gif.c */ 104 static void ng_gif_input(struct ifnet *ifp, struct mbuf **mp, int af); 105 static void ng_gif_input_orphan(struct ifnet *ifp, struct mbuf *m, int af); 106 static void ng_gif_attach(struct ifnet *ifp); 107 static void ng_gif_detach(struct ifnet *ifp); 108 109 /* Other functions */ 110 static void ng_gif_input2(node_p node, struct mbuf **mp, int af); 111 static int ng_gif_glue_af(struct mbuf **mp, int af); 112 static int ng_gif_rcv_lower(node_p node, struct mbuf *m); 113 114 /* Netgraph node methods */ 115 static ng_constructor_t ng_gif_constructor; 116 static ng_rcvmsg_t ng_gif_rcvmsg; 117 static ng_shutdown_t ng_gif_shutdown; 118 static ng_newhook_t ng_gif_newhook; 119 static ng_connect_t ng_gif_connect; 120 static ng_rcvdata_t ng_gif_rcvdata; 121 static ng_disconnect_t ng_gif_disconnect; 122 static int ng_gif_mod_event(module_t mod, int event, void *data); 123 124 /* List of commands and how to convert arguments to/from ASCII */ 125 static const struct ng_cmdlist ng_gif_cmdlist[] = { 126 { 127 NGM_GIF_COOKIE, 128 NGM_GIF_GET_IFNAME, 129 "getifname", 130 NULL, 131 &ng_parse_string_type 132 }, 133 { 134 NGM_GIF_COOKIE, 135 NGM_GIF_GET_IFINDEX, 136 "getifindex", 137 NULL, 138 &ng_parse_int32_type 139 }, 140 { 0 } 141 }; 142 143 static struct ng_type ng_gif_typestruct = { 144 .version = NG_ABI_VERSION, 145 .name = NG_GIF_NODE_TYPE, 146 .mod_event = ng_gif_mod_event, 147 .constructor = ng_gif_constructor, 148 .rcvmsg = ng_gif_rcvmsg, 149 .shutdown = ng_gif_shutdown, 150 .newhook = ng_gif_newhook, 151 .connect = ng_gif_connect, 152 .rcvdata = ng_gif_rcvdata, 153 .disconnect = ng_gif_disconnect, 154 .cmdlist = ng_gif_cmdlist, 155 }; 156 MODULE_DEPEND(ng_gif, if_gif, 1,1,1); 157 NETGRAPH_INIT(gif, &ng_gif_typestruct); 158 159 /****************************************************************** 160 GIF FUNCTION HOOKS 161 ******************************************************************/ 162 163 /* 164 * Handle a packet that has come in on an interface. We get to 165 * look at it here before any upper layer protocols do. 166 */ 167 static void 168 ng_gif_input(struct ifnet *ifp, struct mbuf **mp, int af) 169 { 170 const node_p node = IFP2NG(ifp); 171 const priv_p priv = NG_NODE_PRIVATE(node); 172 173 /* If "lower" hook not connected, let packet continue */ 174 if (priv->lower == NULL || priv->lowerOrphan) 175 return; 176 ng_gif_input2(node, mp, af); 177 } 178 179 /* 180 * Handle a packet that has come in on an interface, and which 181 * does not match any of our known protocols (an ``orphan''). 182 */ 183 static void 184 ng_gif_input_orphan(struct ifnet *ifp, struct mbuf *m, int af) 185 { 186 const node_p node = IFP2NG(ifp); 187 const priv_p priv = NG_NODE_PRIVATE(node); 188 189 /* If "orphan" hook not connected, let packet continue */ 190 if (priv->lower == NULL || !priv->lowerOrphan) { 191 m_freem(m); 192 return; 193 } 194 ng_gif_input2(node, &m, af); 195 if (m != NULL) 196 m_freem(m); 197 } 198 199 /* 200 * Handle a packet that has come in on a gif interface. 201 * Attach the address family to the mbuf for later use. 202 */ 203 static void 204 ng_gif_input2(node_p node, struct mbuf **mp, int af) 205 { 206 const priv_p priv = NG_NODE_PRIVATE(node); 207 int error; 208 209 /* Glue address family on */ 210 if ((error = ng_gif_glue_af(mp, af)) != 0) 211 return; 212 213 /* Send out lower/orphan hook */ 214 NG_SEND_DATA_ONLY(error, priv->lower, *mp); 215 *mp = NULL; 216 } 217 218 /* 219 * A new gif interface has been attached. 220 * Create a new node for it, etc. 221 */ 222 static void 223 ng_gif_attach(struct ifnet *ifp) 224 { 225 priv_p priv; 226 node_p node; 227 228 /* Create node */ 229 KASSERT(!IFP2NG(ifp), ("%s: node already exists?", __func__)); 230 if (ng_make_node_common(&ng_gif_typestruct, &node) != 0) { 231 log(LOG_ERR, "%s: can't %s for %s\n", 232 __func__, "create node", ifp->if_xname); 233 return; 234 } 235 236 /* Allocate private data */ 237 priv = malloc(sizeof(*priv), M_NETGRAPH, M_NOWAIT | M_ZERO); 238 if (priv == NULL) { 239 log(LOG_ERR, "%s: can't %s for %s\n", 240 __func__, "allocate memory", ifp->if_xname); 241 NG_NODE_UNREF(node); 242 return; 243 } 244 NG_NODE_SET_PRIVATE(node, priv); 245 priv->ifp = ifp; 246 IFP2NG_SET(ifp, node); 247 248 /* Try to give the node the same name as the interface */ 249 if (ng_name_node(node, ifp->if_xname) != 0) { 250 log(LOG_WARNING, "%s: can't name node %s\n", 251 __func__, ifp->if_xname); 252 } 253 } 254 255 /* 256 * An interface is being detached. 257 * REALLY Destroy its node. 258 */ 259 static void 260 ng_gif_detach(struct ifnet *ifp) 261 { 262 const node_p node = IFP2NG(ifp); 263 priv_p priv; 264 265 if (node == NULL) /* no node (why not?), ignore */ 266 return; 267 priv = NG_NODE_PRIVATE(node); 268 NG_NODE_REALLY_DIE(node); /* Force real removal of node */ 269 /* 270 * We can't assume the ifnet is still around when we run shutdown 271 * So zap it now. XXX We HOPE that anything running at this time 272 * handles it (as it should in the non netgraph case). 273 */ 274 IFP2NG_SET(ifp, NULL); 275 priv->ifp = NULL; /* XXX race if interrupted an output packet */ 276 ng_rmnode_self(node); /* remove all netgraph parts */ 277 } 278 279 /* 280 * Optimization for gluing the address family onto 281 * the front of an incoming packet. 282 */ 283 static int 284 ng_gif_glue_af(struct mbuf **mp, int af) 285 { 286 struct mbuf *m = *mp; 287 int error = 0; 288 sa_family_t tmp_af; 289 290 tmp_af = (sa_family_t) af; 291 292 /* 293 * XXX: should try to bring back some of the optimizations from 294 * ng_ether.c 295 */ 296 297 /* 298 * Doing anything more is likely to get more 299 * expensive than it's worth.. 300 * it's probable that everything else is in one 301 * big lump. The next node will do an m_pullup() 302 * for exactly the amount of data it needs and 303 * hopefully everything after that will not 304 * need one. So let's just use M_PREPEND. 305 */ 306 M_PREPEND(m, sizeof (tmp_af), M_NOWAIT); 307 if (m == NULL) { 308 error = ENOBUFS; 309 goto done; 310 } 311 312 #if 0 313 copy: 314 #endif 315 /* Copy header and return (possibly new) mbuf */ 316 *mtod(m, sa_family_t *) = tmp_af; 317 #if 0 318 bcopy((caddr_t)&tmp_af, mtod(m, sa_family_t *), sizeof(tmp_af)); 319 #endif 320 done: 321 *mp = m; 322 return error; 323 } 324 325 /****************************************************************** 326 NETGRAPH NODE METHODS 327 ******************************************************************/ 328 329 /* 330 * It is not possible or allowable to create a node of this type. 331 * Nodes get created when the interface is attached (or, when 332 * this node type's KLD is loaded). 333 */ 334 static int 335 ng_gif_constructor(node_p node) 336 { 337 return (EINVAL); 338 } 339 340 /* 341 * Check for attaching a new hook. 342 */ 343 static int 344 ng_gif_newhook(node_p node, hook_p hook, const char *name) 345 { 346 const priv_p priv = NG_NODE_PRIVATE(node); 347 u_char orphan = priv->lowerOrphan; 348 hook_p *hookptr; 349 350 /* Divert hook is an alias for lower */ 351 if (strcmp(name, NG_GIF_HOOK_DIVERT) == 0) 352 name = NG_GIF_HOOK_LOWER; 353 354 /* Which hook? */ 355 if (strcmp(name, NG_GIF_HOOK_LOWER) == 0) { 356 hookptr = &priv->lower; 357 orphan = 0; 358 } else if (strcmp(name, NG_GIF_HOOK_ORPHAN) == 0) { 359 hookptr = &priv->lower; 360 orphan = 1; 361 } else 362 return (EINVAL); 363 364 /* Check if already connected (shouldn't be, but doesn't hurt) */ 365 if (*hookptr != NULL) 366 return (EISCONN); 367 368 /* OK */ 369 *hookptr = hook; 370 priv->lowerOrphan = orphan; 371 return (0); 372 } 373 374 /* 375 * Hooks are attached, adjust to force queueing. 376 * We don't really care which hook it is. 377 * they should all be queuing for outgoing data. 378 */ 379 static int 380 ng_gif_connect(hook_p hook) 381 { 382 NG_HOOK_FORCE_QUEUE(NG_HOOK_PEER(hook)); 383 return (0); 384 } 385 386 /* 387 * Receive an incoming control message. 388 */ 389 static int 390 ng_gif_rcvmsg(node_p node, item_p item, hook_p lasthook) 391 { 392 const priv_p priv = NG_NODE_PRIVATE(node); 393 struct ng_mesg *resp = NULL; 394 int error = 0; 395 struct ng_mesg *msg; 396 397 NGI_GET_MSG(item, msg); 398 switch (msg->header.typecookie) { 399 case NGM_GIF_COOKIE: 400 switch (msg->header.cmd) { 401 case NGM_GIF_GET_IFNAME: 402 NG_MKRESPONSE(resp, msg, IFNAMSIZ, M_NOWAIT); 403 if (resp == NULL) { 404 error = ENOMEM; 405 break; 406 } 407 strlcpy(resp->data, priv->ifp->if_xname, IFNAMSIZ); 408 break; 409 case NGM_GIF_GET_IFINDEX: 410 NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT); 411 if (resp == NULL) { 412 error = ENOMEM; 413 break; 414 } 415 *((u_int32_t *)resp->data) = priv->ifp->if_index; 416 break; 417 default: 418 error = EINVAL; 419 break; 420 } 421 break; 422 default: 423 error = EINVAL; 424 break; 425 } 426 NG_RESPOND_MSG(error, node, item, resp); 427 NG_FREE_MSG(msg); 428 return (error); 429 } 430 431 /* 432 * Receive data on a hook. 433 */ 434 static int 435 ng_gif_rcvdata(hook_p hook, item_p item) 436 { 437 const node_p node = NG_HOOK_NODE(hook); 438 const priv_p priv = NG_NODE_PRIVATE(node); 439 struct mbuf *m; 440 441 NGI_GET_M(item, m); 442 NG_FREE_ITEM(item); 443 444 if (hook == priv->lower) 445 return ng_gif_rcv_lower(node, m); 446 panic("%s: weird hook", __func__); 447 } 448 449 /* 450 * Handle an mbuf received on the "lower" hook. 451 */ 452 static int 453 ng_gif_rcv_lower(node_p node, struct mbuf *m) 454 { 455 struct sockaddr dst; 456 const priv_p priv = NG_NODE_PRIVATE(node); 457 458 bzero(&dst, sizeof(dst)); 459 460 /* Make sure header is fully pulled up */ 461 if (m->m_pkthdr.len < sizeof(sa_family_t)) { 462 NG_FREE_M(m); 463 return (EINVAL); 464 } 465 if (m->m_len < sizeof(sa_family_t) 466 && (m = m_pullup(m, sizeof(sa_family_t))) == NULL) { 467 return (ENOBUFS); 468 } 469 470 dst.sa_family = *mtod(m, sa_family_t *); 471 m_adj(m, sizeof(sa_family_t)); 472 473 /* Send it on its way */ 474 /* 475 * XXX: gif_output only uses dst for the family and passes the 476 * fourth argument (rt) to in{,6}_gif_output which ignore it. 477 * If this changes ng_gif will probably break. 478 */ 479 return gif_output(priv->ifp, m, &dst, NULL); 480 } 481 482 /* 483 * Shutdown node. This resets the node but does not remove it 484 * unless the REALLY_DIE flag is set. 485 */ 486 static int 487 ng_gif_shutdown(node_p node) 488 { 489 const priv_p priv = NG_NODE_PRIVATE(node); 490 491 if (node->nd_flags & NGF_REALLY_DIE) { 492 /* 493 * WE came here because the gif interface is being destroyed, 494 * so stop being persistent. 495 * Actually undo all the things we did on creation. 496 * Assume the ifp has already been freed. 497 */ 498 NG_NODE_SET_PRIVATE(node, NULL); 499 free(priv, M_NETGRAPH); 500 NG_NODE_UNREF(node); /* free node itself */ 501 return (0); 502 } 503 NG_NODE_REVIVE(node); /* Signal ng_rmnode we are persisant */ 504 return (0); 505 } 506 507 /* 508 * Hook disconnection. 509 */ 510 static int 511 ng_gif_disconnect(hook_p hook) 512 { 513 const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 514 515 if (hook == priv->lower) { 516 priv->lower = NULL; 517 priv->lowerOrphan = 0; 518 } else 519 panic("%s: weird hook", __func__); 520 if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0) 521 && (NG_NODE_IS_VALID(NG_HOOK_NODE(hook)))) 522 ng_rmnode_self(NG_HOOK_NODE(hook)); /* reset node */ 523 524 return (0); 525 } 526 527 /****************************************************************** 528 INITIALIZATION 529 ******************************************************************/ 530 531 /* 532 * Handle loading and unloading for this node type. 533 */ 534 static int 535 ng_gif_mod_event(module_t mod, int event, void *data) 536 { 537 VNET_ITERATOR_DECL(vnet_iter); 538 struct ifnet *ifp; 539 int error = 0; 540 541 switch (event) { 542 case MOD_LOAD: 543 544 /* Register function hooks */ 545 if (ng_gif_attach_p != NULL) { 546 error = EEXIST; 547 break; 548 } 549 ng_gif_attach_p = ng_gif_attach; 550 ng_gif_detach_p = ng_gif_detach; 551 ng_gif_input_p = ng_gif_input; 552 ng_gif_input_orphan_p = ng_gif_input_orphan; 553 554 /* Create nodes for any already-existing gif interfaces */ 555 VNET_LIST_RLOCK(); 556 IFNET_RLOCK(); 557 VNET_FOREACH(vnet_iter) { 558 CURVNET_SET_QUIET(vnet_iter); /* XXX revisit quiet */ 559 TAILQ_FOREACH(ifp, &V_ifnet, if_link) { 560 if (ifp->if_type == IFT_GIF) 561 ng_gif_attach(ifp); 562 } 563 CURVNET_RESTORE(); 564 } 565 IFNET_RUNLOCK(); 566 VNET_LIST_RUNLOCK(); 567 break; 568 569 case MOD_UNLOAD: 570 571 /* 572 * Note that the base code won't try to unload us until 573 * all nodes have been removed, and that can't happen 574 * until all gif interfaces are destroyed. In any 575 * case, we know there are no nodes left if the action 576 * is MOD_UNLOAD, so there's no need to detach any nodes. 577 * 578 * XXX: what about manual unloads?!? 579 */ 580 581 /* Unregister function hooks */ 582 ng_gif_attach_p = NULL; 583 ng_gif_detach_p = NULL; 584 ng_gif_input_p = NULL; 585 ng_gif_input_orphan_p = NULL; 586 break; 587 588 default: 589 error = EOPNOTSUPP; 590 break; 591 } 592 return (error); 593 } 594 595