1 /*- 2 * Copyright (c) 2000 Brian Somers <brian (at) 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.6.10.1.4.1 2010/12/21 17:10:29 kensmith Exp $ 27 */ 28 29 #include <sys/param.h> 30 #include <sys/socket.h> 31 #include <sys/un.h> 32 #include <netinet/in.h> 33 #include <arpa/inet.h> 34 #include <netdb.h> 35 #include <netgraph.h> 36 #include <net/ethernet.h> 37 #include <netinet/in_systm.h> 38 #include <netinet/ip.h> 39 #include <netgraph/ng_ether.h> 40 #include <netgraph/ng_message.h> 41 #include <netgraph/ng_socket.h> 42 43 #include <errno.h> 44 #include <stdio.h> 45 #include <stdlib.h> 46 #include <string.h> 47 #include <sysexits.h> 48 #include <sys/fcntl.h> 49 #include <sys/uio.h> 50 #include <termios.h> 51 #include <sys/time.h> 52 #include <unistd.h> 53 54 #include "layer.h" 55 #include "defs.h" 56 #include "mbuf.h" 57 #include "log.h" 58 #include "timer.h" 59 #include "lqr.h" 60 #include "hdlc.h" 61 #include "throughput.h" 62 #include "fsm.h" 63 #include "lcp.h" 64 #include "ccp.h" 65 #include "link.h" 66 #include "async.h" 67 #include "descriptor.h" 68 #include "physical.h" 69 #include "main.h" 70 #include "mp.h" 71 #include "chat.h" 72 #include "auth.h" 73 #include "chap.h" 74 #include "cbcp.h" 75 #include "datalink.h" 76 #include "slcompress.h" 77 #include "iplist.h" 78 #include "ncpaddr.h" 79 #include "ipcp.h" 80 #include "ipv6cp.h" 81 #include "ncp.h" 82 #include "filter.h" 83 #ifndef NORADIUS 84 #include "radius.h" 85 #endif 86 #include "bundle.h" 87 #include "id.h" 88 #include "netgraph.h" 89 90 91 struct ngdevice { 92 struct device dev; /* What struct physical knows about */ 93 int cs; /* Control socket */ 94 char hook[NG_HOOKSIZ]; /* Our socket node hook */ 95 }; 96 97 #define device2ng(d) ((d)->type == NG_DEVICE ? (struct ngdevice *)d : NULL) 98 #define NG_MSGBUFSZ 4096 99 #define NETGRAPH_PREFIX "netgraph:" 100 101 unsigned 102 ng_DeviceSize(void) 103 { 104 return sizeof(struct ngdevice); 105 } 106 107 static int 108 ng_MessageOut(struct ngdevice *dev, const char *data) 109 { 110 char path[NG_PATHSIZ]; 111 char *fmt; 112 size_t len; 113 int pos, dpos; 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 < (int)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 size_t 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, v) ? (ssize_t)n : -1; 229 } 230 return NgSendData(p->fd, dev->hook, v, n) == -1 ? -1 : (ssize_t)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 switch (p->dl->state) { 239 case DATALINK_DIAL: 240 case DATALINK_LOGIN: 241 return ng_MessageIn(p, v, n); 242 } 243 244 return NgRecvData(p->fd, v, n, hook); 245 } 246 247 static int 248 ng_RemoveFromSet(struct physical *p, fd_set *r, fd_set *w, fd_set *e) 249 { 250 struct ngdevice *dev = device2ng(p->handler); 251 int result; 252 253 if (r && dev->cs >= 0 && FD_ISSET(dev->cs, r)) { 254 FD_CLR(dev->cs, r); 255 log_Printf(LogTIMER, "%s: fdunset(ctrl) %d\n", p->link.name, dev->cs); 256 result = 1; 257 } else 258 result = 0; 259 260 /* Careful... physical_RemoveFromSet() called us ! */ 261 262 p->handler->removefromset = NULL; 263 result += physical_RemoveFromSet(p, r, w, e); 264 p->handler->removefromset = ng_RemoveFromSet; 265 266 return result; 267 } 268 269 static void 270 ng_Free(struct physical *p) 271 { 272 struct ngdevice *dev = device2ng(p->handler); 273 274 physical_SetDescriptor(p); 275 if (dev->cs != -1) 276 close(dev->cs); 277 free(dev); 278 } 279 280 static void 281 ng_device2iov(struct device *d, struct iovec *iov, int *niov, 282 int maxiov __unused, int *auxfd, int *nauxfd) 283 { 284 struct ngdevice *dev; 285 int sz = physical_MaxDeviceSize(); 286 287 iov[*niov].iov_base = d = realloc(d, sz); 288 if (d == NULL) { 289 log_Printf(LogALERT, "Failed to allocate memory: %d\n", sz); 290 AbortProgram(EX_OSERR); 291 } 292 iov[*niov].iov_len = sz; 293 (*niov)++; 294 295 dev = device2ng(d); 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 __unused, 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 size_t 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; 473 unsigned f; 474 475 dev = NULL; 476 if (p->fd < 0 && !strncasecmp(p->name.full, NETGRAPH_PREFIX, 477 sizeof NETGRAPH_PREFIX - 1)) { 478 p->fd--; /* We own the device - change fd */ 479 480 if ((dev = malloc(sizeof *dev)) == NULL) 481 return NULL; 482 483 loadmodules(LOAD_VERBOSLY, "netgraph", "ng_socket", NULL); 484 485 /* Create a socket node */ 486 if (ID0NgMkSockNode(NULL, &dev->cs, &p->fd) == -1) { 487 log_Printf(LogWARN, "Cannot create netgraph socket node: %s\n", 488 strerror(errno)); 489 free(dev); 490 p->fd = -2; 491 return NULL; 492 } 493 494 devp = p->name.full + sizeof NETGRAPH_PREFIX - 1; 495 *lasthook = *path = '\0'; 496 log_Printf(LogDEBUG, "%s: Opening netgraph device \"%s\"\n", 497 p->link.name, devp); 498 done = 0; 499 500 while (*devp != '\0' && !done) { 501 if (*devp != '[') { 502 if (*lasthook == '\0') { 503 log_Printf(LogWARN, "%s: Netgraph devices must start with" 504 " [nodetype:nodename]\n", p->link.name); 505 return ng_Abandon(dev, p); 506 } 507 508 /* Get the hook name of the new node */ 509 if (!GETSEGMENT(hook, devp, ".[", &endp)) 510 return ng_Abandon(dev, p); 511 log_Printf(LogDEBUG, "%s: Got hook \"%s\"\n", p->link.name, hook); 512 devp = endp; 513 if (*devp == '\0') { 514 log_Printf(LogWARN, "%s: Netgraph device must not end with a second" 515 " hook\n", p->link.name); 516 return ng_Abandon(dev, p); 517 } 518 if (devp[-1] != '[') { 519 log_Printf(LogWARN, "%s: Expected a [nodetype:nodename] at device" 520 " pos %d\n", p->link.name, devp - p->link.name - 1); 521 return ng_Abandon(dev, p); 522 } 523 } else { 524 /* Use lasthook as the hook name */ 525 strcpy(hook, lasthook); 526 devp++; 527 } 528 529 /* We've got ``lasthook'' and ``hook'', get the node type */ 530 if (!GETSEGMENT(nodetype, devp, "]", &endp)) 531 return ng_Abandon(dev, p); 532 log_Printf(LogDEBUG, "%s: Got node \"%s\"\n", p->link.name, nodetype); 533 534 if ((nodename = strchr(nodetype, ':')) != NULL) { 535 *nodename++ = '\0'; 536 if (*nodename == '\0' && *nodetype == '\0') { 537 log_Printf(LogWARN, "%s: Empty [nodetype:nodename] at device" 538 " pos %d\n", p->link.name, devp - p->link.name - 1); 539 return ng_Abandon(dev, p); 540 } 541 } 542 543 /* Ignore optional colons after nodes */ 544 devp = *endp == ':' ? endp + 1 : endp; 545 if (*devp == '.') 546 devp++; 547 548 if (*lasthook == '\0') { 549 /* This is the first node in the chain */ 550 if (nodename == NULL || *nodename == '\0') { 551 log_Printf(LogWARN, "%s: %s: No initial device nodename\n", 552 p->link.name, devp); 553 return ng_Abandon(dev, p); 554 } 555 556 if (*nodetype != '\0') { 557 /* Attempt to load the module */ 558 snprintf(modname, sizeof modname, "ng_%s", nodetype); 559 log_Printf(LogDEBUG, "%s: Attempting to load %s.ko\n", 560 p->link.name, modname); 561 loadmodules(LOAD_QUIETLY, modname, NULL); 562 } 563 564 snprintf(path, sizeof path, "%s:", nodename); 565 /* XXX: If we have a node type, ensure it's correct */ 566 } else { 567 /* 568 * Ask for a list of hooks attached to the previous node. If we 569 * find the one we're interested in, and if it's connected to a 570 * node of the right type using the correct hook, use that. 571 * If we find the hook connected to something else, fail. 572 * If we find no match, mkpeer the new node. 573 */ 574 if (*nodetype == '\0') { 575 log_Printf(LogWARN, "%s: Nodetype missing at device offset %d\n", 576 p->link.name, 577 devp - p->name.full + sizeof NETGRAPH_PREFIX - 1); 578 return ng_Abandon(dev, p); 579 } 580 581 /* Get a list of node hooks */ 582 if (NgSendMsg(dev->cs, path, NGM_GENERIC_COOKIE, NGM_LISTHOOKS, 583 NULL, 0) < 0) { 584 log_Printf(LogWARN, "%s: %s Cannot send a LISTHOOOKS message: %s\n", 585 p->link.name, path, strerror(errno)); 586 return ng_Abandon(dev, p); 587 } 588 589 /* Get our list back */ 590 resp = (struct ng_mesg *)rbuf; 591 if (NgRecvMsg(dev->cs, resp, sizeof rbuf, NULL) <= 0) { 592 log_Printf(LogWARN, "%s: Cannot get netgraph response: %s\n", 593 p->link.name, strerror(errno)); 594 return ng_Abandon(dev, p); 595 } 596 597 hlist = (const struct hooklist *)resp->data; 598 ninfo = &hlist->nodeinfo; 599 600 log_Printf(LogDEBUG, "List of netgraph node ``%s'' (id %x) hooks:\n", 601 path, ninfo->id); 602 603 /* look for a hook already attached. */ 604 for (f = 0; f < ninfo->hooks; f++) { 605 nlink = &hlist->link[f]; 606 607 log_Printf(LogDEBUG, " Found %s -> %s (type %s)\n", nlink->ourhook, 608 nlink->peerhook, nlink->nodeinfo.type); 609 610 if (!strcmp(nlink->ourhook, lasthook)) { 611 if (strcmp(nlink->peerhook, hook) || 612 strcmp(nlink->nodeinfo.type, nodetype)) { 613 log_Printf(LogWARN, "%s: hook %s:%s is already in use\n", 614 p->link.name, nlink->ourhook, path); 615 return ng_Abandon(dev, p); 616 } 617 /* The node is already hooked up nicely.... reuse it */ 618 break; 619 } 620 } 621 622 if (f == ninfo->hooks) { 623 /* Attempt to load the module */ 624 snprintf(modname, sizeof modname, "ng_%s", nodetype); 625 log_Printf(LogDEBUG, "%s: Attempting to load %s.ko\n", 626 p->link.name, modname); 627 loadmodules(LOAD_QUIETLY, modname, NULL); 628 629 /* Create (mkpeer) the new node */ 630 631 snprintf(mkp.type, sizeof mkp.type, "%s", nodetype); 632 snprintf(mkp.ourhook, sizeof mkp.ourhook, "%s", lasthook); 633 snprintf(mkp.peerhook, sizeof mkp.peerhook, "%s", hook); 634 635 log_Printf(LogDEBUG, "%s: Doing MKPEER %s%s -> %s (type %s)\n", 636 p->link.name, path, mkp.ourhook, mkp.peerhook, nodetype); 637 638 if (NgSendMsg(dev->cs, path, NGM_GENERIC_COOKIE, 639 NGM_MKPEER, &mkp, sizeof mkp) < 0) { 640 log_Printf(LogWARN, "%s Cannot create %s netgraph node: %s\n", 641 path, nodetype, strerror(errno)); 642 return ng_Abandon(dev, p); 643 } 644 } 645 len = strlen(path); 646 snprintf(path + len, sizeof path - len, "%s%s", 647 path[len - 1] == ':' ? "" : ".", lasthook); 648 } 649 650 /* Get a list of node hooks */ 651 if (NgSendMsg(dev->cs, path, NGM_GENERIC_COOKIE, NGM_LISTHOOKS, 652 NULL, 0) < 0) { 653 log_Printf(LogWARN, "%s: %s Cannot send a LISTHOOOKS message: %s\n", 654 p->link.name, path, strerror(errno)); 655 return ng_Abandon(dev, p); 656 } 657 658 /* Get our list back */ 659 resp = (struct ng_mesg *)rbuf; 660 if (NgRecvMsg(dev->cs, resp, sizeof rbuf, NULL) <= 0) { 661 log_Printf(LogWARN, "%s: Cannot get netgraph response: %s\n", 662 p->link.name, strerror(errno)); 663 return ng_Abandon(dev, p); 664 } 665 666 hlist = (const struct hooklist *)resp->data; 667 ninfo = &hlist->nodeinfo; 668 669 if (*lasthook != '\0' && nodename != NULL && *nodename != '\0' && 670 strcmp(ninfo->name, nodename) && 671 NgNameNode(dev->cs, path, "%s", nodename) < 0) { 672 log_Printf(LogWARN, "%s: %s: Cannot name netgraph node: %s\n", 673 p->link.name, path, strerror(errno)); 674 return ng_Abandon(dev, p); 675 } 676 677 if (!GETSEGMENT(lasthook, devp, " \t.[", &endp)) 678 return ng_Abandon(dev, p); 679 log_Printf(LogDEBUG, "%s: Got hook \"%s\"\n", p->link.name, lasthook); 680 681 len = strlen(lasthook); 682 done = strchr(" \t", devp[len]) ? 1 : 0; 683 devp = endp; 684 685 if (*devp != '\0') { 686 if (devp[-1] == '[') 687 devp--; 688 } /* else should moan about devp[-1] being '[' ? */ 689 } 690 691 snprintf(dev->hook, sizeof dev->hook, "%s", lasthook); 692 693 /* Connect the node to our socket node */ 694 snprintf(ngc.path, sizeof ngc.path, "%s", path); 695 snprintf(ngc.ourhook, sizeof ngc.ourhook, "%s", dev->hook); 696 memcpy(ngc.peerhook, ngc.ourhook, sizeof ngc.peerhook); 697 698 log_Printf(LogDEBUG, "Connecting netgraph socket .:%s -> %s.%s\n", 699 ngc.ourhook, ngc.path, ngc.peerhook); 700 if (NgSendMsg(dev->cs, ".:", NGM_GENERIC_COOKIE, 701 NGM_CONNECT, &ngc, sizeof ngc) < 0) { 702 log_Printf(LogWARN, "Cannot connect %s and socket netgraph " 703 "nodes: %s\n", path, strerror(errno)); 704 return ng_Abandon(dev, p); 705 } 706 707 /* Hook things up so that we monitor dev->cs */ 708 p->desc.UpdateSet = ng_UpdateSet; 709 p->desc.IsSet = ng_IsSet; 710 p->desc.Read = ng_DescriptorRead; 711 712 memcpy(&dev->dev, &basengdevice, sizeof dev->dev); 713 714 } else { 715 /* See if we're a netgraph socket */ 716 717 sz = sizeof ngsock; 718 if (getsockname(p->fd, sock, &sz) != -1 && sock->sa_family == AF_NETGRAPH) { 719 /* 720 * It's a netgraph node... We can't determine hook names etc, so we 721 * stay pretty impartial.... 722 */ 723 log_Printf(LogPHASE, "%s: Link is a netgraph node\n", p->link.name); 724 725 if ((dev = malloc(sizeof *dev)) == NULL) { 726 log_Printf(LogWARN, "%s: Cannot allocate an ether device: %s\n", 727 p->link.name, strerror(errno)); 728 return NULL; 729 } 730 731 memcpy(&dev->dev, &basengdevice, sizeof dev->dev); 732 dev->cs = -1; 733 *dev->hook = '\0'; 734 } 735 } 736 737 if (dev) { 738 physical_SetupStack(p, dev->dev.name, PHYSICAL_FORCE_SYNCNOACF); 739 return &dev->dev; 740 } 741 742 return NULL; 743 } 744