1 /* 2 * ng_eiface.c 3 * 4 * Copyright (c) 1999-2000, Vitaly V Belekhov 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice unmodified, this list of conditions, and the following 12 * disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * $Id: ng_eiface.c,v 1.14 2000/03/15 12:28:44 vitaly Exp $ 30 * $FreeBSD: src/sys/netgraph/ng_eiface.c,v 1.4.2.5 2002/12/17 21:47:48 julian Exp $ 31 * $DragonFly: src/sys/netgraph/eiface/ng_eiface.c,v 1.17 2008/03/07 11:34:20 sephe Exp $ 32 */ 33 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/errno.h> 37 #include <sys/kernel.h> 38 #include <sys/malloc.h> 39 #include <sys/mbuf.h> 40 #include <sys/errno.h> 41 #include <sys/sockio.h> 42 #include <sys/socket.h> 43 #include <sys/syslog.h> 44 #include <sys/serialize.h> 45 #include <sys/thread2.h> 46 47 #include <net/if.h> 48 #include <net/if_types.h> 49 #include <net/netisr.h> 50 51 52 #include <netgraph/ng_message.h> 53 #include <netgraph/netgraph.h> 54 #include <netgraph/ng_parse.h> 55 #include "ng_eiface.h" 56 57 #include <net/bpf.h> 58 #include <net/ethernet.h> 59 #include <net/if_arp.h> 60 61 static const struct ng_parse_struct_field ng_eiface_par_fields[] 62 = NG_EIFACE_PAR_FIELDS; 63 64 static const struct ng_parse_type ng_eiface_par_type = { 65 &ng_parse_struct_type, 66 &ng_eiface_par_fields 67 }; 68 69 static const struct ng_cmdlist ng_eiface_cmdlist[] = { 70 { 71 NGM_EIFACE_COOKIE, 72 NGM_EIFACE_SET, 73 "set", 74 &ng_eiface_par_type, 75 NULL 76 }, 77 { 0 } 78 }; 79 80 /* Node private data */ 81 struct ng_eiface_private { 82 struct arpcom arpcom; /* per-interface network data */ 83 struct ifnet *ifp; /* This interface */ 84 node_p node; /* Our netgraph node */ 85 hook_p ether; /* Hook for ethernet stream */ 86 struct private *next; /* When hung on the free list */ 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 struct ucred *cr); 95 #ifdef DEBUG 96 static void ng_eiface_print_ioctl(struct ifnet *ifp, int cmd, caddr_t data); 97 #endif 98 99 /* Netgraph methods */ 100 static ng_constructor_t ng_eiface_constructor; 101 static ng_rcvmsg_t ng_eiface_rcvmsg; 102 static ng_shutdown_t ng_eiface_rmnode; 103 static ng_newhook_t ng_eiface_newhook; 104 static ng_rcvdata_t ng_eiface_rcvdata; 105 static ng_connect_t ng_eiface_connect; 106 static ng_disconnect_t ng_eiface_disconnect; 107 108 /* Node type descriptor */ 109 static struct ng_type typestruct = { 110 NG_VERSION, 111 NG_EIFACE_NODE_TYPE, 112 NULL, 113 ng_eiface_constructor, 114 ng_eiface_rcvmsg, 115 ng_eiface_rmnode, 116 ng_eiface_newhook, 117 NULL, 118 ng_eiface_connect, 119 ng_eiface_rcvdata, 120 ng_eiface_rcvdata, 121 ng_eiface_disconnect, 122 ng_eiface_cmdlist 123 }; 124 NETGRAPH_INIT(eiface, &typestruct); 125 126 static char ng_eiface_ifname[] = NG_EIFACE_EIFACE_NAME; 127 static int ng_eiface_next_unit; 128 129 /************************************************************************ 130 INTERFACE STUFF 131 ************************************************************************/ 132 133 /* 134 * Process an ioctl for the virtual interface 135 */ 136 static int 137 ng_eiface_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cr) 138 { 139 struct ifreq *const ifr = (struct ifreq *) data; 140 int error = 0; 141 142 #ifdef DEBUG 143 ng_eiface_print_ioctl(ifp, cmd, data); 144 #endif 145 crit_enter(); 146 switch (cmd) { 147 148 /* These two are mostly handled at a higher layer */ 149 case SIOCSIFADDR: 150 error = ether_ioctl(ifp, cmd, data); 151 break; 152 case SIOCGIFADDR: 153 break; 154 155 /* Set flags */ 156 case SIOCSIFFLAGS: 157 /* 158 * If the interface is marked up and stopped, then start it. 159 * If it is marked down and running, then stop it. 160 */ 161 if (ifr->ifr_flags & IFF_UP) { 162 if (!(ifp->if_flags & IFF_RUNNING)) { 163 ifp->if_flags &= ~(IFF_OACTIVE); 164 ifp->if_flags |= IFF_RUNNING; 165 } 166 } else { 167 if (ifp->if_flags & IFF_RUNNING) 168 ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); 169 } 170 break; 171 172 /* Set the interface MTU */ 173 case SIOCSIFMTU: 174 if (ifr->ifr_mtu > NG_EIFACE_MTU_MAX 175 || ifr->ifr_mtu < NG_EIFACE_MTU_MIN) 176 error = EINVAL; 177 else 178 ifp->if_mtu = ifr->ifr_mtu; 179 break; 180 181 /* Stuff that's not supported */ 182 case SIOCADDMULTI: 183 case SIOCDELMULTI: 184 error = 0; 185 break; 186 case SIOCSIFPHYS: 187 error = EOPNOTSUPP; 188 break; 189 190 default: 191 error = EINVAL; 192 break; 193 } 194 crit_exit(); 195 return (error); 196 } 197 198 static void 199 ng_eiface_init(void *xsc) 200 { 201 priv_p sc = xsc; 202 struct ifnet *ifp = sc->ifp; 203 204 crit_enter(); 205 206 ifp->if_flags |= IFF_RUNNING; 207 ifp->if_flags &= ~IFF_OACTIVE; 208 209 crit_exit(); 210 211 } 212 213 /* 214 * This routine is called to deliver a packet out the interface. 215 * We simply relay the packet to 216 * the ether hook, if it is connected. 217 */ 218 219 static void 220 ng_eiface_start(struct ifnet *ifp) 221 { 222 const priv_p priv = (priv_p) ifp->if_softc; 223 meta_p meta = NULL; 224 int len, error = 0; 225 struct mbuf *m; 226 227 /* Check interface flags */ 228 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) 229 return; 230 231 /* Don't do anything if output is active */ 232 if( ifp->if_flags & IFF_OACTIVE ) 233 return; 234 235 ifp->if_flags |= IFF_OACTIVE; 236 237 /* 238 * Grab a packet to transmit. 239 */ 240 IF_DEQUEUE(&ifp->if_snd, m); 241 242 /* If there's nothing to send, return. */ 243 if(m == NULL) 244 { 245 ifp->if_flags &= ~IFF_OACTIVE; 246 return; 247 } 248 249 BPF_MTAP(ifp, m); 250 251 /* Copy length before the mbuf gets invalidated */ 252 len = m->m_pkthdr.len; 253 254 /* Send packet; if hook is not connected, mbuf will get freed. */ 255 NG_SEND_DATA(error, priv->ether, m, meta); 256 257 /* Update stats */ 258 if (error == 0) { 259 ifp->if_obytes += len; 260 ifp->if_opackets++; 261 } 262 263 ifp->if_flags &= ~IFF_OACTIVE; 264 265 return; 266 } 267 268 #ifdef DEBUG 269 /* 270 * Display an ioctl to the virtual interface 271 */ 272 273 static void 274 ng_eiface_print_ioctl(struct ifnet *ifp, int cmd, caddr_t data) 275 { 276 char *str; 277 278 switch (cmd & IOC_DIRMASK) { 279 case IOC_VOID: 280 str = "IO"; 281 break; 282 case IOC_OUT: 283 str = "IOR"; 284 break; 285 case IOC_IN: 286 str = "IOW"; 287 break; 288 case IOC_INOUT: 289 str = "IORW"; 290 break; 291 default: 292 str = "IO??"; 293 } 294 log(LOG_DEBUG, "%s: %s('%c', %d, char[%d])\n", 295 ifp->if_xname, 296 str, 297 IOCGROUP(cmd), 298 cmd & 0xff, 299 IOCPARM_LEN(cmd)); 300 } 301 #endif /* DEBUG */ 302 303 /************************************************************************ 304 NETGRAPH NODE STUFF 305 ************************************************************************/ 306 307 /* 308 * Constructor for a node 309 */ 310 static int 311 ng_eiface_constructor(node_p *nodep) 312 { 313 struct ifnet *ifp; 314 node_p node; 315 priv_p priv; 316 int error = 0; 317 318 /* Allocate node and interface private structures */ 319 MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH, M_WAITOK | M_ZERO); 320 321 ifp = &(priv->arpcom.ac_if); 322 323 /* Link them together */ 324 ifp->if_softc = priv; 325 priv->ifp = ifp; 326 327 /* Call generic node constructor */ 328 if ((error = ng_make_node_common(&typestruct, nodep))) { 329 FREE(priv, M_NETGRAPH); 330 return (error); 331 } 332 node = *nodep; 333 334 /* Link together node and private info */ 335 node->private = priv; 336 priv->node = node; 337 338 /* Initialize interface structure */ 339 if_initname(ifp, ng_eiface_ifname, ng_eiface_next_unit++); 340 ifp->if_init = ng_eiface_init; 341 ifp->if_start = ng_eiface_start; 342 ifp->if_ioctl = ng_eiface_ioctl; 343 ifp->if_watchdog = NULL; 344 ifp->if_snd.ifq_maxlen = IFQ_MAXLEN; 345 ifp->if_flags = (IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST); 346 347 /* Give this node name * 348 bzero(ifname, sizeof(ifname)); 349 ksprintf(ifname, "if%s", ifp->if_xname); 350 ng_name_node(node, ifname); 351 */ 352 353 /* Attach the interface */ 354 ether_ifattach(ifp, priv->arpcom.ac_enaddr, NULL); 355 356 /* Done */ 357 return (0); 358 } 359 360 /* 361 * Give our ok for a hook to be added 362 */ 363 static int 364 ng_eiface_newhook(node_p node, hook_p hook, const char *name) 365 { 366 priv_p priv = node->private; 367 368 if (strcmp(name, NG_EIFACE_HOOK_ETHER)) 369 return (EPFNOSUPPORT); 370 if (priv->ether != NULL) 371 return (EISCONN); 372 priv->ether = hook; 373 hook->private = &priv->ether; 374 375 return (0); 376 } 377 378 /* 379 * Receive a control message 380 */ 381 static int 382 ng_eiface_rcvmsg(node_p node, struct ng_mesg *msg, 383 const char *retaddr, struct ng_mesg **rptr) 384 { 385 const priv_p priv = node->private; 386 struct ifnet *const ifp = priv->ifp; 387 struct ng_mesg *resp = NULL; 388 int error = 0; 389 390 switch (msg->header.typecookie) { 391 case NGM_EIFACE_COOKIE: 392 switch (msg->header.cmd) { 393 394 case NGM_EIFACE_SET: 395 { 396 struct ng_eiface_par *eaddr; 397 398 if (msg->header.arglen != sizeof(struct ng_eiface_par)) 399 { 400 error = EINVAL; 401 break; 402 } 403 eaddr = (struct ng_eiface_par *)(msg->data); 404 405 priv->arpcom.ac_enaddr[0] = eaddr->oct0; 406 priv->arpcom.ac_enaddr[1] = eaddr->oct1; 407 priv->arpcom.ac_enaddr[2] = eaddr->oct2; 408 priv->arpcom.ac_enaddr[3] = eaddr->oct3; 409 priv->arpcom.ac_enaddr[4] = eaddr->oct4; 410 priv->arpcom.ac_enaddr[5] = eaddr->oct5; 411 412 break; 413 } 414 415 case NGM_EIFACE_GET_IFNAME: 416 { 417 struct ng_eiface_ifname *arg; 418 419 NG_MKRESPONSE(resp, msg, sizeof(*arg), M_NOWAIT); 420 if (resp == NULL) { 421 error = ENOMEM; 422 break; 423 } 424 arg = (struct ng_eiface_ifname *) resp->data; 425 ksprintf(arg->ngif_name, 426 "%s", ifp->if_xname); /* XXX: strings */ 427 break; 428 } 429 430 case NGM_EIFACE_GET_IFADDRS: 431 { 432 struct ifaddr_container *ifac; 433 caddr_t ptr; 434 int buflen; 435 436 #define SA_SIZE(s) ((s)->sa_len<sizeof(*(s))? sizeof(*(s)):(s)->sa_len) 437 438 /* Determine size of response and allocate it */ 439 buflen = 0; 440 TAILQ_FOREACH(ifac, &ifp->if_addrheads[mycpuid], 441 ifa_link) 442 buflen += SA_SIZE(ifac->ifa->ifa_addr); 443 NG_MKRESPONSE(resp, msg, buflen, M_NOWAIT); 444 if (resp == NULL) { 445 error = ENOMEM; 446 break; 447 } 448 449 /* Add addresses */ 450 ptr = resp->data; 451 TAILQ_FOREACH(ifac, &ifp->if_addrheads[mycpuid], 452 ifa_link) { 453 struct ifaddr *ifa = ifac->ifa; 454 const int len = SA_SIZE(ifa->ifa_addr); 455 456 if (buflen < len) { 457 log(LOG_ERR, "%s: len changed?\n", 458 ifp->if_xname); 459 break; 460 } 461 bcopy(ifa->ifa_addr, ptr, len); 462 ptr += len; 463 buflen -= len; 464 } 465 break; 466 #undef SA_SIZE 467 } 468 469 default: 470 error = EINVAL; 471 break; 472 } 473 break; 474 default: 475 error = EINVAL; 476 break; 477 } 478 if (rptr) 479 *rptr = resp; 480 else if (resp) 481 FREE(resp, M_NETGRAPH); 482 FREE(msg, M_NETGRAPH); 483 return (error); 484 } 485 486 /* 487 * Recive data from a hook. Pass the packet to the ether_input routine. 488 */ 489 static int 490 ng_eiface_rcvdata(hook_p hook, struct mbuf *m, meta_p meta) 491 { 492 const priv_p priv = hook->node->private; 493 struct ifnet *const ifp = priv->ifp; 494 int error = 0; 495 496 /* Meta-data is end its life here... */ 497 NG_FREE_META(meta); 498 499 if (m == NULL) 500 { 501 kprintf("ng_eiface: mbuf is null.\n"); 502 return (EINVAL); 503 } 504 505 lwkt_serialize_enter(ifp->if_serializer); 506 if ( !(ifp->if_flags & IFF_UP) ) { 507 lwkt_serialize_exit(ifp->if_serializer); 508 return (ENETDOWN); 509 } 510 511 /* Note receiving interface */ 512 m->m_pkthdr.rcvif = ifp; 513 514 /* Update interface stats */ 515 ifp->if_ipackets++; 516 517 BPF_MTAP(ifp, m); 518 519 ifp->if_input(ifp, m); 520 lwkt_serialize_exit(ifp->if_serializer); 521 522 /* Done */ 523 return (error); 524 } 525 526 /* 527 * Because the BSD networking code doesn't support the removal of 528 * networking interfaces, iface nodes (once created) are persistent. 529 * So this method breaks all connections and marks the interface 530 * down, but does not remove the node. 531 */ 532 static int 533 ng_eiface_rmnode(node_p node) 534 { 535 const priv_p priv = node->private; 536 struct ifnet *const ifp = priv->ifp; 537 538 ng_cutlinks(node); 539 node->flags &= ~NG_INVALID; 540 lwkt_serialize_enter(ifp->if_serializer); 541 ifp->if_flags &= ~(IFF_UP | IFF_RUNNING | IFF_OACTIVE); 542 lwkt_serialize_exit(ifp->if_serializer); 543 return (0); 544 } 545 546 547 /* 548 * This is called once we've already connected a new hook to the other node. 549 * It gives us a chance to balk at the last minute. 550 */ 551 static int 552 ng_eiface_connect(hook_p hook) 553 { 554 /* be really amiable and just say "YUP that's OK by me! " */ 555 return (0); 556 } 557 558 /* 559 * Hook disconnection 560 */ 561 static int 562 ng_eiface_disconnect(hook_p hook) 563 { 564 const priv_p priv = hook->node->private; 565 566 priv->ether = NULL; 567 return (0); 568 } 569