Adding port number on the ethernet protocol.
/* 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 "main.h"
#include "eth_linux.h"
enum {
ETH_SERVER_PROTO = 0xCACA,
ETH_CLIENT_PROTO = 0xCACC
};
static int fd;
static enum Eth_type eth_type;
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, enum Eth_type type)
{
int i, n;
struct sockaddr_ll sa;
struct ifreq xx;
short int proto_num;
if (type == ETH_SERVER)
{
dump_line("eth_open for server\n");
proto_num = htons(ETH_SERVER_PROTO);
}
else if (type == ETH_CLIENT)
{
dump_line("eth_open for client\n");
proto_num = htons(ETH_CLIENT_PROTO);
}
else
return -1;
/* Note the type server or client for this process */
eth_type = type;
memset(&sa, 0, sizeof sa);
fd = socket(PF_PACKET, SOCK_DGRAM, proto_num);
if (fd == -1) {
perror("got bad socket");
return -1;
}
i = getindx(fd, eth);
sa.sll_family = AF_PACKET;
sa.sll_protocol = proto_num;
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\n");
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;
i = getindx(fd, dev);
sa.sll_family = AF_PACKET;
if (eth_type == ETH_SERVER)
{
dump_line("eth_send from server to client\n");
sa.sll_protocol = htons(ETH_CLIENT_PROTO);
}
else if (eth_type == ETH_CLIENT)
{
dump_line("eth_send from client to server\n");
sa.sll_protocol = htons(ETH_SERVER_PROTO);
}
else
return -1;
sa.sll_ifindex = i;
sa.sll_halen = 6;
memcpy(sa.sll_addr, mac, 6);
if (debug) {
printf("sending %d bytes to eth_protocol %hi\r\n", len, sa.sll_protocol);
dump(p, len);
}
if (len > 1500)
len = 1500;
return sendto(fd, p, len, 0, (struct sockaddr*) &sa, sizeof(sa));
}