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