00001
00002
00003
00004
00005
00006
00007
00008
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
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;
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
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 }