/*******************************************************************************
OpenAirInterface
Copyright(c) 1999 - 2014 Eurecom
OpenAirInterface is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenAirInterface is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
see .
Contact Information
OpenAirInterface Admin: openair_admin@eurecom.fr
OpenAirInterface Tech : openair_tech@eurecom.fr
OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
*******************************************************************************/
/*! \file ethernet_lib.c
* \brief API to stream I/Q samples over standard ethernet
* \author add alcatel Katerina Trilyraki, Navid Nikaein, Pedro Dinis, Lucio Ferreira, Raymond Knopp
* \date 2015
* \version 0.2
* \company Eurecom
* \maintainer: navid.nikaein@eurecom.fr
* \note
* \warning
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "common_lib.h"
#include "ethernet_lib.h"
#include "if_defs.h"
#include "openair1/PHY/LTE_TRANSPORT/if4_tools.h"
#include "openair1/PHY/LTE_TRANSPORT/if5_mobipass_tools.h"
#define DEBUG 0
struct sockaddr_ll dest_addr[MAX_INST];
struct sockaddr_ll local_addr[MAX_INST];
int addr_len[MAX_INST];
struct ifreq if_index[MAX_INST];
int eth_socket_init_raw(openair0_device *device) {
int i = 0;
eth_state_t *eth = (eth_state_t*)device->priv;
int Mod_id = device->Mod_id;
const char *local_mac, *remote_mac;
int local_port=0, remote_port=0;
int sock_dom=0;
int sock_type=0;
int sock_proto=0;
if (device->host_type == RRH_HOST ) { /* RRH doesn't know remote MAC(will be retrieved from first packet send from BBU) and remote port(don't care) */
local_mac = device->openair0_cfg->my_addr;
local_port = device->openair0_cfg->my_port;
remote_mac = malloc(ETH_ALEN);
memset(remote_mac,0,ETH_ALEN);
remote_port = 0;
printf("[%s] local MAC addr %s remote MAC addr %s\n","RRH", local_mac,remote_mac);
} else {
local_mac = device->openair0_cfg->my_addr;
local_port = device->openair0_cfg->my_port;
remote_mac = device->openair0_cfg->remote_addr;
remote_port = device->openair0_cfg->remote_port;
printf("[%s] local MAC addr %s remote MAC addr %s\n","BBU", local_mac,remote_mac);
}
/* Open a RAW socket to send on */
sock_dom=AF_PACKET;
sock_type=SOCK_RAW;
sock_proto=IPPROTO_RAW;
if ((eth->sockfd[Mod_id] = socket(sock_dom, sock_type, sock_proto)) == -1) {
perror("ETHERNET: Error opening RAW socket");
exit(0);
}
/* initialize destination address */
for (i=0; i< MAX_INST; i++) {
bzero((void *)&(local_addr[i]), sizeof(struct sockaddr_ll));
bzero((void *)&(if_index[i]), sizeof(struct ifreq));
}
/* Get the index of the interface to send on */
strcpy(if_index[Mod_id].ifr_name,eth->if_name[Mod_id]);
if (ioctl(eth->sockfd[Mod_id], SIOCGIFINDEX, &(if_index[Mod_id])) < 0)
perror("SIOCGIFINDEX");
local_addr[Mod_id].sll_family = AF_PACKET;
local_addr[Mod_id].sll_ifindex = if_index[Mod_id].ifr_ifindex;
/* hear traffic from specific protocol*/
local_addr[Mod_id].sll_protocol = htons((short)device->openair0_cfg->my_port);
local_addr[Mod_id].sll_halen = ETH_ALEN;
local_addr[Mod_id].sll_pkttype = PACKET_OTHERHOST;
addr_len[Mod_id] = sizeof(struct sockaddr_ll);
if (bind(eth->sockfd[Mod_id],(struct sockaddr *)&local_addr[Mod_id],addr_len[Mod_id])<0) {
perror("ETHERNET: Cannot bind to socket");
exit(0);
}
/* Construct the Ethernet header */
ether_aton_r(local_mac, (struct ether_addr *)(&(eth->eh.ether_shost)));
ether_aton_r(remote_mac, (struct ether_addr *)(&(eth->eh.ether_dhost)));
// if (((*) device->priv)->flags == ETH_RAW_IF5_MOBIPASS) {
eth->eh.ether_type = htons(0xbffe);
// } else {
// eth->eh.ether_type = htons((short)device->openair0_cfg->my_port);
// }
printf("[%s] binding mod_%d to hardware address %x:%x:%x:%x:%x:%x\n",((device->host_type == BBU_HOST) ? "BBU": "RRH"),Mod_id,eth->eh.ether_shost[0],eth->eh.ether_shost[1],eth->eh.ether_shost[2],eth->eh.ether_shost[3],eth->eh.ether_shost[4],eth->eh.ether_shost[5]);
return 0;
}
int trx_eth_write_raw(openair0_device *device, openair0_timestamp timestamp, void **buff, int nsamps,int cc, int flags) {
int bytes_sent=0;
eth_state_t *eth = (eth_state_t*)device->priv;
int Mod_id = device->Mod_id;
int sendto_flag =0;
int i=0;
//sendto_flag|=flags;
eth->tx_nsamps=nsamps;
for (i=0;ieh,MAC_HEADER_SIZE_BYTES);
*(int16_t *)(buff2 + MAC_HEADER_SIZE_BYTES + sizeof(int16_t))=1+(i<<1);
*(openair0_timestamp *)(buff2 + MAC_HEADER_SIZE_BYTES + sizeof(int32_t)) = timestamp;
/*printf("[RRH]write mod_%d %d , len %d, buff %p \n",
Mod_id,eth->sockfd[Mod_id],RAW_PACKET_SIZE_BYTES(nsamps), buff2);*/
while(bytes_sent < RAW_PACKET_SIZE_BYTES(nsamps)) {
#if DEBUG
printf("------- TX ------: buff2 current position=%d remaining_bytes=%d bytes_sent=%d \n",
(void *)(buff2+bytes_sent),
RAW_PACKET_SIZE_BYTES(nsamps) - bytes_sent,
bytes_sent);
#endif
/* Send packet */
bytes_sent += send(eth->sockfd[Mod_id],
buff2,
RAW_PACKET_SIZE_BYTES(nsamps),
sendto_flag);
if ( bytes_sent == -1) {
eth->num_tx_errors++;
perror("ETHERNET WRITE: ");
exit(-1);
} else {
#if DEBUG
printf("------- TX ------: nu=%x an_id=%d ts%d bytes_sent=%d\n",
*(uint8_t *)(buff2+ETH_ALEN),
*(int16_t *)(buff2 + MAC_HEADER_SIZE_BYTES + sizeof(int16_t)),
*(openair0_timestamp *)(buff2 + MAC_HEADER_SIZE_BYTES + sizeof(int32_t)),
bytes_sent);
dump_packet((device->host_type == BBU_HOST)? "BBU":"RRH", buff2, RAW_PACKET_SIZE_BYTES(nsamps), TX_FLAG);
#endif
eth->tx_actual_nsamps=bytes_sent>>2;
eth->tx_count++;
}
}
/* tx buffer values restored */
*(struct ether_header *)buff2 = temp;
*(int32_t *)(buff2 + MAC_HEADER_SIZE_BYTES) = temp0;
*(openair0_timestamp *)(buff2 + MAC_HEADER_SIZE_BYTES + sizeof(int32_t)) = temp1;
}
return (bytes_sent-APP_HEADER_SIZE_BYTES-MAC_HEADER_SIZE_BYTES)>>2;
}
int trx_eth_write_raw_IF4(openair0_device *device, openair0_timestamp timestamp, void **buff, int nsamps, int cc, int flags) {
int nblocks = nsamps;
int bytes_sent = 0;
eth_state_t *eth = (eth_state_t*)device->priv;
int Mod_id = device->Mod_id;
ssize_t packet_size;
if (flags == IF4_PDLFFT) {
packet_size = RAW_IF4_PDLFFT_SIZE_BYTES(nblocks);
} else if (flags == IF4_PULFFT) {
packet_size = RAW_IF4_PULFFT_SIZE_BYTES(nblocks);
} else if (flags == IF5_MOBIPASS) {
packet_size = RAW_IF5_MOBIPASS_SIZE_BYTES;
} else {
packet_size = RAW_IF4_PRACH_SIZE_BYTES;
}
eth->tx_nsamps = nblocks;
memcpy(buff[0], (void*)ð->eh, MAC_HEADER_SIZE_BYTES);
bytes_sent = send(eth->sockfd[Mod_id],
buff[0],
packet_size,
0);
if (bytes_sent == -1) {
eth->num_tx_errors++;
perror("ETHERNET WRITE: ");
exit(-1);
} else {
eth->tx_actual_nsamps = bytes_sent>>1;
eth->tx_count++;
}
return (bytes_sent-MAC_HEADER_SIZE_BYTES);
}
int trx_eth_read_raw(openair0_device *device, openair0_timestamp *timestamp, void **buff, int nsamps, int cc) {
int bytes_received=0;
int i=0;
eth_state_t *eth = (eth_state_t*)device->priv;
int Mod_id = device->Mod_id;
int rcvfrom_flag =0;
eth->rx_nsamps=nsamps;
for (i=0;isockfd[Mod_id],
buff2,
RAW_PACKET_SIZE_BYTES(nsamps),
rcvfrom_flag);
if (bytes_received ==-1) {
eth->num_rx_errors++;
perror("ETHERNET READ: ");
exit(-1);
} else {
/* store the timestamp value from packet's header */
*timestamp = *(openair0_timestamp *)(buff2 + MAC_HEADER_SIZE_BYTES + sizeof(int32_t));
eth->rx_actual_nsamps=bytes_received>>2;
eth->rx_count++;
}
}
#if DEBUG
printf("------- RX------: nu=%x an_id=%d ts%d bytes_recv=%d \n",
*(uint8_t *)(buff2+ETH_ALEN),
*(int16_t *)(buff2 + MAC_HEADER_SIZE_BYTES + sizeof(int16_t)),
*(openair0_timestamp *)(buff2 + MAC_HEADER_SIZE_BYTES + sizeof(int32_t)),
bytes_received);
dump_packet((device->host_type == BBU_HOST)? "BBU":"RRH", buff2, RAW_PACKET_SIZE_BYTES(nsamps),RX_FLAG);
#endif
/* tx buffer values restored */
*(struct ether_header *)buff2 = temp;
*(int32_t *)(buff2 + MAC_HEADER_SIZE_BYTES) = temp0;
*(openair0_timestamp *)(buff2 + MAC_HEADER_SIZE_BYTES + sizeof(int32_t)) = temp1;
}
return (bytes_received-APP_HEADER_SIZE_BYTES-MAC_HEADER_SIZE_BYTES)>>2;
}
int trx_eth_read_raw_IF4(openair0_device *device, openair0_timestamp *timestamp, void **buff, int nsamps, int cc) {
// Read nblocks info from packet itself
int nblocks = nsamps;
int bytes_received=0;
eth_state_t *eth = (eth_state_t*)device->priv;
int Mod_id = device->Mod_id;
ssize_t packet_size = MAC_HEADER_SIZE_BYTES + sizeof_IF4_header_t;
void *test_buffer = (void*)malloc(packet_size);
IF4_header_t *test_header = (IF4_header_t*)(test_buffer + MAC_HEADER_SIZE_BYTES);
bytes_received = recv(eth->sockfd[Mod_id],
test_buffer,
packet_size,
MSG_PEEK);
if (bytes_received ==-1) {
eth->num_rx_errors++;
perror("ETHERNET READ: ");
exit(-1);
}
*timestamp = test_header->sub_type;
if (test_header->sub_type == IF4_PDLFFT) {
packet_size = RAW_IF4_PDLFFT_SIZE_BYTES(nblocks);
} else if (test_header->sub_type == IF4_PULFFT) {
packet_size = RAW_IF4_PULFFT_SIZE_BYTES(nblocks);
} else {
packet_size = RAW_IF4_PRACH_SIZE_BYTES;
}
buff[0] = (void*)malloc(packet_size);
bytes_received = 0;
while(bytes_received < packet_size) {
bytes_received = recv(eth->sockfd[Mod_id],
buff[0],
packet_size,
0);
if (bytes_received ==-1) {
eth->num_rx_errors++;
perror("ETHERNET READ: ");
exit(-1);
} else {
eth->rx_actual_nsamps = bytes_received>>1;
eth->rx_count++;
}
}
eth->rx_nsamps = nsamps;
free(test_buffer);
return(bytes_received);
}
int eth_set_dev_conf_raw(openair0_device *device) {
int Mod_id = device->Mod_id;
eth_state_t *eth = (eth_state_t*)device->priv;
void *msg;
ssize_t msg_len;
/* a BBU client sends to RRH a set of configuration parameters (openair0_config_t)
so that RF front end is configured appropriately and
frame/packet size etc. can be set */
msg = malloc(MAC_HEADER_SIZE_BYTES + sizeof(openair0_config_t));
msg_len = MAC_HEADER_SIZE_BYTES + sizeof(openair0_config_t);
memcpy(msg,(void*)ð->eh,MAC_HEADER_SIZE_BYTES);
memcpy((msg+MAC_HEADER_SIZE_BYTES),(void*)device->openair0_cfg,sizeof(openair0_config_t));
if (send(eth->sockfd[Mod_id],
msg,
msg_len,
0)==-1) {
perror("ETHERNET: ");
exit(0);
}
return 0;
}
int eth_set_dev_conf_raw_IF4(openair0_device *device) {
int Mod_id = device->Mod_id;
eth_state_t *eth = (eth_state_t*)device->priv;
void *msg;
ssize_t msg_len;
/* a BBU client sends to RRH a set of configuration parameters (openair0_config_t)
so that RF front end is configured appropriately and
frame/packet size etc. can be set */
msg = malloc(MAC_HEADER_SIZE_BYTES + sizeof(openair0_config_t));
msg_len = MAC_HEADER_SIZE_BYTES + sizeof(openair0_config_t);
memcpy(msg,(void*)ð->eh,MAC_HEADER_SIZE_BYTES);
memcpy((msg+MAC_HEADER_SIZE_BYTES),(void*)device->openair0_cfg,sizeof(openair0_config_t));
if (send(eth->sockfd[Mod_id],
msg,
msg_len,
0)==-1) {
perror("ETHERNET: ");
exit(0);
}
return 0;
}
int eth_get_dev_conf_raw(openair0_device *device) {
eth_state_t *eth = (eth_state_t*)device->priv;
int Mod_id = device->Mod_id;
char str[INET_ADDRSTRLEN];
void *msg;
ssize_t msg_len;
msg = malloc(MAC_HEADER_SIZE_BYTES + sizeof(openair0_config_t));
msg_len = MAC_HEADER_SIZE_BYTES + sizeof(openair0_config_t);
/* RRH receives from BBU openair0_config_t */
if (recv(eth->sockfd[Mod_id],
msg,
msg_len,
0)==-1) {
perror("ETHERNET: ");
exit(0);
}
/* RRH stores the remote MAC address */
memcpy(eth->eh.ether_dhost,(msg+ETH_ALEN),ETH_ALEN);
//memcpy((void*)&device->openair0_cfg,(msg + MAC_HEADER_SIZE_BYTES), sizeof(openair0_config_t));
device->openair0_cfg=(openair0_config_t *)(msg + MAC_HEADER_SIZE_BYTES);
printf("[%s] binding mod_%d to hardware address %x:%x:%x:%x:%x:%x hardware address %x:%x:%x:%x:%x:%x\n",((device->host_type == BBU_HOST) ? "BBU": "RRH"),Mod_id,eth->eh.ether_shost[0],eth->eh.ether_shost[1],eth->eh.ether_shost[2],eth->eh.ether_shost[3],eth->eh.ether_shost[4],eth->eh.ether_shost[5],eth->eh.ether_dhost[0],eth->eh.ether_dhost[1],eth->eh.ether_dhost[2],eth->eh.ether_dhost[3],eth->eh.ether_dhost[4],eth->eh.ether_dhost[5]);
return 0;
}
int eth_get_dev_conf_raw_IF4(openair0_device *device) {
eth_state_t *eth = (eth_state_t*)device->priv;
int Mod_id = device->Mod_id;
char str[INET_ADDRSTRLEN];
void *msg;
ssize_t msg_len;
msg = malloc(MAC_HEADER_SIZE_BYTES + sizeof(openair0_config_t));
msg_len = MAC_HEADER_SIZE_BYTES + sizeof(openair0_config_t);
/* RRH receives from BBU openair0_config_t */
if (recv(eth->sockfd[Mod_id],
msg,
msg_len,
0)==-1) {
perror("ETHERNET: ");
exit(0);
}
/* RRH stores the remote MAC address */
memcpy(eth->eh.ether_dhost,(msg+ETH_ALEN),ETH_ALEN);
//memcpy((void*)&device->openair0_cfg,(msg + MAC_HEADER_SIZE_BYTES), sizeof(openair0_config_t));
//device->openair0_cfg=(openair0_config_t *)(msg + MAC_HEADER_SIZE_BYTES);
printf("[%s] binding mod_%d to hardware address %x:%x:%x:%x:%x:%x hardware address %x:%x:%x:%x:%x:%x\n",((device->host_type == BBU_HOST) ? "BBU": "RRH"),Mod_id,eth->eh.ether_shost[0],eth->eh.ether_shost[1],eth->eh.ether_shost[2],eth->eh.ether_shost[3],eth->eh.ether_shost[4],eth->eh.ether_shost[5],eth->eh.ether_dhost[0],eth->eh.ether_dhost[1],eth->eh.ether_dhost[2],eth->eh.ether_dhost[3],eth->eh.ether_dhost[4],eth->eh.ether_dhost[5]);
return 0;
}