added authors.
/* Copyright Coraid, Inc. 2006. All rights reserved. */
/* Modified the original with BSD license by Lluis Batlle */
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/time.h>
#include <features.h> /* for the glibc version number */
#if __GLIBC__ >= 2 && __GLIBC_MINOR >= 1
#include <netpacket/packet.h>
#include <net/ethernet.h> /* the L2 protocols */
#else
#include <asm/types.h>
#include <linux/if_packet.h>
#include <linux/if_ether.h> /* The L2 protocols */
#endif
#include <sys/ioctl.h>
#include <net/if.h>
#include <netinet/in.h>
#include <linux/fs.h>
#include <sys/stat.h>
#include "eth_linux.h"
enum {
ETH_PROTO = 0xCACA
};
static int fd;
static char srcaddr[6];
static int debug = 0;
static void dump(unsigned char *buf, int len)
{
int i;
for(i=0; i < len; ++i)
{
printf("%x ", (int) buf[i]);
}
putchar('\n');
}
// return the index of device 'name'
static int getindx(int s, char *name)
{
struct ifreq xx;
int n;
strncpy(xx.ifr_name, name, sizeof(xx.ifr_name));
xx.ifr_name[sizeof(xx.ifr_name)-1] = 0;
n = ioctl(s, SIOCGIFINDEX, &xx);
if (n == -1)
return -1;
return xx.ifr_ifindex;
}
// get us a raw connection to an interface
int eth_open(char *eth)
{
int i, n;
struct sockaddr_ll sa;
struct ifreq xx;
memset(&sa, 0, sizeof sa);
fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_PROTO));
if (fd == -1) {
perror("got bad socket");
return -1;
}
i = getindx(fd, eth);
sa.sll_family = AF_PACKET;
sa.sll_protocol = htons(ETH_PROTO);
sa.sll_ifindex = i;
n = bind(fd, (struct sockaddr *)&sa, sizeof sa);
if (n == -1) {
perror("bind funky");
return -1;
}
strncpy(xx.ifr_name, eth, sizeof(xx.ifr_name));
xx.ifr_name[sizeof(xx.ifr_name)-1] = 0;
n = ioctl(fd, SIOCGIFHWADDR, &xx);
if (n == -1) {
perror("Can't get hw addr");
return -1;
}
memmove(srcaddr, xx.ifr_hwaddr.sa_data, 6);
return fd;
}
int eth_recv(char *buf, int len, char *partner_mac)
{
struct sockaddr_ll sa;
int sa_len = sizeof(sa);
int res;
dump_line("eth_recv");
res = recvfrom(fd, buf, len, 0, (struct sockaddr *) &sa, &sa_len);
if (debug) {
printf("read %d bytes\r\n", res);
dump(buf, res);
}
/* Assume sa_len will be ok */
if (partner_mac)
memcpy(partner_mac, sa.sll_addr, sa.sll_halen);
return res;
}
int eth_send(char *dev, char *mac, void *p, int len)
{
struct sockaddr_ll sa;
int i;
dump_line("eth_send");
i = getindx(fd, dev);
sa.sll_family = AF_PACKET;
sa.sll_protocol = htons(ETH_PROTO);
sa.sll_ifindex = i;
sa.sll_halen = 6;
memcpy(sa.sll_addr, mac, 6);
if (debug) {
printf("sending %d bytes\r\n", len);
dump(p, len);
}
if (len > 1500)
len = 1500;
return sendto(fd, p, len, 0, (struct sockaddr*) &sa, sizeof(sa));
}