Main Page | Modules | Class List | Directories | File List | Class Members | File Members | Related Pages

eth-dlpi.c

Go to the documentation of this file.
00001 /*
00002  * eth-dlpi.c
00003  *
00004  * Based on Neal Nuckolls' 1992 "How to Use DLPI" paper.
00005  *
00006  * Copyright (c) 2001 Dug Song <dugsong@monkey.org>
00007  *
00008  * $Id: eth-dlpi.c,v 1.19 2005/02/10 16:48:36 dugsong Exp $
00009  */
00010 
00011 #include "config.h"
00012 
00013 #include <sys/types.h>
00014 #ifdef HAVE_SYS_BUFMOD_H
00015 #include <sys/bufmod.h>
00016 #endif
00017 #ifdef HAVE_SYS_DLPI_H
00018 #include <sys/dlpi.h>
00019 #elif defined(HAVE_SYS_DLPIHDR_H)
00020 #include <sys/dlpihdr.h>
00021 #endif
00022 #ifdef HAVE_SYS_DLPI_EXT_H
00023 #include <sys/dlpi_ext.h>
00024 #endif
00025 #include <sys/stream.h>
00026 
00027 #include <assert.h>
00028 #include <errno.h>
00029 #include <fcntl.h>
00030 #include <stdio.h>
00031 #include <stdlib.h>
00032 #include <string.h>
00033 #include <stropts.h>
00034 #include <unistd.h>
00035 
00036 #include "dnet.h"
00037 
00038 #ifndef INFTIM
00039 #define INFTIM  -1
00040 #endif
00041 
00042 struct eth_handle {
00043         int     fd;
00044         int     sap_len;
00045 };
00046 
00047 static int
00048 dlpi_msg(int fd, union DL_primitives *dlp, int rlen, int flags,
00049     int ack, int alen, int size)
00050 {
00051         struct strbuf ctl;
00052 
00053         ctl.maxlen = 0;
00054         ctl.len = rlen;
00055         ctl.buf = (caddr_t)dlp;
00056         
00057         if (putmsg(fd, &ctl, NULL, flags) < 0)
00058                 return (-1);
00059         
00060         ctl.maxlen = size;
00061         ctl.len = 0;
00062         
00063         flags = 0;
00064 
00065         if (getmsg(fd, &ctl, NULL, &flags) < 0)
00066                 return (-1);
00067         
00068         if (dlp->dl_primitive != ack || ctl.len < alen)
00069                 return (-1);
00070         
00071         return (0);
00072 }
00073 
00074 #if defined(DLIOCRAW) || defined(HAVE_SYS_DLPIHDR_H)
00075 static int
00076 strioctl(int fd, int cmd, int len, char *dp)
00077 {
00078         struct strioctl str;
00079         
00080         str.ic_cmd = cmd;
00081         str.ic_timout = INFTIM;
00082         str.ic_len = len;
00083         str.ic_dp = dp;
00084         
00085         if (ioctl(fd, I_STR, &str) < 0)
00086                 return (-1);
00087         
00088         return (str.ic_len);
00089 }
00090 #endif
00091 
00092 #ifdef HAVE_SYS_DLPIHDR_H
00093 /* XXX - OSF1 is nuts */
00094 #define ND_GET  ('N' << 8 + 0)
00095 
00096 static int
00097 eth_match_ppa(eth_t *e, const char *device)
00098 {
00099         char *p, dev[16], buf[256];
00100         int len, ppa;
00101 
00102         strlcpy(buf, "dl_ifnames", sizeof(buf));
00103         
00104         if ((len = strioctl(e->fd, ND_GET, sizeof(buf), buf)) < 0)
00105                 return (-1);
00106         
00107         for (p = buf; p < buf + len; p += strlen(p) + 1) {
00108                 ppa = -1;
00109                 if (sscanf(p, "%s (PPA %d)\n", dev, &ppa) != 2)
00110                         break;
00111                 if (strcmp(dev, device) == 0)
00112                         break;
00113         }
00114         return (ppa);
00115 }
00116 #endif
00117 
00118 eth_t *
00119 eth_open(const char *device)
00120 {
00121         union DL_primitives *dlp;
00122         uint32_t buf[8192];
00123         char *p, dev[16];
00124         eth_t *e;
00125         int ppa;
00126 
00127         if ((e = calloc(1, sizeof(*e))) == NULL)
00128                 return (NULL);
00129 
00130 #ifdef HAVE_SYS_DLPIHDR_H
00131         if ((e->fd = open("/dev/streams/dlb", O_RDWR)) < 0)
00132                 return (eth_close(e));
00133         
00134         if ((ppa = eth_match_ppa(e, device)) < 0) {
00135                 errno = ESRCH;
00136                 return (eth_close(e));
00137         }
00138 #else
00139         e->fd = -1;
00140         snprintf(dev, sizeof(dev), "/dev/%s", device);
00141         if ((p = strpbrk(dev, "0123456789")) == NULL) {
00142                 errno = EINVAL;
00143                 return (eth_close(e));
00144         }
00145         ppa = atoi(p);
00146         *p = '\0';
00147 
00148         if ((e->fd = open(dev, O_RDWR)) < 0) {
00149                 snprintf(dev, sizeof(dev), "/dev/%s", device);
00150                 if ((e->fd = open(dev, O_RDWR)) < 0)
00151                         return (eth_close(e));
00152         }
00153 #endif
00154         dlp = (union DL_primitives *)buf;
00155         dlp->info_req.dl_primitive = DL_INFO_REQ;
00156         
00157         if (dlpi_msg(e->fd, dlp, DL_INFO_REQ_SIZE, RS_HIPRI,
00158             DL_INFO_ACK, DL_INFO_ACK_SIZE, sizeof(buf)) < 0)
00159                 return (eth_close(e));
00160         
00161         e->sap_len = dlp->info_ack.dl_sap_length;
00162         
00163         if (dlp->info_ack.dl_provider_style == DL_STYLE2) {
00164                 dlp->attach_req.dl_primitive = DL_ATTACH_REQ;
00165                 dlp->attach_req.dl_ppa = ppa;
00166                 
00167                 if (dlpi_msg(e->fd, dlp, DL_ATTACH_REQ_SIZE, 0,
00168                     DL_OK_ACK, DL_OK_ACK_SIZE, sizeof(buf)) < 0)
00169                         return (eth_close(e));
00170         }
00171         memset(&dlp->bind_req, 0, DL_BIND_REQ_SIZE);
00172         dlp->bind_req.dl_primitive = DL_BIND_REQ;
00173 #ifdef DL_HP_RAWDLS
00174         dlp->bind_req.dl_sap = 24;      /* from HP-UX DLPI programmers guide */
00175         dlp->bind_req.dl_service_mode = DL_HP_RAWDLS;
00176 #else
00177         dlp->bind_req.dl_sap = DL_ETHER;
00178         dlp->bind_req.dl_service_mode = DL_CLDLS;
00179 #endif
00180         if (dlpi_msg(e->fd, dlp, DL_BIND_REQ_SIZE, 0,
00181             DL_BIND_ACK, DL_BIND_ACK_SIZE, sizeof(buf)) < 0)
00182                 return (eth_close(e));
00183 #ifdef DLIOCRAW
00184         if (strioctl(e->fd, DLIOCRAW, 0, NULL) < 0)
00185                 return (eth_close(e));
00186 #endif
00187         return (e);
00188 }
00189 
00190 ssize_t
00191 eth_send(eth_t *e, const void *buf, size_t len)
00192 {
00193 #if defined(DLIOCRAW)
00194         return (write(e->fd, buf, len));
00195 #else
00196         union DL_primitives *dlp;
00197         struct strbuf ctl, data;
00198         struct eth_hdr *eth;
00199         uint32_t ctlbuf[8192];
00200         u_char sap[4] = { 0, 0, 0, 0 };
00201         int dlen;
00202 
00203         dlp = (union DL_primitives *)ctlbuf;
00204 #ifdef DL_HP_RAWDATA_REQ
00205         dlp->dl_primitive = DL_HP_RAWDATA_REQ;
00206         dlen = DL_HP_RAWDATA_REQ_SIZE;
00207 #else
00208         dlp->unitdata_req.dl_primitive = DL_UNITDATA_REQ;
00209         dlp->unitdata_req.dl_dest_addr_length = ETH_ADDR_LEN;
00210         dlp->unitdata_req.dl_dest_addr_offset = DL_UNITDATA_REQ_SIZE;
00211         dlp->unitdata_req.dl_priority.dl_min =
00212             dlp->unitdata_req.dl_priority.dl_max = 0;
00213         dlen = DL_UNITDATA_REQ_SIZE;
00214 #endif
00215         eth = (struct eth_hdr *)buf;
00216         *(uint16_t *)sap = ntohs(eth->eth_type);
00217         
00218         /* XXX - DLSAP setup logic from ISC DHCP */
00219         ctl.maxlen = 0;
00220         ctl.len = dlen + ETH_ADDR_LEN + abs(e->sap_len);
00221         ctl.buf = (char *)ctlbuf;
00222         
00223         if (e->sap_len >= 0) {
00224                 memcpy(ctlbuf + dlen, sap, e->sap_len);
00225                 memcpy(ctlbuf + dlen + e->sap_len,
00226                     eth->eth_dst.data, ETH_ADDR_LEN);
00227         } else {
00228                 memcpy(ctlbuf + dlen, eth->eth_dst.data, ETH_ADDR_LEN);
00229                 memcpy(ctlbuf + dlen + ETH_ADDR_LEN, sap, abs(e->sap_len));
00230         }
00231         data.maxlen = 0;
00232         data.len = len;
00233         data.buf = (char *)buf;
00234 
00235         if (putmsg(e->fd, &ctl, &data, 0) < 0)
00236                 return (-1);
00237 
00238         return (len);
00239 #endif
00240 }
00241 
00242 eth_t *
00243 eth_close(eth_t *e)
00244 {
00245         if (e != NULL) {
00246                 if (e->fd >= 0)
00247                         close(e->fd);
00248                 free(e);
00249         }
00250         return (NULL);
00251 }
00252 
00253 int
00254 eth_get(eth_t *e, eth_addr_t *ea)
00255 {
00256         union DL_primitives *dlp;
00257         u_char buf[2048];
00258         
00259         dlp = (union DL_primitives *)buf;
00260         dlp->physaddr_req.dl_primitive = DL_PHYS_ADDR_REQ;
00261         dlp->physaddr_req.dl_addr_type = DL_CURR_PHYS_ADDR;
00262 
00263         if (dlpi_msg(e->fd, dlp, DL_PHYS_ADDR_REQ_SIZE, 0,
00264             DL_PHYS_ADDR_ACK, DL_PHYS_ADDR_ACK_SIZE, sizeof(buf)) < 0)
00265                 return (-1);
00266 
00267         memcpy(ea, buf + dlp->physaddr_ack.dl_addr_offset, sizeof(*ea));
00268         
00269         return (0);
00270 }
00271 
00272 int
00273 eth_set(eth_t *e, const eth_addr_t *ea)
00274 {
00275         union DL_primitives *dlp;
00276         u_char buf[2048];
00277 
00278         dlp = (union DL_primitives *)buf;
00279         dlp->set_physaddr_req.dl_primitive = DL_SET_PHYS_ADDR_REQ;
00280         dlp->set_physaddr_req.dl_addr_length = ETH_ADDR_LEN;
00281         dlp->set_physaddr_req.dl_addr_offset = DL_SET_PHYS_ADDR_REQ_SIZE;
00282 
00283         memcpy(buf + DL_SET_PHYS_ADDR_REQ_SIZE, ea, sizeof(*ea));
00284         
00285         return (dlpi_msg(e->fd, dlp, DL_SET_PHYS_ADDR_REQ_SIZE + ETH_ADDR_LEN,
00286             0, DL_OK_ACK, DL_OK_ACK_SIZE, sizeof(buf)));
00287 }

Generated on Sun May 14 14:51:11 2006 by  doxygen 1.4.2