Date created: 05/24/12 20:51:45. Last modified: 12/10/17 14:29:41

Etherate Notes

C code snippets:
Printing binary of ints and shorts
Encoding VLAN ID, DEI bit and PCP value
Low level access to network devices
sockaddr_ll - Phy config
htons/htonl/htonll convertions
struct ethhdr
Printing MAC addresses
Opening raw sockets
Promiscuous mode

// Printing binary of ints and shorts

  const int SHIFT = 8 * sizeof( unsigned ) - 1;
  // const int SHIFT = 15; // This would be used for a short
  const unsigned MASK = 1 << SHIFT;

  int myInt = 4096;

  for ( int i = 1; i <= SHIFT + 1; i++ ) {
    cout << ( TCI & MASK ? '1' : '0' );
    myInt <<= 1;

    if ( i % 8 == 0 )
    cout << ' ';
  }
  cout << endl;

// This prints: 00000000 00000000 11111111 11111111

// Encoding VLAN ID, DEI bit and PCP value directly on to the wire
// Assume DEI is 0 for now...

  short PCP = 5
  short vlanID = 1111
  short vlanIDtemp;
  short TPI = 0;
  short TCI = 0;
  short *p = &TPI;
  short *c = &TCI;

  TPI = htons(0x8100);
  memcpy((void*)(txBuffer+offset), p, 2);
  offset+=2;

  cout << "PCP: " <<  PCP << endl;
  cout << "vlanID: " << vlanID << endl;

  TCI = (PCP & 0x07) << 5; // 00000101 gets shifted up to 10100000
  vlanID = vlanID >> 8; // 00000100 01010111 gets shifted down to 00000100
  TCI = TCI | (vlanID & 0x0f); // OR 10100000 and 00000100 to give 10100100
  vlanID = vlanIDtemp; // Bring back the original vlan ID 00000100 01010111
  vlanID = vlanID << 8; // Shift up to 01010111 00000000
  TCI = TCI | (vlanID & 0xffff); // OR 01010111 00000000 with 00000000 10100100
  cout << "TCI: " << TCI << endl; // Gives the result 01010111 10100100

  for ( int i = 1; i <= SHIFT + 1; i++ ) { // Print it out in binary
    cout << ( TCI & MASK ? '1' : '0' );
    TCI <<= 1;

    if ( i % 8 == 0 )
    cout << ' ';
  }
  cout << endl;

 /* Final output on the CLI is;
  * PCP: 5
  * vlanID: 1111
  * 01010111 10100100
  *
  * Gets dumped on to the wire in reverse bytes order (but not reverse bit order!) as
  *
  * 10100100 01010111
  * 
  * Which breaks down into
  * 101|0  |0100 01010111
  * PCP|DEI|VLAN ID
  */

/* 
  netdevice - Low level access to Linux network devices. 
  #include  <sys/ioctl.h>
  #include  <net/if.h>
*/

struct ifreq {
  char    ifr_name[IFNAMSIZ]; // Interface name
  union {
    struct sockaddrifr_addr;
    struct sockaddrifr_dstaddr;
    struct sockaddrifr_broadaddr;
    struct sockaddrifr_netmask;
    struct sockaddrifr_hwaddr;
    short   ifr_flags;
    int     ifr_ifindex;
    int     ifr_metric;
    int     ifr_mtu;
    struct ifmapifr_map;
    char    ifr_slave[IFNAMSIZ];
    char    ifr_newname[IFNAMSIZ];
    char *  ifr_data;
  };
};

struct ifconf { 
  int ifc_len;    // size of buffer
  union {            
    char *  ifc_buf; // buffer address
    struct ifreq *ifc_req; // array of structures
  };  
}; 

/*
 The sockaddr_ll is a device independent physical layer address.
 #include <sys/socket.h>
 #define MAX_IFS 64
 #include <linux/if_packet.h>
 #include <linux/if_ether.h>
 #include <linux/if_arp.h>
*/

struct sockaddr_ll {
  unsigned short  sll_family;    // Always AF_PACKET
  unsigned short  sll_protocol;  // Physical layer protocol
  int             sll_ifindex;   // Interface number
  unsigned short  sll_hatype;    // Header type
  unsigned char   sll_pkttype;   // Packet type
  unsigned char   sll_halen;     // Length of address
  unsigned char   sll_addr[8];   // Physical layer address
};
*/

/*
 * sll_family = PF_PACKET = RAW packet communication
 * sll_protocol = No protocol above the Ethernet layer is actually used
 * sll_ifindex = Index of the network device
 * sll_hatype = ARP hardware identifier is ethernet
 * sll_pkttype = Target is another host
 * sll_halen = Layer 2 address length
 * sll_addr[] = Destination MAC Address
 */

 #include <netinet/in.h>
// Host-to-Network-short htons()
// Host-to-Network-long htonl()
// Network-to-Host-short ntohs()
// Network-to-Host-long ntohl()

#include <byteswap.h>

unsigned long long htonll(unsigned long long val)
{
    if (__BYTE_ORDER == __BIG_ENDIAN) return (val);
    else return __bswap_64(val);
}

unsigned long long ntohll(unsigned long long val)
{
    if (__BYTE_ORDER == __BIG_ENDIAN) return (val);
    else return __bswap_64(val);
}

struct ethhdr {
  unsigned char   h_dest[ETH_ALEN];     // destination eth addr 
  unsigned char   h_source[ETH_ALEN];   // source ether addr   
  __be16          h_proto;              // packet type ID field
} __attribute__((packed));

printf("Ethernet %02x:%02x:%02x:%02x:%02x:%02x\n",
       destMAC[0],destMAC[1],destMAC[2],destMAC[3],destMAC[4], destMAC[5]);

// Opening raw sockets

        TEST_INTERFACE.SOCKET_FD = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
        /* A socket must be opened with three arguments;
         * Communication Domain = AF_PACKET
         * Type/Communication Semantics = SOCK_RAW
         * Protocol = ETH_P_ALL == 0x0003, which is 'everything', from if_ether.h
         */

// Promiscuous mode, this came fromt eh following URL
// http://www.linuxjournal.com/article/4659?page=0,1
        printf("Entering promiscuous mode\n");
        strncpy(ethreq.ifr_name,TEST_INTERFACE.IF_NAME,IFNAMSIZ);

        if (ioctl(TEST_INTERFACE.SOCKET_FD,SIOCGIFFLAGS,&ethreq) == -1) 
        {

            printf("Error getting socket flags, entering promiscuous mode failed!\n");
            perror("ioctl() ");
            close(TEST_INTERFACE.SOCKET_FD);
            return EX_SOFTWARE;

        }

        ethreq.ifr_flags|=IFF_PROMISC;

        if (ioctl(TEST_INTERFACE.SOCKET_FD,SIOCSIFFLAGS,&ethreq) == -1)
        {

            printf("Error setting socket flags, entering promiscuous mode failed!\n");
            perror("ioctl() ");
            close(TEST_INTERFACE.SOCKET_FD);
            return EX_SOFTWARE;

        }

Previous page: Etherate Features
Next page: EtherateMT Notes