00001
00002
00003
00004
00005
00006
00007
00008
00009 #include "config.h"
00010
00011 #include <sys/param.h>
00012 #include <sys/types.h>
00013 #include <sys/ioctl.h>
00014 #include <sys/socket.h>
00015 #include <sys/time.h>
00016 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_ROUTE_RT_MSGHDR)
00017 #include <sys/sysctl.h>
00018 #include <net/route.h>
00019 #include <net/if_dl.h>
00020 #endif
00021 #include <net/bpf.h>
00022 #include <net/if.h>
00023
00024 #include <assert.h>
00025 #include <errno.h>
00026 #include <fcntl.h>
00027 #include <stdio.h>
00028 #include <stdlib.h>
00029 #include <string.h>
00030 #include <unistd.h>
00031
00032 #include "dnet.h"
00033
00034 struct eth_handle {
00035 int fd;
00036 char device[16];
00037 };
00038
00039 eth_t *
00040 eth_open(const char *device)
00041 {
00042 struct ifreq ifr;
00043 char file[32];
00044 eth_t *e;
00045 int i;
00046
00047 if ((e = calloc(1, sizeof(*e))) != NULL) {
00048 for (i = 0; i < 32; i++) {
00049 snprintf(file, sizeof(file), "/dev/bpf%d", i);
00050 e->fd = open(file, O_WRONLY);
00051 if (e->fd != -1 || errno != EBUSY)
00052 break;
00053 }
00054 if (e->fd < 0)
00055 return (eth_close(e));
00056
00057 memset(&ifr, 0, sizeof(ifr));
00058 strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
00059
00060 if (ioctl(e->fd, BIOCSETIF, (char *)&ifr) < 0)
00061 return (eth_close(e));
00062 #ifdef BIOCSHDRCMPLT
00063 i = 1;
00064 if (ioctl(e->fd, BIOCSHDRCMPLT, &i) < 0)
00065 return (eth_close(e));
00066 #endif
00067 strlcpy(e->device, device, sizeof(e->device));
00068 }
00069 return (e);
00070 }
00071
00072 ssize_t
00073 eth_send(eth_t *e, const void *buf, size_t len)
00074 {
00075 return (write(e->fd, buf, len));
00076 }
00077
00078 eth_t *
00079 eth_close(eth_t *e)
00080 {
00081 if (e != NULL) {
00082 if (e->fd >= 0)
00083 close(e->fd);
00084 free(e);
00085 }
00086 return (NULL);
00087 }
00088
00089 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_ROUTE_RT_MSGHDR)
00090 int
00091 eth_get(eth_t *e, eth_addr_t *ea)
00092 {
00093 struct if_msghdr *ifm;
00094 struct sockaddr_dl *sdl;
00095 struct addr ha;
00096 u_char *p, *buf;
00097 size_t len;
00098 int mib[] = { CTL_NET, AF_ROUTE, 0, AF_LINK, NET_RT_IFLIST, 0 };
00099
00100 if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0)
00101 return (-1);
00102
00103 if ((buf = malloc(len)) == NULL)
00104 return (-1);
00105
00106 if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
00107 free(buf);
00108 return (-1);
00109 }
00110 for (p = buf; p < buf + len; p += ifm->ifm_msglen) {
00111 ifm = (struct if_msghdr *)p;
00112 sdl = (struct sockaddr_dl *)(ifm + 1);
00113
00114 if (ifm->ifm_type != RTM_IFINFO ||
00115 (ifm->ifm_addrs & RTA_IFP) == 0)
00116 continue;
00117
00118 if (sdl->sdl_family != AF_LINK || sdl->sdl_nlen == 0 ||
00119 memcmp(sdl->sdl_data, e->device, sdl->sdl_nlen) != 0)
00120 continue;
00121
00122 if (addr_ston((struct sockaddr *)sdl, &ha) == 0)
00123 break;
00124 }
00125 free(buf);
00126
00127 if (p >= buf + len) {
00128 errno = ESRCH;
00129 return (-1);
00130 }
00131 memcpy(ea, &ha.addr_eth, sizeof(*ea));
00132
00133 return (0);
00134 }
00135 #else
00136 int
00137 eth_get(eth_t *e, eth_addr_t *ea)
00138 {
00139 errno = ENOSYS;
00140 return (-1);
00141 }
00142 #endif
00143
00144 #if defined(SIOCSIFLLADDR)
00145 int
00146 eth_set(eth_t *e, const eth_addr_t *ea)
00147 {
00148 struct ifreq ifr;
00149 struct addr ha;
00150
00151 ha.addr_type = ADDR_TYPE_ETH;
00152 ha.addr_bits = ETH_ADDR_BITS;
00153 memcpy(&ha.addr_eth, ea, ETH_ADDR_LEN);
00154
00155 memset(&ifr, 0, sizeof(ifr));
00156 strlcpy(ifr.ifr_name, e->device, sizeof(ifr.ifr_name));
00157 addr_ntos(&ha, &ifr.ifr_addr);
00158
00159 return (ioctl(e->fd, SIOCSIFLLADDR, &ifr));
00160 }
00161 #else
00162 int
00163 eth_set(eth_t *e, const eth_addr_t *ea)
00164 {
00165 errno = ENOSYS;
00166 return (-1);
00167 }
00168 #endif