/******************************************************************************* 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@eurecom.fr Address : Eurecom, Compus SophiaTech 450, route des chappes, 06451 Biot, France. *******************************************************************************/ /*! \file sgi_egress.c * \brief * \author Lionel Gauthier * \company Eurecom * \email: lionel.gauthier@eurecom.fr */ #include #include #include #include #include "sgi.h" #include "gtpv1u.h" #include "intertask_interface.h" #include "assertions.h" #include #include #include struct ipv6hdr { __u8 priority:4, version:4; __u8 flow_lbl[3]; __be16 payload_len; __u8 nexthdr; __u8 hop_limit; struct in6_addr saddr; struct in6_addr daddr; }; #ifdef ENABLE_USE_RAW_SOCKET_FOR_SGI #ifdef SGI_UE_ETHER_TRAFFIC void sgi_process_raw_packet(sgi_data_t *sgi_data_pP, unsigned char* data_pP, int packet_sizeP) { Gtpv1uTunnelDataReq *gtpv1u_tunnel_data_req_p = NULL; MessageDef *message_p = NULL; unsigned char *message_payload_p = NULL ; struct ether_header *eh_p = (struct ether_header *) data_pP; struct arphdr *arph_p = NULL; struct iphdr *iph_p = NULL; struct ipv6hdr *ip6h_p = NULL; //struct arphdr *rarph = NULL; //unsigned char *rarp_ptr = NULL; //unsigned char *sha = NULL; /* Sender hardware address. */ //unsigned char *tha = NULL; /* Target hardware address. */ sgi_addr_mapping_t *addr_mapping_p = NULL; //__be32 sip, tip; /* Sender, target IP address. */ struct in6_addr dest6_addr; u_int32_t dest4_addr; struct in_addr in_dest_addr; switch (htons(eh_p->ether_type)) { //******************* case ETHERTYPE_IP: //******************* iph_p = (struct iphdr *) (data_pP + sizeof(struct ether_header)); dest4_addr = iph_p->daddr; if (hashtable_get(sgi_data_pP->addr_v4_mapping, dest4_addr, (void**)&addr_mapping_p) == HASH_TABLE_OK) { memcpy(eh_p->ether_dhost, addr_mapping_p->ue_mac_addr, ETH_ALEN); //SGI_IF_DEBUG("--------------------------------------------------------------\n%s :\n", __FUNCTION__); //sgi_print_hex_octets(data_pP, packet_sizeP); } else { if (sgi_data_pP->ipv4_addr == dest4_addr) { //SGI_IF_DEBUG("%s Dropping incoming egress IPV4 packet not UE IP flow\n", __FUNCTION__); return; } else { in_dest_addr.s_addr = dest4_addr; //SGI_IF_WARNING("%s Dropping incoming egress IPV4 packet, IPV4 dest %s not found \n", __FUNCTION__, inet_ntoa(in_dest_addr)); return; } } break; //******************* case ETHERTYPE_IPV6: //******************* ip6h_p = (struct ipv6hdr *) (data_pP + sizeof(struct ether_header)); memcpy(dest6_addr.__in6_u.__u6_addr8, ip6h_p->daddr.__in6_u.__u6_addr8, 16); if (obj_hashtable_get(sgi_data_pP->addr_v6_mapping, (void*)&dest6_addr, sizeof(struct in6_addr), (void**)&addr_mapping_p) == HASH_TABLE_OK) { memcpy(eh_p->ether_dhost, addr_mapping_p->ue_mac_addr, ETH_ALEN); //SGI_IF_DEBUG("--------------------------------------------------------------\n%s :\n", __FUNCTION__); //sgi_print_hex_octets(data_pP, packet_sizeP); } else { //SGI_IF_WARNING("%s Dropping incoming egress IPV6 packet, IPV6 dest %X:%X:%X:%X:%X:%X:%X:%X not found \n", __FUNCTION__, NIP6ADDR(&dest6_addr)); return; } break; //******************* case ETHERTYPE_REVARP: //******************* SGI_IF_ERROR("%s UNHANDLED ETHERTYPE_REVARP of incoming egress packet\n", __FUNCTION__); return; break; //******************* case ETHERTYPE_ARP: //******************* SGI_IF_DEBUG("%s HANDLED ETHERTYPE_ARP of incoming egress packet\n", __FUNCTION__); arph_p = (struct arphdr *) (data_pP + sizeof(struct ether_header)); #ifdef SGI_UE_ETHER_TRAFFIC // The entry should be here but all signalling tied with RRC procedures not finished so // a data packet can arrive before the MODIFY_BEARER REQUEST // get " unsigned char __ar_tip[4]; /* Target IP address. */" (from /usr/include/net/if_apr.h line 68) memcpy(&dest4_addr, &((unsigned char*)(&arph_p[1]))[ETH_ALEN*2+4], 4); SGI_IF_DEBUG("%s ARP OPCODE %s TARGET IP %d.%d.%d.%d\n", __FUNCTION__, sgi_arpopcode_2_str(ntohl(arph_p->ar_op)), NIPADDR(dest4_addr)); if (hashtable_get(sgi_data_pP->addr_v4_mapping, dest4_addr, (void**)&addr_mapping_p) == HASH_TABLE_OK) { memcpy(eh_p->ether_dhost, addr_mapping_p->ue_mac_addr, ETH_ALEN); } else { if (sgi_data_pP->ipv4_addr == dest4_addr) { //SGI_IF_DEBUG("%s Dropping incoming egress IPV4 packet not UE IP flow\n", __FUNCTION__); return; } else { in_dest_addr.s_addr = dest4_addr; //SGI_IF_WARNING("%s Dropping incoming egress IPV4 packet, IPV4 dest %s not found \n", __FUNCTION__, inet_ntoa(in_dest_addr)); return; } } #else #endif break; // rarph = (struct arphdr *)(data_pP + sizeof(struct ether_header)); // // // If it's not Ethernet, delete it. // if (rarph->ar_pro != htons(ETH_P_IP)) { // SGI_IF_ERROR("%s ARP PACKET PROTOCOL OG INCOMING PACKET IS NOT ETHERNET\n",__FUNCTION__); // break; // } // rarp_ptr = (unsigned char *) (rarph + 1); // sha = rarp_ptr; // rarp_ptr += ETH_ALEN; // memcpy(&sip, rarp_ptr, 4); // rarp_ptr += 4; // tha = rarp_ptr; // rarp_ptr += ETH_ALEN; // memcpy(&tip, rarp_ptr, 4); // SGI_IF_DEBUG("%s ARP DEST IP transport IP = %d.%d.%d.%d\n",__FUNCTION__, NIPADDR(tip)); // // TO DO IF NECESSARY // break; // default: SGI_IF_ERROR("%s UNHANDLED ether type %d of incoming egress packet\n", __FUNCTION__, eh_p->ether_type); return; } message_p = itti_alloc_new_message(TASK_FW_IP, GTPV1U_TUNNEL_DATA_REQ); if (message_p == NULL) { SGI_IF_ERROR("%s OUT OF MEMORY DROP EGRESS PACKET\n", __FUNCTION__); return; } message_payload_p = itti_malloc(TASK_FW_IP, TASK_GTPV1_U, packet_sizeP); if (message_payload_p == NULL) { SGI_IF_ERROR("%s OUT OF MEMORY DROP EGRESS PACKET\n", __FUNCTION__); return; } memcpy(message_payload_p, data_pP, packet_sizeP); gtpv1u_tunnel_data_req_p = &message_p->ittiMsg.gtpv1uTunnelDataReq; //LG HACK gtpv1u_tunnel_data_req_p->S1u_enb_teid = addr_mapping_p->enb_S1U_teid; #warning forced S1u_enb_teid to 1 for testing, waiting for MODIFY_BEARER REQUEST gtpv1u_tunnel_data_req_p->S1u_enb_teid = 1; gtpv1u_tunnel_data_req_p->local_S1u_teid = addr_mapping_p->sgw_S1U_teid; gtpv1u_tunnel_data_req_p->length = packet_sizeP; gtpv1u_tunnel_data_req_p->buffer = message_payload_p; SGI_IF_DEBUG("%s ETHER send GTPV1U_TUNNEL_DATA_REQ to GTPV1U S1u_enb_teid %u local_S1u_teid %u size %u\n", __FUNCTION__, gtpv1u_tunnel_data_req_p->S1u_enb_teid, gtpv1u_tunnel_data_req_p->local_S1u_teid, packet_sizeP); itti_send_msg_to_task(TASK_GTPV1_U, INSTANCE_DEFAULT, message_p); } #else void sgi_process_raw_packet(sgi_data_t *sgi_data_pP, unsigned char* data_pP, int packet_sizeP) { Gtpv1uTunnelDataReq *gtpv1u_tunnel_data_req_p = NULL; MessageDef *message_p = NULL; unsigned char *message_payload_p = NULL ; struct ether_header *eh_p = (struct ether_header *) data_pP; struct arphdr *arph_p = NULL; struct iphdr *iph_p = NULL; struct ipv6hdr *ip6h_p = NULL; sgi_addr_mapping_t *addr_mapping_p = NULL; struct in6_addr dest6_addr; u_int32_t dest4_addr; u_int32_t src4_addr; struct in_addr in_dest_addr; switch (htons(eh_p->ether_type)) { //sgi_print_hex_octets(data_pP, packet_sizeP); //******************* case ETHERTYPE_IP: //******************* iph_p = (struct iphdr *) (data_pP + sizeof(struct ether_header)); dest4_addr = iph_p->daddr; if (hashtable_get(sgi_data_pP->addr_v4_mapping, dest4_addr, (void**)&addr_mapping_p) != HASH_TABLE_OK) { if (sgi_data_pP->ipv4_addr == dest4_addr) { //SGI_IF_DEBUG("%s Dropping incoming egress IPV4 packet not UE IP flow\n", __FUNCTION__); return; } else { in_dest_addr.s_addr = dest4_addr; //SGI_IF_WARNING("%s Dropping incoming egress IPV4 packet, IPV4 dest %s not found \n", __FUNCTION__, inet_ntoa(in_dest_addr)); return; } } break; //******************* case ETHERTYPE_IPV6: //******************* ip6h_p = (struct ipv6hdr *) (data_pP + sizeof(struct ether_header)); memcpy(dest6_addr.__in6_u.__u6_addr8, ip6h_p->daddr.__in6_u.__u6_addr8, 16); if (obj_hashtable_get(sgi_data_pP->addr_v6_mapping, (void*)&dest6_addr, sizeof(struct in6_addr), (void**)&addr_mapping_p) != HASH_TABLE_OK) { SGI_IF_WARNING("%s Dropping incoming egress IPV6 packet, IPV6 dest %X:%X:%X:%X:%X:%X:%X:%X not found \n", __FUNCTION__, NIP6ADDR(&dest6_addr)); return; } break; //******************* case ETHERTYPE_REVARP: //******************* SGI_IF_ERROR("%s UNHANDLED ETHERTYPE_REVARP of incoming egress packet\n", __FUNCTION__); return; break; //******************* case ETHERTYPE_ARP: //******************* SGI_IF_DEBUG("%s HANDLED ETHERTYPE_ARP of incoming egress packet\n", __FUNCTION__); arph_p = (struct arphdr *) (data_pP + sizeof(struct ether_header)); // The entry should be here but all signalling tied with RRC procedures not finished so // a data packet can arrive before the MODIFY_BEARER REQUEST // get " unsigned char __ar_tip[4]; /* Target IP address. */" (from /usr/include/net/if_apr.h line 68) memcpy(&dest4_addr, &((unsigned char*)(&arph_p[1]))[ETH_ALEN*2+4], 4); SGI_IF_DEBUG("%s ARP OPCODE %s TARGET IP %d.%d.%d.%d\n", __FUNCTION__, sgi_arpopcode_2_str(ntohl(arph_p->ar_op)), NIPADDR(dest4_addr)); if (hashtable_get(sgi_data_pP->addr_v4_mapping, dest4_addr, (void**)&addr_mapping_p) != HASH_TABLE_OK) { if (sgi_data_pP->ipv4_addr == dest4_addr) { SGI_IF_DEBUG("%s Dropping incoming egress IPV4 packet not UE IP flow\n", __FUNCTION__); return; } else { if (sgi_data_pP->hw_address_of_router_captured) { in_dest_addr.s_addr = dest4_addr; SGI_IF_WARNING("%s Dropping incoming egress IPV4 packet, IPV4 dest %s not found \n", __FUNCTION__, inet_ntoa(in_dest_addr)); } else { // may be a response to our ARP request to router if (htons(arph_p->ar_op) == ARPOP_REPLY) { memcpy(&src4_addr, &((unsigned char*)(&arph_p[1]))[ETH_ALEN], 4); SGI_IF_DEBUG("%s FOR ROUTER HW ADDRESS COMPARING: %d - %d %d - %d\n", __FUNCTION__, sgi_data_pP->local_addr_v4_4_hw_address_router_capture, dest4_addr, sgi_data_pP->ipv4_addr_of_router, src4_addr); if ((sgi_data_pP->local_addr_v4_4_hw_address_router_capture == dest4_addr) && (sgi_data_pP->ipv4_addr_of_router == src4_addr)) { sgi_data_pP->hw_address_of_router_captured = 1; sgi_data_pP->eh.ether_dhost[0] = ((unsigned char*)(&arph_p[1]))[0]; sgi_data_pP->eh.ether_dhost[1] = ((unsigned char*)(&arph_p[1]))[1]; sgi_data_pP->eh.ether_dhost[2] = ((unsigned char*)(&arph_p[1]))[2]; sgi_data_pP->eh.ether_dhost[3] = ((unsigned char*)(&arph_p[1]))[3]; sgi_data_pP->eh.ether_dhost[4] = ((unsigned char*)(&arph_p[1]))[4]; sgi_data_pP->eh.ether_dhost[5] = ((unsigned char*)(&arph_p[1]))[5]; SGI_IF_DEBUG("%s FOUND ROUTER HW ADDRESS: %02x:%02x:%02x:%02x:%02x:%02x\n", __FUNCTION__, NMACADDR(sgi_data_pP->eh.ether_dhost)); } } } return; } } break; default: //SGI_IF_ERROR("%s UNHANDLED ether type %d of incoming egress packet\n", __FUNCTION__, eh_p->ether_type); return; } //SGI_IF_DEBUG("--------------------------------------------------------------\n%s :\n", __FUNCTION__); //sgi_print_hex_octets(data_pP+sizeof(sgi_data_pP->eh), packet_sizeP - sizeof(sgi_data_pP->eh)); message_p = itti_alloc_new_message(TASK_FW_IP, GTPV1U_TUNNEL_DATA_REQ); if (message_p == NULL) { SGI_IF_ERROR("%s OUT OF MEMORY DROP EGRESS PACKET\n", __FUNCTION__); return; } AssertFatal((packet_sizeP - sizeof(sgi_data_pP->eh)) > 20, "BAD IP PACKET SIZE"); message_payload_p = itti_malloc(TASK_FW_IP, TASK_GTPV1_U, packet_sizeP - sizeof(sgi_data_pP->eh) + GTPU_HEADER_OVERHEAD_MAX); if (message_payload_p == NULL) { SGI_IF_ERROR("%s OUT OF MEMORY DROP EGRESS PACKET\n", __FUNCTION__); return; } memcpy(message_payload_p + GTPU_HEADER_OVERHEAD_MAX, data_pP+sizeof(sgi_data_pP->eh), packet_sizeP - sizeof(sgi_data_pP->eh)); gtpv1u_tunnel_data_req_p = &message_p->ittiMsg.gtpv1uTunnelDataReq; gtpv1u_tunnel_data_req_p->S1u_enb_teid = addr_mapping_p->enb_S1U_teid; //#warning forced S1u_enb_teid to 1 for testing, waiting for MODIFY_BEARER REQUEST // gtpv1u_tunnel_data_req_p->S1u_enb_teid = 1; gtpv1u_tunnel_data_req_p->local_S1u_teid = addr_mapping_p->sgw_S1U_teid; gtpv1u_tunnel_data_req_p->length = packet_sizeP - sizeof(sgi_data_pP->eh); gtpv1u_tunnel_data_req_p->offset = GTPU_HEADER_OVERHEAD_MAX; gtpv1u_tunnel_data_req_p->buffer = message_payload_p; SGI_IF_DEBUG("%s send GTPV1U_TUNNEL_DATA_REQ to GTPV1U S1u_enb_teid %u local_S1u_teid %u size %u\n", __FUNCTION__, gtpv1u_tunnel_data_req_p->S1u_enb_teid, gtpv1u_tunnel_data_req_p->local_S1u_teid, gtpv1u_tunnel_data_req_p->length); itti_send_msg_to_task(TASK_GTPV1_U, INSTANCE_DEFAULT, message_p); } #endif #endif void sgi_process_dgram_packet(sgi_data_t *sgi_data_pP, unsigned char* data_pP, int packet_sizeP) { Gtpv1uTunnelDataReq *gtpv1u_tunnel_data_req_p = NULL; MessageDef *message_p = NULL; unsigned char *message_payload_p = NULL ; struct arphdr *arph_p = NULL; struct iphdr *iph_p = NULL; struct ipv6hdr *ip6h_p = NULL; sgi_addr_mapping_t *addr_mapping_p = NULL; struct in6_addr dest6_addr; u_int32_t dest4_addr; u_int32_t src4_addr; struct in_addr in_dest_addr; sgi_print_hex_octets(data_pP, packet_sizeP); return; message_p = itti_alloc_new_message(TASK_FW_IP, GTPV1U_TUNNEL_DATA_REQ); if (message_p == NULL) { SGI_IF_ERROR("%s OUT OF MEMORY DROP EGRESS PACKET\n", __FUNCTION__); return; } AssertFatal(packet_sizeP > 20, "BAD IP PACKET SIZE"); message_payload_p = itti_malloc(TASK_FW_IP, TASK_GTPV1_U, packet_sizeP + GTPU_HEADER_OVERHEAD_MAX); if (message_payload_p == NULL) { SGI_IF_ERROR("%s OUT OF MEMORY DROP EGRESS PACKET\n", __FUNCTION__); return; } memcpy(message_payload_p + GTPU_HEADER_OVERHEAD_MAX, data_pP, packet_sizeP); gtpv1u_tunnel_data_req_p = &message_p->ittiMsg.gtpv1uTunnelDataReq; gtpv1u_tunnel_data_req_p->S1u_enb_teid = addr_mapping_p->enb_S1U_teid; //#warning forced S1u_enb_teid to 1 for testing, waiting for MODIFY_BEARER REQUEST // gtpv1u_tunnel_data_req_p->S1u_enb_teid = 1; gtpv1u_tunnel_data_req_p->local_S1u_teid = addr_mapping_p->sgw_S1U_teid; gtpv1u_tunnel_data_req_p->length = packet_sizeP ; gtpv1u_tunnel_data_req_p->offset = GTPU_HEADER_OVERHEAD_MAX; gtpv1u_tunnel_data_req_p->buffer = message_payload_p; SGI_IF_DEBUG("%s send GTPV1U_TUNNEL_DATA_REQ to GTPV1U S1u_enb_teid %u local_S1u_teid %u size %u\n", __FUNCTION__, gtpv1u_tunnel_data_req_p->S1u_enb_teid, gtpv1u_tunnel_data_req_p->local_S1u_teid, gtpv1u_tunnel_data_req_p->length); itti_send_msg_to_task(TASK_GTPV1_U, INSTANCE_DEFAULT, message_p); }