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