1 /*- 2 * Copyright (c) 2000 Brian Somers <brian@Awfulhak.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD: src/usr.sbin/ppp/netgraph.c,v 1.4.2.1 2002/09/01 02:12:29 brian Exp $ 27 * $DragonFly: src/usr.sbin/ppp/netgraph.c,v 1.3 2007/06/04 00:40:32 swildner Exp $ 28 */ 29 30 #include <sys/param.h> 31 #include <sys/socket.h> 32 #include <sys/un.h> 33 #include <netinet/in.h> 34 #include <arpa/inet.h> 35 #include <netdb.h> 36 #include <netgraph.h> 37 #include <net/ethernet.h> 38 #include <netinet/in_systm.h> 39 #include <netinet/ip.h> 40 #ifdef WANT_NETGRAPH7 41 #include <netgraph7/ng_ether.h> 42 #include <netgraph7/ng_message.h> 43 #include <netgraph7/ng_socket.h> 44 #else 45 #include <netgraph/ng_ether.h> 46 #include <netgraph/ng_message.h> 47 #include <netgraph/ng_socket.h> 48 #endif 49 50 #include <errno.h> 51 #include <stdio.h> 52 #include <stdlib.h> 53 #include <string.h> 54 #include <sysexits.h> 55 #include <sys/fcntl.h> 56 #include <sys/uio.h> 57 #include <termios.h> 58 #include <sys/time.h> 59 #include <unistd.h> 60 61 #include "layer.h" 62 #include "defs.h" 63 #include "mbuf.h" 64 #include "log.h" 65 #include "timer.h" 66 #include "lqr.h" 67 #include "hdlc.h" 68 #include "throughput.h" 69 #include "fsm.h" 70 #include "lcp.h" 71 #include "ccp.h" 72 #include "link.h" 73 #include "async.h" 74 #include "descriptor.h" 75 #include "physical.h" 76 #include "main.h" 77 #include "mp.h" 78 #include "chat.h" 79 #include "auth.h" 80 #include "chap.h" 81 #include "cbcp.h" 82 #include "datalink.h" 83 #include "slcompress.h" 84 #include "iplist.h" 85 #include "ncpaddr.h" 86 #include "ipcp.h" 87 #include "ipv6cp.h" 88 #include "ncp.h" 89 #include "filter.h" 90 #ifndef NORADIUS 91 #include "radius.h" 92 #endif 93 #include "bundle.h" 94 #include "id.h" 95 #include "netgraph.h" 96 97 98 struct ngdevice { 99 struct device dev; /* What struct physical knows about */ 100 int cs; /* Control socket */ 101 char hook[NG_HOOKSIZ]; /* Our socket node hook */ 102 }; 103 104 #define device2ng(d) ((d)->type == NG_DEVICE ? (struct ngdevice *)d : NULL) 105 #define NG_MSGBUFSZ 4096 106 #define NETGRAPH_PREFIX "netgraph:" 107 108 unsigned 109 ng_DeviceSize(void) 110 { 111 return sizeof(struct ngdevice); 112 } 113 114 static int 115 ng_MessageOut(struct ngdevice *dev, const char *data) 116 { 117 char path[NG_PATHSIZ]; 118 char *fmt; 119 size_t len; 120 int pos, dpos; 121 122 /* 123 * We expect a node path, one or more spaces, a command, one or more 124 * spaces and an ascii netgraph structure. 125 */ 126 data += strspn(data, " \t"); 127 len = strcspn(data, " \t"); 128 if (len >= sizeof path) { 129 log_Printf(LogWARN, "%s: %.*s: Node path too long\n", 130 dev->dev.name, len, data); 131 return 0; 132 } 133 memcpy(path, data, len); 134 path[len] = '\0'; 135 data += len; 136 137 data += strspn(data, " \t"); 138 len = strcspn(data, " \t"); 139 for (pos = len; pos >= 0; pos--) 140 if (data[pos] == '%') 141 len++; 142 if ((fmt = alloca(len + 4)) == NULL) { 143 log_Printf(LogWARN, "%s: alloca(%d) failure... %s\n", 144 dev->dev.name, len + 4, strerror(errno)); 145 return 0; 146 } 147 148 /* 149 * This is probably a waste of time, but we really don't want to end 150 * up stuffing unexpected % escapes into the kernel.... 151 */ 152 for (pos = dpos = 0; pos < (int)len;) { 153 if (data[dpos] == '%') 154 fmt[pos++] = '%'; 155 fmt[pos++] = data[dpos++]; 156 } 157 strcpy(fmt + pos, " %s"); 158 data += dpos; 159 160 data += strspn(data, " \t"); 161 if (NgSendAsciiMsg(dev->cs, path, fmt, data) < 0) { 162 log_Printf(LogDEBUG, "%s: NgSendAsciiMsg (to %s): \"%s\", \"%s\": %s\n", 163 dev->dev.name, path, fmt, data, strerror(errno)); 164 return 0; 165 } 166 167 return 1; 168 } 169 170 /* 171 * Get a netgraph message 172 */ 173 static ssize_t 174 ng_MessageIn(struct physical *p, char *buf, size_t sz) 175 { 176 char msgbuf[sizeof(struct ng_mesg) * 2 + NG_MSGBUFSZ]; 177 struct ngdevice *dev = device2ng(p->handler); 178 struct ng_mesg *rep = (struct ng_mesg *)msgbuf; 179 char path[NG_PATHSIZ]; 180 size_t len; 181 182 #ifdef BROKEN_SELECT 183 struct timeval t; 184 fd_set *r; 185 int ret; 186 187 if (dev->cs < 0) 188 return 0; 189 190 if ((r = mkfdset()) == NULL) { 191 log_Printf(LogERROR, "DoLoop: Cannot create fd_set\n"); 192 return -1; 193 } 194 zerofdset(r); 195 FD_SET(dev->cs, r); 196 t.tv_sec = t.tv_usec = 0; 197 ret = select(dev->cs + 1, r, NULL, NULL, &t); 198 free(r); 199 200 if (ret <= 0) 201 return 0; 202 #endif 203 204 if (NgRecvAsciiMsg(dev->cs, rep, sizeof msgbuf, path)) { 205 log_Printf(LogWARN, "%s: NgRecvAsciiMsg: %s\n", 206 dev->dev.name, strerror(errno)); 207 return -1; 208 } 209 210 /* XXX: Should we check rep->header.version ? */ 211 212 if (sz == 0) 213 log_Printf(LogWARN, "%s: Unexpected message: %s\n", dev->dev.name, 214 rep->header.cmdstr); 215 else { 216 log_Printf(LogDEBUG, "%s: Received message: %s\n", dev->dev.name, 217 rep->header.cmdstr); 218 len = strlen(rep->header.cmdstr); 219 if (sz > len) 220 sz = len; 221 memcpy(buf, rep->header.cmdstr, sz); 222 } 223 224 return sz; 225 } 226 227 static ssize_t 228 ng_Write(struct physical *p, const void *v, size_t n) 229 { 230 struct ngdevice *dev = device2ng(p->handler); 231 232 switch (p->dl->state) { 233 case DATALINK_DIAL: 234 case DATALINK_LOGIN: 235 return ng_MessageOut(dev, v) ? (ssize_t)n : -1; 236 } 237 return NgSendData(p->fd, dev->hook, v, n) == -1 ? -1 : (ssize_t)n; 238 } 239 240 static ssize_t 241 ng_Read(struct physical *p, void *v, size_t n) 242 { 243 char hook[NG_HOOKSIZ]; 244 245 log_Printf(LogDEBUG, "ng_Read\n"); 246 switch (p->dl->state) { 247 case DATALINK_DIAL: 248 case DATALINK_LOGIN: 249 return ng_MessageIn(p, v, n); 250 } 251 252 return NgRecvData(p->fd, v, n, hook); 253 } 254 255 static int 256 ng_RemoveFromSet(struct physical *p, fd_set *r, fd_set *w, fd_set *e) 257 { 258 struct ngdevice *dev = device2ng(p->handler); 259 int result; 260 261 if (r && dev->cs >= 0 && FD_ISSET(dev->cs, r)) { 262 FD_CLR(dev->cs, r); 263 log_Printf(LogTIMER, "%s: fdunset(ctrl) %d\n", p->link.name, dev->cs); 264 result = 1; 265 } else 266 result = 0; 267 268 /* Careful... physical_RemoveFromSet() called us ! */ 269 270 p->handler->removefromset = NULL; 271 result += physical_RemoveFromSet(p, r, w, e); 272 p->handler->removefromset = ng_RemoveFromSet; 273 274 return result; 275 } 276 277 static void 278 ng_Free(struct physical *p) 279 { 280 struct ngdevice *dev = device2ng(p->handler); 281 282 physical_SetDescriptor(p); 283 if (dev->cs != -1) 284 close(dev->cs); 285 free(dev); 286 } 287 288 static void 289 ng_device2iov(struct device *d, struct iovec *iov, int *niov, 290 int maxiov __unused, int *auxfd, int *nauxfd) 291 { 292 struct ngdevice *dev = device2ng(d); 293 int sz = physical_MaxDeviceSize(); 294 295 iov[*niov].iov_base = realloc(d, sz); 296 if (iov[*niov].iov_base == NULL) { 297 log_Printf(LogALERT, "Failed to allocate memory: %d\n", sz); 298 AbortProgram(EX_OSERR); 299 } 300 iov[*niov].iov_len = sz; 301 (*niov)++; 302 303 *auxfd = dev->cs; 304 (*nauxfd)++; 305 } 306 307 static const struct device basengdevice = { 308 NG_DEVICE, 309 "netgraph", 310 0, 311 { CD_REQUIRED, DEF_NGCDDELAY }, 312 NULL, 313 ng_RemoveFromSet, 314 NULL, 315 NULL, 316 NULL, 317 NULL, 318 NULL, 319 ng_Free, 320 ng_Read, 321 ng_Write, 322 ng_device2iov, 323 NULL, 324 NULL, 325 NULL 326 }; 327 328 struct device * 329 ng_iov2device(int type, struct physical *p, struct iovec *iov, int *niov, 330 int maxiov __unused, int *auxfd, int *nauxfd) 331 { 332 if (type == NG_DEVICE) { 333 struct ngdevice *dev = (struct ngdevice *)iov[(*niov)++].iov_base; 334 335 dev = realloc(dev, sizeof *dev); /* Reduce to the correct size */ 336 if (dev == NULL) { 337 log_Printf(LogALERT, "Failed to allocate memory: %d\n", 338 (int)(sizeof *dev)); 339 AbortProgram(EX_OSERR); 340 } 341 342 if (*nauxfd) { 343 dev->cs = *auxfd; 344 (*nauxfd)--; 345 } else 346 dev->cs = -1; 347 348 /* Refresh function pointers etc */ 349 memcpy(&dev->dev, &basengdevice, sizeof dev->dev); 350 351 /* XXX: Are netgraph always synchronous ? */ 352 physical_SetupStack(p, dev->dev.name, PHYSICAL_FORCE_SYNCNOACF); 353 return &dev->dev; 354 } 355 356 return NULL; 357 } 358 359 static int 360 ng_UpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n) 361 { 362 struct physical *p = descriptor2physical(d); 363 struct ngdevice *dev = device2ng(p->handler); 364 int result; 365 366 switch (p->dl->state) { 367 case DATALINK_DIAL: 368 case DATALINK_LOGIN: 369 if (r) { 370 FD_SET(dev->cs, r); 371 log_Printf(LogTIMER, "%s(ctrl): fdset(r) %d\n", p->link.name, dev->cs); 372 result = 1; 373 } else 374 result = 0; 375 break; 376 377 default: 378 result = physical_doUpdateSet(d, r, w, e, n, 0); 379 break; 380 } 381 382 return result; 383 } 384 385 static int 386 ng_IsSet(struct fdescriptor *d, const fd_set *fdset) 387 { 388 struct physical *p = descriptor2physical(d); 389 struct ngdevice *dev = device2ng(p->handler); 390 int result; 391 392 result = dev->cs >= 0 && FD_ISSET(dev->cs, fdset); 393 result += physical_IsSet(d, fdset); 394 395 return result; 396 } 397 398 static void 399 ng_DescriptorRead(struct fdescriptor *d, struct bundle *bundle, 400 const fd_set *fdset) 401 { 402 struct physical *p = descriptor2physical(d); 403 struct ngdevice *dev = device2ng(p->handler); 404 405 if (dev->cs >= 0 && FD_ISSET(dev->cs, fdset)) 406 ng_MessageIn(p, NULL, 0); 407 408 if (physical_IsSet(d, fdset)) 409 physical_DescriptorRead(d, bundle, fdset); 410 } 411 412 static struct device * 413 ng_Abandon(struct ngdevice *dev, struct physical *p) 414 { 415 /* Abandon our node construction */ 416 close(dev->cs); 417 close(p->fd); 418 p->fd = -2; /* Nobody else need try.. */ 419 free(dev); 420 421 return NULL; 422 } 423 424 425 /* 426 * Populate the ``word'' (of size ``sz'') named ``what'' from ``from'' 427 * ending with any character from ``sep''. Point ``endp'' at the next 428 * word. 429 */ 430 431 #define GETSEGMENT(what, from, sep, endp) \ 432 getsegment(#what, (what), sizeof(what), from, sep, endp) 433 434 static int 435 getsegment(const char *what, char *word, size_t sz, const char *from, 436 const char *sep, const char **endp) 437 { 438 size_t len; 439 440 if ((len = strcspn(from, sep)) == 0) { 441 log_Printf(LogWARN, "%s name should not be empty !\n", what); 442 return 0; 443 } 444 445 if (len >= sz) { 446 log_Printf(LogWARN, "%s name too long, max %d !\n", what, sz - 1); 447 return 0; 448 } 449 450 strncpy(word, from, len); 451 word[len] = '\0'; 452 453 *endp = from + len; 454 *endp += strspn(*endp, sep); 455 456 return 1; 457 } 458 459 struct device * 460 ng_Create(struct physical *p) 461 { 462 struct sockaddr_ng ngsock; 463 u_char rbuf[2048]; 464 struct sockaddr *sock = (struct sockaddr *)&ngsock; 465 const struct hooklist *hlist; 466 const struct nodeinfo *ninfo; 467 const struct linkinfo *nlink; 468 struct ngdevice *dev; 469 struct ng_mesg *resp; 470 struct ngm_mkpeer mkp; 471 struct ngm_connect ngc; 472 const char *devp, *endp; 473 char lasthook[NG_HOOKSIZ]; 474 char hook[NG_HOOKSIZ]; 475 char nodetype[NG_TYPESIZ + NG_NODESIZ]; 476 char modname[NG_TYPESIZ + 3]; 477 char path[NG_PATHSIZ]; 478 char *nodename; 479 int len, sz, done; 480 unsigned f; 481 482 dev = NULL; 483 if (p->fd < 0 && !strncasecmp(p->name.full, NETGRAPH_PREFIX, 484 sizeof NETGRAPH_PREFIX - 1)) { 485 p->fd--; /* We own the device - change fd */ 486 487 if ((dev = malloc(sizeof *dev)) == NULL) 488 return NULL; 489 490 loadmodules(LOAD_VERBOSLY, "netgraph", "ng_socket", NULL); 491 492 /* Create a socket node */ 493 if (ID0NgMkSockNode(NULL, &dev->cs, &p->fd) == -1) { 494 log_Printf(LogWARN, "Cannot create netgraph socket node: %s\n", 495 strerror(errno)); 496 free(dev); 497 p->fd = -2; 498 return NULL; 499 } 500 501 devp = p->name.full + sizeof NETGRAPH_PREFIX - 1; 502 *lasthook = *path = '\0'; 503 log_Printf(LogDEBUG, "%s: Opening netgraph device \"%s\"\n", 504 p->link.name, devp); 505 done = 0; 506 507 while (*devp != '\0' && !done) { 508 if (*devp != '[') { 509 if (*lasthook == '\0') { 510 log_Printf(LogWARN, "%s: Netgraph devices must start with" 511 " [nodetype:nodename]\n", p->link.name); 512 return ng_Abandon(dev, p); 513 } 514 515 /* Get the hook name of the new node */ 516 if (!GETSEGMENT(hook, devp, ".[", &endp)) 517 return ng_Abandon(dev, p); 518 log_Printf(LogDEBUG, "%s: Got hook \"%s\"\n", p->link.name, hook); 519 devp = endp; 520 if (*devp == '\0') { 521 log_Printf(LogWARN, "%s: Netgraph device must not end with a second" 522 " hook\n", p->link.name); 523 return ng_Abandon(dev, p); 524 } 525 if (devp[-1] != '[') { 526 log_Printf(LogWARN, "%s: Expected a [nodetype:nodename] at device" 527 " pos %d\n", p->link.name, devp - p->link.name - 1); 528 return ng_Abandon(dev, p); 529 } 530 } else { 531 /* Use lasthook as the hook name */ 532 strcpy(hook, lasthook); 533 devp++; 534 } 535 536 /* We've got ``lasthook'' and ``hook'', get the node type */ 537 if (!GETSEGMENT(nodetype, devp, "]", &endp)) 538 return ng_Abandon(dev, p); 539 log_Printf(LogDEBUG, "%s: Got node \"%s\"\n", p->link.name, nodetype); 540 541 if ((nodename = strchr(nodetype, ':')) != NULL) { 542 *nodename++ = '\0'; 543 if (*nodename == '\0' && *nodetype == '\0') { 544 log_Printf(LogWARN, "%s: Empty [nodetype:nodename] at device" 545 " pos %d\n", p->link.name, devp - p->link.name - 1); 546 return ng_Abandon(dev, p); 547 } 548 } 549 550 /* Ignore optional colons after nodes */ 551 devp = *endp == ':' ? endp + 1 : endp; 552 if (*devp == '.') 553 devp++; 554 555 if (*lasthook == '\0') { 556 /* This is the first node in the chain */ 557 if (nodename == NULL || *nodename == '\0') { 558 log_Printf(LogWARN, "%s: %s: No initial device nodename\n", 559 p->link.name, devp); 560 return ng_Abandon(dev, p); 561 } 562 563 if (*nodetype != '\0') { 564 /* Attempt to load the module */ 565 snprintf(modname, sizeof modname, "ng_%s", nodetype); 566 log_Printf(LogDEBUG, "%s: Attempting to load %s.ko\n", 567 p->link.name, modname); 568 loadmodules(LOAD_QUIETLY, modname, NULL); 569 } 570 571 snprintf(path, sizeof path, "%s:", nodename); 572 /* XXX: If we have a node type, ensure it's correct */ 573 } else { 574 /* 575 * Ask for a list of hooks attached to the previous node. If we 576 * find the one we're interested in, and if it's connected to a 577 * node of the right type using the correct hook, use that. 578 * If we find the hook connected to something else, fail. 579 * If we find no match, mkpeer the new node. 580 */ 581 if (*nodetype == '\0') { 582 log_Printf(LogWARN, "%s: Nodetype missing at device offset %d\n", 583 p->link.name, 584 devp - p->name.full + sizeof NETGRAPH_PREFIX - 1); 585 return ng_Abandon(dev, p); 586 } 587 588 /* Get a list of node hooks */ 589 if (NgSendMsg(dev->cs, path, NGM_GENERIC_COOKIE, NGM_LISTHOOKS, 590 NULL, 0) < 0) { 591 log_Printf(LogWARN, "%s: %s Cannot send a LISTHOOOKS message: %s\n", 592 p->link.name, path, strerror(errno)); 593 return ng_Abandon(dev, p); 594 } 595 596 /* Get our list back */ 597 resp = (struct ng_mesg *)rbuf; 598 if (NgRecvMsg(dev->cs, resp, sizeof rbuf, NULL) <= 0) { 599 log_Printf(LogWARN, "%s: Cannot get netgraph response: %s\n", 600 p->link.name, strerror(errno)); 601 return ng_Abandon(dev, p); 602 } 603 604 hlist = (const struct hooklist *)resp->data; 605 ninfo = &hlist->nodeinfo; 606 607 log_Printf(LogDEBUG, "List of netgraph node ``%s'' (id %x) hooks:\n", 608 path, ninfo->id); 609 610 /* look for a hook already attached. */ 611 for (f = 0; f < ninfo->hooks; f++) { 612 nlink = &hlist->link[f]; 613 614 log_Printf(LogDEBUG, " Found %s -> %s (type %s)\n", nlink->ourhook, 615 nlink->peerhook, nlink->nodeinfo.type); 616 617 if (!strcmp(nlink->ourhook, lasthook)) { 618 if (strcmp(nlink->peerhook, hook) || 619 strcmp(nlink->nodeinfo.type, nodetype)) { 620 log_Printf(LogWARN, "%s: hook %s:%s is already in use\n", 621 p->link.name, nlink->ourhook, path); 622 return ng_Abandon(dev, p); 623 } 624 /* The node is already hooked up nicely.... reuse it */ 625 break; 626 } 627 } 628 629 if (f == ninfo->hooks) { 630 /* Attempt to load the module */ 631 snprintf(modname, sizeof modname, "ng_%s", nodetype); 632 log_Printf(LogDEBUG, "%s: Attempting to load %s.ko\n", 633 p->link.name, modname); 634 loadmodules(LOAD_QUIETLY, modname, NULL); 635 636 /* Create (mkpeer) the new node */ 637 638 snprintf(mkp.type, sizeof mkp.type, "%s", nodetype); 639 snprintf(mkp.ourhook, sizeof mkp.ourhook, "%s", lasthook); 640 snprintf(mkp.peerhook, sizeof mkp.peerhook, "%s", hook); 641 642 log_Printf(LogDEBUG, "%s: Doing MKPEER %s%s -> %s (type %s)\n", 643 p->link.name, path, mkp.ourhook, mkp.peerhook, nodetype); 644 645 if (NgSendMsg(dev->cs, path, NGM_GENERIC_COOKIE, 646 NGM_MKPEER, &mkp, sizeof mkp) < 0) { 647 log_Printf(LogWARN, "%s Cannot create %s netgraph node: %s\n", 648 path, nodetype, strerror(errno)); 649 return ng_Abandon(dev, p); 650 } 651 } 652 len = strlen(path); 653 snprintf(path + len, sizeof path - len, "%s%s", 654 path[len - 1] == ':' ? "" : ".", lasthook); 655 } 656 657 /* Get a list of node hooks */ 658 if (NgSendMsg(dev->cs, path, NGM_GENERIC_COOKIE, NGM_LISTHOOKS, 659 NULL, 0) < 0) { 660 log_Printf(LogWARN, "%s: %s Cannot send a LISTHOOOKS message: %s\n", 661 p->link.name, path, strerror(errno)); 662 return ng_Abandon(dev, p); 663 } 664 665 /* Get our list back */ 666 resp = (struct ng_mesg *)rbuf; 667 if (NgRecvMsg(dev->cs, resp, sizeof rbuf, NULL) <= 0) { 668 log_Printf(LogWARN, "%s: Cannot get netgraph response: %s\n", 669 p->link.name, strerror(errno)); 670 return ng_Abandon(dev, p); 671 } 672 673 hlist = (const struct hooklist *)resp->data; 674 ninfo = &hlist->nodeinfo; 675 676 if (*lasthook != '\0' && nodename != NULL && *nodename != '\0' && 677 strcmp(ninfo->name, nodename) && 678 NgNameNode(dev->cs, path, "%s", nodename) < 0) { 679 log_Printf(LogWARN, "%s: %s: Cannot name netgraph node: %s\n", 680 p->link.name, path, strerror(errno)); 681 return ng_Abandon(dev, p); 682 } 683 684 if (!GETSEGMENT(lasthook, devp, " \t.[", &endp)) 685 return ng_Abandon(dev, p); 686 log_Printf(LogDEBUG, "%s: Got hook \"%s\"\n", p->link.name, lasthook); 687 688 len = strlen(lasthook); 689 done = strchr(" \t", devp[len]) ? 1 : 0; 690 devp = endp; 691 692 if (*devp != '\0') { 693 if (devp[-1] == '[') 694 devp--; 695 } /* else should moan about devp[-1] being '[' ? */ 696 } 697 698 snprintf(dev->hook, sizeof dev->hook, "%s", lasthook); 699 700 /* Connect the node to our socket node */ 701 snprintf(ngc.path, sizeof ngc.path, "%s", path); 702 snprintf(ngc.ourhook, sizeof ngc.ourhook, "%s", dev->hook); 703 memcpy(ngc.peerhook, ngc.ourhook, sizeof ngc.peerhook); 704 705 log_Printf(LogDEBUG, "Connecting netgraph socket .:%s -> %s.%s\n", 706 ngc.ourhook, ngc.path, ngc.peerhook); 707 if (NgSendMsg(dev->cs, ".:", NGM_GENERIC_COOKIE, 708 NGM_CONNECT, &ngc, sizeof ngc) < 0) { 709 log_Printf(LogWARN, "Cannot connect %s and socket netgraph " 710 "nodes: %s\n", path, strerror(errno)); 711 return ng_Abandon(dev, p); 712 } 713 714 /* Hook things up so that we monitor dev->cs */ 715 p->desc.UpdateSet = ng_UpdateSet; 716 p->desc.IsSet = ng_IsSet; 717 p->desc.Read = ng_DescriptorRead; 718 719 memcpy(&dev->dev, &basengdevice, sizeof dev->dev); 720 721 } else { 722 /* See if we're a netgraph socket */ 723 724 sz = sizeof ngsock; 725 if (getsockname(p->fd, sock, &sz) != -1 && sock->sa_family == AF_NETGRAPH) { 726 /* 727 * It's a netgraph node... We can't determine hook names etc, so we 728 * stay pretty impartial.... 729 */ 730 log_Printf(LogPHASE, "%s: Link is a netgraph node\n", p->link.name); 731 732 if ((dev = malloc(sizeof *dev)) == NULL) { 733 log_Printf(LogWARN, "%s: Cannot allocate an ether device: %s\n", 734 p->link.name, strerror(errno)); 735 return NULL; 736 } 737 738 memcpy(&dev->dev, &basengdevice, sizeof dev->dev); 739 dev->cs = -1; 740 *dev->hook = '\0'; 741 } 742 } 743 744 if (dev) { 745 physical_SetupStack(p, dev->dev.name, PHYSICAL_FORCE_SYNCNOACF); 746 return &dev->dev; 747 } 748 749 return NULL; 750 } 751