pxar
All Classes Namespaces Functions Variables Typedefs Friends
EthernetInterface.cc
1 #include "EthernetInterface.h"
2 #include "rpc_error.h"
3 #include "config.h"
4 
5 #include "log.h"
6 #include "exceptions.h"
7 
8 using namespace std;
9 using namespace pxar;
10 
11 void print_eth_packet(const unsigned char* packet, int len){
12  printf("LEN:%d ", len);
13  for(int i = 0; i < len; i++){
14  printf("%02X:",packet[i]);
15  }
16  printf("\n");
17 }
18 
19 bool packet_equals(const unsigned char* pkt1,
20  const unsigned char* pkt2, int size){
21  for(int i = 0; i < size; i++){
22  if(pkt1[i] != pkt2[i]) return false;
23  }
24  return true;
25 }
26 
27 #ifdef __unix__
28 #include <sys/types.h>
29 #include <sys/socket.h>
30 #include <netinet/in.h>
31 #include <arpa/inet.h>
32 #include <net/if.h>
33 #include <netpacket/packet.h>
34 #include <ifaddrs.h>
35 
36 #include <cstdio>
37 #include <cstdlib>
38 #include <string.h>
39 
40 void Get_MAC(const char* if_name, unsigned char* buffer){
41  ifaddrs * ifap = 0;
42  if(getifaddrs(&ifap) == 0){
43  ifaddrs * iter = ifap;
44  while(iter){
45  sockaddr_ll * sal = reinterpret_cast<sockaddr_ll*>(iter->ifa_addr);
46  if(sal->sll_family == AF_PACKET){
47  if(!strcmp(if_name, iter->ifa_name)){
48  for(int i = 0 ; i < sal->sll_halen; i++){
49  buffer[i] = sal->sll_addr[i];
50  }
51  break;
52  }
53  }
54  iter = iter->ifa_next;
55  }
56  freeifaddrs(ifap);
57  }
58 }
59 #endif
60 
61 #ifdef __APPLE__
62 #include <sys/types.h>
63 #include <sys/socket.h>
64 #include <sys/ioctl.h>
65 #include <sys/sysctl.h>
66 #include <net/if.h>
67 #include <net/if_dl.h>
68 #include <netinet/in.h>
69 #include <arpa/inet.h>
70 #include <errno.h>
71 #include <stdio.h>
72 #include <stdlib.h>
73 
74 void Get_MAC(const char* if_name, unsigned char* buffer){
75  int mib[6];
76  size_t len;
77  char *buf;
78  unsigned char *ptr;
79  struct if_msghdr *ifm;
80  struct sockaddr_dl *sdl;
81 
82  mib[0] = CTL_NET;
83  mib[1] = AF_ROUTE;
84  mib[2] = 0;
85  mib[3] = AF_LINK;
86  mib[4] = NET_RT_IFLIST;
87  if ((mib[5] = if_nametoindex(if_name)) == 0) {
88  perror("if_nametoindex error");
89  exit(2);
90  }
91 
92  if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) {
93  perror("sysctl 1 error");
94  exit(3);
95  }
96 
97  if ((buf = (char*)malloc(len)) == NULL) {
98  perror("malloc error");
99  exit(4);
100  }
101 
102  if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
103  perror("sysctl 2 error");
104  exit(5);
105  }
106 
107  ifm = (struct if_msghdr *)buf;
108  sdl = (struct sockaddr_dl *)(ifm + 1);
109  ptr = (unsigned char *)LLADDR(sdl);
110 
111  for(int i = 0; i < 6; i++){
112  buffer[i] = ptr[i];
113  }
114 }
115 #endif
116 
117 #ifdef _WIN32 //Not finished
118 #include <winsock2.h>
119 #include <iphlpapi.h>
120 
121 void Get_MAC(const char* if_name, unsigned char* buffer){
122 
123  std::vector<unsigned char> buf;
124  DWORD bufLen = 0;
125  GetAdaptersAddresses(0, 0, 0, 0, &bufLen);
126  if(bufLen)
127  {
128  buf.resize(bufLen, 0);
129  IP_ADAPTER_ADDRESSES * ptr =
130  reinterpret_cast<IP_ADAPTER_ADDRESSES*>(&buf[0]);
131  DWORD err = GetAdaptersAddresses(0, 0, 0, ptr, &bufLen);
132  if(err == NO_ERROR)
133  {
134  while(ptr)
135  {
136  if(ptr->PhysicalAddressLength)
137  {
138  // get the mac bytes
139  // copy(ptr->PhysicalAddress,
140  // ptr->PhysicalAddress+ptr->PhysicalAddressLength,
141  // buffer);
142  }
143  ptr = ptr->Next;
144  }
145  }
146  }
147 }
148 #endif
149 
150 
151 
152 
153 CEthernet::CEthernet(){
154  unsigned int ipid = getpid();
155  host_pid[0] = (unsigned char) (ipid>>8);
156  host_pid[1] = (unsigned char) ipid;
157  interface += ETHERNET_INTERFACE;
158  is_open = false;
159  LOG(logINTERFACE) << "Start initializing ethernet interface.";
160  InitInterface();
161 }
162 
163 CEthernet::~CEthernet(){
164  if(is_open){
165  Close();
166  pcap_close(descr);
167  }
168 }
169 
170 void CEthernet::Write(const void *buffer, unsigned int size){
171  for(unsigned int i = 0 ; i < size; i++){
172  if(tx_payload_size == MAX_TX_DATA){
173  Flush();
174  }
175  tx_frame[ETH_HEADER_SIZE + tx_payload_size] = ((char*)buffer)[i];
176  tx_payload_size++;
177  }
178 }
179 void CEthernet::Flush(){
180  for(int i =0; i < 6; i++){
181  tx_frame[i] = dtb_mac[i];
182  tx_frame[i+6] = host_mac[i];
183  }
184  tx_frame[12] = 0x08;
185  tx_frame[13] = 0x09;
186  tx_frame[14] = host_pid[0];
187  tx_frame[15] = host_pid[1];
188  tx_frame[16] = 0x0;
189 
190  tx_frame[17] = tx_payload_size >> 8;
191  tx_frame[18] = tx_payload_size;
192 
193  IFLOG(logINTERFACE) {
194  std::stringstream st;
195  st << std::uppercase << std::hex;
196  for(size_t i = 0; i < tx_payload_size + ETH_HEADER_SIZE; i++) {
197  st << std::setw(2) << std::setfill('0') << tx_frame[i];
198  }
199  st << std::nouppercase << std::dec;
200  LOG(logINTERFACE) << "Sent packet: " << st.str();
201  }
202 
203  pcap_sendpacket(descr, tx_frame, tx_payload_size + ETH_HEADER_SIZE);
204  tx_payload_size = 0;
205 }
206 void CEthernet::Clear(){
207  tx_payload_size = 0;
208  rx_buffer.clear();
209 }
210 void CEthernet::Read(void *buffer, unsigned int size){
211  int timeout = 10000;
212  for(unsigned int i = 0; i < size; i++){
213  if(!rx_buffer.empty()){
214  ((unsigned char*)buffer)[i] = rx_buffer.front();
215  rx_buffer.pop_front();
216  } else{
217  const unsigned char* rx_frame = pcap_next(descr, &header);
218  if(rx_frame == NULL){
219  timeout--;
220  i--;
221  if(timeout == 0){
222  printf("Error reading from ethernet.\n");
223  throw CRpcError(CRpcError::TIMEOUT);
224  }
225  }
226 
227  IFLOG(logINTERFACE) {
228  std::stringstream st;
229  st << std::uppercase << std::hex;
230  for(size_t i = 0; i < header.len; i++){
231  st << std::setw(2) << std::setfill('0') << rx_frame[i];
232  }
233  st << std::nouppercase << std::dec;
234  LOG(logINTERFACE) << "Received packet: " << st.str();
235  }
236 
237  if(header.len < ETH_HEADER_SIZE){ // malformed message
238  i--;
239  continue;
240  }
241 
242  if(!packet_equals(rx_frame,host_mac,6) ||
243  !packet_equals(rx_frame+14,host_pid,2) ||
244  rx_frame[16] != 0) {
245  i--;
246  continue;
247  }
248  LOG(logINTERFACE) << "Passed Filter.";
249 
250  unsigned int rx_payload_size = rx_frame[17];
251  rx_payload_size = (rx_payload_size << 8) | rx_frame[18];
252 
253  for(unsigned int j =0; j < rx_payload_size;j++){
254  rx_buffer.push_back(rx_frame[j + ETH_HEADER_SIZE]);
255  }
256  i--;
257  }
258  }
259 }
260 
261 void CEthernet::InitInterface(){
262  rx_buffer.resize(0);
263  for(int i =0; i < TX_FRAME_SIZE; i++){
264  tx_frame[i] = 0;
265  }
266  tx_payload_size = 0;
267 
268  char errbuf[PCAP_ERRBUF_SIZE];
269  descr = pcap_open_live(interface.c_str(), BUFSIZ,0,100,errbuf);
270  if(descr == NULL) {
271  LOG(logINTERFACE) << "pcap_open_live() failed:";
272  LOG(logINTERFACE) << interface << " | " << errbuf;
273  throw CRpcError(CRpcError::IF_INIT_ERROR);
274  }
275 
276  Get_MAC(interface.c_str(), host_mac);
277  for(int i = 0; i < 6; i++) tx_frame[i+6] = host_mac[i];
278 }
279 
280 bool CEthernet::EnumFirst(unsigned int &nDevices){
281  Hello();
282  nDevices = MAC_addresses.size();
283  return true;
284 }
285 bool CEthernet::EnumNext(char name[]){
286  string MAC = MAC_addresses[MAC_counter];
287  MAC_counter = (MAC_counter + 1) % MAC_addresses.size();
288 
289  for(size_t i = 0; i < MAC.size(); i++){
290  name[i] = MAC.at(i);
291  }
292  return true;
293 }
294 bool CEthernet::Enum(char name[], unsigned int pos){
295  string MAC = MAC_addresses[pos];
296 
297  for(int i = 0; i < 10; i++){
298  name[i] = MAC[i];
299  }
300  return true;
301 }
302 
303 bool CEthernet::Open(char MAC_address[]){
304  if(is_open) Close();
305  bool success = Claim(((unsigned char*)MAC_address)+7,true);
306  if(!success) return false;
307  for(int i =0; i < 6; i++){
308  dtb_mac[i] = MAC_address[7+i];
309  }
310  is_open = true;
311  return true;
312 }
313 
314 void CEthernet::Close(){
315  if(!is_open) return;
316  bool success = Unclaim();
317  if(!success) throw CRpcError(CRpcError::ETH_ERROR);
318  for(int i =0; i < 6; i++){
319  dtb_mac[i] = 0x00;
320  tx_frame[i] = dtb_mac[i];
321  }
322  is_open = false;
323 }
324 
325 void CEthernet::Hello(){
326  unsigned char packet[17];
327 
328  for(int i = 0; i < 6; i++){
329  packet[i] = 0xFF;
330  packet[i+6] = host_mac[i];
331  }
332  packet[12] = 0x08;
333  packet[13] = 0x09;
334  packet[14] = host_pid[0];
335  packet[15] = host_pid[1];
336  packet[16] = 0x1;
337 
338  pcap_sendpacket(descr, packet, sizeof(packet));
339 
340 
341  MAC_addresses.clear();
342  MAC_counter = 0;
343  //wait at least 1 second for responses.
344  time_t startTime = time(NULL);
345  const unsigned char* rx_frame;
346  while(time(NULL) - startTime < 2){
347  rx_frame = pcap_next(descr, &header);
348  if(rx_frame == NULL) continue;
349  if(header.len < 17) continue;
350 
351  if(rx_frame[12] != 0x08 || rx_frame[13] != 0x09) continue;
352 
353  if(!packet_equals(rx_frame + 14, host_pid, 2)) continue;
354 
355 
356  if(packet[16] != 0x1) continue;
357 
358 
359  string mac("DTB_ETH ");
360  for(int i = 0; i < 6; i++) mac[7+i] = rx_frame[6+i];
361  MAC_addresses.push_back(mac);
362  }
363 }
364 
365 bool CEthernet::Claim(const unsigned char* MAC, bool force){
366  unsigned char packet[17];
367 
368  for(int i = 0; i < 6; i++){
369  packet[i] = MAC[i];
370  packet[i+6] = host_mac[i];
371  }
372  packet[12] = 0x08;
373  packet[13] = 0x09;
374  packet[14] = host_pid[0];
375  packet[15] = host_pid[1];
376  packet[16] = (force) ? 0x4 : 0x2;
377 
378  pcap_sendpacket(descr, packet, sizeof(packet));
379 
380 
381  MAC_addresses.clear();
382  MAC_counter = 0;
383  //wait at least 1 second for response.
384  time_t startTime = time(NULL);
385  const unsigned char* rx_frame;
386  while(time(NULL) - startTime < 2){
387  rx_frame = pcap_next(descr, &header);
388  if(rx_frame == NULL) continue;
389  if(header.len < 17) continue;
390 
391  if(rx_frame[12] != 0x08 || rx_frame[13] != 0x09) continue;
392  if(!packet_equals(rx_frame + 14, host_pid, 2)) continue;
393  if(!packet_equals(rx_frame, host_mac, 6)) continue;
394  return rx_frame[16] == 0x1; //value of 1 indicates claim was successful
395 
396  }
397  return false;
398 }
399 
400 bool CEthernet::Unclaim(){
401  unsigned char packet[17];
402 
403  for(int i = 0; i < 6; i++){
404  packet[i] = dtb_mac[i];
405  packet[i+6] = host_mac[i];
406  }
407  packet[12] = 0x08;
408  packet[13] = 0x09;
409  packet[14] = host_pid[0];
410  packet[15] = host_pid[1];
411  packet[16] = 0x3; //unclaim
412 
413  pcap_sendpacket(descr, packet, sizeof(packet));
414 
415  MAC_addresses.clear();
416  MAC_counter = 0;
417  //wait at least 1 second for response.
418  time_t startTime = time(NULL);
419  const unsigned char* rx_frame;
420  while(time(NULL) - startTime < 2){
421  rx_frame = pcap_next(descr, &header);
422  if(rx_frame == NULL) continue;
423  if(header.len < 17) continue;
424 
425  if(rx_frame[12] != 0x08 || rx_frame[13] != 0x09) continue;
426  if(!packet_equals(rx_frame + 14, host_pid, 2)) continue;
427  if(!packet_equals(rx_frame, host_mac, 6)) continue;
428 
429  return rx_frame[16] == 0x1; //value of 1 indicates unclaim was successful
430  }
431  return false;
432 }