Logo Search packages:      
Sourcecode: nmap version File versions  Download package

eth-dlpi.c

/*
 * eth-dlpi.c
 *
 * Based on Neal Nuckolls' 1992 "How to Use DLPI" paper.
 *
 * Copyright (c) 2001 Dug Song <dugsong@monkey.org>
 *
 * $Id: eth-dlpi.c 560 2005-02-10 16:48:36Z dugsong $
 */

#include "config.h"

#include <sys/types.h>
#ifdef HAVE_SYS_BUFMOD_H
#include <sys/bufmod.h>
#endif
#ifdef HAVE_SYS_DLPI_H
#include <sys/dlpi.h>
#elif defined(HAVE_SYS_DLPIHDR_H)
#include <sys/dlpihdr.h>
#endif
#ifdef HAVE_SYS_DLPI_EXT_H
#include <sys/dlpi_ext.h>
#endif
#include <sys/stream.h>

#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stropts.h>
#include <unistd.h>

#include "dnet.h"

#ifndef INFTIM
#define INFTIM    -1
#endif

struct eth_handle {
      int   fd;
      int   sap_len;
};

static int
dlpi_msg(int fd, union DL_primitives *dlp, int rlen, int flags,
    int ack, int alen, int size)
{
      struct strbuf ctl;

      ctl.maxlen = 0;
      ctl.len = rlen;
      ctl.buf = (caddr_t)dlp;
      
      if (putmsg(fd, &ctl, NULL, flags) < 0)
            return (-1);
      
      ctl.maxlen = size;
      ctl.len = 0;
      
      flags = 0;

      if (getmsg(fd, &ctl, NULL, &flags) < 0)
            return (-1);
      
      if (dlp->dl_primitive != ack || ctl.len < alen)
            return (-1);
      
      return (0);
}

#if defined(DLIOCRAW) || defined(HAVE_SYS_DLPIHDR_H)
static int
strioctl(int fd, int cmd, int len, char *dp)
{
      struct strioctl str;
      
      str.ic_cmd = cmd;
      str.ic_timout = INFTIM;
      str.ic_len = len;
      str.ic_dp = dp;
      
      if (ioctl(fd, I_STR, &str) < 0)
            return (-1);
      
      return (str.ic_len);
}
#endif

#ifdef HAVE_SYS_DLPIHDR_H
/* XXX - OSF1 is nuts */
#define ND_GET    ('N' << 8 + 0)

static int
eth_match_ppa(eth_t *e, const char *device)
{
      char *p, dev[16], buf[256];
      int len, ppa;

      strlcpy(buf, "dl_ifnames", sizeof(buf));
      
      if ((len = strioctl(e->fd, ND_GET, sizeof(buf), buf)) < 0)
            return (-1);
      
      for (p = buf; p < buf + len; p += strlen(p) + 1) {
            ppa = -1;
            if (sscanf(p, "%s (PPA %d)\n", dev, &ppa) != 2)
                  break;
            if (strcmp(dev, device) == 0)
                  break;
      }
      return (ppa);
}
#endif

eth_t *
eth_open(const char *device)
{
      union DL_primitives *dlp;
      uint32_t buf[8192];
      char *p, dev[16];
      eth_t *e;
      int ppa;

      if ((e = calloc(1, sizeof(*e))) == NULL)
            return (NULL);

#ifdef HAVE_SYS_DLPIHDR_H
      if ((e->fd = open("/dev/streams/dlb", O_RDWR)) < 0)
            return (eth_close(e));
      
      if ((ppa = eth_match_ppa(e, device)) < 0) {
            errno = ESRCH;
            return (eth_close(e));
      }
#else
      e->fd = -1;
      snprintf(dev, sizeof(dev), "/dev/%s", device);
      if ((p = strpbrk(dev, "0123456789")) == NULL) {
            errno = EINVAL;
            return (eth_close(e));
      }
      ppa = atoi(p);
      *p = '\0';

      if ((e->fd = open(dev, O_RDWR)) < 0) {
            snprintf(dev, sizeof(dev), "/dev/%s", device);
            if ((e->fd = open(dev, O_RDWR)) < 0)
                  return (eth_close(e));
      }
#endif
      dlp = (union DL_primitives *)buf;
      dlp->info_req.dl_primitive = DL_INFO_REQ;
      
      if (dlpi_msg(e->fd, dlp, DL_INFO_REQ_SIZE, RS_HIPRI,
          DL_INFO_ACK, DL_INFO_ACK_SIZE, sizeof(buf)) < 0)
            return (eth_close(e));
      
      e->sap_len = dlp->info_ack.dl_sap_length;
      
      if (dlp->info_ack.dl_provider_style == DL_STYLE2) {
            dlp->attach_req.dl_primitive = DL_ATTACH_REQ;
            dlp->attach_req.dl_ppa = ppa;
            
            if (dlpi_msg(e->fd, dlp, DL_ATTACH_REQ_SIZE, 0,
                DL_OK_ACK, DL_OK_ACK_SIZE, sizeof(buf)) < 0)
                  return (eth_close(e));
      }
      memset(&dlp->bind_req, 0, DL_BIND_REQ_SIZE);
      dlp->bind_req.dl_primitive = DL_BIND_REQ;
#ifdef DL_HP_RAWDLS
      dlp->bind_req.dl_sap = 24;    /* from HP-UX DLPI programmers guide */
      dlp->bind_req.dl_service_mode = DL_HP_RAWDLS;
#else
      dlp->bind_req.dl_sap = DL_ETHER;
      dlp->bind_req.dl_service_mode = DL_CLDLS;
#endif
      if (dlpi_msg(e->fd, dlp, DL_BIND_REQ_SIZE, 0,
          DL_BIND_ACK, DL_BIND_ACK_SIZE, sizeof(buf)) < 0)
            return (eth_close(e));
#ifdef DLIOCRAW
      if (strioctl(e->fd, DLIOCRAW, 0, NULL) < 0)
            return (eth_close(e));
#endif
      return (e);
}

ssize_t
eth_send(eth_t *e, const void *buf, size_t len)
{
#if defined(DLIOCRAW)
      return (write(e->fd, buf, len));
#else
      union DL_primitives *dlp;
      struct strbuf ctl, data;
      struct eth_hdr *eth;
      uint32_t ctlbuf[8192];
      u_char sap[4] = { 0, 0, 0, 0 };
      int dlen;

      dlp = (union DL_primitives *)ctlbuf;
#ifdef DL_HP_RAWDATA_REQ
      dlp->dl_primitive = DL_HP_RAWDATA_REQ;
      dlen = DL_HP_RAWDATA_REQ_SIZE;
#else
      dlp->unitdata_req.dl_primitive = DL_UNITDATA_REQ;
      dlp->unitdata_req.dl_dest_addr_length = ETH_ADDR_LEN;
      dlp->unitdata_req.dl_dest_addr_offset = DL_UNITDATA_REQ_SIZE;
      dlp->unitdata_req.dl_priority.dl_min =
          dlp->unitdata_req.dl_priority.dl_max = 0;
      dlen = DL_UNITDATA_REQ_SIZE;
#endif
      eth = (struct eth_hdr *)buf;
      *(uint16_t *)sap = ntohs(eth->eth_type);
      
      /* XXX - DLSAP setup logic from ISC DHCP */
      ctl.maxlen = 0;
      ctl.len = dlen + ETH_ADDR_LEN + abs(e->sap_len);
      ctl.buf = (char *)ctlbuf;
      
      if (e->sap_len >= 0) {
            memcpy(ctlbuf + dlen, sap, e->sap_len);
            memcpy(ctlbuf + dlen + e->sap_len,
                eth->eth_dst.data, ETH_ADDR_LEN);
      } else {
            memcpy(ctlbuf + dlen, eth->eth_dst.data, ETH_ADDR_LEN);
            memcpy(ctlbuf + dlen + ETH_ADDR_LEN, sap, abs(e->sap_len));
      }
      data.maxlen = 0;
      data.len = len;
      data.buf = (char *)buf;

      if (putmsg(e->fd, &ctl, &data, 0) < 0)
            return (-1);

      return (len);
#endif
}

eth_t *
eth_close(eth_t *e)
{
      if (e != NULL) {
            if (e->fd >= 0)
                  close(e->fd);
            free(e);
      }
      return (NULL);
}

int
eth_get(eth_t *e, eth_addr_t *ea)
{
      union DL_primitives *dlp;
      u_char buf[2048];
      
      dlp = (union DL_primitives *)buf;
      dlp->physaddr_req.dl_primitive = DL_PHYS_ADDR_REQ;
      dlp->physaddr_req.dl_addr_type = DL_CURR_PHYS_ADDR;

      if (dlpi_msg(e->fd, dlp, DL_PHYS_ADDR_REQ_SIZE, 0,
          DL_PHYS_ADDR_ACK, DL_PHYS_ADDR_ACK_SIZE, sizeof(buf)) < 0)
            return (-1);

      memcpy(ea, buf + dlp->physaddr_ack.dl_addr_offset, sizeof(*ea));
      
      return (0);
}

int
eth_set(eth_t *e, const eth_addr_t *ea)
{
      union DL_primitives *dlp;
      u_char buf[2048];

      dlp = (union DL_primitives *)buf;
      dlp->set_physaddr_req.dl_primitive = DL_SET_PHYS_ADDR_REQ;
      dlp->set_physaddr_req.dl_addr_length = ETH_ADDR_LEN;
      dlp->set_physaddr_req.dl_addr_offset = DL_SET_PHYS_ADDR_REQ_SIZE;

      memcpy(buf + DL_SET_PHYS_ADDR_REQ_SIZE, ea, sizeof(*ea));
      
      return (dlpi_msg(e->fd, dlp, DL_SET_PHYS_ADDR_REQ_SIZE + ETH_ADDR_LEN,
          0, DL_OK_ACK, DL_OK_ACK_SIZE, sizeof(buf)));
}

Generated by  Doxygen 1.6.0   Back to index