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