Exemple #1
0
struct device *
udp_iov2device(int type, struct physical *p, struct iovec *iov, int *niov,
               int maxiov, int *auxfd, int *nauxfd)
{
  if (type == UDP_DEVICE) {
    struct udpdevice *dev = (struct udpdevice *)iov[(*niov)++].iov_base;
    struct udpdevice *newdev;

    newdev = realloc(dev, sizeof *dev);	/* Reduce to the correct size */
    if (newdev == NULL) {
      log_Printf(LogALERT, "Failed to allocate memory: %d\n",
                 (int)(sizeof *dev));
      AbortProgram(EX_OSERR);
    }
    dev = newdev;

    /* Refresh function pointers etc */
    memcpy(&dev->dev, &baseudpdevice, sizeof dev->dev);

    physical_SetupStack(p, dev->dev.name, PHYSICAL_FORCE_SYNC);
    return &dev->dev;
  }

  return NULL;
}
Exemple #2
0
struct device *
i4b_iov2device(int type, struct physical *p, struct iovec *iov, int *niov,
               int maxiov, int *auxfd, int *nauxfd)
{
  if (type == I4B_DEVICE) {
    struct i4bdevice *dev = (struct i4bdevice *)iov[(*niov)++].iov_base;

    dev = realloc(dev, sizeof *dev);	/* Reduce to the correct size */
    if (dev == NULL) {
      log_Printf(LogALERT, "Failed to allocate memory: %d\n",
                 (int)(sizeof *dev));
      AbortProgram(EX_OSERR);
    }

    /* Refresh function pointers etc */
    memcpy(&dev->dev, &basei4bdevice, sizeof dev->dev);

    physical_SetupStack(p, dev->dev.name, PHYSICAL_NOFORCE);
    if (dev->Timer.state != TIMER_STOPPED) {
      dev->Timer.state = TIMER_STOPPED;
      p->handler = &dev->dev;		/* For the benefit of StartTimer */
      i4b_StartTimer(p);
    }
    return &dev->dev;
  }

  return NULL;
}
Exemple #3
0
struct device *
ether_iov2device(int type, struct physical *p, struct iovec *iov, int *niov,
                 int maxiov __unused, int *auxfd, int *nauxfd)
{
  if (type == ETHER_DEVICE) {
    struct etherdevice *dev = (struct etherdevice *)iov[(*niov)++].iov_base;

    dev = realloc(dev, sizeof *dev);	/* Reduce to the correct size */
    if (dev == NULL) {
      log_Printf(LogALERT, "Failed to allocate memory: %d\n",
                 (int)(sizeof *dev));
      AbortProgram(EX_OSERR);
    }

    if (*nauxfd) {
      dev->cs = *auxfd;
      (*nauxfd)--;
    } else
      dev->cs = -1;

    /* Refresh function pointers etc */
    memcpy(&dev->dev, &baseetherdevice, sizeof dev->dev);

    physical_SetupStack(p, dev->dev.name, PHYSICAL_FORCE_SYNCNOACF);
    return &dev->dev;
  }

  return NULL;
}
Exemple #4
0
struct device *
atm_Create(struct physical *p)
{
  struct atmdevice *dev;

  dev = NULL;
  if (p->fd < 0 && !strncasecmp(p->name.full, PPPOA, PPPOA_LEN)
      && p->name.full[PPPOA_LEN] == ':') {
    char iface[25];
    unsigned vci, vpi;

    if (sscanf(p->name.full + PPPOA_LEN + 1, "%25[A-Za-z0-9]:%u.%u", iface,
               &vpi, &vci) != 3) {
      log_Printf(LogWARN, "Malformed ATM device name \'%s\', "
                 "PPPoA:if:vpi.vci expected\n", p->name.full);
      return NULL;
    }

    dev = atm_CreateDevice(p, iface, vpi, vci);
  }

  if (dev) {
    memcpy(&dev->dev, &baseatmdevice, sizeof dev->dev);
    physical_SetupStack(p, dev->dev.name, PHYSICAL_FORCE_SYNCNOACF);
    if (p->cfg.cd.necessity != CD_DEFAULT)
      log_Printf(LogWARN, "Carrier settings ignored\n");
    return &dev->dev;
  }

  return NULL;
}
Exemple #5
0
int
physical_Open(struct physical *p, struct bundle *bundle)
{
  int devno, h, wasfd, err;
  char *dev;

  if (p->fd >= 0)
    log_Printf(LogDEBUG, "%s: Open: Modem is already open!\n", p->link.name);
    /* We're going back into "term" mode */
  else if (p->type == PHYS_DIRECT) {
    physical_SetDevice(p, "");
    p->fd = STDIN_FILENO;
    for (h = 0; h < NDEVICES && p->handler == NULL && p->fd >= 0; h++)
      p->handler = (*devices[h].create)(p);
    if (p->fd >= 0) {
      if (p->handler == NULL) {
        physical_SetupStack(p, "unknown", PHYSICAL_NOFORCE);
        log_Printf(LogDEBUG, "%s: stdin is unidentified\n", p->link.name);
      }
      physical_Found(p);
    }
  } else {
    dev = p->cfg.devlist;
    devno = 0;
    while (devno < p->cfg.ndev && p->fd < 0) {
      physical_SetDevice(p, dev);
      if (physical_Lock(p)) {
        err = 0;

        if (*p->name.full == '/') {
          p->fd = ID0open(p->name.full, O_RDWR | O_NONBLOCK);
          if (p->fd < 0)
            err = errno;
        }

        wasfd = p->fd;
        for (h = 0; h < NDEVICES && p->handler == NULL; h++)
          if ((p->handler = (*devices[h].create)(p)) == NULL && wasfd != p->fd)
            break;

        if (p->fd < 0) {
          if (h == NDEVICES) {
            if (err)
	      log_Printf(LogWARN, "%s: %s: %s\n", p->link.name, p->name.full,
                         strerror(errno));
            else
	      log_Printf(LogWARN, "%s: Device (%s) must begin with a '/',"
                         " a '!' or contain at least one ':'\n", p->link.name,
                         p->name.full);
          }
          physical_Unlock(p);
        } else
          physical_Found(p);
      }
      dev += strlen(dev) + 1;
      devno++;
    }
  }

  return p->fd;
}
Exemple #6
0
struct physical *
iov2physical(struct datalink *dl, struct iovec *iov, int *niov, int maxiov,
             int fd, int *auxfd, int *nauxfd)
{
  struct physical *p;
  int len, h, type;

  p = (struct physical *)iov[(*niov)++].iov_base;
  p->link.name = dl->name;
  memset(p->link.Queue, '\0', sizeof p->link.Queue);

  p->desc.UpdateSet = physical_UpdateSet;
  p->desc.IsSet = physical_IsSet;
  p->desc.Read = physical_DescriptorRead;
  p->desc.Write = physical_DescriptorWrite;
  p->type = PHYS_DIRECT;
  p->dl = dl;
  len = strlen(_PATH_DEV);
  p->out = NULL;
  p->connect_count = 1;

  physical_SetDevice(p, p->name.full);

  p->link.lcp.fsm.bundle = dl->bundle;
  p->link.lcp.fsm.link = &p->link;
  memset(&p->link.lcp.fsm.FsmTimer, '\0', sizeof p->link.lcp.fsm.FsmTimer);
  memset(&p->link.lcp.fsm.OpenTimer, '\0', sizeof p->link.lcp.fsm.OpenTimer);
  memset(&p->link.lcp.fsm.StoppedTimer, '\0',
         sizeof p->link.lcp.fsm.StoppedTimer);
  p->link.lcp.fsm.parent = &dl->fsmp;
  lcp_SetupCallbacks(&p->link.lcp);

  p->link.ccp.fsm.bundle = dl->bundle;
  p->link.ccp.fsm.link = &p->link;
  /* Our in.state & out.state are NULL (no link-level ccp yet) */
  memset(&p->link.ccp.fsm.FsmTimer, '\0', sizeof p->link.ccp.fsm.FsmTimer);
  memset(&p->link.ccp.fsm.OpenTimer, '\0', sizeof p->link.ccp.fsm.OpenTimer);
  memset(&p->link.ccp.fsm.StoppedTimer, '\0',
         sizeof p->link.ccp.fsm.StoppedTimer);
  p->link.ccp.fsm.parent = &dl->fsmp;
  ccp_SetupCallbacks(&p->link.ccp);

  p->hdlc.lqm.owner = &p->link.lcp;
  p->hdlc.ReportTimer.state = TIMER_STOPPED;
  p->hdlc.lqm.timer.state = TIMER_STOPPED;

  p->fd = fd;
  p->link.stats.total.in.SampleOctets = (long long *)iov[(*niov)++].iov_base;
  p->link.stats.total.out.SampleOctets = (long long *)iov[(*niov)++].iov_base;
  p->link.stats.parent = dl->bundle->ncp.mp.active ?
    &dl->bundle->ncp.mp.link.stats.total : NULL;
  p->link.stats.gather = 1;

  type = (long)p->handler;
  p->handler = NULL;
  for (h = 0; h < NDEVICES && p->handler == NULL; h++)
    p->handler = (*devices[h].iov2device)(type, p, iov, niov, maxiov,
                                          auxfd, nauxfd);
  if (p->handler == NULL) {
    log_Printf(LogPHASE, "%s: Unknown link type\n", p->link.name);
    free(iov[(*niov)++].iov_base);
    physical_SetupStack(p, "unknown", PHYSICAL_NOFORCE);
  } else
    log_Printf(LogPHASE, "%s: Device %s, link type is %s\n",
               p->link.name, p->name.full, p->handler->name);

  if (p->hdlc.lqm.method && p->hdlc.lqm.timer.load)
    lqr_reStart(&p->link.lcp);
  hdlc_StartTimer(&p->hdlc);

  throughput_restart(&p->link.stats.total, "physical throughput",
                     Enabled(dl->bundle, OPT_THROUGHPUT));

  return p;
}
Exemple #7
0
struct device *
udp_Create(struct physical *p)
{
  char *cp, *host, *port, *svc;
  struct udpdevice *dev;

  dev = NULL;
  if (p->fd < 0) {
    if ((cp = strchr(p->name.full, ':')) != NULL && !strchr(cp + 1, ':')) {
      *cp = '\0';
      host = p->name.full;
      port = cp + 1;
      svc = strchr(port, '/');
      if (svc && strcasecmp(svc, "/udp")) {
        *cp = ':';
        return NULL;
      }
      if (svc) {
        p->fd--;     /* We own the device but maybe can't use it - change fd */
        *svc = '\0';
      }

      if (*host && *port)
        dev = udp_CreateDevice(p, host, port);

      *cp = ':';
      if (svc)
        *svc = '/';
    }
  } else {
    /* See if we're a connected udp socket */
    struct stat st;

    if (fstat(p->fd, &st) != -1 && S_ISSOCK(st.st_mode)) {
      int type, sz;

      sz = sizeof type;
      if (getsockopt(p->fd, SOL_SOCKET, SO_TYPE, &type, &sz) == -1) {
        log_Printf(LogPHASE, "%s: Link is a closed socket !\n", p->link.name);
        close(p->fd);
        p->fd = -1;
        return NULL;
      }

      if (sz == sizeof type && type == SOCK_DGRAM) {
        struct sockaddr_in sock;
        struct sockaddr *sockp = (struct sockaddr *)&sock;

        if ((dev = malloc(sizeof *dev)) == NULL) {
          log_Printf(LogWARN, "%s: Cannot allocate a udp device: %s\n",
                     p->link.name, strerror(errno));
          return NULL;
        }

        if (getpeername(p->fd, sockp, &sz) == 0) {
          log_Printf(LogPHASE, "%s: Link is a connected udp socket\n",
                     p->link.name);
          dev->connected = UDP_CONNECTED;
	} else {
          log_Printf(LogPHASE, "%s: Link is a disconnected udp socket\n",
                     p->link.name);

          dev->connected = UDP_MAYBEUNCONNECTED;

          if (p->link.lcp.cfg.openmode != OPEN_PASSIVE) {
            log_Printf(LogPHASE, "%s:   Changing openmode to PASSIVE\n",
                       p->link.name);
            p->link.lcp.cfg.openmode = OPEN_PASSIVE;
          }
        }
      }
    }
  }

  if (dev) {
    memcpy(&dev->dev, &baseudpdevice, sizeof dev->dev);
    physical_SetupStack(p, dev->dev.name, PHYSICAL_FORCE_SYNC);
    if (p->cfg.cd.necessity != CD_DEFAULT)
      log_Printf(LogWARN, "Carrier settings ignored\n");
    return &dev->dev;
  }

  return NULL;
}
Exemple #8
0
struct device *
i4b_Create(struct physical *p)
{
  struct i4bdevice *dev;
  int oldflag, dial;
  msg_vr_req_t req;
  telno_t number;

  if (p->fd < 0 || ioctl(p->fd, I4B_RBCH_VR_REQ, &req))
    /* Don't want this */
    return NULL;

  /*
   * We don't bother validating the version.... all versions of i4b that
   * support I4B_RBCH_VR_REQ are fair game :-)
   */

  if (*p->name.full == '\0') {
    physical_SetDevice(p, ttyname(p->fd));
    log_Printf(LogDEBUG, "%s: Input is an i4b version %d.%d.%d isdn "
               "device (%s)\n", p->link.name, req.version, req.release,
               req.step, p->name.full);
    dial = 0;
  } else {
    log_Printf(LogDEBUG, "%s: Opened %s (i4b version %d.%d.%d)\n",
               p->link.name, p->name.full, req.version, req.release, req.step);
    dial = 1;
  }

  /* We're gonna return an i4bdevice (unless something goes horribly wrong) */

  if ((dev = malloc(sizeof *dev)) == NULL) {
    /* Complete failure - parent doesn't continue trying to ``create'' */
    close(p->fd);
    p->fd = -1;
    return NULL;
  }

  memcpy(&dev->dev, &basei4bdevice, sizeof dev->dev);
  memset(&dev->Timer, '\0', sizeof dev->Timer);
  dev->mbits = -1;

  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;
  }

  oldflag = fcntl(p->fd, F_GETFL, 0);
  if (oldflag < 0) {
    /* Complete failure - parent doesn't continue trying to ``create'' */

    log_Printf(LogWARN, "%s: Open: Cannot get physical flags: %s\n",
               p->link.name, strerror(errno));
    i4b_Cooked(p);
    close(p->fd);
    p->fd = -1;
    free(dev);
    return NULL;
  } else
    fcntl(p->fd, F_SETFL, oldflag & ~O_NONBLOCK);

  if (dial) {
    strncpy(number, datalink_ChoosePhoneNumber(p->dl), sizeof number - 1);
    number[sizeof number - 1] = '\0';
    if (number[0] == '\0')
      dial = 0;
  }
  if (dial && ioctl(p->fd, I4B_RBCH_DIALOUT, number) == -1) {
    /* Complete failure - parent doesn't continue trying to ``create'' */

    log_Printf(LogWARN, "%s: ioctl(I4B_RBCH_DIALOUT): %s\n",
               p->link.name, strerror(errno));
    i4b_Cooked(p);
    close(p->fd);
    p->fd = -1;
    free(dev);
    return NULL;
  }

  physical_SetupStack(p, dev->dev.name, PHYSICAL_FORCE_SYNC);

  return &dev->dev;
}
Exemple #9
0
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;
}
Exemple #10
0
struct device *
exec_Create(struct physical *p)
{
  struct execdevice *dev;

  dev = NULL;
  if (p->fd < 0) {
    if (*p->name.full == '!') {
      int fids[2], type;
  
      if ((dev = malloc(sizeof *dev)) == NULL) {
        log_Printf(LogWARN, "%s: Cannot allocate an exec device: %s\n",
                   p->link.name, strerror(errno));
        return NULL;
      }
      dev->fd_out = -1;
  
      p->fd--;	/* We own the device but maybe can't use it - change fd */
      type = physical_IsSync(p) ? SOCK_DGRAM : SOCK_STREAM;
  
      if (socketpair(AF_UNIX, type, PF_UNSPEC, fids) < 0) {
        log_Printf(LogPHASE, "Unable to create pipe for line exec: %s\n",
                   strerror(errno));
        free(dev);
        dev = NULL;
      } else {
        static int child_status;		/* This variable is abused ! */
        int stat, argc, i, ret, wret, pidpipe[2];
        pid_t pid, realpid;
        char *argv[MAXARGS];
  
        stat = fcntl(fids[0], F_GETFL, 0);
        if (stat > 0) {
          stat |= O_NONBLOCK;
          fcntl(fids[0], F_SETFL, stat);
        }
        realpid = getpid();
        if (pipe(pidpipe) == -1) {
          log_Printf(LogPHASE, "Unable to pipe for line exec: %s\n",
                     strerror(errno));
          close(fids[1]);
          close(fids[0]);
          free(dev);
          dev = NULL;
        } else switch ((pid = fork())) {
          case -1:
            log_Printf(LogPHASE, "Unable to fork for line exec: %s\n",
                       strerror(errno));
            close(pidpipe[0]);
            close(pidpipe[1]);
            close(fids[1]);
            close(fids[0]);
            break;
  
          case 0:
            close(pidpipe[0]);
            close(fids[0]);
            timer_TermService();
  #ifndef NOSUID
            setuid(ID0realuid());
  #endif
  
            child_status = 0;
            switch ((pid = vfork())) {
              case 0:
                close(pidpipe[1]);
                break;
  
              case -1:
                ret = errno;
                log_Printf(LogPHASE, "Unable to vfork to drop parent: %s\n",
                           strerror(errno));
                close(pidpipe[1]);
                _exit(ret);
  
              default:
                write(pidpipe[1], &pid, sizeof pid);
                close(pidpipe[1]);
                _exit(child_status);	/* The error from exec() ! */
            }
  
            log_Printf(LogDEBUG, "Exec'ing ``%s''\n", p->name.base);
  
            if ((argc = MakeArgs(p->name.base, argv, VECSIZE(argv),
                                 PARSE_REDUCE|PARSE_NOHASH)) < 0) {
              log_Printf(LogWARN, "Syntax error in exec command\n");
              _exit(ESRCH);
            }
  
            command_Expand(argv, argc, (char const *const *)argv,
                           p->dl->bundle, 0, realpid);
  
            dup2(fids[1], STDIN_FILENO);
            dup2(fids[1], STDOUT_FILENO);
            dup2(fids[1], STDERR_FILENO);
            for (i = getdtablesize(); i > STDERR_FILENO; i--)
              fcntl(i, F_SETFD, 1);
  
            execvp(*argv, argv);
            child_status = errno;		/* Only works for vfork() */
            printf("execvp failed: %s: %s\r\n", *argv, strerror(child_status));
            _exit(child_status);
            break;
  
          default:
            close(pidpipe[1]);
            close(fids[1]);
            if (read(pidpipe[0], &p->session_owner, sizeof p->session_owner) !=
                sizeof p->session_owner)
              p->session_owner = (pid_t)-1;
            close(pidpipe[0]);
            while ((wret = waitpid(pid, &stat, 0)) == -1 && errno == EINTR)
              ;
            if (wret == -1) {
              log_Printf(LogWARN, "Waiting for child process: %s\n",
                         strerror(errno));
              close(fids[0]);
              p->session_owner = (pid_t)-1;
              break;
            } else if (WIFSIGNALED(stat)) {
              log_Printf(LogWARN, "Child process received sig %d !\n",
                         WTERMSIG(stat));
              close(fids[0]);
              p->session_owner = (pid_t)-1;
              break;
            } else if (WIFSTOPPED(stat)) {
              log_Printf(LogWARN, "Child process received stop sig %d !\n",
                         WSTOPSIG(stat));
              /* I guess that's ok.... */
            } else if ((ret = WEXITSTATUS(stat))) {
              log_Printf(LogWARN, "Cannot exec \"%s\": %s\n", p->name.base,
                         strerror(ret));
              close(fids[0]);
              p->session_owner = (pid_t)-1;
              break;
            }
            p->fd = fids[0];
            log_Printf(LogDEBUG, "Using descriptor %d for child\n", p->fd);
        }
      }
    }
  } else {
    struct stat st;

    if (fstat(p->fd, &st) != -1 && (st.st_mode & S_IFIFO)) {
      if ((dev = malloc(sizeof *dev)) == NULL)
        log_Printf(LogWARN, "%s: Cannot allocate an exec device: %s\n",
                   p->link.name, strerror(errno));
      else if (p->fd == STDIN_FILENO) {
        log_Printf(LogPHASE, "%s: Using stdin/stdout to communicate with "
                   "parent (pipe mode)\n", p->link.name);
        dev->fd_out = dup(STDOUT_FILENO);

        /* Hook things up so that we monitor dev->fd_out */
        p->desc.UpdateSet = exec_UpdateSet;
        p->desc.IsSet = exec_IsSet;
      } else
        dev->fd_out = -1;
    }
  }

  if (dev) {
    memcpy(&dev->dev, &baseexecdevice, sizeof dev->dev);
    physical_SetupStack(p, dev->dev.name, PHYSICAL_NOFORCE);
    if (p->cfg.cd.necessity != CD_DEFAULT)
      log_Printf(LogWARN, "Carrier settings ignored\n");
    return &dev->dev;
  }

  return NULL;
}
Exemple #11
0
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;
}