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