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