diff options
Diffstat (limited to '')
-rw-r--r-- | libdnet-stripped/src/eth-dlpi.c | 304 |
1 files changed, 304 insertions, 0 deletions
diff --git a/libdnet-stripped/src/eth-dlpi.c b/libdnet-stripped/src/eth-dlpi.c new file mode 100644 index 0000000..dc7b8c9 --- /dev/null +++ b/libdnet-stripped/src/eth-dlpi.c @@ -0,0 +1,304 @@ +/* + * 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); +} +#else +static char * +dev_find_ppa(char *dev) +{ + char *p; + + p = dev + strlen(dev); + while (p > dev && strchr("0123456789", *(p - 1)) != NULL) + p--; + if (*p == '\0') + return NULL; + + return p; +} +#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 = dev_find_ppa(dev)) == 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) { + snprintf(dev, sizeof(dev), "/dev/net/%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))); +} |