static int StatusCmd(int ac, char **av) { u_char sbuf[sizeof(struct ng_mesg) + NG_TEXTRESPONSE]; struct ng_mesg *const resp = (struct ng_mesg *) sbuf; char *const status = (char *) resp->data; char *path; int nostat = 0; /* Get arguments */ switch (ac) { case 2: path = av[1]; break; default: return (CMDRTN_USAGE); } /* Get node status summary */ if (NgSendMsg(csock, path, NGM_GENERIC_COOKIE, NGM_TEXT_STATUS, NULL, 0) < 0) { switch (errno) { case EINVAL: nostat = 1; break; default: warn("send msg"); return (CMDRTN_ERROR); } } else { if (NgRecvMsg(csock, resp, sizeof(sbuf), NULL) < 0 || (resp->header.flags & NGF_RESP) == 0) nostat = 1; } /* Show it */ if (nostat) printf("No status available for \"%s\"\n", path); else printf("Status for \"%s\":\n%s\n", path, status); return (CMDRTN_OK); }
static void do_show(int version, void (*func)(struct ngnf_show_header *)) { struct ng_mesg *ng_mesg; struct ngnf_show_header req, *resp; int token, nread; ng_mesg = alloca(SORCVBUF_SIZE); req.version = version; req.hash_id = req.list_id = 0; for (;;) { /* request set of accounting records */ token = NgSendMsg(cs, ng_path, NGM_NETFLOW_COOKIE, NGM_NETFLOW_SHOW, (void *)&req, sizeof(req)); if (token == -1) err(1, "NgSendMsg(NGM_NETFLOW_SHOW)"); /* read reply */ nread = NgRecvMsg(cs, ng_mesg, SORCVBUF_SIZE, NULL); if (nread == -1) err(1, "NgRecvMsg() failed"); if (ng_mesg->header.token != token) err(1, "NgRecvMsg(NGM_NETFLOW_SHOW): token mismatch"); resp = (struct ngnf_show_header *)ng_mesg->data; if ((ng_mesg->header.arglen < (sizeof(*resp))) || (ng_mesg->header.arglen < (sizeof(*resp) + (resp->nentries * sizeof(struct flow_entry_data))))) err(1, "NgRecvMsg(NGM_NETFLOW_SHOW): arglen too small"); (*func)(resp); if (resp->hash_id != 0) req.hash_id = resp->hash_id; else break; req.list_id = resp->list_id; } }
/* * Receive a control message and convert the arguments to ASCII */ int NgRecvAsciiMsg(int cs, struct ng_mesg *reply, size_t replen, char *path) { struct ng_mesg *msg, *ascii; int bufSize, errnosv; u_char *buf; /* Allocate buffer */ bufSize = 2 * sizeof(*reply) + replen; if ((buf = malloc(bufSize)) == NULL) return (-1); msg = (struct ng_mesg *)buf; ascii = (struct ng_mesg *)msg->data; /* Get binary message */ if (NgRecvMsg(cs, msg, bufSize, path) < 0) goto fail; memcpy(reply, msg, sizeof(*msg)); /* Ask originating node to convert the arguments to ASCII */ if (NgSendMsg(cs, path, NGM_GENERIC_COOKIE, NGM_BINARY2ASCII, msg, sizeof(*msg) + msg->header.arglen) < 0) goto fail; if (NgRecvMsg(cs, msg, bufSize, NULL) < 0) goto fail; /* Copy result to client buffer */ if (sizeof(*ascii) + ascii->header.arglen > replen) { errno = ERANGE; fail: errnosv = errno; free(buf); errno = errnosv; return (-1); } strncpy(reply->data, ascii->data, ascii->header.arglen); /* Done */ free(buf); return (0); }
/* * Read and display the next incoming control message */ void MsgRead(void) { struct ng_mesg *m, *m2; struct ng_mesg *ascii; char path[NG_PATHSIZ]; /* Get incoming message (in binary form) */ if (NgAllocRecvMsg(csock, &m, path) < 0) { warn("recv incoming message"); return; } /* Ask originating node to convert message to ASCII */ if (NgSendMsg(csock, path, NGM_GENERIC_COOKIE, NGM_BINARY2ASCII, m, sizeof(*m) + m->header.arglen) < 0 || NgAllocRecvMsg(csock, &m2, NULL) < 0) { printf("Rec'd %s %d from \"%s\":\n", (m->header.flags & NGF_RESP) != 0 ? "response" : "command", m->header.cmd, path); if (m->header.arglen == 0) printf("No arguments\n"); else DumpAscii((const u_char *)m->data, m->header.arglen); free(m); return; } /* Display message in ASCII form */ free(m); ascii = (struct ng_mesg *)m2->data; printf("Rec'd %s \"%s\" (%d) from \"%s\":\n", (ascii->header.flags & NGF_RESP) != 0 ? "response" : "command", ascii->header.cmdstr, ascii->header.cmd, path); if (*ascii->data != '\0') printf("Args:\t%s\n", ascii->data); else printf("No arguments\n"); free(m2); }
static int ShutdownCmd(int ac, char **av) { char *path; /* Get arguments */ switch (ac) { case 2: path = av[1]; break; default: return (CMDRTN_USAGE); } /* Shutdown node */ if (NgSendMsg(csock, path, NGM_GENERIC_COOKIE, NGM_SHUTDOWN, NULL, 0) < 0) { warn("shutdown"); return (CMDRTN_ERROR); } return (CMDRTN_OK); }
/* * Assign a globally unique name to a node * Returns -1 if error and sets errno. */ int NgNameNode(int cs, const char *path, const char *fmt, ...) { struct ngm_name ngn; va_list args; /* Build message arg */ va_start(args, fmt); vsnprintf(ngn.name, sizeof(ngn.name), fmt, args); va_end(args); /* Send message */ if (NgSendMsg(cs, path, NGM_GENERIC_COOKIE, NGM_NAME, &ngn, sizeof(ngn)) < 0) { if (_gNgDebugLevel >= 1) NGLOGX("%s: failed", __func__); return (-1); } /* Done */ return (0); }
int SetKsocketKeepAlive (char path[NG_PATHSIZ]) { union { u_char buf[sizeof(struct ng_ksocket_sockopt) + sizeof(int)]; struct ng_ksocket_sockopt sockopt; } sockopt_buf; struct ng_ksocket_sockopt * const sockopt = &sockopt_buf.sockopt; int one = 1; // setsockopt resolve TIME_WAIT problem // setsockopt(fd,SOL_SOCKET,SO_REUSEPORT,&one,sizeof(int)) < 0) memset(&sockopt_buf, 0, sizeof(sockopt_buf)); sockopt->level = SOL_SOCKET; sockopt->name = SO_KEEPALIVE; memcpy(sockopt->value, &one, sizeof(int)); if (NgSendMsg(csock, path, NGM_KSOCKET_COOKIE, NGM_KSOCKET_SETOPT, sockopt, sizeof(sockopt_buf)) == -1) { fprintf(stderr, "%s(): Sockopt set failed : %s\n", __FUNCTION__, strerror(errno)); return -1; } return 1; }
int GetKsocketReusePort (char path[NG_PATHSIZ]) { struct ng_ksocket_sockopt *sockopt_resp = malloc(sizeof(struct ng_ksocket_sockopt) + sizeof(int)); struct ng_mesg *resp; memset(sockopt_resp, 0, (sizeof(struct ng_ksocket_sockopt) + sizeof(int))); sockopt_resp->level = SOL_SOCKET; sockopt_resp->name = SO_REUSEPORT; if ( NgSendMsg(csock, path, NGM_KSOCKET_COOKIE, NGM_KSOCKET_GETOPT, sockopt_resp, sizeof(*sockopt_resp)) == -1 ) { printf("Error while trying to get sockopt from %s - %s\n", path, strerror(errno)); return 1; } if ( NgAllocRecvMsg(csock, &resp, 0 ) < 0 ) { fprintf(stderr, "Error while trying to get message from getsockopt: %s\n", strerror(errno)); return 1; } int *option = (int *)(((struct ng_ksocket_sockopt *)resp->data)->value); printf("REUSEPORT = %d\n", htons(*option)); free(sockopt_resp); free(resp); return 1; }
static int NameCmd(int ac, char **av) { struct ngm_name name; char *path; /* Get arguments */ switch (ac) { case 3: path = av[1]; snprintf(name.name, sizeof(name.name), "%s", av[2]); break; default: return (CMDRTN_USAGE); } /* Send message */ if (NgSendMsg(csock, path, NGM_GENERIC_COOKIE, NGM_NAME, &name, sizeof(name)) < 0) { warn("send msg"); return (CMDRTN_ERROR); } return (CMDRTN_OK); }
void netgraphprotopr(u_long off, const char *name, int af1 __unused, int proto __unused) { struct ngpcb *this, *next; struct ngpcb ngpcb; struct socket sockb; int debug = 1; /* If symbol not found, try looking in the KLD module */ if (off == 0) { if (debug) fprintf(stderr, "Error reading symbols from ng_socket.ko"); return; } /* Get pointer to first socket */ kread(off, (char *)&this, sizeof(this)); /* Get my own socket node */ if (csock == -1) NgMkSockNode(NULL, &csock, NULL); for (; this != NULL; this = next) { u_char rbuf[sizeof(struct ng_mesg) + sizeof(struct nodeinfo)]; struct ng_mesg *resp = (struct ng_mesg *) rbuf; struct nodeinfo *ni = (struct nodeinfo *) resp->data; char path[64]; /* Read in ngpcb structure */ kread((u_long)this, (char *)&ngpcb, sizeof(ngpcb)); next = LIST_NEXT(&ngpcb, socks); /* Read in socket structure */ kread((u_long)ngpcb.ng_socket, (char *)&sockb, sizeof(sockb)); /* Check type of socket */ if (strcmp(name, "ctrl") == 0 && ngpcb.type != NG_CONTROL) continue; if (strcmp(name, "data") == 0 && ngpcb.type != NG_DATA) continue; /* Do headline */ if (first) { printf("Netgraph sockets\n"); if (Aflag) printf("%-8.8s ", "PCB"); printf("%-5.5s %-6.6s %-6.6s %-14.14s %s\n", "Type", "Recv-Q", "Send-Q", "Node Address", "#Hooks"); first = 0; } /* Show socket */ if (Aflag) printf("%8lx ", (u_long) this); printf("%-5.5s %6u %6u ", name, sockb.so_rcv.sb_cc, sockb.so_snd.sb_cc); /* Get info on associated node */ if (ngpcb.node_id == 0 || csock == -1) goto finish; snprintf(path, sizeof(path), "[%x]:", ngpcb.node_id); if (NgSendMsg(csock, path, NGM_GENERIC_COOKIE, NGM_NODEINFO, NULL, 0) < 0) goto finish; if (NgRecvMsg(csock, resp, sizeof(rbuf), NULL) < 0) goto finish; /* Display associated node info */ if (*ni->name != '\0') snprintf(path, sizeof(path), "%s:", ni->name); printf("%-14.14s %4d", path, ni->hooks); finish: putchar('\n'); } }
static int ConfigureNode(const char *prog, const char *iface, const char *provider, int cs, int ds, int debug, struct ngm_connect *ngc) { /* * We're going to do this with the passed `ds' & `cs' descriptors: * * .---------. * | ether | * | <iface> | * `---------' * (orphan) ds cs * | | | * | | | * (ethernet) | | * .---------. .-----------. * | pppoe | | socket | * | <iface> |(pppoe-<pid>)<---->(pppoe-<pid>)| <unnamed> | * `--------- `-----------' * (exec-<pid>) * ^ .-----------. .-------------. * | | socket | | ppp -direct | * `--->(exec-<pid>)| <unnamed> |--fd--| provider | * `-----------' `-------------' * * where there are potentially many ppp processes running off of the * same PPPoE node. * The exec-<pid> hook isn't made 'till we Spawn(). */ char *epath, *spath; struct ngpppoe_init_data *data; const struct hooklist *hlist; const struct nodeinfo *ninfo; const struct linkinfo *nlink; struct ngm_mkpeer mkp; struct ng_mesg *resp; u_char rbuf[2048]; int f, plen; /* * Ask for a list of hooks attached to the "ether" node. This node should * magically exist as a way of hooking stuff onto an ethernet device */ epath = (char *)alloca(strlen(iface) + 2); sprintf(epath, "%s:", iface); if (debug) fprintf(stderr, "Sending NGM_LISTHOOKS to %s\n", epath); if (NgSendMsg(cs, epath, NGM_GENERIC_COOKIE, NGM_LISTHOOKS, NULL, 0) < 0) { if (errno == ENOENT) fprintf(stderr, "%s Cannot send a netgraph message: Invalid interface\n", epath); else fprintf(stderr, "%s Cannot send a netgraph message: %s\n", epath, strerror(errno)); return EX_UNAVAILABLE; } /* Get our list back */ resp = (struct ng_mesg *)rbuf; if (NgRecvMsg(cs, resp, sizeof rbuf, NULL) <= 0) { perror("Cannot get netgraph response"); return EX_UNAVAILABLE; } hlist = (const struct hooklist *)resp->data; ninfo = &hlist->nodeinfo; if (debug) fprintf(stderr, "Got reply from id [%x]: Type %s with %d hooks\n", ninfo->id, ninfo->type, ninfo->hooks); /* Make sure we've got the right type of node */ if (strncmp(ninfo->type, NG_ETHER_NODE_TYPE, sizeof NG_ETHER_NODE_TYPE - 1)) { fprintf(stderr, "%s Unexpected node type ``%s'' (wanted ``" NG_ETHER_NODE_TYPE "'')\n", epath, ninfo->type); return EX_DATAERR; } /* look for a hook already attached. */ for (f = 0; f < ninfo->hooks; f++) { nlink = &hlist->link[f]; if (debug) fprintf(stderr, " Got [%x]:%s -> [%x]:%s\n", ninfo->id, nlink->ourhook, nlink->nodeinfo.id, nlink->peerhook); if (!strcmp(nlink->ourhook, NG_ETHER_HOOK_ORPHAN) || !strcmp(nlink->ourhook, NG_ETHER_HOOK_DIVERT)) { /* * Something is using the data coming out of this `ether' node. * If it's a PPPoE node, we use that node, otherwise we complain that * someone else is using the node. */ if (strcmp(nlink->nodeinfo.type, NG_PPPOE_NODE_TYPE)) { fprintf(stderr, "%s Node type %s is currently active\n", epath, nlink->nodeinfo.type); return EX_UNAVAILABLE; } break; } } if (f == ninfo->hooks) { /* * Create a new PPPoE node connected to the `ether' node using * the magic `orphan' and `ethernet' hooks */ snprintf(mkp.type, sizeof mkp.type, "%s", NG_PPPOE_NODE_TYPE); snprintf(mkp.ourhook, sizeof mkp.ourhook, "%s", NG_ETHER_HOOK_ORPHAN); snprintf(mkp.peerhook, sizeof mkp.peerhook, "%s", NG_PPPOE_HOOK_ETHERNET); if (debug) fprintf(stderr, "Send MKPEER: %s%s -> [type %s]:%s\n", epath, mkp.ourhook, mkp.type, mkp.peerhook); if (NgSendMsg(cs, epath, NGM_GENERIC_COOKIE, NGM_MKPEER, &mkp, sizeof mkp) < 0) { fprintf(stderr, "%s Cannot create a peer PPPoE node: %s\n", epath, strerror(errno)); return EX_OSERR; } } /* Connect the PPPoE node to our socket node. */ snprintf(ngc->path, sizeof ngc->path, "%s%s", epath, NG_ETHER_HOOK_ORPHAN); snprintf(ngc->ourhook, sizeof ngc->ourhook, "pppoe-%ld", (long)getpid()); memcpy(ngc->peerhook, ngc->ourhook, sizeof ngc->peerhook); if (NgSendMsg(cs, ".:", NGM_GENERIC_COOKIE, NGM_CONNECT, ngc, sizeof *ngc) < 0) { perror("Cannot CONNECT PPPoE and socket nodes"); return EX_OSERR; } plen = strlen(provider); data = (struct ngpppoe_init_data *)alloca(sizeof *data + plen); snprintf(data->hook, sizeof data->hook, "%s", ngc->peerhook); memcpy(data->data, provider, plen); data->data_len = plen; spath = (char *)alloca(strlen(ngc->peerhook) + 3); strcpy(spath, ".:"); strcpy(spath + 2, ngc->ourhook); if (debug) { if (provider) fprintf(stderr, "Sending PPPOE_LISTEN to %s, provider %s\n", spath, provider); else fprintf(stderr, "Sending PPPOE_LISTEN to %s\n", spath); } if (NgSendMsg(cs, spath, NGM_PPPOE_COOKIE, NGM_PPPOE_LISTEN, data, sizeof *data + plen) == -1) { fprintf(stderr, "%s: Cannot LISTEN on netgraph node: %s\n", spath, strerror(errno)); return EX_OSERR; } return 0; }
static void Spawn(const char *prog, const char *acname, const char *provider, const char *exec, struct ngm_connect ngc, int cs, int ds, void *request, int sz, int debug) { char msgbuf[sizeof(struct ng_mesg) + sizeof(struct ngpppoe_sts)]; struct ng_mesg *rep = (struct ng_mesg *)msgbuf; struct ngpppoe_sts *sts = (struct ngpppoe_sts *)(msgbuf + sizeof *rep); struct ngpppoe_init_data *data; char env[18], unknown[14], sessionid[5], *path; unsigned char *macaddr; const char *msg; int ret, slen; switch ((ret = fork())) { case -1: syslog(LOG_ERR, "fork: %m"); break; case 0: switch (fork()) { case 0: break; case -1: _exit(errno); default: _exit(0); } close(cs); close(ds); /* Create a new socket node */ if (debug) syslog(LOG_INFO, "Creating a new socket node"); if (NgMkSockNode(NULL, &cs, &ds) == -1) { syslog(LOG_ERR, "Cannot create netgraph socket node: %m"); _exit(EX_CANTCREAT); } /* Connect the PPPoE node to our new socket node. */ snprintf(ngc.ourhook, sizeof ngc.ourhook, "exec-%ld", (long)getpid()); memcpy(ngc.peerhook, ngc.ourhook, sizeof ngc.peerhook); if (debug) syslog(LOG_INFO, "Sending CONNECT from .:%s -> %s.%s", ngc.ourhook, ngc.path, ngc.peerhook); if (NgSendMsg(cs, ".:", NGM_GENERIC_COOKIE, NGM_CONNECT, &ngc, sizeof ngc) < 0) { syslog(LOG_ERR, "Cannot CONNECT PPPoE and socket nodes: %m"); _exit(EX_OSERR); } /* * If we tell the socket node not to LINGER, it will go away when * the last hook is removed. */ if (debug) syslog(LOG_INFO, "Sending NGM_SOCK_CMD_NOLINGER to socket"); if (NgSendMsg(cs, ".:", NGM_SOCKET_COOKIE, NGM_SOCK_CMD_NOLINGER, NULL, 0) < 0) { syslog(LOG_ERR, "Cannot send NGM_SOCK_CMD_NOLINGER: %m"); _exit(EX_OSERR); } /* Put the PPPoE node into OFFER mode */ slen = strlen(acname); data = (struct ngpppoe_init_data *)alloca(sizeof *data + slen); snprintf(data->hook, sizeof data->hook, "%s", ngc.ourhook); memcpy(data->data, acname, slen); data->data_len = slen; path = (char *)alloca(strlen(ngc.ourhook) + 3); strcpy(path, ".:"); strcpy(path + 2, ngc.ourhook); syslog(LOG_INFO, "Offering to %s as access concentrator %s", path, acname); if (NgSendMsg(cs, path, NGM_PPPOE_COOKIE, NGM_PPPOE_OFFER, data, sizeof *data + slen) == -1) { syslog(LOG_INFO, "%s: Cannot OFFER on netgraph node: %m", path); _exit(EX_OSERR); } /* If we have a provider code, set it */ if (provider) { slen = strlen(provider); data = (struct ngpppoe_init_data *)alloca(sizeof *data + slen); snprintf(data->hook, sizeof data->hook, "%s", ngc.ourhook); memcpy(data->data, provider, slen); data->data_len = slen; syslog(LOG_INFO, "adding to %s as offered service %s", path, acname); if (NgSendMsg(cs, path, NGM_PPPOE_COOKIE, NGM_PPPOE_SERVICE, data, sizeof *data + slen) == -1) { syslog(LOG_INFO, "%s: Cannot add service on netgraph node: %m", path); _exit(EX_OSERR); } } /* Put the peer's MAC address in the environment */ if (sz >= sizeof(struct ether_header)) { macaddr = ((struct ether_header *)request)->ether_shost; snprintf(env, sizeof(env), "%x:%x:%x:%x:%x:%x", macaddr[0], macaddr[1], macaddr[2], macaddr[3], macaddr[4], macaddr[5]); if (setenv(HISMACADDR, env, 1) != 0) syslog(LOG_INFO, "setenv: cannot set %s: %m", HISMACADDR); } /* And send our request data to the waiting node */ if (debug) syslog(LOG_INFO, "Sending original request to %s (%d bytes)", path, sz); if (NgSendData(ds, ngc.ourhook, request, sz) == -1) { syslog(LOG_ERR, "Cannot send original request to %s: %m", path); _exit(EX_OSERR); } /* Then wait for a success indication */ if (debug) syslog(LOG_INFO, "Waiting for a SUCCESS reply %s", path); do { if ((ret = NgRecvMsg(cs, rep, sizeof msgbuf, NULL)) < 0) { syslog(LOG_ERR, "%s: Cannot receive a message: %m", path); _exit(EX_OSERR); } if (ret == 0) { /* The socket has been closed */ syslog(LOG_INFO, "%s: Client timed out", path); _exit(EX_TEMPFAIL); } if (rep->header.version != NG_VERSION) { syslog(LOG_ERR, "%ld: Unexpected netgraph version, expected %ld", (long)rep->header.version, (long)NG_VERSION); _exit(EX_PROTOCOL); } if (rep->header.typecookie != NGM_PPPOE_COOKIE) { syslog(LOG_INFO, "%ld: Unexpected netgraph cookie, expected %ld", (long)rep->header.typecookie, (long)NGM_PPPOE_COOKIE); continue; } switch (rep->header.cmd) { case NGM_PPPOE_SET_FLAG: msg = "SET_FLAG"; break; case NGM_PPPOE_CONNECT: msg = "CONNECT"; break; case NGM_PPPOE_LISTEN: msg = "LISTEN"; break; case NGM_PPPOE_OFFER: msg = "OFFER"; break; case NGM_PPPOE_SUCCESS: msg = "SUCCESS"; break; case NGM_PPPOE_FAIL: msg = "FAIL"; break; case NGM_PPPOE_CLOSE: msg = "CLOSE"; break; case NGM_PPPOE_GET_STATUS: msg = "GET_STATUS"; break; case NGM_PPPOE_ACNAME: msg = "ACNAME"; if (setenv("ACNAME", sts->hook, 1) != 0) syslog(LOG_WARNING, "setenv: cannot set ACNAME=%s: %m", sts->hook); break; case NGM_PPPOE_SESSIONID: msg = "SESSIONID"; snprintf(sessionid, sizeof sessionid, "%04x", *(u_int16_t *)sts); if (setenv("SESSIONID", sessionid, 1) != 0) syslog(LOG_WARNING, "setenv: cannot set SESSIONID=%s: %m", sessionid); break; default: snprintf(unknown, sizeof unknown, "<%d>", (int)rep->header.cmd); msg = unknown; break; } switch (rep->header.cmd) { case NGM_PPPOE_FAIL: case NGM_PPPOE_CLOSE: syslog(LOG_ERR, "Received NGM_PPPOE_%s (hook \"%s\")", msg, sts->hook); _exit(0); } syslog(LOG_INFO, "Received NGM_PPPOE_%s (hook \"%s\")", msg, sts->hook); } while (rep->header.cmd != NGM_PPPOE_SUCCESS); dup2(ds, STDIN_FILENO); dup2(ds, STDOUT_FILENO); close(ds); close(cs); setsid(); syslog(LOG_INFO, "Executing: %s", exec); execlp(_PATH_BSHELL, _PATH_BSHELL, "-c", exec, (char *)NULL); syslog(LOG_ERR, "execlp failed: %m"); _exit(EX_OSFILE); default: wait(&ret); errno = ret; if (errno) syslog(LOG_ERR, "Second fork failed: %m"); break; } }
/* * Display a negraph message */ void _NgDebugMsg(const struct ng_mesg *msg, const char *path) { u_char buf[2 * sizeof(struct ng_mesg) + ARGS_BUFSIZE]; struct ng_mesg *const req = (struct ng_mesg *)buf; struct ng_mesg *const bin = (struct ng_mesg *)req->data; int arglen, csock = -1; /* Display header stuff */ NGLOGX("NG_MESG :"); NGLOGX(" vers %d", msg->header.version); NGLOGX(" arglen %d", msg->header.arglen); NGLOGX(" flags %u", msg->header.flags); NGLOGX(" token %u", msg->header.token); NGLOGX(" cookie %s (%d)", NgCookie(msg->header.typecookie), msg->header.typecookie); /* At lower debugging levels, skip ASCII translation */ if (_gNgDebugLevel <= 2) goto fail2; /* If path is not absolute, don't bother trying to use relative address on a different socket for the ASCII translation */ if (strchr(path, ':') == NULL) goto fail2; /* Get a temporary socket */ if (NgMkSockNode(NULL, &csock, NULL) < 0) goto fail; /* Copy binary message into request message payload */ arglen = msg->header.arglen; if (arglen > ARGS_BUFSIZE) arglen = ARGS_BUFSIZE; memcpy(bin, msg, sizeof(*msg) + arglen); bin->header.arglen = arglen; /* Lower debugging to avoid infinite recursion */ _gNgDebugLevel -= RECURSIVE_DEBUG_ADJUST; /* Ask the node to translate the binary message to ASCII for us */ if (NgSendMsg(csock, path, NGM_GENERIC_COOKIE, NGM_BINARY2ASCII, bin, sizeof(*bin) + bin->header.arglen) < 0) { _gNgDebugLevel += RECURSIVE_DEBUG_ADJUST; goto fail; } if (NgRecvMsg(csock, req, sizeof(buf), NULL) < 0) { _gNgDebugLevel += RECURSIVE_DEBUG_ADJUST; goto fail; } /* Restore debugging level */ _gNgDebugLevel += RECURSIVE_DEBUG_ADJUST; /* Display command string and arguments */ NGLOGX(" cmd %s (%d)", bin->header.cmdstr, bin->header.cmd); NGLOGX(" args %s", bin->data); goto done; fail: /* Just display binary version */ NGLOGX(" [error decoding message: %s]", strerror(errno)); fail2: NGLOGX(" cmd %d", msg->header.cmd); NGLOGX(" args (%d bytes)", msg->header.arglen); _NgDebugBytes(msg->data, msg->header.arglen); done: if (csock != -1) (void)close(csock); }
/* * Send a message given in ASCII format. We first ask the node to translate * the command into binary, and then we send the binary. */ int NgSendAsciiMsg(int cs, const char *path, const char *fmt, ...) { struct ng_mesg *reply, *binary, *ascii; char *buf, *cmd, *args; va_list fmtargs; int token; /* Parse out command and arguments */ va_start(fmtargs, fmt); vasprintf(&buf, fmt, fmtargs); va_end(fmtargs); if (buf == NULL) return (-1); /* Parse out command, arguments */ for (cmd = buf; isspace(*cmd); cmd++) ; for (args = cmd; *args != '\0' && !isspace(*args); args++) ; if (*args != '\0') { while (isspace(*args)) *args++ = '\0'; } /* Get a bigger buffer to hold inner message header plus arg string */ if ((ascii = malloc(sizeof(struct ng_mesg) + strlen(args) + 1)) == NULL) { free(buf); return (-1); } memset(ascii, 0, sizeof(*ascii)); /* Build inner header (only need cmdstr, arglen, and data fields) */ strncpy((char *)ascii->header.cmdstr, cmd, sizeof(ascii->header.cmdstr) - 1); strcpy(ascii->data, args); ascii->header.arglen = strlen(ascii->data) + 1; free(buf); /* Send node a request to convert ASCII to binary */ if (NgSendMsg(cs, path, NGM_GENERIC_COOKIE, NGM_ASCII2BINARY, (u_char *)ascii, sizeof(*ascii) + ascii->header.arglen) < 0) { free(ascii); return (-1); } free(ascii); /* Get reply */ if (NgAllocRecvMsg(cs, &reply, NULL) < 0) return (-1); /* Now send binary version */ binary = (struct ng_mesg *)reply->data; if (++gMsgId < 0) gMsgId = 1; binary->header.token = gMsgId; binary->header.version = NG_VERSION; if (NgDeliverMsg(cs, path, binary, binary->data, binary->header.arglen) < 0) { free(reply); return (-1); } token = binary->header.token; free(reply); return (token); }
static void CcpLayerUp(Fsm fp) { Bund b = (Bund)fp->arg; CcpState const ccp = &b->ccp; struct ngm_connect cn; char buf[64]; /* If nothing was negotiated in either direction, close CCP */ if ((!ccp->recv || !(*ccp->recv->Negotiated)(b, COMP_DIR_RECV)) && (!ccp->xmit || !(*ccp->xmit->Negotiated)(b, COMP_DIR_XMIT))) { Log(LG_CCP, ("[%s] %s: No compression negotiated", Pref(fp), Fsm(fp))); FsmFailure(fp, FAIL_NEGOT_FAILURE); return; } /* Check for required encryption */ if (CcpCheckEncryption(b) < 0) { return; } /* Initialize each direction */ if (ccp->xmit != NULL && ccp->xmit->Init != NULL && (*ccp->xmit->Init)(b, COMP_DIR_XMIT) < 0) { Log(LG_CCP, ("[%s] %s: compression init failed", Pref(fp), Fsm(fp))); FsmFailure(fp, FAIL_NEGOT_FAILURE); /* XXX */ return; } if (ccp->recv != NULL && ccp->recv->Init != NULL && (*ccp->recv->Init)(b, COMP_DIR_RECV) < 0) { Log(LG_CCP, ("[%s] %s: decompression init failed", Pref(fp), Fsm(fp))); FsmFailure(fp, FAIL_NEGOT_FAILURE); /* XXX */ return; } if (ccp->xmit != NULL && ccp->xmit->Compress != NULL) { /* Connect a hook from the ppp node to our socket node */ snprintf(cn.path, sizeof(cn.path), "[%x]:", b->nodeID); snprintf(cn.ourhook, sizeof(cn.ourhook), "c%d", b->id); strcpy(cn.peerhook, NG_PPP_HOOK_COMPRESS); if (NgSendMsg(gCcpCsock, ".:", NGM_GENERIC_COOKIE, NGM_CONNECT, &cn, sizeof(cn)) < 0) { Perror("[%s] can't connect \"%s\"->\"%s\" and \"%s\"->\"%s\"", b->name, ".:", cn.ourhook, cn.path, cn.peerhook); } } if (ccp->recv != NULL && ccp->recv->Decompress != NULL) { /* Connect a hook from the ppp node to our socket node */ snprintf(cn.path, sizeof(cn.path), "[%x]:", b->nodeID); snprintf(cn.ourhook, sizeof(cn.ourhook), "d%d", b->id); strcpy(cn.peerhook, NG_PPP_HOOK_DECOMPRESS); if (NgSendMsg(gCcpCsock, ".:", NGM_GENERIC_COOKIE, NGM_CONNECT, &cn, sizeof(cn)) < 0) { Perror("[%s] can't connect \"%s\"->\"%s\" and \"%s\"->\"%s\"", b->name, ".:", cn.ourhook, cn.path, cn.peerhook); } } /* Report what we're doing */ Log(LG_CCP, ("[%s] CCP: Compress using: %s (%s)", b->name, !ccp->xmit ? "none" : ccp->xmit->name, (ccp->xmit && ccp->xmit->Describe) ? (*ccp->xmit->Describe)(b, COMP_DIR_XMIT, buf, sizeof(buf)) : "")); Log(LG_CCP, ("[%s] CCP: Decompress using: %s (%s)", b->name, !ccp->recv ? "none" : ccp->recv->name, (ccp->recv && ccp->recv->Describe) ? (*ccp->recv->Describe)(b, COMP_DIR_RECV, buf, sizeof(buf)) : "")); /* Update PPP node config */ b->pppConfig.bund.enableCompression = (ccp->xmit != NULL)?ccp->xmit->mode:0; b->pppConfig.bund.enableDecompression = (ccp->recv != NULL)?ccp->recv->mode:0; NgFuncSetConfig(b); /* Update interface MTU */ BundUpdateParams(b); }
static int ip_account_show(int v, int outgoing) { struct ng_ipacct_ainfo ci; struct ng_ipacct_hinfo hi; int token, nread; struct ng_mesg *ng_mesg; struct ng_ipacct_mesg *ng_cmesg; struct ip_acct_chunk *data; char path[NG_PATHLEN + 1]; ng_cmesg = alloca(sizeof(*ng_cmesg)); snprintf(ng_cmesg->hname, sizeof(ng_cmesg->hname), "%s_%s", ng_hookprefix, outgoing ? "out" : "in"); ng_mesg = alloca(REPL_SIZE); if (ip_account_get_info(NGM_IPACCT_CINFO, &ci, sizeof(ci), outgoing)) { return (-1); } if (ip_account_get_info(NGM_IPACCT_HINFO, &hi, sizeof(hi), outgoing)) { return (-1); } for (;;) { /* request set of accounting records */ token = NgSendMsg(ng_cs, ng_nodename, NGM_IPACCT_COOKIE, NGM_IPACCT_SHOW, ng_cmesg, sizeof(*ng_cmesg)); if (token == -1) { warn("NgSendMsg(NGM_IPACCT_SHOW)"); return (-1); } /* read reply */ if (ng_ready_for_read() != 1) return (-1); nread = NgRecvMsg(ng_cs, ng_mesg, REPL_SIZE, path); if (nread == -1) { warn("NgRecvMsg(NG_IPACCT_SHOW)"); return (-1); } if (ng_mesg->header.token != token) { warnx("NgRecvMsg(NGM_IPACCT_SHOW): token mismatch"); return (-1); } data = (struct ip_acct_chunk*)ng_mesg->data; if (ng_mesg->header.arglen != sizeof(*data)) { warnx("NgRecvMsg(NGM_IPACCT_SHOW): arglen too small"); return (-1); } if (data->nrecs == 0) break; /* no more data available */ ip_account_print(data, hi.hi_flags); } if (ci.ai_th_packets) printf(" Accounting exceed threshold by %u packets (%" PRIu64 " bytes)\n", ci.ai_th_packets, ci.ai_th_bytes); return (0); }
static void IpcpLayerUp(Fsm fp) { Bund b = (Bund)fp->arg; IpcpState const ipcp = &b->ipcp; char ipbuf[20]; #ifdef USE_NG_VJC char path[NG_PATHSIZ]; struct ngm_vjc_config vjc; #endif struct u_addr tmp; /* Determine actual address we'll use for ourselves */ in_addrtou_addr(&ipcp->want_addr, &tmp); if (!IpAddrInRange(&ipcp->self_allow, &tmp)) { Log(LG_IPCP, ("[%s] Note: ignoring negotiated %s IP %s,", b->name, "self", inet_ntoa(ipcp->want_addr))); u_addrtoin_addr(&ipcp->self_allow.addr, &ipcp->want_addr); Log(LG_IPCP, ("[%s] using %s instead.", b->name, inet_ntoa(ipcp->want_addr))); } /* Determine actual address we'll use for peer */ in_addrtou_addr(&ipcp->peer_addr, &tmp); if (!IpAddrInRange(&ipcp->peer_allow, &tmp) && !u_addrempty(&ipcp->peer_allow.addr)) { Log(LG_IPCP, ("[%s] Note: ignoring negotiated %s IP %s,", b->name, "peer", inet_ntoa(ipcp->peer_addr))); u_addrtoin_addr(&ipcp->peer_allow.addr, &ipcp->peer_addr); Log(LG_IPCP, ("[%s] using %s instead.", b->name, inet_ntoa(ipcp->peer_addr))); } /* Report */ strlcpy(ipbuf, inet_ntoa(ipcp->peer_addr), sizeof(ipbuf)); Log(LG_IPCP, ("[%s] %s -> %s", b->name, inet_ntoa(ipcp->want_addr), ipbuf)); #ifdef USE_NG_VJC memset(&vjc, 0, sizeof(vjc)); if (ntohs(ipcp->peer_comp.proto) == PROTO_VJCOMP || ntohs(ipcp->want_comp.proto) == PROTO_VJCOMP) { IpcpNgInitVJ(b); /* Configure VJ compression node */ vjc.enableComp = ntohs(ipcp->peer_comp.proto) == PROTO_VJCOMP; vjc.enableDecomp = ntohs(ipcp->want_comp.proto) == PROTO_VJCOMP; vjc.maxChannel = ipcp->peer_comp.maxchan; vjc.compressCID = ipcp->peer_comp.compcid; snprintf(path, sizeof(path), "[%x]:%s", b->nodeID, NG_PPP_HOOK_VJC_IP); if (NgSendMsg(gLinksCsock, path, NGM_VJC_COOKIE, NGM_VJC_SET_CONFIG, &vjc, sizeof(vjc)) < 0) { Perror("[%s] can't config %s node", b->name, NG_VJC_NODE_TYPE); } } #endif /* USE_NG_VJC */ /* Enable IP packets in the PPP node */ b->pppConfig.bund.enableIP = 1; #ifdef USE_NG_VJC b->pppConfig.bund.enableVJCompression = vjc.enableComp; b->pppConfig.bund.enableVJDecompression = vjc.enableDecomp; #endif NgFuncSetConfig(b); BundNcpsJoin(b, NCP_IPCP); }
/* * main() */ int main(int ac, char *av[]) { struct ngm_connect ngc; const char *path = NULL; const char *hook = DEFAULT_HOOKNAME; int csock, dsock; int asciiFlag = 0; int loopFlag = 0; int noInput = 0; int execFlag = 0; int ch; if ((msgs = sl_init()) == NULL) err(EX_OSERR, NULL); /* Parse flags */ while ((ch = getopt(ac, av, "aedlm:nsS")) != -1) { switch (ch) { case 'a': asciiFlag = 1; break; case 'd': NgSetDebug(NgSetDebug(-1) + 1); break; case 'e': execFlag = 1; break; case 'l': loopFlag = 1; break; case 'n': noInput = 1; break; case 'm': if (sl_add(msgs, optarg) == -1) err(EX_OSERR, NULL); break; case 's': outfd = STDIN_FILENO; break; case 'S': infd = STDOUT_FILENO; break; case '?': default: Usage(); } } ac -= optind; av += optind; if (execFlag) { if (asciiFlag || loopFlag) { fprintf(stderr, "conflicting options\n"); Usage(); } if (ac < 3) Usage(); path = av[0]; hook = av[1]; av += 2; ac -= 2; } else { /* Get params */ switch (ac) { case 2: hook = av[1]; /* FALLTHROUGH */ case 1: path = av[0]; break; default: Usage(); } } /* Get sockets */ if (NgMkSockNode(NULL, &csock, &dsock) < 0) errx(EX_OSERR, "can't get sockets"); /* Connect socket node to specified node */ snprintf(ngc.path, sizeof(ngc.path), "%s", path); snprintf(ngc.ourhook, sizeof(ngc.ourhook), NG_SOCK_HOOK_NAME); snprintf(ngc.peerhook, sizeof(ngc.peerhook), "%s", hook); if (NgSendMsg(csock, ".", NGM_GENERIC_COOKIE, NGM_CONNECT, &ngc, sizeof(ngc)) < 0) errx(EX_OSERR, "can't connect to node"); if (execFlag) { /* move dsock to fd 0 and 1 */ (void)close(0); (void)close(1); if (!noInput) (void)dup2(dsock, 0); (void)dup2(dsock, 1); send_msgs(csock, path); /* try executing the program */ (void)execv(av[0], av); err(EX_OSERR, "%s", av[0]); } else send_msgs(csock, path); /* Close standard input if not reading from it */ if (noInput) fclose(stdin); /* Relay data */ while (1) { fd_set rfds; /* Setup bits */ FD_ZERO(&rfds); if (!noInput) FD_SET(infd, &rfds); FD_SET(dsock, &rfds); /* Wait for something to happen */ if (select(FD_SETSIZE, &rfds, NULL, NULL, NULL) < 0) err(EX_OSERR, "select"); /* Check data from socket */ if (FD_ISSET(dsock, &rfds)) { char buf[BUF_SIZE]; int rl, wl; /* Read packet from socket */ if ((rl = NgRecvData(dsock, buf, sizeof(buf), NULL)) < 0) err(EX_OSERR, "read(hook)"); if (rl == 0) errx(EX_OSERR, "read EOF from hook?!"); /* Write packet to stdout */ if (asciiFlag) WriteAscii((u_char *) buf, rl); else if ((wl = write(outfd, buf, rl)) != rl) { if (wl < 0) { err(EX_OSERR, "write(stdout)"); } else { errx(EX_OSERR, "stdout: read %d, wrote %d", rl, wl); } } /* Loopback */ if (loopFlag) { if (NgSendData(dsock, NG_SOCK_HOOK_NAME, buf, rl) < 0) err(EX_OSERR, "write(hook)"); } } /* Check data from stdin */ if (FD_ISSET(infd, &rfds)) { char buf[BUF_SIZE]; int rl; /* Read packet from stdin */ if ((rl = read(infd, buf, sizeof(buf))) < 0) err(EX_OSERR, "read(stdin)"); if (rl == 0) errx(EX_OSERR, "EOF(stdin)"); /* Write packet to socket */ if (NgSendData(dsock, NG_SOCK_HOOK_NAME, buf, rl) < 0) err(EX_OSERR, "write(hook)"); } } }
static int IpcpNgInitVJ(Bund b) { struct ngm_mkpeer mp; struct ngm_connect cn; char path[NG_PATHSIZ]; struct ngm_name nm; /* Add a VJ compression node */ snprintf(path, sizeof(path), "[%x]:", b->nodeID); strcpy(mp.type, NG_VJC_NODE_TYPE); strcpy(mp.ourhook, NG_PPP_HOOK_VJC_IP); strcpy(mp.peerhook, NG_VJC_HOOK_IP); if (NgSendMsg(gLinksCsock, path, NGM_GENERIC_COOKIE, NGM_MKPEER, &mp, sizeof(mp)) < 0) { Perror("[%s] can't create %s node at \"%s\"->\"%s\"", b->name, NG_VJC_NODE_TYPE, path, mp.ourhook); goto fail; } /* Give it a name */ strlcat(path, NG_PPP_HOOK_VJC_IP, sizeof(path)); snprintf(nm.name, sizeof(nm.name), "mpd%d-%s-vjc", gPid, b->name); if (NgSendMsg(gLinksCsock, path, NGM_GENERIC_COOKIE, NGM_NAME, &nm, sizeof(nm)) < 0) { Perror("[%s] can't name %s node", b->name, NG_VJC_NODE_TYPE); goto fail; } /* Connect the other three hooks between the ppp and vjc nodes */ snprintf(path, sizeof(path), "[%x]:", b->nodeID); strcpy(cn.path, NG_PPP_HOOK_VJC_IP); strcpy(cn.ourhook, NG_PPP_HOOK_VJC_COMP); strcpy(cn.peerhook, NG_VJC_HOOK_VJCOMP); if (NgSendMsg(gLinksCsock, path, NGM_GENERIC_COOKIE, NGM_CONNECT, &cn, sizeof(cn)) < 0) { Perror("[%s] can't connect \"%s\"->\"%s\" and \"%s\"->\"%s\"", b->name, path, cn.ourhook, cn.path, cn.peerhook); goto fail; } strcpy(cn.ourhook, NG_PPP_HOOK_VJC_UNCOMP); strcpy(cn.peerhook, NG_VJC_HOOK_VJUNCOMP); if (NgSendMsg(gLinksCsock, path, NGM_GENERIC_COOKIE, NGM_CONNECT, &cn, sizeof(cn)) < 0) { Perror("[%s] can't connect \"%s\"->\"%s\" and \"%s\"->\"%s\"", b->name, path, cn.ourhook, cn.path, cn.peerhook); goto fail; } strcpy(cn.ourhook, NG_PPP_HOOK_VJC_VJIP); strcpy(cn.peerhook, NG_VJC_HOOK_VJIP); if (NgSendMsg(gLinksCsock, path, NGM_GENERIC_COOKIE, NGM_CONNECT, &cn, sizeof(cn)) < 0) { Perror("[%s] can't connect \"%s\"->\"%s\" and \"%s\"->\"%s\"", b->name, path, cn.ourhook, cn.path, cn.peerhook); goto fail; } return 0; fail: return -1; }
struct device * ng_Create(struct physical *p) { struct sockaddr_ng ngsock; u_char rbuf[2048]; struct sockaddr *sock = (struct sockaddr *)&ngsock; const struct hooklist *hlist; const struct nodeinfo *ninfo; const struct linkinfo *nlink; struct ngdevice *dev; struct ng_mesg *resp; struct ngm_mkpeer mkp; struct ngm_connect ngc; const char *devp, *endp; char lasthook[NG_HOOKSIZ]; char hook[NG_HOOKSIZ]; char nodetype[NG_TYPESIZ + NG_NODESIZ]; char modname[NG_TYPESIZ + 3]; char path[NG_PATHSIZ]; char *nodename; int len, sz, done; unsigned f; dev = NULL; if (p->fd < 0 && !strncasecmp(p->name.full, NETGRAPH_PREFIX, sizeof NETGRAPH_PREFIX - 1)) { p->fd--; /* We own the device - change fd */ if ((dev = malloc(sizeof *dev)) == NULL) return NULL; loadmodules(LOAD_VERBOSLY, "netgraph", "ng_socket", NULL); /* Create a socket node */ if (ID0NgMkSockNode(NULL, &dev->cs, &p->fd) == -1) { log_Printf(LogWARN, "Cannot create netgraph socket node: %s\n", strerror(errno)); free(dev); p->fd = -2; return NULL; } devp = p->name.full + sizeof NETGRAPH_PREFIX - 1; *lasthook = *path = '\0'; log_Printf(LogDEBUG, "%s: Opening netgraph device \"%s\"\n", p->link.name, devp); done = 0; while (*devp != '\0' && !done) { if (*devp != '[') { if (*lasthook == '\0') { log_Printf(LogWARN, "%s: Netgraph devices must start with" " [nodetype:nodename]\n", p->link.name); return ng_Abandon(dev, p); } /* Get the hook name of the new node */ if (!GETSEGMENT(hook, devp, ".[", &endp)) return ng_Abandon(dev, p); log_Printf(LogDEBUG, "%s: Got hook \"%s\"\n", p->link.name, hook); devp = endp; if (*devp == '\0') { log_Printf(LogWARN, "%s: Netgraph device must not end with a second" " hook\n", p->link.name); return ng_Abandon(dev, p); } if (devp[-1] != '[') { log_Printf(LogWARN, "%s: Expected a [nodetype:nodename] at device" " pos %d\n", p->link.name, devp - p->link.name - 1); return ng_Abandon(dev, p); } } else { /* Use lasthook as the hook name */ strcpy(hook, lasthook); devp++; } /* We've got ``lasthook'' and ``hook'', get the node type */ if (!GETSEGMENT(nodetype, devp, "]", &endp)) return ng_Abandon(dev, p); log_Printf(LogDEBUG, "%s: Got node \"%s\"\n", p->link.name, nodetype); if ((nodename = strchr(nodetype, ':')) != NULL) { *nodename++ = '\0'; if (*nodename == '\0' && *nodetype == '\0') { log_Printf(LogWARN, "%s: Empty [nodetype:nodename] at device" " pos %d\n", p->link.name, devp - p->link.name - 1); return ng_Abandon(dev, p); } } /* Ignore optional colons after nodes */ devp = *endp == ':' ? endp + 1 : endp; if (*devp == '.') devp++; if (*lasthook == '\0') { /* This is the first node in the chain */ if (nodename == NULL || *nodename == '\0') { log_Printf(LogWARN, "%s: %s: No initial device nodename\n", p->link.name, devp); return ng_Abandon(dev, p); } if (*nodetype != '\0') { /* Attempt to load the module */ snprintf(modname, sizeof modname, "ng_%s", nodetype); log_Printf(LogDEBUG, "%s: Attempting to load %s.ko\n", p->link.name, modname); loadmodules(LOAD_QUIETLY, modname, NULL); } snprintf(path, sizeof path, "%s:", nodename); /* XXX: If we have a node type, ensure it's correct */ } else { /* * Ask for a list of hooks attached to the previous node. If we * find the one we're interested in, and if it's connected to a * node of the right type using the correct hook, use that. * If we find the hook connected to something else, fail. * If we find no match, mkpeer the new node. */ if (*nodetype == '\0') { log_Printf(LogWARN, "%s: Nodetype missing at device offset %d\n", p->link.name, devp - p->name.full + sizeof NETGRAPH_PREFIX - 1); return ng_Abandon(dev, p); } /* Get a list of node hooks */ if (NgSendMsg(dev->cs, path, NGM_GENERIC_COOKIE, NGM_LISTHOOKS, NULL, 0) < 0) { log_Printf(LogWARN, "%s: %s Cannot send a LISTHOOOKS message: %s\n", p->link.name, path, strerror(errno)); return ng_Abandon(dev, p); } /* Get our list back */ resp = (struct ng_mesg *)rbuf; if (NgRecvMsg(dev->cs, resp, sizeof rbuf, NULL) <= 0) { log_Printf(LogWARN, "%s: Cannot get netgraph response: %s\n", p->link.name, strerror(errno)); return ng_Abandon(dev, p); } hlist = (const struct hooklist *)resp->data; ninfo = &hlist->nodeinfo; log_Printf(LogDEBUG, "List of netgraph node ``%s'' (id %x) hooks:\n", path, ninfo->id); /* look for a hook already attached. */ for (f = 0; f < ninfo->hooks; f++) { nlink = &hlist->link[f]; log_Printf(LogDEBUG, " Found %s -> %s (type %s)\n", nlink->ourhook, nlink->peerhook, nlink->nodeinfo.type); if (!strcmp(nlink->ourhook, lasthook)) { if (strcmp(nlink->peerhook, hook) || strcmp(nlink->nodeinfo.type, nodetype)) { log_Printf(LogWARN, "%s: hook %s:%s is already in use\n", p->link.name, nlink->ourhook, path); return ng_Abandon(dev, p); } /* The node is already hooked up nicely.... reuse it */ break; } } if (f == ninfo->hooks) { /* Attempt to load the module */ snprintf(modname, sizeof modname, "ng_%s", nodetype); log_Printf(LogDEBUG, "%s: Attempting to load %s.ko\n", p->link.name, modname); loadmodules(LOAD_QUIETLY, modname, NULL); /* Create (mkpeer) the new node */ snprintf(mkp.type, sizeof mkp.type, "%s", nodetype); snprintf(mkp.ourhook, sizeof mkp.ourhook, "%s", lasthook); snprintf(mkp.peerhook, sizeof mkp.peerhook, "%s", hook); log_Printf(LogDEBUG, "%s: Doing MKPEER %s%s -> %s (type %s)\n", p->link.name, path, mkp.ourhook, mkp.peerhook, nodetype); if (NgSendMsg(dev->cs, path, NGM_GENERIC_COOKIE, NGM_MKPEER, &mkp, sizeof mkp) < 0) { log_Printf(LogWARN, "%s Cannot create %s netgraph node: %s\n", path, nodetype, strerror(errno)); return ng_Abandon(dev, p); } } len = strlen(path); snprintf(path + len, sizeof path - len, "%s%s", path[len - 1] == ':' ? "" : ".", lasthook); } /* Get a list of node hooks */ if (NgSendMsg(dev->cs, path, NGM_GENERIC_COOKIE, NGM_LISTHOOKS, NULL, 0) < 0) { log_Printf(LogWARN, "%s: %s Cannot send a LISTHOOOKS message: %s\n", p->link.name, path, strerror(errno)); return ng_Abandon(dev, p); } /* Get our list back */ resp = (struct ng_mesg *)rbuf; if (NgRecvMsg(dev->cs, resp, sizeof rbuf, NULL) <= 0) { log_Printf(LogWARN, "%s: Cannot get netgraph response: %s\n", p->link.name, strerror(errno)); return ng_Abandon(dev, p); } hlist = (const struct hooklist *)resp->data; ninfo = &hlist->nodeinfo; if (*lasthook != '\0' && nodename != NULL && *nodename != '\0' && strcmp(ninfo->name, nodename) && NgNameNode(dev->cs, path, "%s", nodename) < 0) { log_Printf(LogWARN, "%s: %s: Cannot name netgraph node: %s\n", p->link.name, path, strerror(errno)); return ng_Abandon(dev, p); } if (!GETSEGMENT(lasthook, devp, " \t.[", &endp)) return ng_Abandon(dev, p); log_Printf(LogDEBUG, "%s: Got hook \"%s\"\n", p->link.name, lasthook); len = strlen(lasthook); done = strchr(" \t", devp[len]) ? 1 : 0; devp = endp; if (*devp != '\0') { if (devp[-1] == '[') devp--; } /* else should moan about devp[-1] being '[' ? */ } snprintf(dev->hook, sizeof dev->hook, "%s", lasthook); /* Connect the node to our socket node */ snprintf(ngc.path, sizeof ngc.path, "%s", path); snprintf(ngc.ourhook, sizeof ngc.ourhook, "%s", dev->hook); memcpy(ngc.peerhook, ngc.ourhook, sizeof ngc.peerhook); log_Printf(LogDEBUG, "Connecting netgraph socket .:%s -> %s.%s\n", ngc.ourhook, ngc.path, ngc.peerhook); if (NgSendMsg(dev->cs, ".:", NGM_GENERIC_COOKIE, NGM_CONNECT, &ngc, sizeof ngc) < 0) { log_Printf(LogWARN, "Cannot connect %s and socket netgraph " "nodes: %s\n", path, strerror(errno)); return ng_Abandon(dev, p); } /* Hook things up so that we monitor dev->cs */ p->desc.UpdateSet = ng_UpdateSet; p->desc.IsSet = ng_IsSet; p->desc.Read = ng_DescriptorRead; memcpy(&dev->dev, &basengdevice, sizeof dev->dev); } else { /* See if we're a netgraph socket */ sz = sizeof ngsock; if (getsockname(p->fd, sock, &sz) != -1 && sock->sa_family == AF_NETGRAPH) { /* * It's a netgraph node... We can't determine hook names etc, so we * stay pretty impartial.... */ log_Printf(LogPHASE, "%s: Link is a netgraph node\n", p->link.name); if ((dev = malloc(sizeof *dev)) == NULL) { log_Printf(LogWARN, "%s: Cannot allocate an ether device: %s\n", p->link.name, strerror(errno)); return NULL; } memcpy(&dev->dev, &basengdevice, sizeof dev->dev); dev->cs = -1; *dev->hook = '\0'; } } if (dev) { physical_SetupStack(p, dev->dev.name, PHYSICAL_FORCE_SYNCNOACF); return &dev->dev; } return NULL; }
/* * Create a socket type node and give it the supplied name. * Return data and control sockets corresponding to the node. * Returns -1 if error and sets errno. */ int NgMkSockNode(const char *name, int *csp, int *dsp) { char namebuf[NG_NODESIZ]; int cs = -1; /* control socket */ int ds = -1; /* data socket */ int errnosv; /* Empty name means no name */ if (name && *name == 0) name = NULL; /* Create control socket; this also creates the netgraph node. If we get an EPROTONOSUPPORT then the socket node type is not loaded, so load it and try again. */ if ((cs = socket(AF_NETGRAPH, SOCK_DGRAM, NG_CONTROL)) < 0) { if (errno == EPROTONOSUPPORT) { if (kldload(NG_SOCKET_KLD) < 0) { errnosv = errno; if (_gNgDebugLevel >= 1) NGLOG("can't load %s", NG_SOCKET_KLD); goto errout; } cs = socket(AF_NETGRAPH, SOCK_DGRAM, NG_CONTROL); if (cs >= 0) goto gotNode; } errnosv = errno; if (_gNgDebugLevel >= 1) NGLOG("socket"); goto errout; } gotNode: /* Assign the node the desired name, if any */ if (name != NULL) { u_char sbuf[NG_NODESIZ + NGSA_OVERHEAD]; struct sockaddr_ng *const sg = (struct sockaddr_ng *) sbuf; /* Assign name */ strlcpy(sg->sg_data, name, NG_NODESIZ); sg->sg_family = AF_NETGRAPH; sg->sg_len = strlen(sg->sg_data) + 1 + NGSA_OVERHEAD; if (bind(cs, (struct sockaddr *) sg, sg->sg_len) < 0) { errnosv = errno; if (_gNgDebugLevel >= 1) NGLOG("bind(%s)", sg->sg_data); goto errout; } /* Save node name */ strlcpy(namebuf, name, sizeof(namebuf)); } else if (dsp != NULL) { u_char rbuf[sizeof(struct ng_mesg) + sizeof(struct nodeinfo)]; struct ng_mesg *const resp = (struct ng_mesg *) rbuf; struct nodeinfo *const ni = (struct nodeinfo *) resp->data; /* Find out the node ID */ if (NgSendMsg(cs, ".", NGM_GENERIC_COOKIE, NGM_NODEINFO, NULL, 0) < 0) { errnosv = errno; if (_gNgDebugLevel >= 1) NGLOG("send nodeinfo"); goto errout; } if (NgRecvMsg(cs, resp, sizeof(rbuf), NULL) < 0) { errnosv = errno; if (_gNgDebugLevel >= 1) NGLOG("recv nodeinfo"); goto errout; } /* Save node "name" */ snprintf(namebuf, sizeof(namebuf), "[%lx]", (u_long) ni->id); } /* Create data socket if desired */ if (dsp != NULL) { u_char sbuf[NG_NODESIZ + 1 + NGSA_OVERHEAD]; struct sockaddr_ng *const sg = (struct sockaddr_ng *) sbuf; /* Create data socket, initially just "floating" */ if ((ds = socket(AF_NETGRAPH, SOCK_DGRAM, NG_DATA)) < 0) { errnosv = errno; if (_gNgDebugLevel >= 1) NGLOG("socket"); goto errout; } /* Associate the data socket with the node */ snprintf(sg->sg_data, NG_NODESIZ + 1, "%s:", namebuf); sg->sg_family = AF_NETGRAPH; sg->sg_len = strlen(sg->sg_data) + 1 + NGSA_OVERHEAD; if (connect(ds, (struct sockaddr *) sg, sg->sg_len) < 0) { errnosv = errno; if (_gNgDebugLevel >= 1) NGLOG("connect(%s)", sg->sg_data); goto errout; } } /* Return the socket(s) */ if (csp) *csp = cs; else close(cs); if (dsp) *dsp = ds; return (0); errout: /* Failed */ if (cs >= 0) close(cs); if (ds >= 0) close(ds); errno = errnosv; return (-1); }
static int ShowCmd(int ac, char **av) { char *path; struct ng_mesg *resp; struct hooklist *hlist; struct nodeinfo *ninfo; int ch, no_hooks = 0; /* Get options */ optind = 1; while ((ch = getopt(ac, av, "n")) != -1) { switch (ch) { case 'n': no_hooks = 1; break; case '?': default: return (CMDRTN_USAGE); break; } } ac -= optind; av += optind; /* Get arguments */ switch (ac) { case 1: path = av[0]; break; default: return (CMDRTN_USAGE); } /* Get node info and hook list */ if (NgSendMsg(csock, path, NGM_GENERIC_COOKIE, NGM_LISTHOOKS, NULL, 0) < 0) { warn("send msg"); return (CMDRTN_ERROR); } if (NgAllocRecvMsg(csock, &resp, NULL) < 0) { warn("recv msg"); return (CMDRTN_ERROR); } /* Show node information */ hlist = (struct hooklist *) resp->data; ninfo = &hlist->nodeinfo; if (!*ninfo->name) snprintf(ninfo->name, sizeof(ninfo->name), "%s", UNNAMED); printf(" Name: %-15s Type: %-15s ID: %08x Num hooks: %d\n", ninfo->name, ninfo->type, ninfo->id, ninfo->hooks); if (!no_hooks && ninfo->hooks > 0) { u_int k; printf(FMT, "Local hook", "Peer name", "Peer type", "Peer ID", "Peer hook"); printf(FMT, "----------", "---------", "---------", "-------", "---------"); for (k = 0; k < ninfo->hooks; k++) { struct linkinfo *const link = &hlist->link[k]; struct nodeinfo *const peer = &hlist->link[k].nodeinfo; char idbuf[20]; if (!*peer->name) { snprintf(peer->name, sizeof(peer->name), "%s", UNNAMED); } snprintf(idbuf, sizeof(idbuf), "%08x", peer->id); printf(FMT, link->ourhook, peer->name, peer->type, idbuf, link->peerhook); } } free(resp); return (CMDRTN_OK); }
static int DotCmd(int ac, char **av) { struct ng_mesg *nlresp; struct namelist *nlist; FILE *f = stdout; int ch; u_int i; /* Get options */ optind = 1; while ((ch = getopt(ac, av, "")) != -1) { switch (ch) { case '?': default: return (CMDRTN_USAGE); break; } } ac -= optind; av += optind; /* Get arguments */ switch (ac) { case 1: f = fopen(av[0], "w"); if (f == NULL) { warn("Could not open %s for writing", av[0]); return (CMDRTN_ERROR); } case 0: break; default: if (f != stdout) (void)fclose(f); return (CMDRTN_USAGE); } /* Get list of nodes */ if (NgSendMsg(csock, ".", NGM_GENERIC_COOKIE, NGM_LISTNODES, NULL, 0) < 0) { warn("send listnodes msg"); goto error; } if (NgAllocRecvMsg(csock, &nlresp, NULL) < 0) { warn("recv listnodes msg"); goto error; } nlist = (struct namelist *)nlresp->data; fprintf(f, "graph netgraph {\n"); /* TODO: implement rank = same or subgraphs at some point */ fprintf(f, "\tedge [ weight = 1.0 ];\n"); fprintf(f, "\tnode [ shape = record, fontsize = 12 ] {\n"); for (i = 0; i < nlist->numnames; i++) fprintf(f, "\t\t\"%jx\" [ label = \"{%s:|{%s|[%jx]:}}\" ];\n", (uintmax_t)nlist->nodeinfo[i].id, nlist->nodeinfo[i].name[0] != '\0' ? nlist->nodeinfo[i].name : UNNAMED, nlist->nodeinfo[i].type, (uintmax_t)nlist->nodeinfo[i].id); fprintf(f, "\t};\n"); fprintf(f, "\tsubgraph cluster_disconnected {\n"); fprintf(f, "\t\tbgcolor = pink;\n"); for (i = 0; i < nlist->numnames; i++) if (nlist->nodeinfo[i].hooks == 0) fprintf(f, "\t\t\"%jx\";\n", (uintmax_t)nlist->nodeinfo[i].id); fprintf(f, "\t};\n"); for (i = 0; i < nlist->numnames; i++) { struct ng_mesg *hlresp; struct hooklist *hlist; struct nodeinfo *ninfo; char path[NG_PATHSIZ]; u_int j; (void)snprintf(path, sizeof(path), "[%jx]:", (uintmax_t)nlist->nodeinfo[i].id); /* Get node info and hook list */ if (NgSendMsg(csock, path, NGM_GENERIC_COOKIE, NGM_LISTHOOKS, NULL, 0) < 0) { free(nlresp); warn("send listhooks msg"); goto error; } if (NgAllocRecvMsg(csock, &hlresp, NULL) < 0) { free(nlresp); warn("recv listhooks msg"); goto error; } hlist = (struct hooklist *)hlresp->data; ninfo = &hlist->nodeinfo; if (ninfo->hooks == 0) { free(hlresp); continue; } fprintf(f, "\tnode [ shape = octagon, fontsize = 10 ] {\n"); for (j = 0; j < ninfo->hooks; j++) fprintf(f, "\t\t\"%jx.%s\" [ label = \"%s\" ];\n", (uintmax_t)nlist->nodeinfo[i].id, hlist->link[j].ourhook, hlist->link[j].ourhook); fprintf(f, "\t};\n"); fprintf(f, "\t{\n\t\tedge [ weight = 2.0, style = bold ];\n"); for (j = 0; j < ninfo->hooks; j++) fprintf(f, "\t\t\"%jx\" -- \"%jx.%s\";\n", (uintmax_t)nlist->nodeinfo[i].id, (uintmax_t)nlist->nodeinfo[i].id, hlist->link[j].ourhook); fprintf(f, "\t};\n"); for (j = 0; j < ninfo->hooks; j++) { /* Only print the edges going in one direction. */ if (hlist->link[j].nodeinfo.id > nlist->nodeinfo[i].id) continue; fprintf(f, "\t\"%jx.%s\" -- \"%jx.%s\";\n", (uintmax_t)nlist->nodeinfo[i].id, hlist->link[j].ourhook, (uintmax_t)hlist->link[j].nodeinfo.id, hlist->link[j].peerhook); } free(hlresp); } fprintf(f, "};\n"); free(nlresp); if (f != stdout) (void)fclose(f); return (CMDRTN_OK); error: if (f != stdout) (void)fclose(f); return (CMDRTN_ERROR); }
struct device * ether_Create(struct physical *p) { u_char rbuf[2048]; struct etherdevice *dev; struct ng_mesg *resp; const struct hooklist *hlist; const struct nodeinfo *ninfo; char *path, *sessionid; const char *mode; size_t ifacelen; unsigned f; dev = NULL; path = NULL; ifacelen = 0; if (p->fd < 0 && !strncasecmp(p->name.full, NG_PPPOE_NODE_TYPE, PPPOE_NODE_TYPE_LEN) && p->name.full[PPPOE_NODE_TYPE_LEN] == ':') { const struct linkinfo *nlink; struct ngpppoe_init_data *data; struct ngm_mkpeer mkp; struct ngm_connect ngc; const char *iface, *provider; char etherid[12]; int providerlen; char connectpath[sizeof dev->hook + 2]; /* .:<hook> */ p->fd--; /* We own the device - change fd */ loadmodules(LOAD_VERBOSLY, "netgraph", "ng_ether", "ng_pppoe", "ng_socket", NULL); if ((dev = malloc(sizeof *dev)) == NULL) return NULL; iface = p->name.full + PPPOE_NODE_TYPE_LEN + 1; provider = strchr(iface, ':'); if (provider) { ifacelen = provider - iface; provider++; providerlen = strlen(provider); } else { ifacelen = strlen(iface); provider = ""; providerlen = 0; } /* * We're going to do this (where tunN is our tunnel device): * * .---------. * | ether | * | <iface> | dev->cs * `---------' | * (orphan) p->fd | * | | | * | | | * (ethernet) | | * .---------. .-----------. * | pppoe | | socket | * | <iface> |(tunN)<---->(tunN)| <unnamed> | * `--------- `-----------' * (tunX) * ^ * | * `--->(tunX) */ /* Create a socket node */ if (ID0NgMkSockNode(NULL, &dev->cs, &p->fd) == -1) { log_Printf(LogWARN, "Cannot create netgraph socket node: %s\n", strerror(errno)); free(dev); p->fd = -2; return NULL; } /* * Ask for a list of hooks attached to the "ether" node. This node should * magically exist as a way of hooking stuff onto an ethernet device */ path = (char *)alloca(ifacelen + 2); sprintf(path, "%.*s:", (int)ifacelen, iface); if (NgSendMsg(dev->cs, path, NGM_GENERIC_COOKIE, NGM_LISTHOOKS, NULL, 0) < 0) { log_Printf(LogWARN, "%s Cannot send a netgraph message: %s\n", path, strerror(errno)); return ether_Abandon(dev, p); } /* Get our list back */ resp = (struct ng_mesg *)rbuf; if (NgRecvMsg(dev->cs, resp, sizeof rbuf, NULL) <= 0) { log_Printf(LogWARN, "Cannot get netgraph response: %s\n", strerror(errno)); return ether_Abandon(dev, p); } hlist = (const struct hooklist *)resp->data; ninfo = &hlist->nodeinfo; /* Make sure we've got the right type of node */ if (strncmp(ninfo->type, NG_ETHER_NODE_TYPE, sizeof NG_ETHER_NODE_TYPE - 1)) { log_Printf(LogWARN, "%s Unexpected node type ``%s'' (wanted ``" NG_ETHER_NODE_TYPE "'')\n", path, ninfo->type); return ether_Abandon(dev, p); } log_Printf(LogDEBUG, "List of netgraph node ``%s'' (id %x) hooks:\n", path, ninfo->id); /* look for a hook already attached. */ for (f = 0; f < ninfo->hooks; f++) { nlink = &hlist->link[f]; log_Printf(LogDEBUG, " Found %s -> %s\n", nlink->ourhook, nlink->peerhook); if (!strcmp(nlink->ourhook, NG_ETHER_HOOK_ORPHAN) || !strcmp(nlink->ourhook, NG_ETHER_HOOK_DIVERT)) { /* * Something is using the data coming out of this ``ether'' node. * If it's a PPPoE node, we use that node, otherwise we complain that * someone else is using the node. */ if (!strcmp(nlink->nodeinfo.type, NG_PPPOE_NODE_TYPE)) /* Use this PPPoE node ! */ snprintf(ngc.path, sizeof ngc.path, "[%x]:", nlink->nodeinfo.id); else { log_Printf(LogWARN, "%s Node type ``%s'' is currently active\n", path, nlink->nodeinfo.type); return ether_Abandon(dev, p); } break; } } if (f == ninfo->hooks) { /* * Create a new ``PPPoE'' node connected to the ``ether'' node using * the ``orphan'' and ``ethernet'' hooks */ snprintf(mkp.type, sizeof mkp.type, "%s", NG_PPPOE_NODE_TYPE); snprintf(mkp.ourhook, sizeof mkp.ourhook, "%s", NG_ETHER_HOOK_ORPHAN); snprintf(mkp.peerhook, sizeof mkp.peerhook, "%s", NG_PPPOE_HOOK_ETHERNET); snprintf(etherid, sizeof etherid, "[%x]:", ninfo->id); log_Printf(LogDEBUG, "Creating PPPoE netgraph node %s%s -> %s\n", etherid, mkp.ourhook, mkp.peerhook); if (NgSendMsg(dev->cs, etherid, NGM_GENERIC_COOKIE, NGM_MKPEER, &mkp, sizeof mkp) < 0) { log_Printf(LogWARN, "%s Cannot create PPPoE netgraph node: %s\n", etherid, strerror(errno)); return ether_Abandon(dev, p); } snprintf(ngc.path, sizeof ngc.path, "%s%s", path, NG_ETHER_HOOK_ORPHAN); } snprintf(dev->hook, sizeof dev->hook, "%s%d", TUN_NAME, p->dl->bundle->unit); /* * Connect the PPPoE node to our socket node. * ngc.path has already been set up */ snprintf(ngc.ourhook, sizeof ngc.ourhook, "%s", dev->hook); memcpy(ngc.peerhook, ngc.ourhook, sizeof ngc.peerhook); log_Printf(LogDEBUG, "Connecting netgraph socket .:%s -> %s:%s\n", ngc.ourhook, ngc.path, ngc.peerhook); if (NgSendMsg(dev->cs, ".:", NGM_GENERIC_COOKIE, NGM_CONNECT, &ngc, sizeof ngc) < 0) { log_Printf(LogWARN, "Cannot connect PPPoE and socket netgraph " "nodes: %s\n", strerror(errno)); return ether_Abandon(dev, p); } /* Bring the Ethernet interface up */ path[ifacelen] = '\0'; /* Remove the trailing ':' */ if (!iface_SetFlags(path, IFF_UP)) log_Printf(LogWARN, "%s: Failed to set the IFF_UP flag on %s\n", p->link.name, path); snprintf(connectpath, sizeof connectpath, ".:%s", dev->hook); /* Configure node to 3Com mode if needed */ if (p->cfg.pppoe_configured) { mode = p->cfg.nonstandard_pppoe ? NG_PPPOE_NONSTANDARD : NG_PPPOE_STANDARD; if (NgSendMsg(dev->cs, connectpath, NGM_PPPOE_COOKIE, NGM_PPPOE_SETMODE, mode, strlen(mode) + 1) == -1) { log_Printf(LogWARN, "``%s'': Cannot configure netgraph node: %s\n", connectpath, strerror(errno)); return ether_Abandon(dev, p); } } /* And finally, request a connection to the given provider */ data = (struct ngpppoe_init_data *)alloca(sizeof *data + providerlen); snprintf(data->hook, sizeof data->hook, "%s", dev->hook); memcpy(data->data, provider, providerlen); data->data_len = providerlen; log_Printf(LogDEBUG, "Sending PPPOE_CONNECT to %s\n", connectpath); if (NgSendMsg(dev->cs, connectpath, NGM_PPPOE_COOKIE, NGM_PPPOE_CONNECT, data, sizeof *data + providerlen) == -1) { log_Printf(LogWARN, "``%s'': Cannot start netgraph node: %s\n", connectpath, strerror(errno)); return ether_Abandon(dev, p); } /* Hook things up so that we monitor dev->cs */ p->desc.UpdateSet = ether_UpdateSet; p->desc.IsSet = ether_IsSet; p->desc.Read = ether_DescriptorRead; memcpy(&dev->dev, &baseetherdevice, sizeof dev->dev); switch (p->cfg.cd.necessity) { case CD_VARIABLE: dev->dev.cd.delay = p->cfg.cd.delay; break; case CD_REQUIRED: dev->dev.cd = p->cfg.cd; break; case CD_NOTREQUIRED: log_Printf(LogWARN, "%s: Carrier must be set, using ``set cd %d!''\n", p->link.name, dev->dev.cd.delay); case CD_DEFAULT: break; } dev->timeout = dev->dev.cd.delay; dev->connected = CARRIER_PENDING; /* This will be overridden by our session id - if provided by netgraph */ dev->slot = GetIfIndex(path); } else { /* See if we're a netgraph socket */ struct stat st; if (fstat(p->fd, &st) != -1 && (st.st_mode & S_IFSOCK)) { struct sockaddr_storage ssock; struct sockaddr *sock = (struct sockaddr *)&ssock; int sz; sz = sizeof ssock; if (getsockname(p->fd, sock, &sz) == -1) { log_Printf(LogPHASE, "%s: Link is a closed socket !\n", p->link.name); close(p->fd); p->fd = -1; return NULL; } if (sock->sa_family == AF_NETGRAPH) { /* * It's a netgraph node... We can't determine hook names etc, so we * stay pretty impartial.... */ log_Printf(LogPHASE, "%s: Link is a netgraph node\n", p->link.name); if ((dev = malloc(sizeof *dev)) == NULL) { log_Printf(LogWARN, "%s: Cannot allocate an ether device: %s\n", p->link.name, strerror(errno)); return NULL; } memcpy(&dev->dev, &baseetherdevice, sizeof dev->dev); dev->cs = -1; dev->timeout = 0; dev->connected = CARRIER_OK; *dev->hook = '\0'; /* * If we're being envoked from pppoed(8), we may have a SESSIONID * set in the environment. If so, use it as the slot */ if ((sessionid = getenv("SESSIONID")) != NULL) { char *end; u_long slot; slot = strtoul(sessionid, &end, 16); dev->slot = end != sessionid && *end == '\0' ? slot : 0; } else dev->slot = 0; } } } if (dev) { physical_SetupStack(p, dev->dev.name, PHYSICAL_FORCE_SYNCNOACF); return &dev->dev; } return NULL; }