1 /* Copyright Coraid, Inc. 2006.  All rights reserved. */
2 /* Modified the original with BSD license by Lluis Batlle */
3 
4 #include <sys/types.h>
5 #include <sys/socket.h>
6 #include <stdio.h>
7 #include <string.h>
8 #include <stdlib.h>
9 #include <unistd.h>
10 #include <sys/time.h>
11 #include <features.h>    /* for the glibc version number */
12 #if __GLIBC__ >= 2 && __GLIBC_MINOR >= 1
13 #include <netpacket/packet.h>
14 #include <net/ethernet.h>     /* the L2 protocols */
15 #else
16 #include <asm/types.h>
17 #include <linux/if_packet.h>
18 #include <linux/if_ether.h>   /* The L2 protocols */
19 #endif
20 
21 #include <sys/ioctl.h>
22 #include <net/if.h>
23 #include <netinet/in.h>
24 #include <linux/fs.h>
25 #include <sys/stat.h>
26 
27 #include "main.h"
28 #include "eth_linux.h"
29 
30 enum {
31     ETH_SERVER_PROTO = 0xCACA,
32     ETH_CLIENT_PROTO = 0xCACC
33 };
34 
35 static int fd;
36 static enum Eth_type eth_type;
37 static char srcaddr[6];
38 static int debug = 0;
39 
dump(unsigned char * buf,int len)40 static void dump(unsigned char *buf, int len)
41 {
42   int i;
43   for(i=0; i < len; ++i)
44   {
45     printf("%x ", (int) buf[i]);
46   }
47   putchar('\n');
48 }
49 
50 // return the index of device 'name'
getindx(int s,char * name)51 static int getindx(int s, char *name)
52 {
53     struct ifreq xx;
54     int n;
55 
56     strncpy(xx.ifr_name, name, sizeof(xx.ifr_name));
57     xx.ifr_name[sizeof(xx.ifr_name)-1] = 0;
58     n = ioctl(s, SIOCGIFINDEX, &xx);
59     if (n == -1)
60         return -1;
61     return xx.ifr_ifindex;
62 }
63 
64 // get us a raw connection to an interface
eth_open(char * eth,enum Eth_type type)65 int eth_open(char *eth, enum Eth_type type)
66 {
67     int i, n;
68     struct sockaddr_ll sa;
69     struct ifreq xx;
70     short int proto_num;
71 
72     if (type == ETH_SERVER)
73     {
74         dump_line("eth_open for server\n");
75         proto_num = htons(ETH_SERVER_PROTO);
76     }
77     else if (type == ETH_CLIENT)
78     {
79         dump_line("eth_open for client\n");
80         proto_num = htons(ETH_CLIENT_PROTO);
81     }
82     else
83         return -1;
84 
85     /* Note the type server or client for this process */
86     eth_type = type;
87 
88     memset(&sa, 0, sizeof sa);
89     fd = socket(PF_PACKET, SOCK_DGRAM, proto_num);
90     if (fd == -1) {
91         perror("got bad socket");
92         return -1;
93     }
94     i = getindx(fd, eth);
95     sa.sll_family = AF_PACKET;
96     sa.sll_protocol = proto_num;
97     sa.sll_ifindex = i;
98     n = bind(fd, (struct sockaddr *)&sa, sizeof sa);
99     if (n == -1) {
100         perror("bind funky");
101         return -1;
102     }
103     strncpy(xx.ifr_name, eth, sizeof(xx.ifr_name));
104     xx.ifr_name[sizeof(xx.ifr_name)-1] = 0;
105     n = ioctl(fd, SIOCGIFHWADDR, &xx);
106     if (n == -1) {
107         perror("Can't get hw addr");
108         return -1;
109     }
110     memmove(srcaddr, xx.ifr_hwaddr.sa_data, 6);
111     return fd;
112 }
113 
eth_recv(char * buf,int len,char * partner_mac)114 int eth_recv(char *buf, int len, char *partner_mac)
115 {
116     struct sockaddr_ll sa;
117     int sa_len = sizeof(sa);
118     int res;
119     dump_line("eth_recv\n");
120     res = recvfrom(fd, buf, len, 0, (struct sockaddr *) &sa, &sa_len);
121     if (debug) {
122         printf("read %d bytes\r\n", res);
123         dump(buf, res);
124     }
125     /* Assume sa_len will be ok */
126     if (partner_mac)
127         memcpy(partner_mac, sa.sll_addr, sa.sll_halen);
128     return res;
129 }
130 
eth_send(char * dev,char * mac,void * p,int len)131 int eth_send(char *dev, char *mac, void *p, int len)
132 {
133     struct sockaddr_ll sa;
134     int i;
135 
136     i = getindx(fd, dev);
137     sa.sll_family = AF_PACKET;
138     if (eth_type == ETH_SERVER)
139     {
140         dump_line("eth_send from server to client\n");
141         sa.sll_protocol = htons(ETH_CLIENT_PROTO);
142     }
143     else if (eth_type == ETH_CLIENT)
144     {
145         dump_line("eth_send from client to server\n");
146         sa.sll_protocol = htons(ETH_SERVER_PROTO);
147     }
148     else
149         return -1;
150     sa.sll_ifindex = i;
151     sa.sll_halen = 6;
152     memcpy(sa.sll_addr, mac, 6);
153     if (debug) {
154         printf("sending %d bytes to eth_protocol %hi\r\n", len, sa.sll_protocol);
155         dump(p, len);
156     }
157     if (len > 1500)
158         len = 1500;
159     return sendto(fd, p, len, 0, (struct sockaddr*) &sa, sizeof(sa));
160 }
161