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