Commit 6b21dea1 authored by Robert Schmidt's avatar Robert Schmidt

Remove legacy 4G kernel modules

I don't know about any user of the kernel modules. It is effectively
legacy code we carry around, for no good reason. Remove it for the
moment. If we ever need it, we can revert.
parent 8f549a54
......@@ -508,9 +508,6 @@ include_directories ("${OPENAIR_DIR}/radio/COMMON")
# ???!!! TO BE DOCUMENTED OPTIONS !!!???
##############################################################
add_boolean_option(OAI_NW_DRIVER_TYPE_ETHERNET False "????" ON)
add_boolean_option(OAI_NW_DRIVER_USE_NETLINK True "????" ON)
add_boolean_option(UE_EXPANSION False "enable UE_EXPANSION with max 256 UE" ON)
add_boolean_option(PHY_TX_THREAD False "enable UE_EXPANSION with max 256 UE" ON)
add_boolean_option(PRE_SCD_THREAD False "enable UE_EXPANSION with max 256 UE" ON)
......@@ -2331,7 +2328,7 @@ endforeach(myExe)
#ensure that the T header files are generated before targets depending on them
if (${T_TRACER})
foreach(i
#all "add_executable" definitions (except tests, rb_tool, updatefw)
#all "add_executable" definitions (except tests, updatefw)
lte-softmodem lte-uesoftmodem nr-softmodem
nr-uesoftmodem dlsim dlsim_tm4 dlsim_tm7
ulsim pbchsim scansim mbmssim pdcchsim pucchsim prachsim
......@@ -2354,85 +2351,6 @@ if (${T_TRACER})
endforeach(i)
endif (${T_TRACER})
##################################################
# Generated specific cases is not regular code
###############################################
################
# Kernel modules
###############
# Set compiler options for kernel modules
# we need to get out cmake to use the regular Linux Kernel process
# this is documented as https://www.kernel.org/doc/Documentation/kbuild/modules.txt
######################################
# retrieve the compiler options to send it to gccxml
get_directory_property(DirDefs COMPILE_DEFINITIONS )
foreach( d ${DirDefs} )
set(module_cc_opt "${module_cc_opt} -D${d}")
endforeach()
get_directory_property( DirDefs INCLUDE_DIRECTORIES )
foreach( d ${DirDefs} )
set(module_cc_opt "${module_cc_opt} -I${d}")
endforeach()
EXECUTE_PROCESS(COMMAND uname -r
OUTPUT_VARIABLE os_release
OUTPUT_STRIP_TRAILING_WHITESPACE)
SET(module_build_path /lib/modules/${os_release}/build)
function(make_driver name dir)
file(MAKE_DIRECTORY ${OPENAIR_BIN_DIR}/${name})
foreach(f IN ITEMS ${ARGN})
list(APPEND src_path_list ${dir}/${f})
string(REGEX REPLACE "c *$" "o" obj ${f})
set(objs "${objs} ${obj}")
endforeach()
CONFIGURE_FILE(${OPENAIR_CMAKE}/tools/Kbuild.cmake ${OPENAIR_BIN_DIR}/${name}/Kbuild)
add_custom_command(OUTPUT ${name}.ko
COMMAND make -C ${module_build_path} M=${OPENAIR_BIN_DIR}/${name}
WORKING_DIRECTORY ${OPENAIR_BIN_DIR}/${name}
COMMENT "building ${module}.ko"
VERBATIM
SOURCES ${src_path_list}
)
add_custom_target(${name} DEPENDS ${name}.ko)
endfunction(make_driver name dir src)
# nashmesh module
################
list(APPEND nasmesh_src device.c common.c ioctl.c classifier.c tool.c mesh.c)
# legacy Makefile was using NAS_NETLINK flag, but other drivers the hereafter flag
# so, this cmake use OAI_NW_DRIVER_USE_NETLINK everywhere
if (OAI_NW_DRIVER_USE_NETLINK)
list(APPEND nasmesh_src netlink.c)
endif()
make_driver(nasmesh ${OPENAIR2_DIR}/NETWORK_DRIVER/MESH ${nasmesh_src})
# user space tool for configuring MESH IP driver
################
add_executable(rb_tool
${OPENAIR2_DIR}/NETWORK_DRIVER/MESH/RB_TOOL/rb_tool.c
)
target_include_directories(rb_tool PRIVATE ${OPENAIR2_DIR}/NETWORK_DRIVER/MESH/)
# ???
####################
list(APPEND oai_nw_drv_src device.c common.c ioctl.c classifier.c tool.c)
if(OAI_NW_DRIVER_USE_NETLINK)
list(APPEND oai_nw_drv_src netlink.c)
endif()
make_driver(oai_nw_drv ${OPENAIR2_DIR}/NETWORK_DRIVER/LTE ${oai_nw_drv_src})
# ue_ip: purpose ???
###############
list(APPEND ue_ip_src device.c common.c)
if(OAI_NW_DRIVER_USE_NETLINK)
list(APPEND ue_ip_src netlink.c)
endif()
make_driver(ue_ip ${OPENAIR2_DIR}/NETWORK_DRIVER/UE_IP ${ue_ip_src})
include(${OPENAIR1_DIR}/PHY/CODING/nrLDPC_decoder/nrLDPC_tools/CMakeLists.txt)
set(ENABLE_TESTS OFF CACHE STRING "Activate build of tests")
......
......@@ -85,7 +85,7 @@ Options:
--RU
Makes the OAI RRU
--UE
Makes the UE specific parts (ue_ip, usim, nvram) from the given configuration file
Makes the UE specific parts (usim, nvram) from the given configuration file
--nrUE
Makes the NR UE softmodem
--UE-conf-nvram [configuration file]
......@@ -271,9 +271,6 @@ function main() {
--UE-gen-nvram)
gen_nvram_path=$(readlink -f "$2")
shift 2;;
--UE-ip)
TARGET_LIST="$TARGET_LIST ue_ip"
shift;;
-w | --hardware)
case "$2" in
"USRP" | "BLADERF" | "LMSSDR" | "IRIS")
......
......@@ -171,10 +171,6 @@ clean_kernel() {
$SUDO iptables -t filter -F
$SUDO iptables -t raw -F
echo_info "Flushed iptables"
$SUDO rmmod nasmesh > /dev/null 2>&1
$SUDO rmmod oai_nw_drv > /dev/null 2>&1
$SUDO rmmod ue_ip > /dev/null 2>&1
echo_info "removed drivers from kernel"
}
clean_all_files() {
......
#!/bin/bash
#/*
# * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
# * contributor license agreements. See the NOTICE file distributed with
# * this work for additional information regarding copyright ownership.
# * The OpenAirInterface Software Alliance licenses this file to You under
# * the OAI Public License, Version 1.1 (the "License"); you may not use this file
# * except in compliance with the License.
# * You may obtain a copy of the License at
# *
# * http://www.openairinterface.org/?page_id=698
# *
# * Unless required by applicable law or agreed to in writing, software
# * distributed under the License is distributed on an "AS IS" BASIS,
# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# * See the License for the specific language governing permissions and
# * limitations under the License.
# *-------------------------------------------------------------------------------
# * For more information about the OpenAirInterface (OAI) Software Alliance:
# * contact@openairinterface.org
# */
# file init_nas_nos1
# brief loads the nasmesh module and sets up the radio bearers (used to provide ip interface without S1 interface)
# author Florian Kaltenberger
#
#######################################
load_module() {
mod_name=${1##*/}
mod_name=${mod_name%.*}
if awk "/$mod_name/ {found=1 ;exit} END {if (found!=1) exit 1}" /proc/modules
then
echo "module $mod_name already loaded: I remove it first"
sudo rmmod $mod_name
fi
echo loading $mod_name
sudo insmod $1
}
load_module $OPENAIR_DIR/cmake_targets/ran_build/build/nasmesh.ko
if [ "$1" = "eNB" ]; then
echo "bring up oai0 interface for enb"
sudo ifconfig oai0 10.0.1.1 netmask 255.255.255.0 broadcast 10.0.1.255
$OPENAIR_DIR/cmake_targets/ran_build/build/rb_tool -a -c0 -i0 -z0 -s 10.0.1.1 -t 10.0.1.2 -r 1
else
if [ "$1" = "UE" ]; then
echo "bring up oai0 interface for UE"
sudo ifconfig oai0 10.0.1.2 netmask 255.255.255.0 broadcast 10.0.1.255
$OPENAIR_DIR/cmake_targets/ran_build/build/rb_tool -a -c0 -i0 -z0 -s 10.0.1.2 -t 10.0.1.1 -r 1
fi
fi
#!/bin/bash
#WARNING: this file may not work properly, be sure to know what you
#do when using it
#/*
# * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
# * contributor license agreements. See the NOTICE file distributed with
# * this work for additional information regarding copyright ownership.
# * The OpenAirInterface Software Alliance licenses this file to You under
# * the OAI Public License, Version 1.1 (the "License"); you may not use this file
# * except in compliance with the License.
# * You may obtain a copy of the License at
# *
# * http://www.openairinterface.org/?page_id=698
# *
# * Unless required by applicable law or agreed to in writing, software
# * distributed under the License is distributed on an "AS IS" BASIS,
# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# * See the License for the specific language governing permissions and
# * limitations under the License.
# *-------------------------------------------------------------------------------
# * For more information about the OpenAirInterface (OAI) Software Alliance:
# * contact@openairinterface.org
# */
################################################################################
# file init_nas_s1
# brief loads the ue_ip module and sets up IP for the UE
# you may want to edit it to fit your settings (replace oip0 by oipX for
# instance)
# author Florian Kaltenberger
#
#######################################
LTEIF=oip1
#OPENAIR_DIR=/home/oai/svn-oai/openair4G
load_module() {
mod_name=${1##*/}
mod_name=${mod_name%.*}
if awk "/$mod_name/ {found=1 ;exit} END {if (found!=1) exit 1}" /proc/modules
then
echo "module $mod_name already loaded: I remove it first"
sudo rmmod $mod_name
fi
echo loading $mod_name
sudo insmod $1
}
load_module ../ran_build/build/ue_ip.ko
if [ "$1" = "UE" ]; then
echo "bring up $LTEIF interface for UE"
sudo ifconfig $LTEIF up
fi
sudo ip route flush cache
sleep 1
sudo sysctl -w net.ipv4.conf.all.log_martians=1
echo "Disabling reverse path filtering"
sudo sysctl -w net.ipv4.conf.all.rp_filter=0
sudo ip route flush cache
# Check table 200 lte in /etc/iproute2/rt_tables
fgrep lte /etc/iproute2/rt_tables > /dev/null
if [ $? -ne 0 ]; then
echo "200 lte " >> /etc/iproute2/rt_tables
fi
sudo ip rule add fwmark 1 table lte
sudo ip route add default dev $LTEIF table lte
......@@ -38,7 +38,6 @@ Running the [build_oai](../cmake_targets/build_oai) script also generates some
- `conf2uedata`: a binary used to build the (4G) UE data from a configuration file. The created file emulates the sim card of a 3GPP compliant phone.
- `nvram`: a binary used to build (4G) UE (IMEI...) and EMM (IMSI, registered PLMN) non volatile data.
- `rb_tool`: radio bearer utility for (4G) UE
- `genids` T Tracer utility, used at build time to generate `T_IDs.h` include file. This binary is located in the [T Tracer source file directory](../common/utils/T) .
The build system for OAI uses [cmake](https://cmake.org/) which is a tool to generate makefiles. The `build_oai` script is a wrapper using `cmake` and `make`/`ninja` to ease the oai build and use. It logs the `cmake` and `ninja`/`make` commands it executes. The file describing how to build the executables from source files is the [CMakeLists.txt](../CMakeLists.txt), it is used as input by cmake to generate the makefiles.
......
......@@ -49,7 +49,6 @@ extern int otg_enabled;
#include "../MAC/mac_extern.h"
#include "RRC/L2_INTERFACE/openair_rrc_L2_interface.h"
#include "NETWORK_DRIVER/LITE/constant.h"
//#include "SIMULATION/ETH_TRANSPORT/extern.h"
#include "common/utils/LOG/log.h"
#include "UTIL/OTG/otg_tx.h"
......@@ -63,7 +62,6 @@ extern int otg_enabled;
#include <sys/socket.h>
#include <linux/netlink.h>
#include "NETWORK_DRIVER/UE_IP/constant.h"
extern char nl_rx_buf[NL_MAX_PAYLOAD];
extern struct sockaddr_nl nas_src_addr, nas_dest_addr;
......@@ -521,7 +519,7 @@ int pdcp_fifo_read_input_sdus_fromnetlinksock (const protocol_ctxt_t *const ctx
ctxt.rntiMaybeUEid = pdcp_UE_UE_module_id_to_rnti[ctxt.module_id];
if (rab_id != 0) {
if (rab_id == UE_IP_DEFAULT_RAB_ID) {
if (rab_id == 1) {
LOG_D(PDCP, "PDCP_COLL_KEY_DEFAULT_DRB_VALUE(module_id=%d, rnti=%lx, enb_flag=%d)\n", ctxt.module_id, ctxt.rntiMaybeUEid, ctxt.enb_flag);
key = PDCP_COLL_KEY_DEFAULT_DRB_VALUE(ctxt.module_id, ctxt.rntiMaybeUEid, ctxt.enb_flag);
h_rc = hashtable_get(pdcp_coll_p, key, (void **)&pdcp_p);
......@@ -695,7 +693,7 @@ void pdcp_fifo_read_input_sdus_frompc5s (const protocol_ctxt_t *const ctxt_pP)
//UE
if (!ctxt.enb_flag) {
if (rab_id != 0) {
if (rab_id == UE_IP_DEFAULT_RAB_ID) {
if (rab_id == 1) {
LOG_D(PDCP, "PDCP_COLL_KEY_DEFAULT_DRB_VALUE(module_id=%d, rnti=%lx, enb_flag=%d)\n", ctxt.module_id, ctxt.rntiMaybeUEid, ctxt.enb_flag);
key = PDCP_COLL_KEY_DEFAULT_DRB_VALUE(ctxt.module_id, ctxt.rntiMaybeUEid, ctxt.enb_flag);
h_rc = hashtable_get(pdcp_coll_p, key, (void **)&pdcp_p);
......
CC = gcc
NAS_DIR = ..
rb_tool: rb_tool.c
$(CC) rb_tool.c -o rb_tool -I../ -g -ggdb
all: rb_tool
clean:
rm rb_tool
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/***************************************************************************
rb_tool.c - User-space utility for driving NASMESH IOCTL interface
-------------------
copyright : (C) 2008 by Eurecom
email : raymond.knopp@eurecom.fr and navid.nikaein@eurecom.fr
***************************************************************************
***************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
//#include "rrc_nas_primitives.h"
#include "ioctl.h"
#include "constant.h"
#define NIPADDR(addr) \
(uint8_t)(addr & 0x000000FF), \
(uint8_t)((addr & 0x0000FF00) >> 8), \
(uint8_t)((addr & 0x00FF0000) >> 16), \
(uint8_t)((addr & 0xFF000000) >> 24)
#define NIP6ADDR(addr) \
ntohs((addr)->s6_addr16[0]), \
ntohs((addr)->s6_addr16[1]), \
ntohs((addr)->s6_addr16[2]), \
ntohs((addr)->s6_addr16[3]), \
ntohs((addr)->s6_addr16[4]), \
ntohs((addr)->s6_addr16[5]), \
ntohs((addr)->s6_addr16[6]), \
ntohs((addr)->s6_addr16[7])
// Global variables
int fd;
//ioctl
char dummy_buffer[1024];
struct oai_nw_drv_ioctl gifr;
//int wait_start_nas;
//---------------------------------------------------------------------------
void IAL_NAS_ioctl_init(int inst)
//---------------------------------------------------------------------------
{
struct oai_nw_drv_msg_statistic_reply *msgrep;
int err,rc;
sprintf(gifr.name, "oai%d",inst);
// Get an UDP IPv6 socket ??
fd=socket(AF_INET6, SOCK_DGRAM, 0);
if (fd<0) {
printf("Error opening socket\n");
exit(1);
}
sprintf(gifr.name, "oai%d",inst);
gifr.type = OAI_NW_DRV_MSG_STATISTIC_REQUEST;
memset ((void *)dummy_buffer,0,800);
gifr.msg= &(dummy_buffer[0]);
msgrep=(struct oai_nw_drv_msg_statistic_reply *)(gifr.msg);
printf("ioctl :Statistics requested\n");
err=ioctl(fd, OAI_NW_DRV_IOCTL_RRM, &gifr);
if (err<0) {
printf("IOCTL error, err=%d\n",err);
rc = -1;
}
printf("tx_packets = %u, rx_packets = %u\n", msgrep->tx_packets, msgrep->rx_packets);
printf("tx_bytes = %u, rx_bytes = %u\n", msgrep->tx_bytes, msgrep->rx_bytes);
printf("tx_errors = %u, rx_errors = %u\n", msgrep->tx_errors, msgrep->rx_errors);
printf("tx_dropped = %u, rx_dropped = %u\n", msgrep->tx_dropped, msgrep->rx_dropped);
}
#define NO_ACTION_RB 0
#define ADD_RB 1
#define DEL_RB 2
//---------------------------------------------------------------------------
int main(int argc,char **argv)
//---------------------------------------------------------------------------
{
int done;
int rc;
int meas_polling_counter;
fd_set readfds;
struct timeval tv;
int i;
int err;
char *buffer;
int c;
int action;
int rbset = 0;
int cxset = 0;
int classrefset = 0;
int instset = 0;
int saddr_ipv4set = 0;
int saddr_ipv6set = 0;
int daddr_ipv4set = 0;
int daddr_ipv6set = 0;
int dscpset = 0;
int dplen = 0;
int splen = 0;
int mpls_outlabelset = 0;
int mpls_inlabelset;
char rb[20];
char cx[20];
char classref[20];
char dscp[20];
char inst[20];
char mpls_outgoinglabel[100];
char mpls_incominglabel[100];
int index;
struct oai_nw_drv_msg_rb_establishment_request *msgreq;
struct oai_nw_drv_msg_class_add_request *msgreq_class;
in_addr_t saddr_ipv4;
in_addr_t daddr_ipv4;
struct in6_addr saddr_ipv6;
struct in6_addr daddr_ipv6;
unsigned int mpls_outlabel;
unsigned int mpls_inlabel;
char addr_str[46];
char mask_len_delims[] = "/";
char *result;
// scan options
rb[0] = '\0';
cx[0] = '\0';
dscp[0] = '\0';
mpls_incominglabel[0] = '\0';
mpls_outgoinglabel[0] = '\0';
action = NO_ACTION_RB;
while ((c = getopt (argc, argv, "adr:i:c:f:l:m:s:t:x:y:z:")) != -1)
switch (c) {
case 'a':
action = ADD_RB;
break;
case 'd':
action = DEL_RB;
break;
case 'r':
strcpy(rb,optarg);
rbset = 1;
break;
case 'i':
strcpy(inst,optarg);
instset = 1;
break;
case 'c':
strcpy(cx,optarg);
cxset = 1;
break;
case 'f':
strcpy(classref,optarg);
classrefset = 1;
break;
case 'l':
strcpy(mpls_outgoinglabel,optarg);
mpls_outlabelset=1;
break;
case 'm':
strcpy(mpls_incominglabel,optarg);
mpls_inlabelset=1;
break;
case 's':
result = strtok( optarg, mask_len_delims );
if ( result != NULL ) {
inet_aton(result,&saddr_ipv4);
printf("Arg Source Addr IPv4 string: %s\n",result);
saddr_ipv4set = 1;
} else {
printf("Arg Source Addr IPv4 string: ERROR\n");
break;
}
result = strtok( NULL, mask_len_delims );
if ( result != NULL ) {
splen = atoi(result);
} else {
splen = 32;
}
printf("Arg Source Addr IPv4 mask len: %d\n",splen);
break;
case 't':
result = strtok( optarg, mask_len_delims );
if ( result != NULL ) {
inet_aton(result,&daddr_ipv4);
printf("Arg Dest Addr IPv4 string: %s\n",result);
daddr_ipv4set = 1;
} else {
printf("Arg Dest Addr IPv4 string: ERROR\n");
break;
}
result = strtok( NULL, mask_len_delims );
if ( result != NULL ) {
dplen = atoi(result);
} else {
dplen = 32;
}
printf("Arg Dest Addr IPv4 mask len: %d\n",dplen);
break;
case 'x':
result = strtok( optarg, mask_len_delims );
if ( result != NULL ) {
printf("Arg Source Addr IPv6 string: %s\n",result);
inet_pton(AF_INET6,result,(void *)&saddr_ipv6);
saddr_ipv6set = 1;
} else {
printf("Arg Source Addr IPv6 string: ERROR\n");
break;
}
result = strtok( NULL, mask_len_delims );
if ( result != NULL ) {
splen = atoi(result);
} else {
splen = 128;
}
printf("Arg Source Addr IPv6 mask len: %d\n",splen);
break;
case 'y':
result = strtok( optarg, mask_len_delims );
if ( result != NULL ) {
printf("Arg Dest Addr IPv6 string: %s\n",result);
inet_pton(AF_INET6,result,(void *)&daddr_ipv6);
daddr_ipv6set = 1;
} else {
printf("Arg Dest Addr IPv6 string: ERROR\n");
break;
}
result = strtok( NULL, mask_len_delims );
if ( result != NULL ) {
dplen = atoi(result);
} else {
dplen = 128;
}
printf("Arg Dest Addr IPv6 mask len: %d\n",dplen);
break;
case 'z':
dscpset=1;
strcpy(dscp,optarg);
break;
case '?':
if (isprint (optopt))
fprintf (stderr, "Unknown option `-%c'.\n", optopt);
else
fprintf (stderr,
"Unknown option character `\\x%x'.\n",
optopt);
return 1;
default:
abort ();
}
printf ("action = %d, rb = %s,cx = %s\n", action, rb, cx);
if (rbset==0) {
printf("ERROR: Specify a RAB id!!\n");
exit(-1);
}
if (cxset==0) {
printf("ERROR: Specify an LCR !!\n");
exit(-1);
}
if (classrefset==0) {
printf("ERROR: Specify an Class reference !!\n");
exit(-1);
}
if (instset==0) {
printf("ERROR: Specify an interface !!\n");
exit(-1);
}
if ((mpls_outlabelset == 0) && (saddr_ipv4set==0) && (saddr_ipv6set==0)) {
printf("ERROR: Specify a source IP address\n");
exit(-1);
}
if ((mpls_outlabelset == 0) && (daddr_ipv4set==0) && (daddr_ipv6set==0)) {
printf("ERROR: Specify a destination IP address\n");
exit(-1);
}
if ((mpls_outlabelset == 1) && (mpls_inlabelset == 0)) {
printf("ERROR: Specify an incoming MPLS label\n");
exit(-1);
}
if ((mpls_inlabelset == 1) && (mpls_outlabelset == 0)) {
printf("ERROR: Specify an outgoing MPLS label\n");
exit(-1);
}
IAL_NAS_ioctl_init(atoi(inst));
msgreq = (struct oai_nw_drv_msg_rb_establishment_request *)(gifr.msg);
msgreq->rab_id = atoi(rb);
msgreq->lcr = atoi(cx);
msgreq->qos = 0;
if (action == ADD_RB) {
gifr.type = OAI_NW_DRV_MSG_RB_ESTABLISHMENT_REQUEST;
printf("OAI_NW_DRV_MSG_RB_ESTABLISHMENT_REQUEST: RB %d LCR %d QOS %d\n ", msgreq->rab_id, msgreq->lcr, msgreq->qos);
err=ioctl(fd, OAI_NW_DRV_IOCTL_RRM, &gifr);
}
// only add classification rule
if ((action == ADD_RB ) || (action == NO_ACTION_RB)) {
if (saddr_ipv4set == 1) {
msgreq_class = (struct oai_nw_drv_msg_class_add_request *)(gifr.msg);
msgreq_class->rab_id = atoi(rb);
msgreq_class->lcr = atoi(cx);
msgreq_class->version = 4;
msgreq_class->classref = atoi(classref) + (msgreq_class->lcr<<8);
msgreq_class->dir = OAI_NW_DRV_DIRECTION_SEND;
msgreq_class->fct = OAI_NW_DRV_FCT_QOS_SEND;
msgreq_class->saddr.ipv4 = saddr_ipv4;
msgreq_class->daddr.ipv4 = daddr_ipv4;
msgreq_class->dplen = dplen;
msgreq_class->splen = splen;
// TO BE FIXED WHEN WE CAN SPECIFY A PROTOCOL-based rule
msgreq_class->protocol = OAI_NW_DRV_PROTOCOL_DEFAULT;
if (dscpset==0) {
msgreq_class->dscp=0;
} else {
msgreq_class->dscp=atoi(dscp);
}
printf("OAI_NW_DRV_MSG_CLASS_ADD_REQUEST: OAI_NW_DRV_DIRECTION_SEND RB %d LCR %d ClassRef %d ", msgreq_class->rab_id, msgreq_class->lcr, msgreq_class->classref);
printf("IPV4: Source = %d.%d.%d.%d/%d ", NIPADDR(msgreq_class->saddr.ipv4), msgreq_class->splen);
printf(" IPV4: Dest = %d.%d.%d.%d/%d\n", NIPADDR(msgreq_class->daddr.ipv4), msgreq_class->dplen);
gifr.type = OAI_NW_DRV_MSG_CLASS_ADD_REQUEST;
err=ioctl(fd, OAI_NW_DRV_IOCTL_RRM, &gifr);
msgreq_class->rab_id = atoi(rb);
msgreq_class->lcr = atoi(cx);
msgreq_class->version = 4;
msgreq_class->classref = atoi(classref) + 1 + (msgreq_class->lcr<<8);
msgreq_class->dir = OAI_NW_DRV_DIRECTION_RECEIVE;
msgreq_class->fct = OAI_NW_DRV_FCT_QOS_SEND;
msgreq_class->daddr.ipv4 = saddr_ipv4;
msgreq_class->saddr.ipv4 = daddr_ipv4;
msgreq_class->dplen = splen;
msgreq_class->splen = dplen;
printf("OAI_NW_DRV_MSG_CLASS_ADD_REQUEST: OAI_NW_DRV_DIRECTION_RECEIVE RB %d LCR %d ClassRef %d ", msgreq_class->rab_id, msgreq_class->lcr, msgreq_class->classref);
printf("IPV4: Source = %d.%d.%d.%d/%d ", NIPADDR(msgreq_class->saddr.ipv4), msgreq_class->splen);
printf("IPV4: Dest = %d.%d.%d.%d/%d\n", NIPADDR(msgreq_class->daddr.ipv4), msgreq_class->dplen);
gifr.type = OAI_NW_DRV_MSG_CLASS_ADD_REQUEST;
err=ioctl(fd, OAI_NW_DRV_IOCTL_RRM, &gifr);
}
if (saddr_ipv6set == 1) {
msgreq_class = (struct oai_nw_drv_msg_class_add_request *)(gifr.msg);
msgreq_class->rab_id = atoi(rb);
msgreq_class->lcr = atoi(cx);
msgreq_class->version = 6;
msgreq_class->dplen = dplen;
msgreq_class->splen = splen;
if (dscpset==0)
msgreq_class->dscp = 0;
else
msgreq_class->dscp = atoi(dscp);
msgreq_class->classref = atoi(classref) + (msgreq_class->lcr<<8);
msgreq_class->dir = OAI_NW_DRV_DIRECTION_SEND;
msgreq_class->fct = OAI_NW_DRV_FCT_QOS_SEND;
// TO BE FIXED WHEN WE CAN SPECIFY A PROTOCOL-based rule
msgreq_class->protocol = OAI_NW_DRV_PROTOCOL_DEFAULT;
memcpy(&msgreq_class->saddr.ipv6,&saddr_ipv6,16);
memcpy(&msgreq_class->daddr.ipv6,&daddr_ipv6,16);
printf("OAI_NW_DRV_MSG_CLASS_ADD_REQUEST: OAI_NW_DRV_DIRECTION_SEND RB %d LCR %d ClassRef %d ", msgreq_class->rab_id, msgreq_class->lcr, msgreq_class->classref);
printf("IPV6: Source = %x:%x:%x:%x:%x:%x:%x:%x/%d ", NIP6ADDR(&msgreq_class->saddr.ipv6), msgreq_class->splen);
printf("IPV6: Dest = %x:%x:%x:%x:%x:%x:%x:%x/%d\n", NIP6ADDR(&msgreq_class->daddr.ipv6), msgreq_class->dplen);
gifr.type = OAI_NW_DRV_MSG_CLASS_ADD_REQUEST;
err=ioctl(fd, OAI_NW_DRV_IOCTL_RRM, &gifr);
msgreq_class->rab_id = atoi(rb);
msgreq_class->lcr = atoi(cx);
msgreq_class->dplen = splen;
msgreq_class->splen = dplen;
msgreq_class->classref = atoi(classref) + 1 + (msgreq_class->lcr<<8);
msgreq_class->dir = OAI_NW_DRV_DIRECTION_RECEIVE;
memcpy(&msgreq_class->daddr.ipv6,&saddr_ipv6,16);
memcpy(&msgreq_class->saddr.ipv6,&daddr_ipv6,16);
printf("OAI_NW_DRV_MSG_CLASS_ADD_REQUEST: OAI_NW_DRV_DIRECTION_RECEIVE RB %d LCR %d ClassRef %d ", msgreq_class->rab_id, msgreq_class->lcr, msgreq_class->classref);
printf("IPV6: Source = %x:%x:%x:%x:%x:%x:%x:%x/%d ", NIP6ADDR(&msgreq_class->saddr.ipv6), msgreq_class->splen);
printf("IPV6: Dest = %x:%x:%x:%x:%x:%x:%x:%x/%d\n", NIP6ADDR(&msgreq_class->daddr.ipv6), msgreq_class->dplen);
gifr.type = OAI_NW_DRV_MSG_CLASS_ADD_REQUEST;
err=ioctl(fd, OAI_NW_DRV_IOCTL_RRM, &gifr);
}
if (mpls_inlabelset == 1) {
msgreq_class = (struct oai_nw_drv_msg_class_add_request *)(gifr.msg);
msgreq_class->rab_id = atoi(rb);
msgreq_class->lcr = atoi(cx);
msgreq_class->version = OAI_NW_DRV_MPLS_VERSION_CODE;
if (dscpset==0)
msgreq_class->dscp=0;
else
msgreq_class->dscp=atoi(dscp);
msgreq_class->classref = atoi(classref) + (msgreq_class->lcr<<8);
//msgreq_class->classref = 4 + (msgreq_class->lcr<<3);
msgreq_class->dir=OAI_NW_DRV_DIRECTION_SEND;
msgreq_class->fct=OAI_NW_DRV_FCT_QOS_SEND;
// TO BE FIXED WHEN WE CAN SPECIFY A PROTOCOL-based rule
msgreq_class->protocol = OAI_NW_DRV_PROTOCOL_DEFAULT;
mpls_outlabel = atoi(mpls_outgoinglabel);
printf("Setting MPLS outlabel %u with exp %d\n",mpls_outlabel,msgreq_class->dscp);
msgreq_class->daddr.mpls_label = mpls_outlabel;
gifr.type = OAI_NW_DRV_MSG_CLASS_ADD_REQUEST;
err=ioctl(fd, OAI_NW_DRV_IOCTL_RRM, &gifr);
msgreq_class->rab_id = atoi(rb);
msgreq_class->lcr = atoi(cx);
msgreq_class->classref = atoi(classref) + 1 + (msgreq_class->lcr<<8);
//msgreq_class->classref = 5 + (msgreq_class->lcr<<3);
msgreq_class->dir=OAI_NW_DRV_DIRECTION_RECEIVE;
// TO BE FIXED WHEN WE CAN SPECIFY A PROTOCOL-based rule
msgreq_class->protocol = OAI_NW_DRV_PROTOCOL_DEFAULT;
mpls_inlabel = atoi(mpls_incominglabel);
printf("Setting MPLS inlabel %u with exp %d\n",mpls_inlabel,msgreq_class->dscp);
msgreq_class->daddr.mpls_label = mpls_inlabel;
gifr.type = OAI_NW_DRV_MSG_CLASS_ADD_REQUEST;
err=ioctl(fd, OAI_NW_DRV_IOCTL_RRM, &gifr);
}
} else if (action == DEL_RB) {
gifr.type = OAI_NW_DRV_MSG_RB_RELEASE_REQUEST;
err=ioctl(fd, OAI_NW_DRV_IOCTL_RRM, &gifr);
}
}
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/*! \file classifier.c
* \brief Classify IP packets
* \author Navid Nikaein, Lionel GAUTHIER, Raymond knopp
* \company Eurecom
* \email: navid.nikaein@eurecom.fr, lionel.gauthier@eurecom.fr, knopp@eurecom.fr
*/
#include "local.h"
#include "proto_extern.h"
#include <net/ip6_fib.h>
#include <net/route.h>
#ifdef MPLS
#include <net/mpls.h>
#endif
#define IN_CLASSA(a) ((((long int) (a)) & 0x80000000) == 0)
#define IN_CLASSB(a) ((((long int) (a)) & 0xc0000000) == 0x80000000)
#define IN_CLASSC(a) ((((long int) (a)) & 0xe0000000) == 0xc0000000)
#define IN_CLASSD(a) ((((long int) (a)) & 0xf0000000) == 0xe0000000)
#define IN_MULTICAST(a) IN_CLASSD(a)
#define IN_EXPERIMENTAL(a) ((((long int) (a)) & 0xf0000000) == 0xf0000000)
#define IN_BADCLASS(a) IN_EXPERIMENTAL((a))
/* Address to accept any incoming messages. */
#define INADDR_ANY ((unsigned long int) 0x00000000)
/* Address to send to all hosts. */
#define INADDR_BROADCAST ((unsigned long int) 0xffffffff)
/* Address indicating an error return. */
#define INADDR_NONE ((unsigned long int) 0xffffffff)
#define NIPADDR(addr) \
(uint8_t)(addr & 0x000000FF), \
(uint8_t)((addr & 0x0000FF00) >> 8), \
(uint8_t)((addr & 0x00FF0000) >> 16), \
(uint8_t)((addr & 0xFF000000) >> 24)
#define NIP6ADDR(addr) \
ntohs((addr)->s6_addr16[0]), \
ntohs((addr)->s6_addr16[1]), \
ntohs((addr)->s6_addr16[2]), \
ntohs((addr)->s6_addr16[3]), \
ntohs((addr)->s6_addr16[4]), \
ntohs((addr)->s6_addr16[5]), \
ntohs((addr)->s6_addr16[6]), \
ntohs((addr)->s6_addr16[7])
#define IN6_IS_ADDR_UNSPECIFIED(a) \
(((__const uint32_t *) (a))[0] == 0 \
&& ((__const uint32_t *) (a))[1] == 0 \
&& ((__const uint32_t *) (a))[2] == 0 \
&& ((__const uint32_t *) (a))[3] == 0)
#define IN6_IS_ADDR_LOOPBACK(a) \
(((__const uint32_t *) (a))[0] == 0 \
&& ((__const uint32_t *) (a))[1] == 0 \
&& ((__const uint32_t *) (a))[2] == 0 \
&& ((__const uint32_t *) (a))[3] == htonl (1))
#define IN6_IS_ADDR_MULTICAST(a) (((__const uint8_t *) (a))[0] == 0xff)
#define IN6_IS_ADDR_LINKLOCAL(a) \
((((__const uint32_t *) (a))[0] & htonl (0xffc00000)) \
== htonl (0xfe800000))
#define IN6_IS_ADDR_SITELOCAL(a) \
((((__const uint32_t *) (a))[0] & htonl (0xffc00000)) \
== htonl (0xfec00000))
#define IN6_IS_ADDR_V4MAPPED(a) \
((((__const uint32_t *) (a))[0] == 0) \
&& (((__const uint32_t *) (a))[1] == 0) \
&& (((__const uint32_t *) (a))[2] == htonl (0xffff)))
#define IN6_IS_ADDR_V4COMPAT(a) \
((((__const uint32_t *) (a))[0] == 0) \
&& (((__const uint32_t *) (a))[1] == 0) \
&& (((__const uint32_t *) (a))[2] == 0) \
&& (ntohl (((__const uint32_t *) (a))[3]) > 1))
#define IN6_ARE_ADDR_EQUAL(a,b) \
((((__const uint32_t *) (a))[0] == ((__const uint32_t *) (b))[0]) \
&& (((__const uint32_t *) (a))[1] == ((__const uint32_t *) (b))[1]) \
&& (((__const uint32_t *) (a))[2] == ((__const uint32_t *) (b))[2]) \
&& (((__const uint32_t *) (a))[3] == ((__const uint32_t *) (b))[3]))
#define IN6_IS_ADDR_MC_NODELOCAL(a) \
(IN6_IS_ADDR_MULTICAST(a) \
&& ((((__const uint8_t *) (a))[1] & 0xf) == 0x1))
#define IN6_IS_ADDR_MC_LINKLOCAL(a) \
(IN6_IS_ADDR_MULTICAST(a) \
&& ((((__const uint8_t *) (a))[1] & 0xf) == 0x2))
#define IN6_IS_ADDR_MC_SITELOCAL(a) \
(IN6_IS_ADDR_MULTICAST(a) \
&& ((((__const uint8_t *) (a))[1] & 0xf) == 0x5))
#define IN6_IS_ADDR_MC_ORGLOCAL(a) \
(IN6_IS_ADDR_MULTICAST(a) \
&& ((((__const uint8_t *) (a))[1] & 0xf) == 0x8))
#define IN6_IS_ADDR_MC_GLOBAL(a) \
(IN6_IS_ADDR_MULTICAST(a) \
&& ((((__const uint8_t *) (a))[1] & 0xf) == 0xe))
#define IN6_ARE_ADDR_MASKED_EQUAL(a,b,m) \
(((((__const uint32_t *) (a))[0] & (((__const uint32_t *) (m))[0])) == (((__const uint32_t *) (b))[0] & (((__const uint32_t *) (m))[0]))) \
&& ((((__const uint32_t *) (a))[1] & (((__const uint32_t *) (m))[1])) == (((__const uint32_t *) (b))[1] & (((__const uint32_t *) (m))[1]))) \
&& ((((__const uint32_t *) (a))[2] & (((__const uint32_t *) (m))[2])) == (((__const uint32_t *) (b))[2] & (((__const uint32_t *) (m))[2]))) \
&& ((((__const uint32_t *) (a))[3] & (((__const uint32_t *) (m))[3])) == (((__const uint32_t *) (b))[3] & (((__const uint32_t *) (m))[3]))))
#define IN_ARE_ADDR_MASKED_EQUAL(a,b,m) \
(((((__const uint8_t *) (a))[0] & (((__const uint8_t *) (m))[0])) == (((__const uint8_t *) (b))[0] & (((__const uint8_t *) (m))[0]))) \
&& ((((__const uint8_t *) (a))[1] & (((__const uint8_t *) (m))[1])) == (((__const uint8_t *) (b))[1] & (((__const uint8_t *) (m))[1]))) \
&& ((((__const uint8_t *) (a))[2] & (((__const uint8_t *) (m))[2])) == (((__const uint8_t *) (b))[2] & (((__const uint8_t *) (m))[2]))) \
&& ((((__const uint8_t *) (a))[3] & (((__const uint8_t *) (m))[3])) == (((__const uint8_t *) (b))[3] & (((__const uint8_t *) (m))[3]))))
//---------------------------------------------------------------------------
// Find the IP traffic type (UNICAST, MULTICAST, BROADCAST)
ip_traffic_type_t oai_nw_drv_find_traffic_type(struct sk_buff *skb)
{
//---------------------------------------------------------------------------
ip_traffic_type_t traffic_type = TRAFFIC_IPVX_TYPE_UNKNOWN;
if (skb!=NULL) {
switch (ntohs(skb->protocol)) {
case ETH_P_IPV6:
traffic_type = TRAFFIC_IPV6_TYPE_UNKNOWN;
#ifdef OAI_DRV_DEBUG_CLASS
printk("SOURCE ADDR %X:%X:%X:%X:%X:%X:%X:%X",NIP6ADDR(&(ipv6_hdr(skb)->saddr)));
printk(" DEST ADDR %X:%X:%X:%X:%X:%X:%X:%X\n",NIP6ADDR(&(ipv6_hdr(skb)->daddr)));
#endif
if (IN6_IS_ADDR_MULTICAST(&ipv6_hdr(skb)->daddr.in6_u.u6_addr32[0])) {
traffic_type = TRAFFIC_IPV6_TYPE_MULTICAST;
} else {
traffic_type = TRAFFIC_IPV6_TYPE_UNICAST;
}
break;
case ETH_P_IP:
traffic_type = TRAFFIC_IPV4_TYPE_UNKNOWN;
//print_TOOL_pk_ipv4((struct iphdr *)skb->network_header);
if (IN_MULTICAST(htonl(ip_hdr(skb)->daddr))) {
traffic_type = TRAFFIC_IPV4_TYPE_MULTICAST;
} else {
traffic_type = TRAFFIC_IPV4_TYPE_UNICAST;
}
// TO DO BROADCAST
break;
case ETH_P_ARP:
traffic_type = TRAFFIC_IPV4_TYPE_BROADCAST;
break;
default:
;
}
}
return traffic_type;
}
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/*! \file common.c
* \brief implementation of emultor tx and rx
* \author Navid Nikaein, Lionel GAUTHIER, and Raymomd Knopp
* \date 2011
* \version 1.0
* \company Eurecom
* \email: navid.nikaein@eurecom.fr, lionel.gauthier@eurecom.fr
*/
#include "local.h"
#include "proto_extern.h"
#ifndef OAI_NW_DRIVER_USE_NETLINK
#include "rtai_fifos.h"
#endif
#include <linux/inetdevice.h>
#ifdef OAI_NW_DRIVER_TYPE_ETHERNET
#include <linux/etherdevice.h>
#endif
#include <net/tcp.h>
#include <net/udp.h>
#define NIPADDR(addr) \
(uint8_t)(addr & 0x000000FF), \
(uint8_t)((addr & 0x0000FF00) >> 8), \
(uint8_t)((addr & 0x00FF0000) >> 16), \
(uint8_t)((addr & 0xFF000000) >> 24)
#define NIP6ADDR(addr) \
ntohs((addr)->s6_addr16[0]), \
ntohs((addr)->s6_addr16[1]), \
ntohs((addr)->s6_addr16[2]), \
ntohs((addr)->s6_addr16[3]), \
ntohs((addr)->s6_addr16[4]), \
ntohs((addr)->s6_addr16[5]), \
ntohs((addr)->s6_addr16[6]), \
ntohs((addr)->s6_addr16[7])
//#define OAI_DRV_DEBUG_SEND
//#define OAI_DRV_DEBUG_RECEIVE
void oai_nw_drv_common_class_wireless2ip(uint16_t dlen,
void *pdcp_sdu,
int inst,
OaiNwDrvRadioBearerId_t rb_id)
{
//---------------------------------------------------------------------------
struct sk_buff *skb;
struct ipversion *ipv;
struct oai_nw_drv_priv *gpriv=netdev_priv(oai_nw_drv_dev[inst]);
unsigned int hard_header_len = 0;
uint16_t *p_ether_type;
uint16_t ether_type;
#ifdef OAI_DRV_DEBUG_RECEIVE
int i;
unsigned char *addr;
#endif
unsigned char protocol;
struct iphdr *network_header;
#ifdef NAS_ADDRESS_FIX
uint32_t odaddr,osaddr;
unsigned char *addr,*daddr,*saddr,*ifaddr;
uint16_t *cksum,check;
#endif // NAS_ADDRESS_FIX
#ifdef OAI_DRV_DEBUG_RECEIVE
printk("[OAI_IP_DRV][%s] begin RB %d Inst %d Length %d bytes\n",__FUNCTION__, rb_id,inst,dlen);
#endif
skb = dev_alloc_skb( dlen + 2 );
if(!skb) {
printk("[OAI_IP_DRV][%s] low on memory\n",__FUNCTION__);
++gpriv->stats.rx_dropped;
return;
}
skb_reserve(skb,2);
memcpy(skb_put(skb, dlen), pdcp_sdu,dlen);
skb->dev = oai_nw_drv_dev[inst];
hard_header_len = oai_nw_drv_dev[inst]->hard_header_len;
skb_set_mac_header(skb, 0);
skb_set_network_header(skb, hard_header_len);
skb->mark = rb_id;
skb->pkt_type = PACKET_HOST;
#ifdef OAI_DRV_DEBUG_RECEIVE
printk("[OAI_IP_DRV][%s] Receiving packet @%p of size %d from PDCP \n",__FUNCTION__, skb->data, skb->len);
for (i=0; i<skb->len; i++)
printk("%2x ",((unsigned char *)(skb->data))[i]);
printk("\n");
#endif
// LG TEST skb->ip_summed = CHECKSUM_NONE;
skb->ip_summed = CHECKSUM_UNNECESSARY;
ipv = (struct ipversion *)skb_network_header(skb);
switch (ipv->version) {
case 6:
#ifdef OAI_DRV_DEBUG_RECEIVE
printk("[OAI_IP_DRV][%s] receive IPv6 message\n",__FUNCTION__);
#endif
skb_set_network_header(skb, hard_header_len);
//skb->network_header = &skb->data[hard_header_len];
if (hard_header_len == 0) {
skb->protocol = htons(ETH_P_IPV6);
} else {
#ifdef OAI_NW_DRIVER_TYPE_ETHERNET
skb->protocol = eth_type_trans(skb, oai_nw_drv_dev[inst]);
#else
#endif
}
//printk("Writing packet with protocol %x\n",ntohs(skb->protocol));
break;
case 4:
#ifdef NAS_ADDRESS_FIX
// Make the third byte of both the source and destination equal to the fourth of the destination
daddr = (unsigned char *)&((struct iphdr *)&skb->data[hard_header_len])->daddr;
odaddr = ((struct iphdr *)skb->data)->daddr;
//sn = addr[3];
saddr = (unsigned char *)&((struct iphdr *)&skb->data[hard_header_len])->saddr;
osaddr = ((struct iphdr *)&skb->data[hard_header_len])->saddr;
if (daddr[0] == saddr[0]) {// same network
daddr[2] = daddr[3]; // set third byte of destination to that of local machine so that local IP stack accepts the packet
saddr[2] = daddr[3]; // set third byte of source to that of local machine so that local IP stack accepts the packet
} else { // get the 3rd byte from device address in net_device structure
ifaddr = (unsigned char *)(&(((struct in_device *)((oai_nw_drv_dev[inst])->ip_ptr))->ifa_list->ifa_local));
if (saddr[0] == ifaddr[0]) { // source is in same network as local machine
daddr[0] += saddr[3]; // fix address of remote destination to undo change at source
saddr[2] = ifaddr[2]; // set third byte to that of local machine so that local IP stack accepts the packet
} else { // source is remote machine from outside network
saddr[0] -= daddr[3]; // fix address of remote source to be understood by destination
daddr[2] = daddr[3]; // fix 3rd byte of local address to be understood by IP stack of
// destination
}
}
#endif //NAS_ADDRESS_FIX
#ifdef OAI_DRV_DEBUG_RECEIVE
//printk("NAS_TOOL_RECEIVE: receive IPv4 message\n");
addr = (unsigned char *)&((struct iphdr *)&skb->data[hard_header_len])->saddr;
if (addr) {
//addr[2]^=0x01;
printk("[OAI_IP_DRV][%s] Source %d.%d.%d.%d\n",__FUNCTION__, addr[0],addr[1],addr[2],addr[3]);
}
addr = (unsigned char *)&((struct iphdr *)&skb->data[hard_header_len])->daddr;
if (addr) {
//addr[2]^=0x01;
printk("[OAI_IP_DRV][%s] Dest %d.%d.%d.%d\n",__FUNCTION__, addr[0],addr[1],addr[2],addr[3]);
}
printk("[OAI_IP_DRV][%s] protocol %d\n",__FUNCTION__, ((struct iphdr *)&skb->data[hard_header_len])->protocol);
#endif
skb_set_network_header(skb, hard_header_len);
//skb->network_header = &skb->data[hard_header_len];
network_header = (struct iphdr *)skb_network_header(skb);
protocol = network_header->protocol;
#ifdef OAI_DRV_DEBUG_RECEIVE
switch (protocol) {
case IPPROTO_IP:
printk("[OAI_IP_DRV][%s] Received Raw IPv4 packet\n",__FUNCTION__);
break;
case IPPROTO_IPV6:
printk("[OAI_IP_DRV][%s] Received Raw IPv6 packet\n",__FUNCTION__);
break;
case IPPROTO_ICMP:
printk("[OAI_IP_DRV][%s] Received Raw ICMP packet\n",__FUNCTION__);
break;
case IPPROTO_TCP:
printk("[OAI_IP_DRV][%s] Received TCP packet\n",__FUNCTION__);
break;
case IPPROTO_UDP:
printk("[OAI_IP_DRV][%s] Received UDP packet\n",__FUNCTION__);
break;
default:
break;
}
#endif
#ifdef NAS_ADDRESS_FIX
network_header->check = 0;
network_header->check = ip_fast_csum((unsigned char *) network_header, network_header->ihl);
//printk("[OAI_IP_DRV][COMMON][RECEIVE] IP Fast Checksum %x \n", network_header->check);
switch(protocol) {
case IPPROTO_TCP:
cksum = (uint16_t*)&(((struct tcphdr*)((network_header + (network_header->ihl<<2))))->check);
check = csum_tcpudp_magic(((struct iphdr *)network_header)->saddr, ((struct iphdr *)network_header)->daddr, 0,0, ~(*cksum));
//check = csum_tcpudp_magic(((struct iphdr *)network_header)->saddr, ((struct iphdr *)network_header)->daddr, tcp_hdrlen(skb), IPPROTO_TCP, ~(*cksum));
//check = csum_tcpudp_magic(((struct iphdr *)network_header)->saddr, ((struct iphdr *)network_header)->daddr, dlen, IPPROTO_TCP, ~(*cksum));
*cksum = csum_tcpudp_magic(~osaddr, ~odaddr, 0, 0, ~check);
//*cksum = csum_tcpudp_magic(~osaddr, ~odaddr, dlen, IPPROTO_TCP, ~check);
#ifdef OAI_DRV_DEBUG_RECEIVE
printk("[OAI_IP_DRV][%s] Inst %d TCP packet calculated CS %x, CS = %x (before), SA (%x)%x, DA (%x)%x\n",__FUNCTION__,
inst,
network_header->check,
*cksum,
osaddr,
((struct iphdr *)skb->data)->saddr,
odaddr,
((struct iphdr *)skb->data)->daddr);
printk("[OAI_IP_DRV][%s] Inst %d TCP packet NEW CS %x\n",__FUNCTION__,
inst,
*cksum);
#endif
break;
case IPPROTO_UDP:
cksum = (uint16_t*)&(((struct udphdr*)((network_header + (network_header->ihl<<2))))->check);
check = csum_tcpudp_magic(((struct iphdr *)network_header)->saddr, ((struct iphdr *)network_header)->daddr, 0,0, ~(*cksum));
// check = csum_tcpudp_magic(((struct iphdr *)network_header)->saddr, ((struct iphdr *)network_header)->daddr, udp_hdr(skb)->len, IPPROTO_UDP, ~(*cksum));
//check = csum_tcpudp_magic(((struct iphdr *)network_header)->saddr, ((struct iphdr *)network_header)->daddr, dlen, IPPROTO_UDP, ~(*cksum));
*cksum= csum_tcpudp_magic(~osaddr, ~odaddr,0,0, ~check);
//*cksum= csum_tcpudp_magic(~osaddr, ~odaddr,udp_hdr(skb)->len, IPPROTO_UDP, ~check);
//*cksum= csum_tcpudp_magic(~osaddr, ~odaddr,dlen, IPPROTO_UDP, ~check);
#ifdef OAI_DRV_DEBUG_RECEIVE
printk("[OAI_IP_DRV][%s] Inst %d UDP packet CS = %x (before), SA (%x)%x, DA (%x)%x\n",__FUNCTION__,
inst,*cksum,osaddr,((struct iphdr *)&skb->data[hard_header_len])->saddr,odaddr,((struct iphdr *)&skb->data[hard_header_len])->daddr);
printk("[OAI_IP_DRV][%s] Inst %d UDP packet NEW CS %x\n",__FUNCTION__,inst,*cksum);
#endif
//if ((check = *cksum) != 0) {
// src, dst, len, proto, sum
// }
break;
default:
break;
}
#endif //NAS_ADDRESS_FIX
if (hard_header_len == 0) {
skb->protocol = htons(ETH_P_IP);
} else {
#ifdef OAI_NW_DRIVER_TYPE_ETHERNET
skb->protocol = eth_type_trans(skb, oai_nw_drv_dev[inst]);
#else
#endif
}
//printk("[OAI_IP_DRV][COMMON] Writing packet with protocol %x\n",ntohs(skb->protocol));
break;
default:
// fill skb->pkt_type, skb->dev
skb->protocol = eth_type_trans(skb, oai_nw_drv_dev[inst]);
// minus 1(short) instead of 2(bytes) because uint16_t*
p_ether_type = (uint16_t *)(skb_network_header(skb)-2);
ether_type = ntohs(*p_ether_type);
switch (ether_type) {
case ETH_P_ARP:
#ifdef OAI_DRV_DEBUG_RECEIVE
printk("[OAI_IP_DRV][%s] ether_type = ETH_P_ARP\n",__FUNCTION__);
#endif
//skb->pkt_type = PACKET_HOST;
skb->protocol = htons(ETH_P_ARP);
break;
default:
;
}
printk("[OAI_IP_DRV][%s] begin RB %d Inst %d Length %d bytes\n",__FUNCTION__,rb_id,inst,dlen);
printk("[OAI_IP_DRV][%s] Inst %d: receive unknown message (version=%d)\n",__FUNCTION__,inst,ipv->version);
}
++gpriv->stats.rx_packets;
gpriv->stats.rx_bytes += dlen;
#ifdef OAI_DRV_DEBUG_RECEIVE
printk("[OAI_IP_DRV][%s] sending packet of size %d to kernel\n",__FUNCTION__,skb->len);
for (i=0; i<skb->len; i++)
printk("%2x ",((unsigned char *)(skb->data))[i]);
printk("\n");
#endif //OAI_DRV_DEBUG_RECEIVE
netif_rx_ni(skb);
#ifdef OAI_DRV_DEBUG_RECEIVE
printk("[OAI_IP_DRV][%s] end\n",__FUNCTION__);
#endif
}
//---------------------------------------------------------------------------
// Delete the data
void oai_nw_drv_common_ip2wireless_drop(struct sk_buff *skb, int inst)
{
//---------------------------------------------------------------------------
struct oai_nw_drv_priv *priv=netdev_priv(oai_nw_drv_dev[inst]);
++priv->stats.tx_dropped;
}
//---------------------------------------------------------------------------
// Request the transfer of data (QoS SAP)
void oai_nw_drv_common_ip2wireless(struct sk_buff *skb, int inst)
{
//---------------------------------------------------------------------------
struct pdcp_data_req_header_s pdcph;
struct oai_nw_drv_priv *priv=netdev_priv(oai_nw_drv_dev[inst]);
#ifdef LOOPBACK_TEST
int i;
#endif
#ifdef OAI_DRV_DEBUG_SEND
int j;
#endif
unsigned int bytes_wrote;
// Start debug information
#ifdef OAI_DRV_DEBUG_SEND
printk("[OAI_IP_DRV][%s] inst %d begin \n",__FUNCTION__,inst);
#endif
if (skb==NULL) {
#ifdef OAI_DRV_DEBUG_SEND
printk("[OAI_IP_DRV][%s] input parameter skb is NULL \n",__FUNCTION__);
#endif
return;
}
pdcph.data_size = skb->len;
pdcph.rb_id = skb->mark;
pdcph.inst = inst;
pdcph.traffic_type = oai_nw_drv_find_traffic_type(skb);
bytes_wrote = oai_nw_drv_netlink_send((char *)&pdcph,OAI_NW_DRV_PDCPH_SIZE);
#ifdef OAI_DRV_DEBUG_SEND
printk("[OAI_IP_DRV][%s] Wrote %d bytes (header for %d byte skb) to PDCP RB %d via netlink\n",__FUNCTION__,
bytes_wrote,skb->len, pdcph.rb_id);
#endif
if (bytes_wrote != OAI_NW_DRV_PDCPH_SIZE) {
printk("[OAI_IP_DRV][%s] problem while writing PDCP's header (bytes wrote = %d to fifo %d)\n",__FUNCTION__,bytes_wrote,IP2PDCP_FIFO);
printk("rb_id %u, Wrote %u, Header Size %lu \n", pdcph.rb_id , bytes_wrote, OAI_NW_DRV_PDCPH_SIZE);
priv->stats.tx_dropped ++;
return;
}
bytes_wrote += oai_nw_drv_netlink_send((char *)skb->data,skb->len);
if (bytes_wrote != skb->len+OAI_NW_DRV_PDCPH_SIZE) {
printk("[OAI_IP_DRV][%s] Inst %d, RB_ID %u: problem while writing PDCP's data, bytes_wrote = %u, Data_len %u, PDCPH_SIZE %lu\n",
__FUNCTION__,
inst,
pdcph.rb_id,
bytes_wrote,
skb->len,
OAI_NW_DRV_PDCPH_SIZE); // congestion
priv->stats.tx_dropped ++;
return;
}
#ifdef OAI_DRV_DEBUG_SEND
printk("[OAI_IP_DRV][%s] Sending packet of size %d to PDCP traffic type %d\n",__FUNCTION__,skb->len, pdcph.traffic_type);
for (j=0; j<skb->len; j++)
printk("%2x ",((unsigned char *)(skb->data))[j]);
printk("\n");
#endif
priv->stats.tx_bytes += skb->len;
priv->stats.tx_packets ++;
#ifdef OAI_DRV_DEBUG_SEND
printk("[OAI_IP_DRV][%s] end \n",__FUNCTION__);
#endif
}
//---------------------------------------------------------------------------
void oai_nw_drv_common_wireless2ip(struct nlmsghdr *nlh)
{
//---------------------------------------------------------------------------
struct pdcp_data_ind_header_s *pdcph = (struct pdcp_data_ind_header_s *)NLMSG_DATA(nlh);
struct oai_nw_drv_priv *priv;
priv = netdev_priv(oai_nw_drv_dev[pdcph->inst]);
#ifdef OAI_DRV_DEBUG_RECEIVE
printk("[OAI_IP_DRV][%s] QOS receive from PDCP, size %d, rab %d, inst %d\n",__FUNCTION__,
pdcph->data_size,pdcph->rb_id,pdcph->inst);
#endif //OAI_DRV_DEBUG_RECEIVE
oai_nw_drv_common_class_wireless2ip(pdcph->data_size,
(unsigned char *)NLMSG_DATA(nlh) + OAI_NW_DRV_PDCPH_SIZE,
pdcph->inst,
pdcph->rb_id);
}
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#ifndef _OAI_NW_DRV_CST
#define _OAI_NW_DRV_CST
#define MAX_MEASURE_NB 5
#define OAI_NW_DRV_MAX_LENGTH 180
//Debug flags
//#define OAI_NW_DRV_DEBUG_DC
#define OAI_NW_DRV_DEBUG_SEND
#define OAI_NW_DRV_DEBUG_RECEIVE
//#define OAI_NW_DRV_DEBUG_CLASS
//#define OAI_NW_DRV_DEBUG_GC
//#define OAI_NW_DRV_DEBUG_DC_MEASURE
//#define OAI_NW_DRV_DEBUG_TIMER
//#define OAI_NW_DRV_DEBUG_DEVICE
//#define OAI_NW_DRV_DEBUG_INTERRUPT
//#define OAI_NW_DRV_DEBUG_TOOL
// Other flags
#define DEMO_3GSM
// General Constants
#define OAI_NW_DRV_MTU 1500
#define OAI_NW_DRV_TX_QUEUE_LEN 100
#define OAI_NW_DRV_ADDR_LEN 8
#define OAI_NW_DRV_INET6_ADDRSTRLEN 46
#define OAI_NW_DRV_INET_ADDRSTRLEN 16
#define OAI_NW_DRV_RESET_RX_FLAGS 0
#define OAI_NW_DRV_CX_MAX 32 //Identical to RRC constant
//#define OAI_NW_DRV_CX_MULTICAST_ALLNODE 2
#define OAI_NW_DRV_RETRY_LIMIT_DEFAULT 5
#define OAI_NW_DRV_MESSAGE_MAXLEN 5004
#define OAI_NW_DRV_SIG_SRB3 3
#define OAI_NW_DRV_SIG_SRB4 3 // not used yet
//peer-to-peer messages between NAS entities
#define OAI_NW_DRV_CMD_OPEN_RB 1
//#define OAI_NW_DRV_IID1_CONTROL 0x0
//#define OAI_NW_DRV_IID2_CONTROL __constant_htonl(0xffffffff)
//#define OAI_NW_DRV_STATE_IDLE 0
//#define OAI_NW_DRV_STATE_CONNECTED 1
//#define OAI_NW_DRV_STATE_ESTABLISHMENT_REQUEST 2
//#define OAI_NW_DRV_STATE_ESTABLISHMENT_FAILURE 3
//#define OAI_NW_DRV_STATE_RELEASE_FAILURE 4
#define OAI_NW_DRV_CX_RELEASE_UNDEF_CAUSE 1
// MT+RG NAS States
#define OAI_NW_DRV_IDLE 0x01
// Connection
#define OAI_NW_DRV_CX_FACH 0x06
#define OAI_NW_DRV_CX_DCH 0x0A
#define OAI_NW_DRV_CX_RECEIVED 0x10
#define OAI_NW_DRV_CX_CONNECTING 0x04
#define OAI_NW_DRV_CX_RELEASING 0x08
#define OAI_NW_DRV_CX_CONNECTING_FAILURE 0x14
#define OAI_NW_DRV_CX_RELEASING_FAILURE 0x18
// Radio Bearers
#define OAI_NW_DRV_RB_ESTABLISHING 0x24
#define OAI_NW_DRV_RB_RELEASING 0x28
#define OAI_NW_DRV_RB_DCH 0x2A
#define OAI_NW_DRV_TIMER_ESTABLISHMENT_DEFAULT 12
#define OAI_NW_DRV_TIMER_RELEASE_DEFAULT 2
#define OAI_NW_DRV_TIMER_IDLE UINT_MAX
#define OAI_NW_DRV_TIMER_TICK HZ
#define OAI_NW_DRV_PDCPH_SIZE sizeof(struct pdcp_data_req_header_s)
#define OAI_NW_DRV_IPV4_SIZE 20
#define OAI_NW_DRV_IPV6_SIZE 40
#define OAI_NW_DRV_DIRECTION_SEND 0
#define OAI_NW_DRV_DIRECTION_RECEIVE 1
#define OAI_NW_DRV_DIRECTION_FORWARD 2
// function number
#define OAI_NW_DRV_FCT_DEL_SEND 1
#define OAI_NW_DRV_FCT_QOS_SEND 2
#define OAI_NW_DRV_FCT_DC_SEND 3
#define OAI_NW_DRV_FCT_CTL_SEND 4
// type of IOCTL command
#define OAI_NW_DRV_IOCTL_RRM 0x89F0
// Error cause
#define OAI_NW_DRV_ERROR_ALREADYEXIST 1
#define OAI_NW_DRV_ERROR_NOMEMORY 3
#define OAI_NW_DRV_ERROR_NOTMT 9
#define OAI_NW_DRV_ERROR_NOTRG 10
#define OAI_NW_DRV_ERROR_NOTIDLE 11
#define OAI_NW_DRV_ERROR_NOTCONNECTED 12
#define OAI_NW_DRV_ERROR_NORB 14
#define OAI_NW_DRV_ERROR_NOTCORRECTVALUE 32
#define OAI_NW_DRV_ERROR_NOTCORRECTLCR 33
#define OAI_NW_DRV_ERROR_NOTCORRECTDIR 34
#define OAI_NW_DRV_ERROR_NOTCORRECTDSCP 35
#define OAI_NW_DRV_ERROR_NOTCORRECTVERSION 36
#define OAI_NW_DRV_ERROR_NOTCORRECTRABI 37
/**********************************************************/
/* Constants related with IP protocols */
/**********************************************************/
//#define OAI_NW_DRV_PORT_CONTROL __constant_htons(0xc45)
//#define OAI_NW_DRV_PORT_AUTHENTICATION __constant_htons(1811)
#define OAI_NW_DRV_TRAFFICCLASS_MASK __constant_htonl(0x0fc00000)
// Network control codepoint 111000 + IP version 6
#define OAI_NW_DRV_FLOWINFO_NCONTROL __constant_htonl(0x6e000000)
// network control codepoint 111000
#define OAI_NW_DRV_DSCP_NCONTROL 56 //0x38
// default codepoint 1000000
#define OAI_NW_DRV_DSCP_DEFAULT 64
#define OAI_NW_DRV_DSCP_MAX 193
#define OAI_NW_DRV_PROTOCOL_DEFAULT 0
#define OAI_NW_DRV_PROTOCOL_TCP IPPROTO_TCP
#define OAI_NW_DRV_PROTOCOL_UDP IPPROTO_UDP
#define OAI_NW_DRV_PROTOCOL_ICMP4 IPPROTO_ICMP
#define OAI_NW_DRV_PROTOCOL_ICMP6 IPPROTO_ICMPV6
//#warning "OAI_NW_DRV_PROTOCOL_ARP value 200 may collide with new defined values in kernel"
#define OAI_NW_DRV_PROTOCOL_ARP 200
#define OAI_NW_DRV_PORT_DEFAULT __constant_htons(65535)
#define OAI_NW_DRV_PORT_HTTP __constant_htons(80)
#define OAI_NW_DRV_IP_VERSION_ALL 0
#define OAI_NW_DRV_IP_VERSION_4 4
#define OAI_NW_DRV_IP_VERSION_6 6
#define OAI_NW_DRV_DEFAULT_IPV4_ADDR 0
#define OAI_NW_DRV_DEFAULT_IPV6_ADDR0 0
#define OAI_NW_DRV_DEFAULT_IPV6_ADDR1 0
#define OAI_NW_DRV_DEFAULT_IPV6_ADDR2 0
#define OAI_NW_DRV_DEFAULT_IPV6_ADDR3 0
#define OAI_NW_DRV_MPLS_VERSION_CODE 99
#define OAI_NW_DRV_NB_INSTANCES_MAX 8
#endif
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/*! \file device.c
* \brief Networking Device Driver for OpenAirInterface Ethernet
* \author navid.nikaein, Lionel Gauthier, raymond.knopp,
* \company Eurecom
* \email:navid.nikaein@eurecom.fr, lionel.gauthier@eurecom.fr, raymond.knopp@eurecom.fr
*/
/*******************************************************************************/
#include "constant.h"
#include "local.h"
#include "proto_extern.h"
//#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/version.h>
#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/moduleparam.h>
#ifdef OAI_NW_DRIVER_TYPE_ETHERNET
#include <linux/if_ether.h>
#endif
#include <asm/io.h>
#include <asm/bitops.h>
#include <asm/uaccess.h>
#include <asm/segment.h>
#include <asm/page.h>
#include <asm/delay.h>
#include <asm/unistd.h>
#include <linux/netdevice.h>
#ifdef OAI_NW_DRIVER_TYPE_ETHERNET
#include <linux/etherdevice.h>
#endif
struct net_device *oai_nw_drv_dev[OAI_NW_DRV_NB_INSTANCES_MAX];
#ifdef OAI_NW_DRIVER_USE_NETLINK
extern void oai_nw_drv_netlink_release(void);
extern int oai_nw_drv_netlink_init(void);
#endif
uint8_t NULL_IMEI[14]= {0x05, 0x04, 0x03, 0x01, 0x02 ,0x00, 0x00, 0x00, 0x05, 0x04, 0x03 ,0x00, 0x01, 0x08};
static unsigned char oai_nw_drv_IMEI[14];
static int m_arg=0;
static unsigned int oai_nw_drv_is_clusterhead=0;
//---------------------------------------------------------------------------
int oai_nw_drv_find_inst(struct net_device *dev)
{
//---------------------------------------------------------------------------
int i;
for (i=0; i<OAI_NW_DRV_NB_INSTANCES_MAX; i++)
if (oai_nw_drv_dev[i] == dev)
return(i);
return(-1);
}
//---------------------------------------------------------------------------
#ifndef OAI_NW_DRIVER_USE_NETLINK
void *oai_nw_drv_interrupt(void)
{
//---------------------------------------------------------------------------
uint8_t cxi;
// struct oai_nw_drv_priv *priv=netdev_priv(dev_id);
// unsigned int flags;
// priv->lock = SPIN_LOCK_UNLOCKED;
#ifdef OAI_DRV_DEBUG_INTERRUPT
printk("INTERRUPT - begin\n");
#endif
// spin_lock_irqsave(&priv->lock,flags);
cxi=0;
// mesh_GC_receive();
// mesh_DC_receive(naspriv->cx+cxi);
#ifndef OAI_NW_DRIVER_USE_NETLINK
oai_nw_drv_common_wireless2ip();
#endif
// spin_unlock_irqrestore(&priv->lock,flags);
#ifdef OAI_DRV_DEBUG_INTERRUPT
printk("INTERRUPT: end\n");
#endif
// return 0;
}
#endif //NETLINK
//---------------------------------------------------------------------------
void oai_nw_drv_timer(unsigned long data)
{
//---------------------------------------------------------------------------
struct oai_nw_drv_priv *priv=(struct oai_nw_drv_priv *)data;
spin_lock(&priv->lock);
(priv->timer).function=oai_nw_drv_timer;
(priv->timer).expires=jiffies+OAI_NW_DRV_TIMER_TICK;
(priv->timer).data=data;
add_timer(&priv->timer);
spin_unlock(&priv->lock);
return;
// add_timer(&gpriv->timer);
// spin_unlock(&gpriv->lock);
}
//---------------------------------------------------------------------------
// Called by ifconfig when the device is activated by ifconfig
int oai_nw_drv_open(struct net_device *dev)
{
//---------------------------------------------------------------------------
struct oai_nw_drv_priv *priv=netdev_priv(dev);
// Address has already been set at init
#ifndef OAI_NW_DRIVER_USE_NETLINK
if (pdcp_2_oai_nw_drv_irq==-EBUSY) {
printk("[OAI_IP_DRV][%s] : irq failure\n", __FUNCTION__);
return -EBUSY;
}
#endif //OAI_NW_DRIVER_USE_NETLINK
if(!netif_queue_stopped(dev))
netif_start_queue(dev);
else
netif_wake_queue(dev);
init_timer(&priv->timer);
(priv->timer).expires = jiffies+OAI_NW_DRV_TIMER_TICK;
(priv->timer).data = (unsigned long)priv;
(priv->timer).function = oai_nw_drv_timer;
//add_timer(&priv->timer);
printk("[OAI_IP_DRV][%s] name = %s\n", __FUNCTION__, dev->name);
return 0;
}
//---------------------------------------------------------------------------
// Called by ifconfig when the device is desactivated
int oai_nw_drv_stop(struct net_device *dev)
{
//---------------------------------------------------------------------------
struct oai_nw_drv_priv *priv = netdev_priv(dev);
printk("[OAI_IP_DRV][%s] Begin\n", __FUNCTION__);
del_timer(&(priv->timer));
netif_stop_queue(dev);
// MOD_DEC_USE_COUNT;
printk("[OAI_IP_DRV][%s] End\n", __FUNCTION__);
return 0;
}
//---------------------------------------------------------------------------
void oai_nw_drv_teardown(struct net_device *dev)
{
//---------------------------------------------------------------------------
struct oai_nw_drv_priv *priv;
int inst;
printk("[OAI_IP_DRV][%s] Begin\n", __FUNCTION__);
if (dev) {
priv = netdev_priv(dev);
inst = oai_nw_drv_find_inst(dev);
if ((inst<0) || (inst>=OAI_NW_DRV_NB_INSTANCES_MAX)) {
printk("[OAI_IP_DRV][%s] ERROR, couldn't find instance\n", __FUNCTION__);
return;
}
/*oai_nw_drv_class_flush_recv_classifier(priv);
for (cxi=0;cxi<OAI_NW_DRV_CX_MAX;cxi++) {
oai_nw_drv_common_flush_rb(priv->cx+cxi);
oai_nw_drv_class_flush_send_classifier(priv->cx+cxi);
}*/
printk("[OAI_IP_DRV][%s] End\n", __FUNCTION__);
} // check dev
else {
printk("[OAI_IP_DRV][%s] Device is null\n", __FUNCTION__);
}
}
//---------------------------------------------------------------------------
int oai_nw_drv_set_config(struct net_device *dev, struct ifmap *map)
{
//---------------------------------------------------------------------------
printk("[OAI_IP_DRV][%s] Begin\n", __FUNCTION__);
if (dev->flags & IFF_UP)
return -EBUSY;
if (map->base_addr != dev->base_addr) {
printk(KERN_WARNING "[OAI_IP_DRV][%s] Can't change I/O address\n", __FUNCTION__);
return -EOPNOTSUPP;
}
if (map->irq != dev->irq)
dev->irq = map->irq;
printk("[OAI_IP_DRV][%s] End\n", __FUNCTION__);
return 0;
}
//---------------------------------------------------------------------------
//
int oai_nw_drv_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
//---------------------------------------------------------------------------
int inst;
if (dev) {
inst = oai_nw_drv_find_inst(dev);
} else {
printk("[OAI_IP_DRV][%s] ERROR, device is null\n", __FUNCTION__);
return -1;
}
if ((inst>=0) && (inst<OAI_NW_DRV_NB_INSTANCES_MAX)) {
#ifdef OAI_DRV_OAI_DRV_DEBUG_DEVICE
printk("[OAI_IP_DRV][%s] inst %d, begin\n", __FUNCTION__,inst);
#endif
if (!skb) {
printk("[OAI_IP_DRV][%s] input parameter skb is NULL\n", __FUNCTION__);
return -1;
}
// End debug information
netif_stop_queue(dev);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,7,0)
netif_trans_update(dev);
#else
dev->trans_start = jiffies;
#endif
#ifdef OAI_DRV_DEBUG_DEVICE
printk("[OAI_IP_DRV][%s] step 1\n", __FUNCTION__);
#endif
oai_nw_drv_common_ip2wireless(skb,inst);
#ifdef OAI_DRV_DEBUG_DEVICE
printk("[OAI_IP_DRV][%s] step 2\n", __FUNCTION__);
#endif
dev_kfree_skb(skb);
#ifdef OAI_DRV_DEBUG_DEVICE
printk("[OAI_IP_DRV][%s] step 3\n", __FUNCTION__);
#endif
netif_wake_queue(dev);
#ifdef OAI_DRV_DEBUG_DEVICE
printk("[OAI_IP_DRV][%s] end\n", __FUNCTION__);
#endif
} else {
printk("[OAI_IP_DRV][%s] ERROR, couldn't find instance\n", __FUNCTION__);
return(-1);
}
return 0;
}
//---------------------------------------------------------------------------
struct net_device_stats *oai_nw_drv_get_stats(struct net_device *dev)
{
//---------------------------------------------------------------------------
// return &((struct oai_nw_drv_priv *)dev->priv)->stats;
struct oai_nw_drv_priv *priv = netdev_priv(dev);
//printk("[OAI_IP_DRV][%s]\n", __FUNCTION__);
return &priv->stats;
}
//---------------------------------------------------------------------------
int oai_nw_drv_set_mac_address(struct net_device *dev, void *mac)
{
//---------------------------------------------------------------------------
struct sockaddr *addr = mac;
printk("[OAI_IP_DRV][%s] CHANGE MAC ADDRESS\n", __FUNCTION__);
memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
return 0;
}
//---------------------------------------------------------------------------
int oai_nw_drv_change_mtu(struct net_device *dev, int mtu)
{
//---------------------------------------------------------------------------
printk("[OAI_IP_DRV][%s] CHANGE MTU %d bytes\n", __FUNCTION__, mtu);
if ((mtu<50) || (mtu>1500))
return -EINVAL;
dev->mtu = mtu;
return 0;
}
//---------------------------------------------------------------------------
void oai_nw_drv_change_rx_flags(struct net_device *dev, int flags)
{
//---------------------------------------------------------------------------
struct oai_nw_drv_priv *priv = netdev_priv(dev);
printk("[OAI_IP_DRV][%s] CHANGE RX FLAGS %08X\n", __FUNCTION__, flags);
priv->rx_flags ^= flags;
}
//---------------------------------------------------------------------------
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,6,0)
void oai_nw_drv_tx_timeout(struct net_device *dev, unsigned int txqueue)
#else
void oai_nw_drv_tx_timeout(struct net_device *dev)
#endif
{
//---------------------------------------------------------------------------
// Transmitter timeout, serious problems.
struct oai_nw_drv_priv *priv = netdev_priv(dev);
printk("[OAI_IP_DRV][%s] begin\n", __FUNCTION__);
// (struct oai_nw_drv_priv *)(dev->priv)->stats.tx_errors++;
(priv->stats).tx_errors++;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,7,0)
netif_trans_update(dev);
#else
dev->trans_start = jiffies;
#endif
netif_wake_queue(dev);
printk("[OAI_IP_DRV][%s] transmit timed out %s\n", __FUNCTION__,dev->name);
}
static const struct net_device_ops nasmesh_netdev_ops = {
.ndo_open = oai_nw_drv_open,
.ndo_stop = oai_nw_drv_stop,
.ndo_start_xmit = oai_nw_drv_hard_start_xmit,
.ndo_validate_addr = NULL,
.ndo_get_stats = oai_nw_drv_get_stats,
.ndo_set_mac_address = oai_nw_drv_set_mac_address,
.ndo_set_config = oai_nw_drv_set_config,
.ndo_do_ioctl = oai_nw_drv_CTL_ioctl,
.ndo_change_mtu = oai_nw_drv_change_mtu,
.ndo_tx_timeout = oai_nw_drv_tx_timeout,
.ndo_change_rx_flags = oai_nw_drv_change_rx_flags,
};
/*.ndo_set_multicast_list = NULL,*/
//---------------------------------------------------------------------------
// Initialisation of the network device
void oai_nw_drv_init(struct net_device *dev)
{
//---------------------------------------------------------------------------
uint8_t cxi;
struct oai_nw_drv_priv *priv;
int index;
if (dev) {
priv = netdev_priv(dev);
memset(priv, 0, sizeof(struct oai_nw_drv_priv));
#ifndef OAI_NW_DRIVER_TYPE_ETHERNET
dev->type = ARPHRD_EURECOM_LTE;
dev->features = NETIF_F_NO_CSUM;
dev->hard_header_len = 0;
dev->addr_len = ETH_ALEN; // 6
dev->flags = IFF_BROADCAST | IFF_MULTICAST | IFF_NOARP;
dev->tx_queue_len = NAS_TX_QUEUE_LEN;
dev->mtu = NAS_MTU;
#endif
// Can be one of the following enum defined in include/linux/netdevice.h:
// enum netdev_state_t {
// __LINK_STATE_START,
// __LINK_STATE_PRESENT,
// __LINK_STATE_NOCARRIER,
// __LINK_STATE_LINKWATCH_PENDING,
// __LINK_STATE_DORMANT,
// };
set_bit(__LINK_STATE_PRESENT, &dev->state);
//
dev->netdev_ops = &nasmesh_netdev_ops;
#ifdef OAI_NW_DRIVER_TYPE_ETHERNET
printk("[OAI_IP_DRV][%s] Driver type ETHERNET\n", __FUNCTION__);
// Memo: linux-source-3.2.0/net/ethernet/eth.c:
//334 void ether_setup(struct net_device *dev)
//335 {
//336 dev->header_ops = &eth_header_ops;
//337 dev->type = ARPHRD_ETHER;
//338 dev->hard_header_len = ETH_HLEN;
//339 dev->mtu = ETH_DATA_LEN;
//340 dev->addr_len = ETH_ALEN;
//341 dev->tx_queue_len = 1000; /* Ethernet wants good queues */
//342 dev->flags = IFF_BROADCAST|IFF_MULTICAST;
//343 dev->priv_flags |= IFF_TX_SKB_SHARING;
//344
//345 memset(dev->broadcast, 0xFF, ETH_ALEN);
//346 }
ether_setup(dev);
#endif
//
// Initialize private structure
priv->rx_flags = OAI_NW_DRV_RESET_RX_FLAGS;
priv->sap[OAI_NW_DRV_RAB_INPUT_SAPI] = PDCP2IP_FIFO;//QOS_DEVICE_CONVERSATIONAL_INPUT;
priv->sap[OAI_NW_DRV_RAB_OUTPUT_SAPI] = IP2PDCP_FIFO;//QOS_DEVICE_STREAMING_INPUT;
// priv->retry_limit=RETRY_LIMIT_DEFAULT;
// priv->timer_establishment=TIMER_ESTABLISHMENT_DEFAULT;
// priv->timer_release=TIMER_RELEASE_DEFAULT;
/*for (dscpi=0; dscpi<OAI_NW_DRV_DSCP_MAX; ++dscpi) {
priv->rclassifier[dscpi]=NULL;
}
priv->nrclassifier=0;*/
//
for (cxi=0; cxi<OAI_NW_DRV_CX_MAX; cxi++) {
#ifdef OAI_DRV_DEBUG_DEVICE
printk("[OAI_IP_DRV][%s] init classifiers, state and timer for MT %u\n", __FUNCTION__, cxi);
#endif
// priv->cx[cxi].sap[NAS_DC_INPUT_SAPI] = RRC_DEVICE_DC_INPUT0;
// priv->cx[cxi].sap[NAS_DC_OUTPUT_SAPI] = RRC_DEVICE_DC_OUTPUT0;
priv->cx[cxi].state = OAI_NW_DRV_IDLE;
priv->cx[cxi].countimer = OAI_NW_DRV_TIMER_IDLE;
priv->cx[cxi].retry = 0;
priv->cx[cxi].lcr = cxi;
/*priv->cx[cxi].rb = NULL;
priv->cx[cxi].num_rb = 0;
// initialisation of the classifier
for (dscpi=0; dscpi<65; ++dscpi) {
priv->cx[cxi].sclassifier[dscpi] = NULL;
priv->cx[cxi].fclassifier[dscpi] = NULL;
}
priv->cx[cxi].nsclassifier=0;
priv->cx[cxi].nfclassifier=0;
*/
// initialisation of the IP address
oai_nw_drv_TOOL_eNB_imei2iid(oai_nw_drv_IMEI, (uint8_t *)priv->cx[cxi].iid6, dev->addr_len);
priv->cx[cxi].iid4=0;
//
}
spin_lock_init(&priv->lock);
//this requires kernel patch for OAI driver: typically for RF/hard realtime emu experimentation
#define ADDRCONF
#ifdef ADDRCONF
#ifdef OAI_NW_DRIVER_USE_NETLINK
oai_nw_drv_TOOL_eNB_imei2iid(oai_nw_drv_IMEI, dev->dev_addr, dev->addr_len);// IMEI to device address (for stateless autoconfiguration address)
oai_nw_drv_TOOL_eNB_imei2iid(oai_nw_drv_IMEI, (uint8_t *)priv->cx[0].iid6, dev->addr_len);
#else
oai_nw_drv_TOOL_imei2iid(oai_nw_drv_IMEI, dev->dev_addr);// IMEI to device address (for stateless autoconfiguration address)
oai_nw_drv_TOOL_imei2iid(oai_nw_drv_IMEI, (uint8_t *)priv->cx[0].iid6);
#endif
// this is more appropriate for user space soft realtime emulation
#else
// LG: strange
for (index = 0; index < dev->addr_len; index++) {
dev->dev_addr[index] = 16*oai_nw_drv_IMEI[index]+oai_nw_drv_IMEI[index+1]);
}
memcpy((uint8_t *)priv->cx[0].iid6,&oai_nw_drv_IMEI[0],dev->addr_len);
printk("INIT: init IMEI to IID\n");
#endif
printk("[OAI_IP_DRV][%s] Setting HW addr to : ", __FUNCTION__);
for (index = 0; index < dev->addr_len; index++) {
printk("%02X", dev->dev_addr[index]);
}
printk("\n[OAI_IP_DRV][%s] Setting priv->cx to : ", __FUNCTION__);
for (index = 0; index < 8; index++) {
printk("%02X", ((uint8_t *)(priv->cx[0].iid6))[index]);
}
printk("\n");
printk("[OAI_IP_DRV][%s] INIT: end\n", __FUNCTION__);
return;
} else {
printk("[OAI_IP_DRV][%s] ERROR, Device is NULL!!\n", __FUNCTION__);
return;
}
}
//---------------------------------------------------------------------------
int init_module (void)
{
//---------------------------------------------------------------------------
int err,inst, index;
struct oai_nw_drv_priv *priv;
char devicename[100];
// Initialize parameters shared with RRC
printk("[OAI_IP_DRV][%s] Starting NASMESH, number of IMEI parameters %d, IMEI ", __FUNCTION__, m_arg);
for (index = 0; index < m_arg; index++) {
printk("%02X", oai_nw_drv_IMEI[index]);
}
printk("\n");
#ifndef OAI_NW_DRIVER_USE_NETLINK
if (pdcp_2_oai_nw_drv_irq == -EBUSY || pdcp_2_oai_nw_drv_irq == -EINVAL) {
printk("[OAI_IP_DRV][%s] No interrupt resource available\n", __FUNCTION__);
return -EBUSY;
} else
printk("[OAI_IP_DRV][%s] Interrupt %d\n", __FUNCTION__, pdcp_2_oai_nw_drv_irq);
#endif //NETLINK
for (inst=0; inst<OAI_NW_DRV_NB_INSTANCES_MAX; inst++) {
printk("[OAI_IP_DRV][%s] begin init instance %d\n", __FUNCTION__,inst);
sprintf(devicename,"oai%d",inst);
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0)
oai_nw_drv_dev[inst] = alloc_netdev(sizeof(struct oai_nw_drv_priv),devicename, oai_nw_drv_init);
#else
oai_nw_drv_dev[inst] = alloc_netdev(sizeof(struct oai_nw_drv_priv),devicename, NET_NAME_PREDICTABLE, oai_nw_drv_init);
#endif
//netif_stop_queue(oai_nw_drv_dev[inst]);
if (oai_nw_drv_dev[inst] == NULL) {
printk("[OAI_IP_DRV][%s][INST %02d] alloc_netdev FAILED\n", __FUNCTION__,inst);
} else {
priv = netdev_priv(oai_nw_drv_dev[inst]);
if (oai_nw_drv_dev[inst]) {
oai_nw_drv_IMEI[9] += 1;
if (oai_nw_drv_IMEI[9] > 0x0F) {
oai_nw_drv_IMEI[8] = oai_nw_drv_IMEI[9] >> 4;
oai_nw_drv_IMEI[9] = oai_nw_drv_IMEI[9] & 0x0F;
}
}
// linux/net/core/dev.c line 4767
err= register_netdev(oai_nw_drv_dev[inst]);
if (err) {
printk("[OAI_IP_DRV][%s] (inst %d): error %i registering device %s\n", __FUNCTION__, inst,err, oai_nw_drv_dev[inst]->name);
} else {
printk("[OAI_IP_DRV][%s] registering device %s, ifindex = %d\n\n", __FUNCTION__,oai_nw_drv_dev[inst]->name, oai_nw_drv_dev[inst]->ifindex);
}
}
}
#ifdef OAI_NW_DRIVER_USE_NETLINK
printk("[OAI_IP_DRV][%s] NETLINK INIT\n", __FUNCTION__);
if ((err=oai_nw_drv_netlink_init()) == -1)
printk("[OAI_IP_DRV][%s] NETLINK failed\n", __FUNCTION__);
#endif //NETLINK
return err;
}
//---------------------------------------------------------------------------
void cleanup_module(void)
{
//---------------------------------------------------------------------------
int inst;
printk("[OAI_IP_DRV][CLEANUP]nasmesh_cleanup_module: begin\n");
#ifndef OAI_NW_DRIVER_USE_NETLINK
if (pdcp_2_oai_nw_drv_irq!=-EBUSY) {
pdcp_2_oai_nw_drv_irq=0;
// Start IRQ linux
//free_irq(priv->irq, NULL);
// End IRQ linux
}
#else // NETLINK
#endif //NETLINK
for (inst=0; inst<OAI_NW_DRV_NB_INSTANCES_MAX; inst++) {
#ifdef OAI_DRV_DEBUG_DEVICE
printk("nasmesh_cleanup_module: unregister and free net device instance %d\n",inst);
#endif
if (oai_nw_drv_dev[inst]) {
unregister_netdev(oai_nw_drv_dev[inst]);
oai_nw_drv_teardown(oai_nw_drv_dev[inst]);
free_netdev(oai_nw_drv_dev[inst]);
}
}
#ifdef OAI_NW_DRIVER_USE_NETLINK
oai_nw_drv_netlink_release();
#endif //OAI_NW_DRIVER_USE_NETLINK
printk("nasmesh_cleanup_module: end\n");
}
#define DRV_NAME "NASMESH"
#define DRV_VERSION "3.0.2"DRV_NAME
#define DRV_DESCRIPTION "OPENAIR MESH Device Driver"
#define DRV_COPYRIGHT "-Copyright(c) GNU GPL Eurecom 2009"
#define DRV_AUTHOR "Raymond Knopp, and Navid Nikaein: <firstname.name@eurecom.fr>"DRV_COPYRIGHT
module_param_array_named(oai_nw_drv_IMEI,oai_nw_drv_IMEI,byte,&m_arg,0);
//module_param_array(oai_nw_drv_IMEI,byte,&m_arg,0444);
MODULE_PARM_DESC(oai_nw_drv_IMEI,"The IMEI Hardware address (64-bit, decimal nibbles)");
//module_param(oai_nw_drv_is_clusterhead,uint,0444);
module_param_named(oai_nw_drv_is_clusterhead,oai_nw_drv_is_clusterhead,uint,0444);
MODULE_PARM_DESC(oai_nw_drv_is_clusterhead,"The Clusterhead Indicator");
//MODULE_AUTHOR(DRV_AUTHOR);
//MODULE_DESCRIPTION(DRV_DESCRIPTION);
//MODULE_LICENSE("GPL");
//MODULE_VERSION(DRV_VERSION);
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#include "local.h"
#include "ioctl.h"
#include "proto_extern.h"
#include <asm/uaccess.h>
#include <asm/checksum.h>
#include <asm/uaccess.h>
#define NIP6ADDR(addr) \
ntohs((addr)->s6_addr16[0]), \
ntohs((addr)->s6_addr16[1]), \
ntohs((addr)->s6_addr16[2]), \
ntohs((addr)->s6_addr16[3]), \
ntohs((addr)->s6_addr16[4]), \
ntohs((addr)->s6_addr16[5]), \
ntohs((addr)->s6_addr16[6]), \
ntohs((addr)->s6_addr16[7])
uint8_t g_msgrep[OAI_NW_DRV_LIST_CLASS_MAX*sizeof(struct oai_nw_drv_msg_class_list_reply)+1];
// Statistic
//---------------------------------------------------------------------------
void oai_nw_drv_set_msg_statistic_reply(struct oai_nw_drv_msg_statistic_reply *msgrep,
struct oai_nw_drv_priv *priv)
{
//---------------------------------------------------------------------------
msgrep->rx_packets=priv->stats.rx_packets;
msgrep->tx_packets=priv->stats.tx_packets;
msgrep->rx_bytes=priv->stats.rx_bytes;
msgrep->tx_bytes=priv->stats.tx_bytes;
msgrep->rx_errors=priv->stats.rx_errors;
msgrep->tx_errors=priv->stats.tx_errors;
msgrep->rx_dropped=priv->stats.rx_dropped;
msgrep->tx_dropped=priv->stats.tx_dropped;
}
//---------------------------------------------------------------------------
int oai_nw_drv_ioCTL_statistic_request(struct oai_nw_drv_ioctl *gifr,
struct oai_nw_drv_priv *priv)
{
//---------------------------------------------------------------------------
struct oai_nw_drv_msg_statistic_reply msgrep;
printk("NAS_IOCTL_STATISTIC: stat requested\n");
oai_nw_drv_set_msg_statistic_reply(&msgrep,priv);
if (copy_to_user(gifr->msg, &msgrep, sizeof(msgrep))) {
printk("NAS_IOCTL_STATISTIC: copy_to_user failure\n");
return -EFAULT;
}
return 0;
}
///////////////////////////////////////////////////////////////////////////////
// IMEI
// Messages for IMEI transfer
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// IOCTL command
//---------------------------------------------------------------------------
int oai_nw_drv_CTL_ioctl(struct net_device *dev,
struct ifreq *ifr,
int cmd)
{
//---------------------------------------------------------------------------
struct oai_nw_drv_ioctl *gifr;
struct oai_nw_drv_priv *priv=netdev_priv(dev);
int r;
// printk("NAS_CTL_IOCTL: begin ioctl for instance %d\n",find_inst(dev));
switch(cmd) {
case OAI_NW_DRV_IOCTL_RRM:
gifr=(struct oai_nw_drv_ioctl *)ifr;
switch(gifr->type) {
case OAI_NW_DRV_MSG_STATISTIC_REQUEST:
r=oai_nw_drv_ioCTL_statistic_request(gifr,priv);
break;
default:
// printk("NAS_IOCTL_RRM: unkwon request type, type=%x\n", gifr->type);
r=-EFAULT;
}
break;
default:
// printk("NAS_CTL_IOCTL: Unknown ioctl command, cmd=%x\n", cmd);
r=-EFAULT;
}
// printk("NAS_CTL_IOCTL: end\n");
return r;
}
//---------------------------------------------------------------------------
void oai_nw_drv_CTL_send(struct sk_buff *skb, int inst)
{
//---------------------------------------------------------------------------
printk("NAS_CTL_SEND - void \n");
}
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/***************************************************************************
ioctl.h - description
-------------------
copyright : (C) 2002 by Eurecom
email : michelle.wetterwald@eurecom.fr
yan.moret@eurecom.fr
knopp@eurecom.fr
***************************************************************************
***************************************************************************/
#ifndef OAI_IOCTL_H
#define OAI_IOCTL_H
#include <asm/byteorder.h>
#include <asm/types.h>
#include <linux/udp.h>
#include <linux/tcp.h>
#include <linux/if.h>
#include "sap.h"
//#include <linux/ipv6.h>
#define OAI_NW_DRV_MSG_MAXLEN 1100/// change???
// type of CTL message
#define OAI_NW_DRV_MSG_STATISTIC_REQUEST 1
#define OAI_NW_DRV_MSG_STATISTIC_REPLY 2
#define OAI_NW_DRV_MSG_ECHO_REQUEST 3
#define OAI_NW_DRV_MSG_ECHO_REPLY 4
#define OAI_NW_DRV_MSG_CX_ESTABLISHMENT_REQUEST 5
#define OAI_NW_DRV_MSG_CX_ESTABLISHMENT_REPLY 6
#define OAI_NW_DRV_MSG_CX_RELEASE_REQUEST 7
#define OAI_NW_DRV_MSG_CX_RELEASE_REPLY 8
#define OAI_NW_DRV_MSG_CX_LIST_REQUEST 9
#define OAI_NW_DRV_MSG_CX_LIST_REPLY 10
#define OAI_NW_DRV_MSG_RB_ESTABLISHMENT_REQUEST 11
#define OAI_NW_DRV_MSG_RB_ESTABLISHMENT_REPLY 12
#define OAI_NW_DRV_MSG_RB_RELEASE_REQUEST 13
#define OAI_NW_DRV_MSG_RB_RELEASE_REPLY 14
#define OAI_NW_DRV_MSG_RB_LIST_REQUEST 15
#define OAI_NW_DRV_MSG_RB_LIST_REPLY 16
#define OAI_NW_DRV_MSG_CLASS_ADD_REQUEST 17
#define OAI_NW_DRV_MSG_CLASS_ADD_REPLY 18
#define OAI_NW_DRV_MSG_CLASS_DEL_REQUEST 19
#define OAI_NW_DRV_MSG_CLASS_DEL_REPLY 20
#define OAI_NW_DRV_MSG_CLASS_LIST_REQUEST 21
#define OAI_NW_DRV_MSG_CLASS_LIST_REPLY 22
#define OAI_NW_DRV_MSG_MEAS_REQUEST 23
#define OAI_NW_DRV_MSG_MEAS_REPLY 24
#define OAI_NW_DRV_MSG_IMEI_REQUEST 25
#define OAI_NW_DRV_MSG_IMEI_REPLY 26
// Max number of entry of a message list
#define OAI_NW_DRV_LIST_CX_MAX 32
#define OAI_NW_DRV_LIST_RB_MAX 32
#define OAI_NW_DRV_LIST_CLASS_MAX 32
typedef unsigned short oai_nw_drv_MsgType_t;
struct oai_nw_drv_ioctl {
char name[IFNAMSIZ];
oai_nw_drv_MsgType_t type;
char *msg;
};
struct oai_nw_drv_msg_statistic_reply {
unsigned int rx_packets;
unsigned int tx_packets;
unsigned int rx_bytes;
unsigned int tx_bytes;
unsigned int rx_errors;
unsigned int tx_errors;
unsigned int rx_dropped;
unsigned int tx_dropped;
};
struct oai_nw_drv_msg_cx_list_reply {
OaiNwDrvLocalConnectionRef_t lcr; // Local Connection reference
unsigned char state;
OaiNwDrvCellID_t cellid; // cell identification
unsigned int iid6[2]; // IPv6 interface identification
unsigned char iid4; // IPv4 interface identification
unsigned short num_rb;
unsigned short nsclassifier;
};
struct oai_nw_drv_msg_cx_establishment_reply {
int status;
};
struct oai_nw_drv_msg_cx_establishment_request {
OaiNwDrvLocalConnectionRef_t lcr; // Local Connection reference
OaiNwDrvCellID_t cellid; // Cell identification
};
struct oai_nw_drv_msg_cx_release_reply {
int status;
};
struct oai_nw_drv_msg_cx_release_request {
OaiNwDrvLocalConnectionRef_t lcr; // Local Connection reference
};
struct oai_nw_drv_msg_rb_list_reply {
OaiNwDrvRadioBearerId_t rab_id;
OaiNwDrvSapId_t sapi;
OaiNwDrvQoSTrafficClass_t qos;
unsigned char state;
};
struct oai_nw_drv_msg_rb_list_request {
OaiNwDrvLocalConnectionRef_t lcr; // Local Connection reference
};
struct oai_nw_drv_msg_rb_establishment_reply {
int status;
};
struct oai_nw_drv_msg_rb_establishment_request {
OaiNwDrvLocalConnectionRef_t lcr; // Local Connection reference
OaiNwDrvRadioBearerId_t rab_id;
OaiNwDrvQoSTrafficClass_t qos;
};
struct oai_nw_drv_msg_rb_release_reply {
int status;
};
struct oai_nw_drv_msg_rb_release_request {
OaiNwDrvLocalConnectionRef_t lcr; // Local Connection reference
OaiNwDrvRadioBearerId_t rab_id;
};
/*
struct saddr {
struct in6_addr ipv6;
unsigned int ipv4;
};
struct daddr {
struct in6_addr ipv6;
unsigned int ipv4;
unsigned int mpls_label;
};
*/
struct oai_nw_drv_msg_class_add_request {
OaiNwDrvLocalConnectionRef_t lcr; // Local Connection reference
OaiNwDrvRadioBearerId_t rab_id;
OaiNwDrvRadioBearerId_t rab_id_rx;
unsigned char dir; // direction (send or receive, forward)
unsigned char dscp; // codepoint
unsigned char fct;
unsigned short classref;
unsigned char version;
//struct daddr daddr;
//struct saddr saddr;
unsigned char splen; // prefix length
union {
struct in6_addr ipv6;
// begin navid
//in_addr_t ipv4;
unsigned int ipv4;
//end navid
unsigned int mpls_label;
} daddr; // IP destination address
union {
struct in6_addr ipv6;
// begin navid
//in_addr_t ipv4;
unsigned int ipv4;
//end navid
} saddr; // IP source address
unsigned char dplen; // prefix length
unsigned char protocol; //!< transport layer protocol type (ANY,TCP,UDP,ICMPv4,ICMPv6)
unsigned char protocol_message_type; //!< transport layer protocol message (ROUTER_ADV, ROUTER_SOLL, etc.)
unsigned short sport; //!< source port
unsigned short dport; //!< destination port
};
struct oai_nw_drv_msg_class_add_reply {
int status;
};
struct oai_nw_drv_msg_class_del_request {
OaiNwDrvLocalConnectionRef_t lcr; // Local Connection reference
unsigned char dir; // direction (send or receive)
unsigned char dscp; // codepoint
unsigned short classref;
};
struct oai_nw_drv_msg_class_del_reply {
int status;
};
#define oai_nw_drv_msg_class_list_reply oai_nw_drv_msg_class_add_request
struct oai_nw_drv_msg_class_list_request {
OaiNwDrvLocalConnectionRef_t lcr; // Local Connection reference
unsigned char dir;
unsigned char dscp;
};
// Messages for Measurement transfer - MW 01/04/2005
typedef unsigned int nioctlProviderId_t;
typedef unsigned short nioctlSignalLoss_t;
typedef struct nioctlMeasures {
OaiNwDrvCellID_t cell_id;
OaiNwDrvSigLevel_t level;
nioctlProviderId_t provider_id;
} nioctlMeasures_t;
struct oai_nw_drv_msg_measure_request {
OaiNwDrvNumRGsMeas_t num_cells;
OaiNwDrvCellID_t cellid[OAI_NW_DRV_MAX_MEASURE_NB]; // Cell identification
unsigned short num_providers;
nioctlProviderId_t provider_id[OAI_NW_DRV_MAX_MEASURE_NB]; // Provider identification
};
struct oai_nw_drv_msg_measure_reply {
OaiNwDrvNumRGsMeas_t num_cells;
nioctlMeasures_t measures[OAI_NW_DRV_MAX_MEASURE_NB];
nioctlSignalLoss_t signal_lost_flag;
};
// Messages for Measurement transfer - MW 01/04/2005
typedef unsigned int nioctlL2Id_t[2];
struct oai_nw_drv_msg_l2id_reply {
nioctlL2Id_t l2id;
};
#endif
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/***************************************************************************
local.h - description
-------------------
copyright : (C) 2002 by Eurecom
email :navid.nikaein@eurecom.fr
lionel.gauthier@eurecom.fr
knopp@eurecom.fr
***************************************************************************
***************************************************************************/
#ifndef OAI_LOCAL_H
#define OAI_LOCAL_H
#include <linux/if_arp.h>
#include <linux/types.h>
#include <linux/spinlock.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/ipv6.h>
#include <linux/ip.h>
#include <linux/sysctl.h>
#include <linux/timer.h>
#include <linux/unistd.h>
#include <asm/param.h>
//#include <sys/sysctl.h>
#include <linux/udp.h>
#include <linux/tcp.h>
#include <linux/icmp.h>
#include <linux/icmpv6.h>
#include <linux/in.h>
#include <net/ndisc.h>
#define PDCP2IP_FIFO 21
#define IP2PDCP_FIFO 22
#include "constant.h"
#include "common/platform_types.h"
#include "sap.h"
struct cx_entity {
int sap[OAI_NW_DRV_SAPI_CX_MAX];
uint8_t state; // state of the connection
OaiNwDrvLocalConnectionRef_t lcr; // Local connection reference
OaiNwDrvCellID_t cellid; // cell identification
uint32_t countimer; // timeout's counter
uint8_t retry; // number of retransmission
uint32_t iid6[2]; // IPv6 interface identification
uint8_t iid4; // IPv4 interface identification
int lastRRCprimitive;
//measures
int req_prov_id [OAI_NW_DRV_MAX_MEASURE_NB];
int num_measures;
int meas_cell_id[OAI_NW_DRV_MAX_MEASURE_NB];
int meas_level [OAI_NW_DRV_MAX_MEASURE_NB];
int provider_id [OAI_NW_DRV_MAX_MEASURE_NB];
};
struct oai_nw_drv_priv {
int irq;
int rx_flags;
struct timer_list timer;
spinlock_t lock;
struct net_device_stats stats;
uint8_t retry_limit;
uint32_t timer_establishment;
uint32_t timer_release;
struct cx_entity cx[OAI_NW_DRV_CX_MAX];
//struct classifier_entity *rclassifier[OAI_NW_DRV_DSCP_MAX]; // receive classifier
uint16_t nrclassifier;
int sap[OAI_NW_DRV_SAPI_MAX];
struct sock *nl_sk;
uint8_t nlmsg[OAI_NW_DRV_PRIMITIVE_MAX_LENGTH+sizeof(struct nlmsghdr)];
uint8_t xbuffer[OAI_NW_DRV_PRIMITIVE_MAX_LENGTH]; // transmition buffer
uint8_t rbuffer[OAI_NW_DRV_PRIMITIVE_MAX_LENGTH]; // reception buffer
};
struct ipversion {
#if defined(__LITTLE_ENDIAN_BITFIELD)
uint8_t reserved:4,
version:4;
#else
uint8_t version:4,
reserved:4;
#endif
};
typedef struct pdcp_data_req_header_s {
rb_id_t rb_id;
sdu_size_t data_size;
signed int inst;
ip_traffic_type_t traffic_type;
} pdcp_data_req_header_t;
typedef struct pdcp_data_ind_header_s {
rb_id_t rb_id;
sdu_size_t data_size;
signed int inst;
ip_traffic_type_t dummy_traffic_type;
} pdcp_data_ind_header_t;
extern struct net_device *oai_nw_drv_dev[OAI_NW_DRV_NB_INSTANCES_MAX];
extern uint8_t OAI_NW_DRV_NULL_IMEI[14];
#endif
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/*! \file netlink.c
* \brief establish a netlink
* \author Navid Nikaein, Lionel Gauthier, and Raymond knopp
* \company Eurecom
* \email:navid.nikaein@eurecom.fr, lionel.gauthier@eurecom.fr, knopp@eurecom.fr
*/
#include <linux/version.h>
//#include <linux/config.h>
#include <linux/socket.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/netlink.h>
#include <net/sock.h>
#include <linux/kthread.h>
#include <linux/mutex.h>
#include "local.h"
#include "proto_extern.h"
//#define NETLINK_DEBUG 1
#define OAI_IP_DRIVER_NETLINK_ID 31
#define NL_DEST_PID 1
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0)
struct netlink_kernel_cfg oai_netlink_cfg;
#endif
static struct sock *nas_nl_sk = NULL;
static int exit_netlink_thread=0;
static int nas_netlink_rx_thread(void *);
static DEFINE_MUTEX(nasmesh_mutex);
static inline void nasmesh_lock(void)
{
mutex_lock(&nasmesh_mutex);
}
static inline void nasmesh_unlock(void)
{
mutex_unlock(&nasmesh_mutex);
}
// This can also be implemented using thread to get the data from PDCP without blocking.
static void nas_nl_data_ready (struct sk_buff *skb)
{
// wake_up_interruptible(skb->sk->sk_sleep);
//nasmesh_lock();
//netlink_rcv_skb(skb, &my_rcv_msg);// my_rcv_msg is the call back func>
//nasmesh_unlock();
struct nlmsghdr *nlh = NULL;
if (skb) {
#ifdef NETLINK_DEBUG
printk("[OAI_IP_DRV][NETLINK] Received socket from PDCP\n");
#endif //NETLINK_DEBUG
nlh = (struct nlmsghdr *)skb->data;
oai_nw_drv_common_wireless2ip(nlh);
//kfree_skb(skb); // not required,
}
}
int oai_nw_drv_netlink_init(void)
{
printk("[OAI_IP_DRV][NETLINK] Running init ...\n");
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0)
oai_netlink_cfg.groups = 0;
oai_netlink_cfg.input = nas_nl_data_ready;
oai_netlink_cfg.cb_mutex = &nasmesh_mutex;
oai_netlink_cfg.bind = NULL;
nas_nl_sk = netlink_kernel_create(
&init_net,
OAI_IP_DRIVER_NETLINK_ID,
# if LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0)
THIS_MODULE,
# endif
&oai_netlink_cfg);
#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0) */
nas_nl_sk = netlink_kernel_create(
&init_net,
OAI_IP_DRIVER_NETLINK_ID,
0,
nas_nl_data_ready,
&nasmesh_mutex, // NULL
THIS_MODULE);
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0) */
if (nas_nl_sk == NULL) {
printk("[OAI_IP_DRV][NETLINK] netlink_kernel_create failed \n");
return(-1);
}
return(0);
}
void oai_nw_drv_netlink_release(void)
{
exit_netlink_thread=1;
printk("[OAI_IP_DRV][NETLINK] Releasing netlink socket\n");
if(nas_nl_sk) {
netlink_kernel_release(nas_nl_sk); //or skb->sk
}
// printk("[OAI_IP_DRV][NETLINK] Removing netlink_rx_thread\n");
//kthread_stop(netlink_rx_thread);
}
int oai_nw_drv_netlink_send(unsigned char *data,unsigned int len)
{
struct sk_buff *nl_skb = alloc_skb(NLMSG_SPACE(len),GFP_ATOMIC);
struct nlmsghdr *nlh = (struct nlmsghdr *)nl_skb->data;
int status;
// printk("[OAI_IP_DRV][NETLINK] Sending %d bytes (%d)\n",len,NLMSG_SPACE(len));
skb_put(nl_skb, NLMSG_SPACE(len));
memcpy(NLMSG_DATA(nlh),data,len);
nlh->nlmsg_len = NLMSG_SPACE(len);
nlh->nlmsg_pid = 0; /* from kernel */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
NETLINK_CB(nl_skb).portid = 0;
#else
NETLINK_CB(nl_skb).pid = 0;
#endif
#ifdef NETLINK_DEBUG
printk("[OAI_IP_DRV][NETLINK] In nas_netlink_send, nl_skb %p, nl_sk %x, nlh %p, nlh->nlmsg_len %d\n",nl_skb,nas_nl_sk,nlh,nlh->nlmsg_len);
#endif //DEBUG_NETLINK
if (nas_nl_sk) {
// nasmesh_lock();
status = netlink_unicast(nas_nl_sk, nl_skb, NL_DEST_PID, MSG_DONTWAIT);
// mutex_unlock(&nasmesh_mutex);
if (status < 0) {
printk("[OAI_IP_DRV][NETLINK] SEND status is %d\n",status);
return(0);
} else {
#ifdef NETLINK_DEBUG
printk("[OAI_IP_DRV][NETLINK] SEND status is %d\n",status);
#endif
return len;
}
} else {
printk("[OAI_IP_DRV][SEND] socket is NULL\n");
return(0);
}
}
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/***************************************************************************
proto_extern.h - description
-------------------
copyright : (C) 2002 by Eurecom
email : michelle.wetterwald@eurecom.fr
yan.moret@eurecom.fr
knopp@eurecom.fr
***************************************************************************
***************************************************************************/
#ifndef __NETWORK_DRIVER_LITE_PROTO_EXTERN__H__
#define __NETWORK_DRIVER_LITE_PROTO_EXTERN__H__
#include <linux/if_arp.h>
#include <linux/types.h>
#include <linux/spinlock.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/ipv6.h>
#include <linux/ip.h>
#include <linux/sysctl.h>
#include <linux/timer.h>
#include <asm/param.h>
//#include <sys/sysctl.h>
#include <linux/udp.h>
#include <linux/tcp.h>
#include <linux/icmp.h>
#include <linux/icmpv6.h>
#include <linux/in.h>
#include <net/ndisc.h>
#include "local.h"
// device.c
/** @defgroup _oai_nw_drv_impl_ OAI Network Device for RRC Lite
* @ingroup _ref_implementation_
* @{
\fn int oai_nw_drv_find_inst(struct net_device *dev)
\brief This function determines the instance id for a particular device pointer.
@param dev Pointer to net_device structure
*/
int oai_nw_drv_find_inst(struct net_device *dev);
// common.c
/**
\fn void oai_nw_drv_common_class_wireless2ip(unsigned short dlen, void* pdcp_sdu,int inst,OaiNwDrvRadioBearerId_t rb_id)
\brief Receive classified LTE packet, build skbuff struct with it and deliver it to the OS network layer.
@param dlen Length of SDU in bytes
@param pdcp_sdu Pointer to received SDU
@param inst Instance number
@param rb_id Radio Bearer Id
*/
void oai_nw_drv_common_class_wireless2ip(unsigned short dlen,
void *pdcp_sdu,
int inst,
OaiNwDrvRadioBearerId_t rb_id);
/**
\fn void oai_nw_drv_common_ip2wireless(struct sk_buff *skb, int inst)
\brief Request the transfer of data (QoS SAP)
@param skb pointer to socket buffer
@param inst device instance
*/
void oai_nw_drv_common_ip2wireless(struct sk_buff *skb, int inst);
/**
\fn void oai_nw_drv_common_ip2wireless_drop(struct sk_buff *skb, int inst)
\brief Drop the IP packet comming from the OS network layer.
@param skb pointer to socket buffer
@param inst device instance
*/
void oai_nw_drv_common_ip2wireless_drop(struct sk_buff *skb, int inst);
#ifndef OAI_NW_DRIVER_USE_NETLINK
/**
\fn void oai_nw_drv_common_wireless2ip()
\brief Retrieve PDU from PDCP through RT-fifos for delivery to the IP stack.
*/
void oai_nw_drv_common_wireless2ip(void);
#else
/**
\fn void oai_nw_drv_common_wireless2ip(struct nlmsghdr *nlh)
\brief Retrieve PDU from PDCP through netlink sockets for delivery to the IP stack.
*/
void oai_nw_drv_common_wireless2ip(struct nlmsghdr *nlh);
#endif //OAI_NW_DRIVER_USE_NETLINK
#ifdef OAI_NW_DRIVER_USE_NETLINK
/**
\fn int oai_nw_drv_netlink_send(unsigned char *data,unsigned int len)
\brief Request the transfer of data by PDCP via netlink socket
@param data pointer to SDU
@param len length of SDU in bytes
@returns Numeber of bytes transfered by netlink socket
*/
int oai_nw_drv_netlink_send(unsigned char *data,unsigned int len);
/**
\fn void oai_nw_drv_COMMON_QOS_receive(struct nlmsghdr *nlh)
\brief Request a PDU from PDCP
@param nlh pointer to netlink message header
*/
void oai_nw_drv_COMMON_QOS_receive(struct nlmsghdr *nlh);
#endif //OAI_NW_DRIVER_USE_NETLINK
// iocontrol.c
void oai_nw_drv_CTL_send(struct sk_buff *skb, int inst);
int oai_nw_drv_CTL_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
// classifier.c
/**
\brief Find the IP traffic type (UNICAST, MULTICAST, BROADCAST) of the IP packet attached to sk_buff.
*/
ip_traffic_type_t oai_nw_drv_find_traffic_type(struct sk_buff *skb);
// tool.c
void oai_nw_drv_TOOL_imei2iid(unsigned char *imei, unsigned char *iid);
void oai_nw_drv_TOOL_eNB_imei2iid(unsigned char *imei, unsigned char *iid, unsigned char len);
unsigned char oai_nw_drv_TOOL_get_dscp6(struct ipv6hdr *iph);
unsigned char oai_nw_drv_TOOL_get_dscp4(struct iphdr *iph);
unsigned char *oai_nw_drv_TOOL_get_protocol6(struct ipv6hdr *iph, unsigned char *protocol);
unsigned char *oai_nw_drv_TOOL_get_protocol4(struct iphdr *iph, unsigned char *protocol);
char *oai_nw_drv_TOOL_get_udpmsg(struct udphdr *udph);
unsigned short oai_nw_drv_TOOL_udpcksum(struct in6_addr *saddr, struct in6_addr *daddr, unsigned char proto, unsigned int udplen, void *data);
int oai_nw_drv_TOOL_network6(struct in6_addr *addr, struct in6_addr *prefix, unsigned char plen);
int oai_nw_drv_TOOL_network4(unsigned int *addr, unsigned int *prefix, unsigned char plen);
void print_TOOL_pk_icmp6(struct icmp6hdr *icmph);
void print_TOOL_pk_all(struct sk_buff *skb);
void print_TOOL_pk_ipv6(struct ipv6hdr *iph);
void print_TOOL_state(unsigned char state);
void oai_nw_drv_tool_print_buffer(char * buffer,int length);
#ifdef OAI_NW_DRIVER_USE_NETLINK
// netlink.c
void oai_nw_drv_netlink_release(void);
int oai_nw_drv_netlink_init(void);
#endif
/** @} */
#endif
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#ifndef OAI_SAP_H
#define OAI_SAP_H
typedef unsigned short OaiNwDrvRadioBearerId_t;
typedef unsigned int OaiNwDrvSapId_t; // Id of the QoS SAP to use
typedef unsigned short OaiNwDrvQoSTrafficClass_t; // QoS traffic class requested
typedef unsigned int OaiNwDrvLocalConnectionRef_t; // local identifier
typedef unsigned short OaiNwDrvCellID_t; // ID of the cell for connection
typedef unsigned short OaiNwDrvNumRGsMeas_t; // number of RGs that could be measured
typedef unsigned int OaiNwDrvSigLevel_t; // Signal level measured
#define OAI_NW_DRV_SAPI_CX_MAX 2
#define OAI_NW_DRV_MAX_MEASURE_NB 5
#define OAI_NW_DRV_PRIMITIVE_MAX_LENGTH 180 // maximum length of a NAS primitive
#define OAI_NW_DRV_SAPI_MAX 4
#define OAI_NW_DRV_RAB_INPUT_SAPI 2
#define OAI_NW_DRV_RAB_OUTPUT_SAPI 3
#define OAI_NW_DRV_MAX_RABS 8 * 64 //NB_RAB_MAX * MAX_MOBILES_PER_RG //27 // = MAXURAB
#define OAI_NW_DRV_LIST_RB_MAX 32
#endif
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#include "local.h"
#include "proto_extern.h"
//#include <linux/in.h>
//#include <net/ndisc.h>
//#include <linux/icmpv6.h>
//#include <linux/icmp.h>
//#include <linux/udp.h>
//#include <linux/tcp.h>
//#define OAI_NW_DRV_DEBUG_TOOL 1
//---------------------------------------------------------------------------
uint8_t oai_nw_drv_TOOL_get_dscp6(struct ipv6hdr *iph)
{
//---------------------------------------------------------------------------
// Start debug information
#ifdef OAI_NW_DRV_DEBUG_TOOL
printk("OAI_NW_DRV_TOOL_GET_DSCP6 - begin \n");
#endif
if (iph==NULL) {
#ifdef OAI_NW_DRV_DEBUG_TOOL
printk("OAI_NW_DRV_TOOL_GET_DSCP6 - input parameter iph is NULL \n");
#endif
return 0;
}
// End debug information
return (ntohl(((*(__u32 *)iph)&OAI_NW_DRV_TRAFFICCLASS_MASK)))>>22;
//return ntohs(*(const __be16 *)iph) >> 4; // see linux/dsfield.h
}
//---------------------------------------------------------------------------
uint8_t oai_nw_drv_TOOL_get_dscp4(struct iphdr *iph)
{
//---------------------------------------------------------------------------
// Start debug information
#ifdef OAI_NW_DRV_DEBUG_TOOL
printk("OAI_NW_DRV_TOOL_GET_DSCP4 - begin \n");
#endif
if (iph==NULL) {
#ifdef OAI_NW_DRV_DEBUG_TOOL
printk("OAI_NW_DRV_TOOL_GET_DSCP4 - input parameter iph is NULL \n");
#endif
return 0;
}
// End debug information
return (iph->tos);
}
//---------------------------------------------------------------------------
int oai_nw_drv_TOOL_network6(struct in6_addr *addr, struct in6_addr *prefix, uint8_t plen)
{
//---------------------------------------------------------------------------
// Start debug information
#ifdef OAI_NW_DRV_DEBUG_TOOL
printk("OAI_NW_DRV_TOOL_NETWORK6 - begin \n");
#endif
if (addr==NULL) {
#ifdef OAI_NW_DRV_DEBUG_TOOL
printk("OAI_NW_DRV_TOOL_NETWORK6 - input parameter addr is NULL \n");
#endif
return 0;
}
if (prefix==NULL) {
#ifdef OAI_NW_DRV_DEBUG_TOOL
printk("OAI_NW_DRV_TOOL_NETWORK6 - input parameter prefix is NULL \n");
#endif
return 0;
}
// End debug information
switch(plen/32) {
case 0:
return (((addr->s6_addr32[0]>>(32-plen))<<(32-plen))==prefix->s6_addr[0]);
case 1:
return ((addr->s6_addr32[0]==prefix->s6_addr[0])&&
(((addr->s6_addr32[1]>>(64-plen))<<(64-plen))==prefix->s6_addr[1]));
case 2:
return ((addr->s6_addr32[0]==prefix->s6_addr[0])&&
(addr->s6_addr32[1]==prefix->s6_addr[1])&&
(((addr->s6_addr32[2]>>(96-plen))<<(96-plen))==prefix->s6_addr[2]));
case 3:
return ((addr->s6_addr32[0]==prefix->s6_addr[0])&&
(addr->s6_addr32[1]==prefix->s6_addr[1])&&
(addr->s6_addr32[2]==prefix->s6_addr[2])&&
(((addr->s6_addr32[3]>>(128-plen))<<(128-plen))==prefix->s6_addr[3]));
default:
return ((addr->s6_addr32[0]==prefix->s6_addr[0])&&
(addr->s6_addr32[1]==prefix->s6_addr[1])&&
(addr->s6_addr32[2]==prefix->s6_addr[2])&&
(addr->s6_addr32[3]==prefix->s6_addr[3]));
}
}
//---------------------------------------------------------------------------
int oai_nw_drv_TOOL_network4(uint32_t *addr, uint32_t *prefix, uint8_t plen)
{
//---------------------------------------------------------------------------
// Start debug information
#ifdef OAI_NW_DRV_DEBUG_TOOL
printk("OAI_NW_DRV_TOOL_NETWORK4 - begin \n");
#endif
if (addr==NULL) {
#ifdef OAI_NW_DRV_DEBUG_TOOL
printk("OAI_NW_DRV_TOOL_NETWORK4 - input parameter addr is NULL \n");
#endif
return 0;
}
if (prefix==NULL) {
#ifdef OAI_NW_DRV_DEBUG_TOOL
printk("OAI_NW_DRV_TOOL_NETWORK4 - input parameter prefix is NULL \n");
#endif
return 0;
}
// End debug information
if (plen>=32)
return (*addr==*prefix);
else
return (((*addr>>(32-plen))<<(32-plen))==*prefix);
}
//---------------------------------------------------------------------------
//struct udphdr *oai_nw_drv_TOOL_get_udp6(struct ipv6hdr *iph){
//---------------------------------------------------------------------------
// return (struct udphdr *)((char *)iph+OAI_NW_DRV_IPV6_SIZE); // to modify
//}
//---------------------------------------------------------------------------
uint8_t *oai_nw_drv_TOOL_get_protocol6(struct ipv6hdr *iph, uint8_t *protocol)
{
//---------------------------------------------------------------------------
uint16_t size;
// Start debug information
#ifdef OAI_NW_DRV_DEBUG_TOOL
printk("OAI_NW_DRV_TOOL_GET_PROTOCOL6 - begin \n");
#endif
if (iph==NULL) {
#ifdef OAI_NW_DRV_DEBUG_TOOL
printk("OAI_NW_DRV_TOOL_GET_PROTOCOL6 - input parameter iph is NULL \n");
#endif
return NULL;
}
if (protocol==NULL) {
#ifdef OAI_NW_DRV_DEBUG_TOOL
printk("OAI_NW_DRV_TOOL_GET_PROTOCOL6 - input parameter protocol is NULL \n");
#endif
return NULL;
}
// End debug information
*protocol=iph->nexthdr;
size=OAI_NW_DRV_IPV6_SIZE;
while (1) {
switch(*protocol) {
case IPPROTO_UDP:
case IPPROTO_TCP:
case IPPROTO_ICMPV6:
return (uint8_t *)((uint8_t *)iph+size);
case IPPROTO_HOPOPTS:
case IPPROTO_ROUTING:
case IPPROTO_DSTOPTS:
*protocol=((uint8_t *)iph+size)[0];
size+=((uint8_t *)iph+size)[1]*8+8;
break;
case IPPROTO_FRAGMENT:
*protocol=((uint8_t *)iph+size)[0];
size+=((uint8_t *)iph+size)[1]+8;
break;
case IPPROTO_NONE:
case IPPROTO_AH:
case IPPROTO_ESP:
default:
return NULL;
}
}
}
//---------------------------------------------------------------------------
uint8_t *oai_nw_drv_TOOL_get_protocol4(struct iphdr *iph, uint8_t *protocol)
{
//---------------------------------------------------------------------------
// Start debug information
#ifdef OAI_NW_DRV_DEBUG_TOOL
printk("OAI_NW_DRV_TOOL_GET_PROTOCOL4 - begin \n");
#endif
if (iph==NULL) {
#ifdef OAI_NW_DRV_DEBUG_TOOL
printk("OAI_NW_DRV_TOOL_GET_PROTOCOL4 - input parameter iph is NULL \n");
#endif
return NULL;
}
if (protocol==NULL) {
#ifdef OAI_NW_DRV_DEBUG_TOOL
printk("OAI_NW_DRV_TOOL_GET_PROTOCOL4 - input parameter protocol is NULL \n");
#endif
return NULL;
}
// End debug information
*protocol=iph->protocol;
switch(*protocol) {
case IPPROTO_UDP:
case IPPROTO_TCP:
case IPPROTO_ICMP:
return (uint8_t *)((uint8_t *)iph+iph->tot_len);
default:
return NULL;
}
}
//---------------------------------------------------------------------------
// Convert the IMEI to iid
void oai_nw_drv_TOOL_imei2iid(uint8_t *imei, uint8_t *iid)
{
//---------------------------------------------------------------------------
// Start debug information
#ifdef OAI_NW_DRV_DEBUG_TOOL
printk("OAI_NW_DRV_TOOL_IMEI2IID - begin \n");
#endif
if (imei==NULL) {
#ifdef OAI_NW_DRV_DEBUG_TOOL
printk("OAI_NW_DRV_TOOL_IMEI2IID - input parameter imei is NULL \n");
#endif
return;
}
if (iid==NULL) {
#ifdef OAI_NW_DRV_DEBUG_TOOL
printk("OAI_NW_DRV_TOOL_IMEI2IID - input parameter iid is NULL \n");
#endif
return;
}
// End debug information
memset(iid, 0, OAI_NW_DRV_ADDR_LEN);
iid[0] = 0x03;
iid[1] = 16*imei[0]+imei[1];
iid[2] = 16*imei[2]+imei[3];
iid[3] = 16*imei[4]+imei[5];
iid[4] = 16*imei[6]+imei[7];
iid[5] = 16*imei[8]+imei[9];
iid[6] = 16*imei[10]+imei[11];
iid[7] = 16*imei[12]+imei[13];
}
//---------------------------------------------------------------------------
// Convert the IMEI to iid
void oai_nw_drv_TOOL_eNB_imei2iid(unsigned char *imei, unsigned char *iid, unsigned char len)
{
//---------------------------------------------------------------------------
unsigned int index;
// Start debug information
#ifdef OAI_NW_DRV_DEBUG_TOOL
printk("OAI_NW_DRV_TOOL_eNB_IMEI2IID - begin \n");
#endif
if (imei==NULL) {
#ifdef OAI_NW_DRV_DEBUG_TOOL
printk("OAI_NW_DRV_TOOL_eNB_IMEI2IID - input parameter imei is NULL \n");
#endif
return;
}
if (iid==NULL) {
#ifdef OAI_NW_DRV_DEBUG_TOOL
printk("OAI_NW_DRV_TOOL_eNB_IMEI2IID - input parameter iid is NULL \n");
#endif
return;
}
// End debug information
memset(iid, 0, len);
iid[0] = 0x00; // to be compatible between link local and global
// len -1 because of insertion of 0 above
for (index = 0; index < (len-1); index++) {
iid[index+1] = 16*imei[index*2]+imei[index*2+1];
}
}
//struct udphdr *oai_nw_drv_TOOL_get_udp4(struct iphdr *iph)
//{
// return (struct udphdr *)((char *)iph+OAI_NW_DRV_IPV4_SIZE); // to modify
//}
//---------------------------------------------------------------------------
char *oai_nw_drv_TOOL_get_udpmsg(struct udphdr *udph)
{
//---------------------------------------------------------------------------
// Start debug information
#ifdef OAI_NW_DRV_DEBUG_TOOL
printk("OAI_NW_DRV_TOOL_GET_UDPMSG - begin \n");
#endif
if (udph==NULL) {
#ifdef OAI_NW_DRV_DEBUG_TOOL
printk("OAI_NW_DRV_TOOL_GET_UDPMSG - input parameter udph is NULL \n");
#endif
return NULL;
}
// End debug information
return ((char *)udph+sizeof(struct udphdr));
}
//---------------------------------------------------------------------------
// Compute the UDP checksum (the data size must be odd)
uint16_t oai_nw_drv_TOOL_udpcksum(struct in6_addr *saddr, struct in6_addr *daddr, uint8_t proto, uint32_t udplen, void *data)
{
//---------------------------------------------------------------------------
uint32_t i;
uint16_t *data16;
uint32_t csum=0;
// Start debug information
#ifdef OAI_NW_DRV_DEBUG_TOOL
printk("OAI_NW_DRV_TOOL_UDPCKSUM - begin \n");
#endif
if (saddr==NULL) {
#ifdef OAI_NW_DRV_DEBUG_TOOL
printk("OAI_NW_DRV_TOOL_UDPCKSUM - input parameter saddr is NULL \n");
#endif
return 0;
}
if (daddr==NULL) {
#ifdef OAI_NW_DRV_DEBUG_TOOL
printk("OAI_NW_DRV_TOOL_UDPCKSUM - input parameter daddr is NULL \n");
#endif
return 0;
}
if (data==NULL) {
#ifdef OAI_NW_DRV_DEBUG_TOOL
printk("OAI_NW_DRV_TOOL_UDPCKSUM - input parameter data is NULL \n");
#endif
return 0;
}
// End debug information
data16=data;
for (i=0; i<8; ++i) {
csum+=ntohs(saddr->s6_addr16[i]);
if (csum>0xffff)
csum-=0xffff;
}
for (i=0; i<8; ++i) {
csum+=ntohs(daddr->s6_addr16[i]);
if (csum>0xffff)
csum-=0xffff;
}
csum+=(udplen>>16); // udplen checksum
if (csum>0xffff)
csum -= 0xffff;
csum+=udplen & 0xffff;
if (csum>0xffff)
csum -= 0xffff;
csum+=proto; // protocol checksum
if (csum>0xffff)
csum-=0xffff;
for (i = 0; 2*i < udplen; i++) {
csum+=ntohs(data16[i]);
if (csum>0xffff)
csum-=0xffff;
}
return htons((uint16_t)(~csum)&0xffff);
}
//---------------------------------------------------------------------------
void print_TOOL_pk_udp(struct udphdr *udph)
{
//---------------------------------------------------------------------------
// Start debug information
#ifdef OAI_NW_DRV_DEBUG_TOOL
printk("PRINT_TOOL_PK_UDP - begin \n");
#endif
if (udph==NULL) {
#ifdef OAI_NW_DRV_DEBUG_TOOL
printk("OAI_NW_DRV_TOOL_PK_UDP - input parameter udph is NULL \n");
#endif
return;
}
// End debug information
if (udph!=NULL) {
printk("UDP:\t source = %u, dest = %u, len = %u, check = %x\n", ntohs(udph->source), ntohs(udph->dest), ntohs(udph->len), udph->check);
}
}
//---------------------------------------------------------------------------
void print_TOOL_pk_tcp(struct tcphdr *tcph)
{
//---------------------------------------------------------------------------
// Start debug information
#ifdef OAI_NW_DRV_DEBUG_TOOL
printk("PRINT_TOOL_PK_TDP - begin \n");
#endif
if (tcph==NULL) {
#ifdef OAI_NW_DRV_DEBUG_TOOL
printk("OAI_NW_DRV_TOOL_PK_TDP - input parameter tcph is NULL \n");
#endif
return;
}
// End debug information
if (tcph!=NULL) {
printk("TCP:\t source = %u, dest = %u\n", tcph->source, tcph->dest);
}
}
//---------------------------------------------------------------------------
void print_TOOL_pk_icmp6(struct icmp6hdr *icmph)
{
//---------------------------------------------------------------------------
// Start debug information
#ifdef OAI_NW_DRV_DEBUG_TOOL
printk("PRINT_TOOL_PK_ICMP6 - begin \n");
#endif
if (icmph==NULL) {
#ifdef OAI_NW_DRV_DEBUG_TOOL
printk("OAI_NW_DRV_TOOL_PK_ICMP6 - input parameter icmph is NULL \n");
#endif
return;
}
// End debug information
if (icmph!=NULL) {
printk("ICMPv6:\t type= %d, code = %d\n", icmph->icmp6_type, icmph->icmp6_code);
switch(icmph->icmp6_type) {
case ICMPV6_DEST_UNREACH:
printk("Destination unreachable\n");
break;
case ICMPV6_PKT_TOOBIG:
printk("Packet too big\n");
break;
case ICMPV6_TIME_EXCEED:
printk("Time exceeded\n");
break;
case ICMPV6_PARAMPROB:
printk("Parameter problem\n");
break;
case ICMPV6_ECHO_REQUEST:
printk("Echo request\n");
break;
case ICMPV6_ECHO_REPLY:
printk("Echo reply\n");
break;
case ICMPV6_MGM_QUERY:
printk("Multicast listener query\n");
break;
case ICMPV6_MGM_REPORT:
printk("Multicast listener report\n");
break;
case ICMPV6_MGM_REDUCTION:
printk("Multicast listener done\n");
break;
case NDISC_ROUTER_SOLICITATION:
printk("Router solicitation\n");
break;
case NDISC_ROUTER_ADVERTISEMENT:
printk("Router advertisment\n");
break;
case NDISC_NEIGHBOUR_SOLICITATION:
printk("Neighbour solicitation\n");
break;
case NDISC_NEIGHBOUR_ADVERTISEMENT:
printk("Neighbour advertisment\n");
break;
case NDISC_REDIRECT:
printk("redirect message\n");
break;
}
}
}
//---------------------------------------------------------------------------
void print_TOOL_pk_ipv6(struct ipv6hdr *iph)
{
//---------------------------------------------------------------------------
// Start debug information
#ifdef OAI_NW_DRV_DEBUG_TOOL
printk("PRINT_TOOL_PK_IPv6 - begin \n");
#endif
if (iph==NULL) {
#ifdef OAI_NW_DRV_DEBUG_TOOL
printk("OAI_NW_DRV_TOOL_PK_IPv6 - input parameter iph is NULL \n");
#endif
return;
}
// End debug information
if (iph!=NULL) {
// char addr[OAI_NW_DRV_INET6_ADDRSTRLEN];
printk("IP:\t version = %u, priority = %u, payload_len = %u\n", iph->version, iph->priority, ntohs(iph->payload_len));
printk("\t fl0 = %u, fl1 = %u, fl2 = %u\n",iph->flow_lbl[0],iph->flow_lbl[1],iph->flow_lbl[2]);
printk("\t next header = %u, hop_limit = %u\n", iph->nexthdr, iph->hop_limit);
// inet_ntop(AF_INET6, (void *)(&iph->saddr), addr, OAI_NW_DRV_INET6_ADDRSTRLEN);
// printk("\t saddr = %s",addr);
// inet_ntop(AF_INET6, (void *)(&iph->daddr), addr, OAI_NW_DRV_INET6_ADDRSTRLEN);
// printk(", daddr = %s\n",addr);
switch(iph->nexthdr) {
case IPPROTO_UDP:
print_TOOL_pk_udp((struct udphdr *)((char *)iph+sizeof(struct ipv6hdr)));
break;
case IPPROTO_TCP:
print_TOOL_pk_tcp((struct tcphdr *)((char *)iph+sizeof(struct ipv6hdr)));
break;
case IPPROTO_ICMPV6:
print_TOOL_pk_icmp6((struct icmp6hdr *)((char *)iph+sizeof(struct ipv6hdr)));
break;
case IPPROTO_IPV6:
print_TOOL_pk_ipv6((struct ipv6hdr *)((char *)iph+sizeof(struct ipv6hdr)));
break;
default:
printk("Unknown upper layer\n");
}
}
}
//---------------------------------------------------------------------------
void print_TOOL_pk_ipv4(struct iphdr *iph)
{
//---------------------------------------------------------------------------
// Start debug information
#ifdef OAI_NW_DRV_DEBUG_TOOL
printk("PRINT_TOOL_PK_IPv4 - begin \n");
#endif
if (iph==NULL) {
#ifdef OAI_NW_DRV_DEBUG_TOOL
printk("OAI_NW_DRV_TOOL_PK_IPv4 - input parameter iph is NULL \n");
#endif
return;
}
// End debug information
if (iph!=NULL) {
// char addr[OAI_NW_DRV_INET_ADDRSTRLEN];
printk("IP:\t version = %u, IP length = %u\n", iph->version, iph->ihl);
// inet_ntop(AF_INET, (void *)(&iph->saddr), addr, OAI_NW_DRV_INET_ADDRSTRLEN);
// printk("\t saddr = %s", addr);
// inet_ntop(AF_INET, (void *)(&iph->saddr), addr, OAI_NW_DRV_INET_ADDRSTRLEN);
// printk("\t saddr = %s", addr);
}
}
//---------------------------------------------------------------------------
void print_TOOL_pk_all(struct sk_buff *skb)
{
//---------------------------------------------------------------------------
printk("Skb:\t %u, len = %u\n", (unsigned int)skb, skb->len);
//navid: need to calculate the current used space: fixme?
printk("Skb:\t available buf space = %u \n", skb->truesize);
switch (ntohs(skb->protocol)) {
case ETH_P_IPV6:
print_TOOL_pk_ipv6((struct ipv6hdr *)skb->network_header);
break;
case ETH_P_IP:
print_TOOL_pk_ipv4((struct iphdr *)skb->network_header);
break;
}
}
//---------------------------------------------------------------------------
/*int isdigit(char c)
{
switch(c)
{
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
return 1;
default:
return 0;
}
}*/
/*int oai_nw_drv_TOOL_inet_pton4(char *src, uint32_t *dst)
{
uint32_t val;
int n;
uint8_t c;
uint32_t parts[4];
c = *src;
val=0;
n=0
for (;;)
{
for (;;)
{
if (isdigit(c))
{
val = (val * 10) + c - '0';
c = *++src;
}
else
break;
}
if (c == '.')
{
if (n>4)
return -1;
parts[n]=val;
c = *++src;
++n;
}
else
break;
}
if ((c != '\0')||(n!=3))
return (0);
if ((parts[0] | parts[1] | parts[2] | val) > 256)
return (0);
val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
if (dst)
dst = htonl(val);
return (1);
}*/
//-----------------------------------------------------------------------------
// Print the content of a buffer in hexadecimal
void oai_nw_drv_tool_print_buffer(char * buffer,int length)
{
//-----------------------------------------------------------------------------
int i;
// Start debug information
#ifdef OAI_NW_DRV_DEBUG_TOOL
printk("OAI_NW_DRV_TOOL_PRINT_BUFFER - begin \n");
#endif
if (buffer==NULL) {
#ifdef OAI_NW_DRV_DEBUG_TOOL
printk("OAI_NW_DRV_TOOL_PRINT_BUFFER - input parameter buffer is NULL \n");
#endif
return;
}
// End debug information
printk("\nBuffer content: ");
for (i=0; i<length; i++)
printk("-%hx-",buffer[i]);
printk(",\t length %d\n", length);
}
CC = gcc
NAS_DIR = ..
rb_tool: rb_tool.c
$(CC) rb_tool.c -o rb_tool -I../ -g -ggdb
all: rb_tool
clean:
rm -f rb_tool
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/***************************************************************************
rb_tool.c - User-space utility for driving NASMESH IOCTL interface
-------------------
copyright : (C) 2008 by Eurecom
email : raymond.knopp@eurecom.fr and navid.nikaein@eurecom.fr
***************************************************************************
***************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <ctype.h>
#include <netinet/in.h>
#include <arpa/inet.h>
//
//#include "ral_cdma_variables.h"
//#include "ral_cdma_proto.h"
#include "rrc_nas_primitives.h"
#include "ioctl.h"
#include "constant.h"
//#include "nasmt_constant.h"
//#include "nasmt_iocontrol.h"
// Global variables
//int sd_graal;
int fd;
//char myIPAddr[16]; // local IP Address
//int meas_counter;
//struct ralu_priv ru_priv;
//struct ralu_priv *ralupriv;
//ioctl
char dummy_buffer[1024];
struct nas_ioctl gifr;
//int wait_start_nas;
/*
//---------------------------------------------------------------------------
int NAS_RALconnect(void)
//---------------------------------------------------------------------------
{
struct sockaddr_un remote;
int len,s;
if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
perror("NAS_RALconnect - socket");
exit(1);
}
//
printf("Trying to connect to NAS ...\n");
remote.sun_family = AF_UNIX;
strcpy(remote.sun_path, SOCKET_RAL_TD_CDMA_NAME);
len = strlen(remote.sun_path) + sizeof(remote.sun_family);
while (wait_start_graal){
if (connect(s, (struct sockaddr *)&remote, len) == -1) {
perror("NAS_RALconnect - waiting for connection - ");
// exit(1);
wait_start_graal = 1;
sleep(5);
} else {
wait_start_graal =0;
printf("RAL connected to NAS.\n");
}
}
return s;
}
*/
//---------------------------------------------------------------------------
void IAL_NAS_ioctl_init(int inst)
//---------------------------------------------------------------------------
{
struct nas_msg_statistic_reply *msgrep;
int err;
sprintf(gifr.name, "oai%d",inst);
// Get an UDP IPv6 socket ??
fd=socket(AF_INET6, SOCK_DGRAM, 0);
if (fd<0) {
printf("Error opening socket\n");
exit(1);
}
sprintf(gifr.name, "oai%d",inst);
gifr.type = NAS_MSG_STATISTIC_REQUEST;
memset ((void *)dummy_buffer,0,800);
gifr.msg= &(dummy_buffer[0]);
msgrep=(struct nas_msg_statistic_reply *)(gifr.msg);
printf("ioctl :Statistics requested\n");
err=ioctl(fd, NAS_IOCTL_RRM, &gifr);
if (err<0) {
printf("IOCTL error, err=%d\n",err);
}
printf("tx_packets = %u, rx_packets = %u\n", msgrep->tx_packets, msgrep->rx_packets);
printf("tx_bytes = %u, rx_bytes = %u\n", msgrep->tx_bytes, msgrep->rx_bytes);
printf("tx_errors = %u, rx_errors = %u\n", msgrep->tx_errors, msgrep->rx_errors);
printf("tx_dropped = %u, rx_dropped = %u\n", msgrep->tx_dropped, msgrep->rx_dropped);
}
#define ADD_RB 0
#define DEL_RB 1
//---------------------------------------------------------------------------
int main(int argc,char **argv)
//---------------------------------------------------------------------------
{
int err = 0;
int c = 0;
int action=0,rbset=0,cxset=0,instset=0,saddr_ipv4set=0,saddr_ipv6set=0,daddr_ipv4set=0,daddr_ipv6set=0,dscpset=0,mpls_outlabelset=0,mpls_inlabelset=0;
char rb[100],cx[100],dscp[100],inst[100],mpls_outgoinglabel[100],mpls_incominglabel[100];
struct nas_msg_rb_establishment_request *msgreq = NULL;
struct nas_msg_class_add_request *msgreq_class = NULL;
in_addr_t saddr_ipv4 = 0,daddr_ipv4 = 0;
struct in6_addr saddr_ipv6,daddr_ipv6;
unsigned int mpls_outlabel=0,mpls_inlabel=0;
char addr_str[46];
// scan options
rb[0] = '\0';
cx[0] = '\0';
dscp[0] = '\0';
mpls_incominglabel[0] = '\0';
mpls_outgoinglabel[0] = '\0';
while ((c = getopt (argc, argv, "adr:i:c:l:m:s:t:x:y:z:")) != -1)
switch (c) {
case 'a':
action = ADD_RB;
break;
case 'd':
action = DEL_RB;
break;
case 'r':
strcpy(rb,optarg);
rbset = 1;
break;
case 'i':
strcpy(inst,optarg);
instset = 1;
break;
case 'c':
strcpy(cx,optarg);
cxset = 1;
break;
case 'l':
strcpy(mpls_outgoinglabel,optarg);
mpls_outlabelset=1;
break;
case 'm':
strcpy(mpls_incominglabel,optarg);
mpls_inlabelset=1;
break;
case 's': {
struct in_addr a;
inet_aton(optarg,&a);
saddr_ipv4 = a.s_addr;
saddr_ipv4set = 1;
break;
}
case 't': {
struct in_addr a;
inet_aton(optarg,&a);
daddr_ipv4 = a.s_addr;
daddr_ipv4set = 1;
break;
}
case 'x':
printf("IPv6: %s\n",optarg);
inet_pton(AF_INET6,optarg,(void *)&saddr_ipv6);
saddr_ipv6set = 1;
break;
case 'y':
inet_pton(AF_INET6,optarg,(void *)&daddr_ipv6);
daddr_ipv6set = 1;
break;
case 'z':
dscpset=1;
strcpy(dscp,optarg);
break;
case '?':
if (isprint (optopt))
fprintf (stderr, "Unknown option `-%c'.\n", optopt);
else
fprintf (stderr,
"Unknown option character `\\x%x'.\n",
optopt);
return 1;
default:
abort ();
}
printf ("action = %d, rb = %s,cx = %s\n", action, rb, cx);
if (rbset==0) {
printf("ERROR: Specify a RAB id!!\n");
exit(-1);
}
if (cxset==0) {
printf("ERROR: Specify an LCR !!\n");
exit(-1);
}
if (instset==0) {
printf("ERROR: Specify an interface !!\n");
exit(-1);
}
if ((mpls_outlabelset == 0) && (saddr_ipv4set==0) && (saddr_ipv6set==0)) {
printf("ERROR: Specify a source IP address\n");
exit(-1);
}
if ((mpls_outlabelset == 0) && (daddr_ipv4set==0) && (daddr_ipv6set==0)) {
printf("ERROR: Specify a destination IP address\n");
exit(-1);
}
if ((mpls_outlabelset == 1) && (mpls_inlabelset == 0)) {
printf("ERROR: Specify an incoming MPLS label\n");
exit(-1);
}
if ((mpls_inlabelset == 1) && (mpls_outlabelset == 0)) {
printf("ERROR: Specify an outgoing MPLS label\n");
exit(-1);
}
IAL_NAS_ioctl_init(atoi(inst));
msgreq = (struct nas_msg_rb_establishment_request *)(gifr.msg);
msgreq->rab_id = atoi(rb);
msgreq->lcr = atoi(cx);
msgreq->qos = 0;
if (action == ADD_RB) {
gifr.type = NAS_MSG_RB_ESTABLISHMENT_REQUEST;
err=ioctl(fd, NAS_IOCTL_RRM, &gifr);
if (err == -1) perror("ioctl");
if (saddr_ipv4set == 1) {
msgreq_class = (struct nas_msg_class_add_request *)(gifr.msg);
msgreq_class->rab_id = atoi(rb);
msgreq_class->lcr = atoi(cx);
msgreq_class->version = 4;
msgreq_class->classref = 0 + (msgreq_class->lcr<<3);
msgreq_class->dir = NAS_DIRECTION_SEND;
msgreq_class->fct = NAS_FCT_QOS_SEND;
msgreq_class->saddr.ipv4 = saddr_ipv4;
msgreq_class->daddr.ipv4 = daddr_ipv4;
// TO BE FIXED WHEN WE CAN SPECIFY A PROTOCOL-based rule
msgreq_class->protocol = NAS_PROTOCOL_DEFAULT;
if (dscpset==0)
msgreq_class->dscp=0;
else
msgreq_class->dscp=atoi(dscp);
gifr.type = NAS_MSG_CLASS_ADD_REQUEST;
err=ioctl(fd, NAS_IOCTL_RRM, &gifr);
if (err == -1) perror("ioctl");
msgreq_class->rab_id = atoi(rb);
msgreq_class->lcr = atoi(cx);
msgreq_class->classref = 1+(msgreq_class->lcr<<3);
msgreq_class->dir = NAS_DIRECTION_RECEIVE;
msgreq_class->daddr.ipv4 = saddr_ipv4;
msgreq_class->saddr.ipv4 = daddr_ipv4;
gifr.type = NAS_MSG_CLASS_ADD_REQUEST;
err=ioctl(fd, NAS_IOCTL_RRM, &gifr);
if (err == -1) perror("ioctl");
}
if (saddr_ipv6set == 1) {
msgreq_class = (struct nas_msg_class_add_request *)(gifr.msg);
msgreq_class->rab_id = atoi(rb);
msgreq_class->lcr = atoi(cx);
msgreq_class->version = 6;
if (dscpset==0)
msgreq_class->dscp=0;
else
msgreq_class->dscp=atoi(dscp);
msgreq_class->classref = 2+(msgreq_class->lcr<<3);
msgreq_class->dir=NAS_DIRECTION_SEND;
msgreq_class->fct=NAS_FCT_QOS_SEND;
// TO BE FIXED WHEN WE CAN SPECIFY A PROTOCOL-based rule
msgreq_class->protocol = NAS_PROTOCOL_DEFAULT;
memcpy(&msgreq_class->saddr.ipv6,&saddr_ipv6,16);
memcpy(&msgreq_class->daddr.ipv6,&daddr_ipv6,16);
inet_ntop(AF_INET6,(void *)&saddr_ipv6,addr_str,46);
printf("IPV6: Source %s\n",addr_str);
inet_ntop(AF_INET6,(void *)&daddr_ipv6,addr_str,46);
printf("IPV6: Dest %s\n",addr_str);
gifr.type = NAS_MSG_CLASS_ADD_REQUEST;
err=ioctl(fd, NAS_IOCTL_RRM, &gifr);
if (err == -1) perror("ioctl");
msgreq_class->rab_id = atoi(rb);
msgreq_class->lcr = atoi(cx);
msgreq_class->classref = 3+(msgreq_class->lcr<<3);
msgreq_class->dir=NAS_DIRECTION_RECEIVE;
memcpy(&msgreq_class->daddr.ipv6,&saddr_ipv6,16);
memcpy(&msgreq_class->saddr.ipv6,&daddr_ipv6,16);
gifr.type = NAS_MSG_CLASS_ADD_REQUEST;
err=ioctl(fd, NAS_IOCTL_RRM, &gifr);
if (err == -1) perror("ioctl");
}
if (mpls_inlabelset == 1) {
msgreq_class = (struct nas_msg_class_add_request *)(gifr.msg);
msgreq_class->rab_id = atoi(rb);
msgreq_class->lcr = atoi(cx);
msgreq_class->version = NAS_MPLS_VERSION_CODE;
if (dscpset==0)
msgreq_class->dscp=0;
else
msgreq_class->dscp=atoi(dscp);
msgreq_class->classref = 4 + (msgreq_class->lcr<<3);
msgreq_class->dir=NAS_DIRECTION_SEND;
msgreq_class->fct=NAS_FCT_QOS_SEND;
// TO BE FIXED WHEN WE CAN SPECIFY A PROTOCOL-based rule
msgreq_class->protocol = NAS_PROTOCOL_DEFAULT;
mpls_outlabel = atoi(mpls_outgoinglabel);
printf("Setting MPLS outlabel %u with exp %d\n",mpls_outlabel,msgreq_class->dscp);
msgreq_class->daddr.mpls_label = mpls_outlabel;
gifr.type = NAS_MSG_CLASS_ADD_REQUEST;
err=ioctl(fd, NAS_IOCTL_RRM, &gifr);
if (err == -1) perror("ioctl");
msgreq_class->rab_id = atoi(rb);
msgreq_class->lcr = atoi(cx);
msgreq_class->classref = 5 + (msgreq_class->lcr<<3);
msgreq_class->dir=NAS_DIRECTION_RECEIVE;
// TO BE FIXED WHEN WE CAN SPECIFY A PROTOCOL-based rule
msgreq_class->protocol = NAS_PROTOCOL_DEFAULT;
mpls_inlabel = atoi(mpls_incominglabel);
printf("Setting MPLS inlabel %u with exp %d\n",mpls_inlabel,msgreq_class->dscp);
msgreq_class->daddr.mpls_label = mpls_inlabel;
gifr.type = NAS_MSG_CLASS_ADD_REQUEST;
err=ioctl(fd, NAS_IOCTL_RRM, &gifr);
if (err == -1) perror("ioctl");
}
} else if (action == DEL_RB) {
gifr.type = NAS_MSG_RB_RELEASE_REQUEST;
err=ioctl(fd, NAS_IOCTL_RRM, &gifr);
if (err == -1) perror("ioctl");
}
}
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#include <sys/types.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
typedef unsigned int sdu_size_t;
typedef unsigned int rb_id_t;
typedef struct pdcp_data_req_header_t {
rb_id_t rb_id;
sdu_size_t data_size;
int inst;
} pdcp_data_req_header_t;
typedef struct pdcp_data_ind_header_t {
rb_id_t rb_id;
sdu_size_t data_size;
int inst;
} pdcp_data_ind_header_t;
#define MAX_PAYLOAD 1024 /* maximum payload size*/
struct sockaddr_nl src_addr, dest_addr;
struct nlmsghdr *nlh = NULL;
struct iovec iov;
int sock_fd;
struct msghdr msg;
void foo( int sig )
{
printf("I got cntl-C, closing socket\n");
close(sock_fd);
exit(-1);
}
#define OAI_IP_DRIVER_NETLINK_ID 31
void main()
{
struct sigaction newaction;
int i=0;
int ret;
int len;
newaction.sa_handler = foo;
if ( sigaction( SIGINT, &newaction, NULL ) == -1)
perror("Could not install the new signal handler");
sock_fd = socket(PF_NETLINK, SOCK_RAW,OAI_IP_DRIVER_NETLINK_ID);
printf("Opened socket with fd %d\n",sock_fd);
ret = fcntl(sock_fd,F_SETFL,O_NONBLOCK);
printf("fcntl returns %d\n",ret);
memset(&src_addr, 0, sizeof(src_addr));
src_addr.nl_family = AF_NETLINK;
src_addr.nl_pid = 1;//getpid(); /* self pid */
src_addr.nl_groups = 0; /* not in mcast groups */
ret = bind(sock_fd, (struct sockaddr*)&src_addr,
sizeof(src_addr));
printf("bind returns %d\n",ret);
memset(&dest_addr, 0, sizeof(dest_addr));
dest_addr.nl_family = AF_NETLINK;
dest_addr.nl_pid = 0; /* For Linux Kernel */
dest_addr.nl_groups = 0; /* unicast */
nlh=(struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD));
/* Fill the netlink message header */
nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD);
nlh->nlmsg_pid = 1;//getpid(); /* self pid */
nlh->nlmsg_flags = 0;
iov.iov_base = (void *)nlh;
iov.iov_len = nlh->nlmsg_len;
memset(&msg,0,sizeof(msg));
msg.msg_name = (void *)&dest_addr;
msg.msg_namelen = sizeof(dest_addr);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
/* Read message from kernel */
memset(nlh, 0, NLMSG_SPACE(MAX_PAYLOAD));
while (1) {
len = recvmsg(sock_fd, &msg, 0);
if (len<0) {
// exit(-1);
} else {
printf("Received socket with length %d (nlmsg_len = %d)\n",len,nlh->nlmsg_len);
}
usleep(1000);
i=i+1;
if ((i % 100) == 0)
printf("%d\n",i);
/*
for (i=0;i<nlh->nlmsg_len - sizeof(struct nlmsghdr);i++) {
printf("%x ",
((unsigned char *)NLMSG_DATA(nlh))[i]);
}
*/
}
/* Close Netlink Socket */
}
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/*! \file classifier.c
* \brief Classify IP packets
* \author Navid Nikaein, Lionel GAUTHIER, Raymond knopp
* \company Eurecom
* \email: navid.nikaein@eurecom.fr, lionel.gauthier@eurecom.fr, knopp@eurecom.fr
*/
#include "local.h"
#include "proto_extern.h"
#include <net/ip6_fib.h>
#include <net/route.h>
//#define MPLS
#ifdef MPLS
#include <net/mpls.h>
#endif
//#define NAS_DEBUG_CLASS 1
//#define NAS_DEBUG_SEND 1
//---------------------------------------------------------------------------
// Add a new classifier rule (send direction)
struct classifier_entity *nas_CLASS_add_sclassifier(struct cx_entity *cx, uint8_t dscp, uint16_t classref) {
//---------------------------------------------------------------------------
struct classifier_entity *gc;
#ifdef NAS_DEBUG_CLASS
printk("NAS_CLASS_ADD_SCLASSIFIER: begin for dscp %d, classref %d\n", dscp,classref);
#endif
if (cx==NULL) {
#ifdef NAS_DEBUG_CLASS
printk("NAS_CLASS_ADD_SCLASSIFIER - input parameter cx is NULL \n");
#endif
return NULL;
}
for (gc=cx->sclassifier[dscp]; gc!=NULL; gc=gc->next) {
if (gc->classref==classref) {
#ifdef NAS_DEBUG_CLASS
printk("NAS_CLASS_ADD_SCLASSIFIER: classifier already exist for dscp %d, classref %d\n",dscp,classref);
#endif
return gc;
}
}
gc=(struct classifier_entity *)kmalloc(sizeof(struct classifier_entity), GFP_KERNEL);
if (gc==NULL)
return NULL;
gc->next=cx->sclassifier[dscp];
gc->classref=classref;
cx->sclassifier[dscp]=gc;
++cx->nsclassifier;
#ifdef NAS_DEBUG_CLASS
printk("NAS_CLASS_ADD_SCLASSIFIER: classifier created for dscp %d, classref %d\n",dscp,classref);
#endif
return gc;
}
//---------------------------------------------------------------------------
// Add a new classifier rule (receive direction)
struct classifier_entity *nas_CLASS_add_rclassifier(uint8_t dscp,
uint16_t classref,
struct nas_priv *gpriv) {
//---------------------------------------------------------------------------
struct classifier_entity *gc;
#ifdef NAS_DEBUG_CLASS
printk("NAS_CLASS_ADD_RCLASSIFIER: begin\n");
#endif
for (gc=gpriv->rclassifier[dscp]; gc!=NULL; gc=gc->next) {
if (gc->classref==classref) {
#ifdef NAS_DEBUG_CLASS
printk("NAS_CLASS_ADD_RCLASSIFIER: classifier already exist for dscp %d, classref %d\n",dscp,classref);
#endif
return gc;
}
}
gc=(struct classifier_entity *)kmalloc(sizeof(struct classifier_entity), GFP_KERNEL);
if (gc==NULL)
return NULL;
gc->next=gpriv->rclassifier[dscp];
gc->classref=classref;
gpriv->rclassifier[dscp]=gc;
++gpriv->nrclassifier;
#ifdef NAS_DEBUG_CLASS
printk("NAS_CLASS_ADD_RCLASSIFIER: classifier created for dscp %d, classref %d\n",dscp,classref);
#endif
return gc;
}
//---------------------------------------------------------------------------
// Add a new classifier rule (forwarding)
struct classifier_entity *nas_CLASS_add_fclassifier(struct cx_entity *cx, uint8_t dscp, uint16_t classref) {
//---------------------------------------------------------------------------
struct classifier_entity *gc;
#ifdef NAS_DEBUG_CLASS
printk("NAS_CLASS_ADD_FCLASSIFIER: begin for dscp %d, classref %d\n", dscp,classref);
#endif
if (cx==NULL) {
#ifdef NAS_DEBUG_CLASS
printk("NAS_CLASS_ADD_FCLASSIFIER - input parameter cx is NULL \n");
#endif
return NULL;
}
for (gc=cx->fclassifier[dscp]; gc!=NULL; gc=gc->next) {
if (gc->classref==classref) {
#ifdef NAS_DEBUG_CLASS
printk("NAS_CLASS_ADD_SCLASSIFIER: classifier already exist for dscp %d, classref %d\n",dscp,classref);
#endif
return gc;
}
}
gc=(struct classifier_entity *)kmalloc(sizeof(struct classifier_entity), GFP_KERNEL);
if (gc==NULL)
return NULL;
gc->next=cx->fclassifier[dscp];
gc->classref=classref;
cx->fclassifier[dscp]=gc;
++cx->nfclassifier;
#ifdef NAS_DEBUG_CLASS
printk("NAS_CLASS_ADD_FCLASSIFIER: classifier created for dscp %d, classref %d\n",dscp,classref);
#endif
return gc;
}
//---------------------------------------------------------------------------
void nas_CLASS_flush_sclassifier(struct cx_entity *cx) {
//---------------------------------------------------------------------------
uint8_t dscpi;
struct classifier_entity *gc;
#ifdef NAS_DEBUG_CLASS
printk("NAS_CLASS_FLUSH_SCLASSIFIER: begin\n");
#endif
if (cx==NULL) {
#ifdef NAS_DEBUG_CLASS
printk("NAS_CLASS_FLUSH_SCLASSIFIER - input parameter cx is NULL \n");
#endif
return;
}
//
for (dscpi=0; dscpi<NAS_DSCP_MAX; ++dscpi) {
for (gc=cx->sclassifier[dscpi]; gc!=NULL; gc=cx->sclassifier[dscpi]) {
cx->sclassifier[dscpi]=gc->next;
kfree(gc);
}
}
cx->nsclassifier=0;
#ifdef NAS_DEBUG_CLASS
printk("NAS_CLASS_FLUSH_SCLASSIFIER: end\n");
#endif
}
//---------------------------------------------------------------------------
void nas_CLASS_flush_fclassifier(struct cx_entity *cx) {
//---------------------------------------------------------------------------
uint8_t dscpi;
struct classifier_entity *gc;
#ifdef NAS_DEBUG_CLASS
printk("NAS_CLASS_FLUSH_FCLASSIFIER: begin\n");
#endif
if (cx==NULL) {
#ifdef NAS_DEBUG_CLASS
printk("NAS_CLASS_FLUSH_FCLASSIFIER - input parameter cx is NULL \n");
#endif
return;
}
//
for (dscpi=0; dscpi<NAS_DSCP_MAX; ++dscpi) {
for (gc=cx->fclassifier[dscpi]; gc!=NULL; gc=cx->fclassifier[dscpi]) {
cx->fclassifier[dscpi]=gc->next;
kfree(gc);
}
}
cx->nfclassifier=0;
#ifdef NAS_DEBUG_CLASS
printk("NAS_CLASS_FLUSH_FCLASSIFIER: end\n");
#endif
}
//---------------------------------------------------------------------------
void nas_CLASS_flush_rclassifier(struct nas_priv *gpriv) {
//---------------------------------------------------------------------------
uint8_t dscpi;
struct classifier_entity *gc;
#ifdef NAS_DEBUG_CLASS
printk("NAS_CLASS_FLUSH_RCLASSIFIER: begin\n");
#endif
for (dscpi=0; dscpi<NAS_DSCP_MAX; ++dscpi) {
for (gc=gpriv->rclassifier[dscpi]; gc!=NULL; gc=gpriv->rclassifier[dscpi]) {
gpriv->rclassifier[dscpi]=gc->next;
kfree(gc);
}
}
gpriv->nrclassifier=0;
#ifdef NAS_DEBUG_CLASS
printk("NAS_CLASS_FLUSH_RCLASSIFIER: end\n");
#endif
}
//---------------------------------------------------------------------------
// Delete a classifier rule (send direction)
void nas_CLASS_del_sclassifier(struct cx_entity *cx, uint8_t dscp, uint16_t classref) {
//---------------------------------------------------------------------------
struct classifier_entity *p,*np;
#ifdef NAS_DEBUG_CLASS
printk("NAS_CLASS_DEL_SCLASSIFIER: begin\n");
#endif
if (cx==NULL) {
#ifdef NAS_DEBUG_CLASS
printk("NAS_CLASS_DEL_SCLASSIFIER - input parameter cx is NULL \n");
#endif
return;
}
//
p=cx->sclassifier[dscp];
if (p==NULL)
return;
if (p->classref==classref) {
cx->sclassifier[dscp]=p->next;
kfree(p);
--cx->nsclassifier;
return;
}
for (np=p->next; np!=NULL; p=np) {
if (np->classref==classref) {
p->next=np->next;
kfree(np);
--cx->nsclassifier;
return;
}
}
#ifdef NAS_DEBUG_CLASS
printk("NAS_CLASS_DEL_SCLASSIFIER: end\n");
#endif
}
//---------------------------------------------------------------------------
// Delete a classifier rule (send direction)
void nas_CLASS_del_fclassifier(struct cx_entity *cx, uint8_t dscp, uint16_t classref) {
//---------------------------------------------------------------------------
struct classifier_entity *p,*np;
#ifdef NAS_DEBUG_CLASS
printk("NAS_CLASS_DEL_FCLASSIFIER: begin\n");
#endif
if (cx==NULL) {
#ifdef NAS_DEBUG_CLASS
printk("NAS_CLASS_DEL_FCLASSIFIER - input parameter cx is NULL \n");
#endif
return;
}
//
p=cx->fclassifier[dscp];
if (p==NULL)
return;
if (p->classref==classref) {
cx->fclassifier[dscp]=p->next;
kfree(p);
--cx->nfclassifier;
return;
}
for (np=p->next; np!=NULL; p=np) {
if (np->classref==classref) {
p->next=np->next;
kfree(np);
--cx->nfclassifier;
return;
}
}
#ifdef NAS_DEBUG_CLASS
printk("NAS_CLASS_DEL_FCLASSIFIER: end\n");
#endif
}
//---------------------------------------------------------------------------
// Delete a classifier rule (receive direction)
void nas_CLASS_del_rclassifier(uint8_t dscp, uint16_t classref,struct nas_priv *gpriv) {
//---------------------------------------------------------------------------
struct classifier_entity *p,*np;
#ifdef NAS_DEBUG_CLASS
printk("NAS_CLASS_DEL_RCLASSIFIER: begin\n");
#endif
p=gpriv->rclassifier[dscp];
if (p==NULL)
return;
if (p->classref==classref) {
gpriv->rclassifier[dscp]=p->next;
kfree(p);
--gpriv->nrclassifier;
return;
}
for (np=p->next; np!=NULL; p=np) {
if (np->classref==classref) {
p->next=np->next;
kfree(np);
--gpriv->nrclassifier;
return;
}
}
#ifdef NAS_DEBUG_CLASS
printk("NAS_CLASS_DEL_RCLASSIFIER: end\n");
#endif
}
//---------------------------------------------------------------------------
// Search the entity with the IPv6 address 'addr'
// Navid: the ipv6 classifier is not fully tested
struct cx_entity *nas_CLASS_cx6(struct sk_buff *skb,
unsigned char dscp,
struct nas_priv *gpriv,
int inst,
unsigned char *cx_searcher) {
//---------------------------------------------------------------------------
unsigned char cxi;
unsigned int *addr,*dst=NULL;
struct cx_entity *default_ip=NULL;
struct classifier_entity *p=NULL;
if (skb!=NULL) {
for (cxi=*cx_searcher; cxi<NAS_CX_MAX; cxi++) {
(*cx_searcher)++;
p = gpriv->cx[cxi].sclassifier[dscp];
while (p!=NULL) {
if (p->version == 6) { // verify that this is an IPv4 rule
if ((addr = (unsigned int *)(&(p->daddr.ipv6)))== NULL) {
printk("nas_CLASS_cx6: addr is null \n");
p = p->next;
continue;
}
#ifdef NAS_DEBUG_CLASS
printk("cx %d : %X,%X.%X,%X\n",cxi,addr[0],addr[1],addr[2],addr[3]);
#endif //NAS_DEBUG_CLASS
if ( (dst = &((struct iphdr *)(skb_network_header(skb)))->daddr) == NULL) {
printk("nas_CLASS_cx6: dst addr is null \n");
p = p->next;
continue;
}
if ((addr[0] == dst[0]) &&
(addr[1] == dst[1]) &&
(addr[2] == dst[2]) &&
(addr[3] == dst[3])) {
//#ifdef NAS_DEBUG_CLASS
printk("nas_CLASS_cx6: found cx %d: %X.%X.%X.%X\n",cxi,
dst[0],
dst[1],
dst[2],
dst[3]);
//#endif //NAS_DEBUG_CLASS
return gpriv->cx+cxi;
}
/*
else if ((addr[0]==NAS_DEFAULT_IPV6_ADDR0) &&
(addr[1]==NAS_DEFAULT_IPV6_ADDR1) &&
(addr[2]==NAS_DEFAULT_IPV6_ADDR2) &&
(addr[3]==NAS_DEFAULT_IPV6_ADDR3))
default_ip = gpriv->cx+cxi;
*/
}
// Go to next classifier entry for connection
p = p->next;
}
}
}
if (dst ) {
printk("nas_CLASS_cx6 NOT FOUND: %X.%X.%X.%X\n",
dst[0],
dst[1],
dst[2],
dst[3]);
}
return default_ip;
}
//---------------------------------------------------------------------------
// Search the entity with the IPv4 address 'addr'
struct cx_entity *nas_CLASS_cx4(struct sk_buff *skb,
unsigned char dscp,
struct nas_priv *gpriv,
int inst,
unsigned char *cx_searcher) {
//---------------------------------------------------------------------------
unsigned char cxi;
unsigned char *addr;
uint32_t daddr;
struct cx_entity *default_ip=NULL;
struct classifier_entity *p=NULL;
// if (inst >0)
// return(gpriv->cx); //dump to clusterhead
if (skb!=NULL) {
daddr = ((struct iphdr *)(skb_network_header(skb)))->daddr;
if (daddr!=0) {
#ifdef NAS_DEBUG_CLASS
printk("[NAS][CLASS][IPv4] Searching for %d.%d.%d.%d\n",
((unsigned char *)&daddr)[0],
((unsigned char *)&daddr)[1],
((unsigned char *)&daddr)[2],
((unsigned char *)&daddr)[3]);
#endif
for (cxi=*cx_searcher; cxi<NAS_CX_MAX; ++cxi) {
(*cx_searcher)++;
p = gpriv->cx[cxi].sclassifier[dscp];
while (p!=NULL) {
if (p->version == 4) { // verify that this is an IPv4 rule
#ifdef NAS_DEBUG_CLASS
addr = (char *)(&(p->daddr.ipv4));
printk("found classifier cx %d for destination: %d.%d.%d.%d\n",cxi,addr[0],addr[1],addr[2],addr[3]);
#endif //NAS_DEBUG_CLASS
if ((p->daddr.ipv4)== daddr) {
addr = (char *)(&(p->daddr.ipv4));
#ifdef NAS_DEBUG_CLASS
printk("found cx %d: %d.%d.%d.%d\n",cxi,
addr[0],
addr[1],
addr[2],
addr[3]);
#endif //NAS_DEBUG_CLASS
return gpriv->cx+cxi;
}
/*
else if (gpriv->cx[cxi].sclassifier[dscp]->daddr.ipv4==NAS_DEFAULT_IPV4_ADDR) {
#ifdef NAS_DEBUG_CLASS
printk("found default_ip rule\n");
#endif //NAS_DEBUG_CLASS
default_ip = gpriv->cx+cxi;
}
*/
}
// goto to next classification rule for the connection
p = p->next;
}
}
}
}
return default_ip;
}
#ifdef MPLS
//---------------------------------------------------------------------------
// Search the entity with the mpls label and given exp
struct cx_entity *nas_CLASS_MPLS(struct sk_buff *skb,
unsigned char exp,
struct nas_priv *gpriv,
int inst,
unsigned char *cx_searcher) {
//---------------------------------------------------------------------------
unsigned char cxi;
struct cx_entity *default_label=NULL;
struct classifier_entity *p=NULL;
// if (inst >0)
// return(gpriv->cx); //dump to clusterhead
#ifdef NAS_DEBUG_CLASS
printk("[NAS][CLASS][MPLS] Searching for label %d\n",MPLSCB(skb)->label);
#endif
for (cxi=*cx_searcher; cxi<NAS_CX_MAX; ++cxi) {
(*cx_searcher)++;
p = gpriv->cx[cxi].sclassifier[exp];
while (p!=NULL) {
if (p->version == NAS_MPLS_VERSION_CODE) { // verify that this is an MPLS rule
#ifdef NAS_DEBUG_CLASS
printk("cx %d : label %d\n",cxi,p->daddr.mpls_label);
#endif //NAS_DEBUG_CLASS
if (p->daddr.mpls_label==MPLSCB(skb)->label) {
#ifdef NAS_DEBUG_CLASS
printk("found cx %d: label %d, RB %d\n",cxi,
MPLSCB(skb)->label,
p->rab_id);
#endif //NAS_DEBUG_CLASS
return gpriv->cx+cxi;
}
/*
else if (gpriv->cx[cxi].sclassifier[dscp]->daddr.ipv4==NAS_DEFAULT_IPV4_ADDR) {
#ifdef NAS_DEBUG_CLASS
printk("found default_ip rule\n");
#endif //NAS_DEBUG_CLASS
default_ip = gpriv->cx+cxi;
}
*/
}
// goto to next classification rule for the connection
p = p->next;
}
}
return default_label;
}
#endif
//---------------------------------------------------------------------------
// Search the sending function
void nas_CLASS_send(struct sk_buff *skb,int inst) {
//---------------------------------------------------------------------------
struct classifier_entity *p, *sp;
uint8_t *protocolh,version;
uint8_t protocol, dscp /*, exp,label*/ ;
uint16_t classref;
struct cx_entity *cx;
//unsigned int i;
//unsigned int router_adv = 0;
struct net_device *dev=nasdev[inst];
struct nas_priv *gpriv=netdev_priv(dev);
unsigned char cx_searcher,no_connection=1;
#ifdef NAS_DEBUG_CLASS
printk("NAS_CLASS_SEND: begin - inst %d\n",inst);
#endif
if (skb==NULL) {
#ifdef NAS_DEBUG_SEND
printk("NAS_CLASS_SEND - input parameter skb is NULL \n");
#endif
return;
}
#ifdef NAS_DEBUG_SEND
printk("[NAS][CLASS][SEND] Got packet from kernel:\n");
for (int i=0; i<256; i++)
printk("%2x ",((unsigned char *)skb->data)[i]);
printk("\n");
#endif
// find all connections related to socket
cx_searcher = 0;
no_connection = 1;
//while (cx_searcher<NAS_CX_MAX) {
cx = NULL;
// Address classification
switch (ntohs(skb->protocol)) {
case ETH_P_IPV6:
version = 6;
protocolh=nas_TOOL_get_protocol6(
(struct ipv6hdr *)(skb_network_header(skb)),
&protocol);
dscp=nas_TOOL_get_dscp6(
(struct ipv6hdr *)(skb_network_header(skb))
);
#ifdef NAS_DEBUG_CLASS
printk("NAS_CLASS_SEND: %p %d %p %d %p \n",skb, dscp, gpriv, inst, &cx_searcher);
#endif
cx=nas_CLASS_cx6(skb,dscp,gpriv,inst,&cx_searcher);
#ifdef NAS_DEBUG_CLASS
printk("NAS_CLASS_SEND: Got IPv6 packet, dscp = %d\n",dscp);
#endif
break;
case ETH_P_IP:
dscp=nas_TOOL_get_dscp4((struct iphdr *)(skb_network_header(skb)));
cx=nas_CLASS_cx4(skb,dscp,gpriv,inst,&cx_searcher);
protocolh=nas_TOOL_get_protocol4(
(struct iphdr *)(skb_network_header(skb)),
&protocol);
#ifdef NAS_DEBUG_CLASS
printk("NAS_CLASS_SEND: Got IPv4 packet (%x), dscp = %d, cx = %x\n",ntohs(skb->protocol),dscp,cx);
#endif
version = 4;
break;
#ifdef MPLS
case ETH_P_MPLS_UC:
cx=nas_CLASS_MPLS(skb,MPLSCB(skb)->exp,gpriv,inst,&cx_searcher);
#ifdef NAS_DEBUG_CLASS
printk("NAS_CLASS_SEND: Got MPLS unicast packet, exp = %d, label = %d, cx = %x\n",MPLSCB(skb)->exp,MPLSCB(skb)->label,cx);
#endif
dscp = MPLSCB(skb)->exp;
version = NAS_MPLS_VERSION_CODE;
protocol = version;
break;
#endif
default:
printk("NAS_CLASS_SEND: Unknown protocol\n");
version = 0;
return;
}
// If a valid connection for the DSCP/EXP with destination address
// is found scan all protocol-based classification rules
if (cx) {
classref=0;
sp=NULL;
#ifdef NAS_DEBUG_CLASS
printk("[NAS][CLASSIFIER] DSCP/EXP %d : looking for classifier entry\n",dscp);
#endif
for (p=cx->sclassifier[dscp]; p!=NULL; p=p->next) {
#ifdef NAS_DEBUG_CLASS
printk("[NAS][CLASSIFIER] DSCP %d p->classref=%d,p->protocol=%d,p->version=%d\n",dscp,p->classref,p->protocol,p->version);
#endif
// Check if transport protocol/message match
/*
if ((p->protocol == protocol))
if ((protocol == NAS_PROTOCOL_ICMP6) && (version == 6))
if (p->protocol_message_type == (p->protocol_message_type )) {
printk("[GRAAL][CLASSIFIER] Router advertisement\n");
}
*/
// normal rule checks that network protocol version matches
if (p->version == version) {
sp=p;
classref=sp->classref;
break;
}
}
if (sp!=NULL) {
#ifdef NAS_DEBUG_CLASS
char sfct[10], sprotocol[10];
if (sp->fct==nas_COMMON_QOS_send)
strcpy(sfct, "qos");
if (sp->fct==nas_CTL_send)
strcpy(sfct, "ctl");
if (sp->fct==nas_COMMON_del_send)
strcpy(sfct, "del");
if (sp->fct==nas_mesh_DC_send_sig_data_request)
strcpy(sfct, "dc");
switch(protocol) {
case NAS_PROTOCOL_UDP:
strcpy(sprotocol, "udp");
printk("udp packet\n");
break;
case NAS_PROTOCOL_TCP:
strcpy(sprotocol, "tcp");
printk("tcp packet\n");
break;
case NAS_PROTOCOL_ICMP4:
strcpy(sprotocol, "icmp4");
printk("icmp4 packet\n");
break;
case NAS_PROTOCOL_ICMP6:
strcpy(sprotocol, "icmp6");
print_TOOL_pk_icmp6((struct icmp6hdr *)protocolh);
break;
#ifdef MPLS
case NAS_MPLS_VERSION_CODE:
strcpy(sprotocol,"mpls");
break;
#endif
}
printk("NAS_CLASS_SEND: (dscp %u, %s) received, (classref %u, fct %s, rab_id %u) classifier rule\n",
dscp, sprotocol, sp->classref, sfct, sp->rab_id);
#endif
sp->fct(skb, cx, sp,inst, NULL);
} // if classifier entry match found
else {
printk("NAS_CLASS_SEND: no corresponding item in the classifier, so the message is dropped\n");
// nas_COMMON_del_send(skb, cx, NULL,inst);
}
no_connection = 0;
} // if connection found
#ifdef NAS_DEBUG_CLASS
if (no_connection == 1)
printk("NAS_CLASS_SEND: no corresponding connection, so the message is dropped\n");
#endif /* NAS_DEBUG_CLASS */
// } // while loop over connections
#ifdef NAS_DEBUG_CLASS
printk("NAS_CLASS_SEND: end\n");
#endif
}
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/*! \file common.c
* \brief implementation of emultor tx and rx
* \author Navid Nikaein, Lionel GAUTHIER, and Raymomd Knopp
* \date 2011
* \version 1.0
* \company Eurecom
* \email: navid.nikaein@eurecom.fr, lionel.gauthier@eurecom.fr
*/
#include "local.h"
#include "proto_extern.h"
//#define NAS_DEBUG_RECEIVE 1
//#define NAS_DEBUG_SEND 1
//#define NAS_DEBUG_CLASS 1
//#define NAS_ADDRESS_FIX 1
#include <linux/inetdevice.h>
#include <net/tcp.h>
#include <net/udp.h>
void nas_COMMON_receive(uint16_t dlen,
void *pdcp_sdu,
int inst,
struct classifier_entity *rclass,
nasRadioBearerId_t rb_id)
{
//---------------------------------------------------------------------------
struct sk_buff *skb;
struct ipversion *ipv;
struct nas_priv *gpriv=netdev_priv(nasdev[inst]);
//int i;
unsigned char protocol;
//struct udphdr *uh;
//struct tcphdr *th;
struct iphdr *network_header;
#ifdef NAS_DEBUG_RECEIVE
printk("NAS_COMMON_RECEIVE: begin RB %d Inst %d Length %d bytes\n",rb_id,inst,dlen);
#endif
skb = dev_alloc_skb( dlen + 2 );
if(!skb) {
printk("NAS_COMMON_RECEIVE: low on memory\n");
++gpriv->stats.rx_dropped;
return;
}
skb_reserve(skb,2);
memcpy(skb_put(skb, dlen), pdcp_sdu,dlen);
skb->dev = nasdev[inst];
skb_reset_mac_header(skb);
//printk("[NAC_COMMIN_RECEIVE]: Packet Type %d (%d,%d)",skb->pkt_type,PACKET_HOST,PACKET_BROADCAST);
skb->pkt_type = PACKET_HOST;
if (rclass->version != NAS_MPLS_VERSION_CODE) { // This is an IP packet
skb->ip_summed = CHECKSUM_NONE;
ipv = (struct ipversion *)skb->data;
switch (ipv->version) {
case 6:
#ifdef NAS_DEBUG_RECEIVE
printk("NAS_COMMON_RECEIVE: receive IPv6 message\n");
#endif
skb_reset_network_header(skb);
skb->protocol = htons(ETH_P_IPV6);
// printk("Writing packet with protocol %x\n",ntohs(skb->protocol));
break;
case 4:
#ifdef NAS_ADDRESS_FIX
// Make the third byte of both the source and destination equal to the fourth of the destination
unsigned char * ifaddr, *saddr, daddr;
uint32_t odaddr = 0, osaddr;
daddr = (unsigned char *)&((struct iphdr *)skb->data)->daddr;
odaddr = ((struct iphdr *)skb->data)->daddr;
//sn = addr[3];
saddr = (unsigned char *)&((struct iphdr *)skb->data)->saddr;
osaddr = ((struct iphdr *)skb->data)->saddr;
if (daddr[0] == saddr[0]) {// same network
daddr[2] = daddr[3]; // set third byte of destination to that of local machine so that local IP stack accepts the packet
saddr[2] = daddr[3]; // set third byte of source to that of local machine so that local IP stack accepts the packet
} else { // get the 3rd byte from device address in net_device structure
ifaddr = (unsigned char *)(&(((struct in_device *)((nasdev[inst])->ip_ptr))->ifa_list->ifa_local));
if (saddr[0] == ifaddr[0]) { // source is in same network as local machine
daddr[0] += saddr[3]; // fix address of remote destination to undo change at source
saddr[2] = ifaddr[2]; // set third byte to that of local machine so that local IP stack accepts the packet
} else { // source is remote machine from outside network
saddr[0] -= daddr[3]; // fix address of remote source to be understood by destination
daddr[2] = daddr[3]; // fix 3rd byte of local address to be understood by IP stack of
// destination
}
}
#endif //NAS_ADDRESS_FIX
#ifdef NAS_DEBUG_RECEIVE
// printk("NAS_TOOL_RECEIVE: receive IPv4 message\n");
addr = (unsigned char *)&((struct iphdr *)skb->data)->saddr;
if (addr) {
// addr[2]^=0x01;
printk("[NAS][COMMON][RECEIVE] Source %d.%d.%d.%d\n",addr[0],addr[1],addr[2],addr[3]);
}
addr = (unsigned char *)&((struct iphdr *)skb->data)->daddr;
if (addr) {
// addr[2]^=0x01;
printk("[NAS][COMMON][RECEIVE] Dest %d.%d.%d.%d\n",addr[0],addr[1],addr[2],addr[3]);
}
printk("[NAS][COMMON][RECEIVE] protocol %d\n",((struct iphdr *)skb->data)->protocol);
#endif
skb_reset_network_header(skb);
network_header = (struct iphdr *)skb_network_header(skb);
protocol = network_header->protocol;
#ifdef NAS_DEBUG_RECEIVE
switch (protocol) {
case IPPROTO_IP:
printk("[NAS][COMMON][RECEIVE] Received Raw IPv4 packet\n");
break;
case IPPROTO_IPV6:
printk("[NAS][COMMON][RECEIVE] Received Raw IPv6 packet\n");
break;
case IPPROTO_ICMP:
printk("[NAS][COMMON][RECEIVE] Received Raw ICMP packet\n");
break;
case IPPROTO_TCP:
printk("[NAS][COMMON][RECEIVE] Received TCP packet\n");
break;
case IPPROTO_UDP:
printk("[NAS][COMMON][RECEIVE] Received UDP packet\n");
break;
default:
break;
}
#endif
#ifdef NAS_ADDRESS_FIX
#ifdef NAS_DEBUG_RECEIVE
printk("NAS_COMMON_RECEIVE: dumping the packet before the csum recalculation (len %d)\n",skb->len);
for (i=0; i<skb->len; i++)
printk("%2x ",((unsigned char *)(skb->data))[i]);
printk("\n");
#endif //NAS_DEBUG_RECEIVE
network_header->check = 0;
network_header->check = ip_fast_csum((unsigned char *) network_header,
network_header->ihl);
#ifdef NAS_DEBUG_RECEIVE
printk("[NAS][COMMON][RECEIVE] IP Fast Checksum %x \n", network_header->check);
#endif
// if (!(skb->nh.iph->frag_off & htons(IP_OFFSET))) {
switch(protocol) {
case IPPROTO_TCP:
uint16_t *cksum,check;
cksum = (uint16_t*)&(((struct tcphdr*)(((char *)network_header + (network_header->ihl<<2))))->check);
//check = csum_tcpudp_magic(((struct iphdr *)network_header)->saddr, ((struct iphdr *)network_header)->daddr, tcp_hdrlen(skb), IPPROTO_TCP, ~(*cksum));
#ifdef NAS_DEBUG_RECEIVE
printk("[NAS][COMMON] Inst %d TCP packet calculated CS %x, CS = %x (before), SA (%x)%x, DA (%x)%x\n",
inst,
network_header->check,
*cksum,
osaddr,
((struct iphdr *)skb->data)->saddr,
odaddr,
((struct iphdr *)skb->data)->daddr);
#endif
check = csum_tcpudp_magic(((struct iphdr *)skb->data)->saddr, ((struct iphdr *)skb->data)->daddr,0,0, ~(*cksum));
*cksum = csum_tcpudp_magic(~osaddr, ~odaddr, 0, 0, ~check);
#ifdef NAS_DEBUG_RECEIVE
printk("[NAS][COMMON] Inst %d TCP packet NEW CS %x\n",
inst,
*cksum);
#endif
break;
case IPPROTO_UDP:
cksum = (uint16_t*)&(((struct udphdr*)(((char *)network_header + (network_header->ihl<<2))))->check);
// check = csum_tcpudp_magic(((struct iphdr *)network_header)->saddr, ((struct iphdr *)network_header)->daddr, udp_hdr(skb)->len, IPPROTO_UDP, ~(*cksum));
#ifdef NAS_DEBUG_RECEIVE
printk("[NAS][COMMON] Inst %d UDP packet CS = %x (before), SA (%x)%x, DA (%x)%x\n",
inst,
*cksum,
osaddr,
((struct iphdr *)skb->data)->saddr,
odaddr,
((struct iphdr *)skb->data)->daddr);
#endif
check = csum_tcpudp_magic(((struct iphdr *)skb->data)->saddr, ((struct iphdr *)skb->data)->daddr, 0,0, ~(*cksum));
*cksum= csum_tcpudp_magic(~osaddr, ~odaddr,0,0, ~check);
//*cksum= csum_tcpudp_magic(~osaddr, ~odaddr,udp_hdr(skb)->len, IPPROTO_UDP, ~check);
#ifdef NAS_DEBUG_RECEIVE
printk("[NAS][COMMON] Inst %d UDP packet NEW CS %x\n",
inst,
*cksum);
#endif
// if ((check = *cksum) != 0) {
// src, dst, len, proto, sum
// }
break;
default:
break;
}
// }
#endif //NAS_ADDRESS_FIX
skb->protocol = htons(ETH_P_IP);
// printk("[NAS][COMMON] Writing packet with protocol %x\n",ntohs(skb->protocol));
break;
default:
printk("NAS_COMMON_RECEIVE: begin RB %d Inst %d Length %d bytes\n",rb_id,inst,dlen);
printk("[NAS][COMMON] Inst %d: receive unknown message (version=%d)\n",inst,ipv->version);
}
} else { // This is an MPLS packet
#ifdef NAS_DEBUG_RECEIVE
printk("NAS_COMMON_RECEIVE: Received an MPLS packet on RB %d\n",rb_id);
#endif
skb->protocol = htons(ETH_P_MPLS_UC);
}
++gpriv->stats.rx_packets;
gpriv->stats.rx_bytes += dlen;
#ifdef NAS_DEBUG_RECEIVE
printk("NAS_COMMON_RECEIVE: sending packet of size %d to kernel\n",skb->len);
for (i=0; i<skb->len; i++)
printk("%2x ",((unsigned char *)(skb->data))[i]);
printk("\n");
#endif //NAS_DEBUG_RECEIVE
netif_rx_ni(skb);
#ifdef NAS_DEBUG_RECEIVE
printk("NAS_COMMON_RECEIVE: end\n");
#endif
}
//---------------------------------------------------------------------------
// Delete the data
void nas_COMMON_del_send(struct sk_buff *skb, struct cx_entity *cx, struct classifier_entity *sp,int inst,struct nas_priv *gpriv)
{
struct nas_priv *priv=netdev_priv(nasdev[inst]);
//---------------------------------------------------------------------------
++priv->stats.tx_dropped;
}
//---------------------------------------------------------------------------
// Request the transfer of data (QoS SAP)
void nas_COMMON_QOS_send(struct sk_buff *skb, struct cx_entity *cx, struct classifier_entity *gc,int inst, struct nas_priv *gpriv)
{
//---------------------------------------------------------------------------
struct pdcp_data_req_header_s pdcph;
struct nas_priv *priv=netdev_priv(nasdev[inst]);
#ifdef LOOPBACK_TEST
int i;
#endif
unsigned int bytes_wrote;
//unsigned char j;
// Start debug information
#ifdef NAS_DEBUG_SEND
printk("NAS_COMMON_QOS_SEND - inst %d begin \n",inst);
#endif
// if (cx->state!=NAS_STATE_CONNECTED) // <--- A REVOIR
// {
// priv->stats.tx_dropped ++;
// printk("NAS_QOS_SEND: No connected, so message are dropped \n");
// return;
// }
if (skb==NULL) {
#ifdef NAS_DEBUG_SEND
printk("NAS_COMMON_QOS_SEND - input parameter skb is NULL \n");
#endif
return;
}
if (gc==NULL) {
#ifdef NAS_DEBUG_SEND
printk("NAS_COMMON_QOS_SEND - input parameter gc is NULL \n");
#endif
return;
}
if (cx==NULL) {
#ifdef NAS_DEBUG_SEND
printk("NAS_COMMON_QOS_SEND - input parameter cx is NULL \n");
#endif
return;
}
// End debug information
if (gc->rb==NULL) {
gc->rb=nas_COMMON_search_rb(cx, gc->rab_id);
if (gc->rb==NULL) {
++priv->stats.tx_dropped;
printk("NAS_COMMON_QOS_SEND: No corresponding Radio Bearer, so message are dropped, rab_id=%u \n", gc->rab_id);
return;
}
}
#ifdef NAS_DEBUG_SEND
printk("NAS_COMMON_QOS_SEND #1 :");
printk("lcr %u, rab_id %u, rab_id %u, skb_len %d\n", cx->lcr, (gc->rb)->rab_id, gc->rab_id,skb->len);
nas_print_classifier(gc);
#endif
pdcph.data_size = skb->len;
pdcph.rb_id = (gc->rb)->rab_id;
pdcph.inst = inst;
pdcph.sourceL2Id = 0;
pdcph.destinationL2Id = 0;
bytes_wrote = nas_netlink_send((char *)&pdcph,NAS_PDCPH_SIZE);
#ifdef NAS_DEBUG_SEND
printk("[NAS] Wrote %d bytes (header for %d byte skb) to PDCP via netlink\n",
bytes_wrote,skb->len);
#endif
if (bytes_wrote != NAS_PDCPH_SIZE) {
printk("NAS_COMMON_QOS_SEND: problem while writing PDCP's header (bytes wrote = %d )\n",bytes_wrote);
printk("rb_id %ld, Wrote %d, Header Size %lu\n", pdcph.rb_id , bytes_wrote, NAS_PDCPH_SIZE);
return;
}
bytes_wrote += nas_netlink_send((char *)skb->data,skb->len);
if (bytes_wrote != skb->len+NAS_PDCPH_SIZE) {
printk("NAS_COMMON_QOS_SEND: Inst %d, RB_ID %ld: problem while writing PDCP's data, bytes_wrote = %d, Data_len %d, PDCPH_SIZE %lu\n",
inst,
pdcph.rb_id,
bytes_wrote,
skb->len,
NAS_PDCPH_SIZE); // congestion
return;
}
#ifdef NAS_DEBUG_SEND
printk("NAS_SEND: Sending packet of size %d to PDCP \n",skb->len);
for (j=0; j<skb->len; j++)
printk("%2x ",((unsigned char *)(skb->data))[j]);
printk("\n");
#endif
priv->stats.tx_bytes += skb->len;
priv->stats.tx_packets ++;
#ifdef NAS_DEBUG_SEND
printk("NAS_COMMON_QOS_SEND - end \n");
#endif
}
void nas_COMMON_QOS_receive(struct nlmsghdr *nlh)
{
struct pdcp_data_ind_header_s *pdcph = (struct pdcp_data_ind_header_s *)NLMSG_DATA(nlh);
struct classifier_entity *rclass;
struct nas_priv *priv;
priv = netdev_priv(nasdev[pdcph->inst]);
#ifdef NAS_DEBUG_RECEIVE
printk("[NAS][COMMON][NETLINK] QOS receive from PDCP, size %d, rab %d, inst %d\n",
pdcph->data_size,pdcph->rb_id,pdcph->inst);
#endif //NAS_DEBUG_RECEIVE
rclass = nas_COMMON_search_class_for_rb(pdcph->rb_id,priv);
if (rclass) {
#ifdef NAS_DEBUG_RECEIVE
printk("[NAS][COMMON][NETLINK] Found corresponding connection in classifier for RAB\n");
#endif //NAS_DEBUG_RECEIVE
nas_COMMON_receive(pdcph->data_size,
(unsigned char *)NLMSG_DATA(nlh) + NAS_PDCPH_SIZE,
pdcph->inst,
rclass,
pdcph->rb_id);
}
}
//---------------------------------------------------------------------------
struct cx_entity *nas_COMMON_search_cx(nasLocalConnectionRef_t lcr,struct nas_priv *priv)
{
//---------------------------------------------------------------------------
#ifdef NAS_DEBUG_CLASS
printk("NAS_COMMON_SEARCH_CX - lcr %d\n",lcr);
#endif
if (lcr<NAS_CX_MAX)
return priv->cx+lcr;
else
return NULL;
}
//---------------------------------------------------------------------------
// Search a Radio Bearer
struct rb_entity *nas_COMMON_search_rb(struct cx_entity *cx, nasRadioBearerId_t rab_id)
{
//---------------------------------------------------------------------------
struct rb_entity *rb;
#ifdef NAS_DEBUG_CLASS
printk("NAS_COMMON_SEARCH_RB - rab_id %d\n", rab_id);
#endif
for (rb=cx->rb; rb!=NULL; rb=rb->next) {
#ifdef NAS_DEBUG_CLASS
printk("SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS\n");
printk("NAS_COMMON_SEARCH_RB - rab_id %d Comparing rb_entity.rab_id %u \n", rb->rab_id, rab_id);
//printk("NAS_COMMON_SEARCH_RB - rab_id %d Comparing rb_entity.sapi %u \n", rb->sapi);
//printk("NAS_COMMON_SEARCH_RB - rab_id %d Comparing rb_entity.qos %u \n", rb->qos);
//printk("NAS_COMMON_SEARCH_RB - rab_id %d Comparing rb_entity.state %u \n", rb->state);
//printk("NAS_COMMON_SEARCH_RB - rab_id %d Comparing rb_entity.retry %u \n", rb->retry);
//printk("NAS_COMMON_SEARCH_RB - rab_id %d Comparing rb_entity.countimer %u \n\n", rb->countimer);
#endif
if (rb->rab_id==rab_id)
return rb;
}
return NULL;
}
//
// Search for a classifier with corresponding radio bearer
struct classifier_entity *nas_COMMON_search_class_for_rb(nasRadioBearerId_t rab_id,struct nas_priv *priv)
{
//struct rb_entity *rb;
int dscp;
struct classifier_entity *rclass;
#ifdef NAS_DEBUG_CLASS
printk("[NAS][COMMON] NAS_COMMON_SEARCH_CLASS_FOR_RB - rab_id %d\n", rab_id);
#endif
for (dscp=0; dscp<NAS_DSCP_MAX; dscp++) {
// printk("[NAS][COMMON] priv->rclassifier[%d] = %p\n",dscp,priv->rclassifier[dscp]);
for (rclass=priv->rclassifier[dscp]; rclass!=NULL; rclass=rclass->next) {
#ifdef NAS_DEBUG_CLASS
printk("[NAS][COMMON] NAS_COMMON_SEARCH_CLASS_FOR_RB - dscp %d, rb %d\n", dscp,rclass->rab_id);
#endif
if (rclass->rab_id==rab_id)
return rclass;
}
}
return NULL;
}
//---------------------------------------------------------------------------
struct rb_entity *nas_COMMON_add_rb(struct cx_entity *cx, nasRadioBearerId_t rab_id, nasQoSTrafficClass_t qos)
{
//--------------------------------------------------------------------------
struct rb_entity *rb;
#ifdef NAS_DEBUG_CLASS
printk("NAS_COMMON_ADD_RB - begin for rab_id %d , qos %d\n", rab_id, qos );
#endif
if (cx==NULL) {
#ifdef NAS_DEBUG_CLASS
printk("NAS_COMMON_ADD_RB - input parameter cx is NULL \n");
#endif
return NULL;
}
rb=nas_COMMON_search_rb(cx, rab_id);
if (rb==NULL) {
rb=(struct rb_entity *)kmalloc(sizeof(struct rb_entity), GFP_KERNEL);
if (rb!=NULL) {
rb->retry=0;
rb->countimer=NAS_TIMER_IDLE;
rb->rab_id=rab_id;
// rb->rab_id=rab_id+(32*cx->lcr);
#ifdef NAS_DEBUG_DC
printk("NAS_COMMON_ADD_RB: rab_id=%u, mt_id=%u\n",rb->rab_id, cx->lcr);
#endif
rb->qos=qos;
rb->sapi=NAS_RAB_INPUT_SAPI;
rb->state=NAS_IDLE;
rb->next=cx->rb;
cx->rb=rb;
++cx->num_rb;
} else
printk("NAS_ADD_CTL_RB: no memory\n");
}
#ifdef NAS_DEBUG_CLASS
printk("NAS_COMMON_ADD_RB - end \n" );
#endif
return rb;
}
//---------------------------------------------------------------------------
void nas_COMMON_flush_rb(struct cx_entity *cx)
{
//---------------------------------------------------------------------------
struct rb_entity *rb;
struct classifier_entity *gc;
uint8_t dscp;
// End debug information
#ifdef NAS_DEBUG_CLASS
printk("NAS_COMMON_FLUSH_RB - begin\n");
#endif
if (cx==NULL) {
#ifdef NAS_DEBUG_CLASS
printk("NAS_COMMON_FLUSH_RB - input parameter cx is NULL \n");
#endif
return;
}
// End debug information
for (rb=cx->rb; rb!=NULL; rb=cx->rb) {
printk("NAS_COMMON_FLUSH_RB: del rab_id %u\n", rb->rab_id);
cx->rb=rb->next;
kfree(rb);
}
cx->num_rb=0;
cx->rb=NULL;
for(dscp=0; dscp<NAS_DSCP_MAX; ++dscp) {
for (gc=cx->sclassifier[dscp]; gc!=NULL; gc=gc->next)
gc->rb=NULL;
}
#ifdef NAS_DEBUG_CLASS
printk("NAS_COMMON_FLUSH_RB - end\n");
#endif
}
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#ifndef _NAS_CST
#define _NAS_CST
#define MAX_MEASURE_NB 5
#define NAS_MAX_LENGTH 180
//Debug flags
//#define NAS_DEBUG_DC
//#define NAS_DEBUG_SEND
//#define NAS_DEBUG_RECEIVE
//#define NAS_DEBUG_CLASS
//#define NAS_DEBUG_GC
//#define NAS_DEBUG_DC_MEASURE
//#define NAS_DEBUG_TIMER
//#define NAS_DEBUG_DEVICE
//#define NAS_DEBUG_INTERRUPT
//#define NAS_DEBUG_TOOL
// Other flags
#define DEMO_3GSM
// General Constants
#define NAS_MTU 1500
#define NAS_TX_QUEUE_LEN 100
#define NAS_ADDR_LEN 8
#define NAS_INET6_ADDRSTRLEN 46
#define NAS_INET_ADDRSTRLEN 16
#define NAS_CX_MAX 32 //128 //Identical to RRC constant: no you cannot
/* increase to 128 without risking stack problems: KEEP ATTENTION TO COMPILATION WARNINGS */
//#define NAS_CX_MULTICAST_ALLNODE 2
#define NAS_RETRY_LIMIT_DEFAULT 5
#define NAS_MESSAGE_MAXLEN 5004
#define NAS_SIG_SRB3 3
#define NAS_SIG_SRB4 3 // not used yet
//peer-to-peer messages between NAS entities
#define NAS_CMD_OPEN_RB 1
//#define NAS_IID1_CONTROL 0x0
//#define NAS_IID2_CONTROL __constant_htonl(0xffffffff)
//#define NAS_STATE_IDLE 0
//#define NAS_STATE_CONNECTED 1
//#define NAS_STATE_ESTABLISHMENT_REQUEST 2
//#define NAS_STATE_ESTABLISHMENT_FAILURE 3
//#define NAS_STATE_RELEASE_FAILURE 4
#define NAS_CX_RELEASE_UNDEF_CAUSE 1
// MT+RG NAS States
#define NAS_IDLE 0x01
// Connection
#define NAS_CX_FACH 0x06
#define NAS_CX_DCH 0x0A
#define NAS_CX_RECEIVED 0x10
#define NAS_CX_CONNECTING 0x04
#define NAS_CX_RELEASING 0x08
#define NAS_CX_CONNECTING_FAILURE 0x14
#define NAS_CX_RELEASING_FAILURE 0x18
// Radio Bearers
#define NAS_RB_ESTABLISHING 0x24
#define NAS_RB_RELEASING 0x28
#define NAS_RB_DCH 0x2A
#define NAS_TIMER_ESTABLISHMENT_DEFAULT 12
#define NAS_TIMER_RELEASE_DEFAULT 2
#define NAS_TIMER_IDLE UINT_MAX
#define NAS_TIMER_TICK HZ
#define NAS_PDCPH_SIZE sizeof(struct pdcp_data_req_header_s)
#define NAS_IPV4_SIZE 20
#define NAS_IPV6_SIZE 40
#define NAS_DIRECTION_SEND 0
#define NAS_DIRECTION_RECEIVE 1
#define NAS_DIRECTION_FORWARD 2
// function number
#define NAS_FCT_DEL_SEND 1
#define NAS_FCT_QOS_SEND 2
#define NAS_FCT_DC_SEND 3
#define NAS_FCT_CTL_SEND 4
// type of IOCTL command
#define NAS_IOCTL_RRM 0x89F0
// Error cause
#define NAS_ERROR_ALREADYEXIST 1
#define NAS_ERROR_NOMEMORY 3
#define NAS_ERROR_NOTMT 9
#define NAS_ERROR_NOTRG 10
#define NAS_ERROR_NOTIDLE 11
#define NAS_ERROR_NOTCONNECTED 12
#define NAS_ERROR_NORB 14
#define NAS_ERROR_NOTCORRECTVALUE 32
#define NAS_ERROR_NOTCORRECTLCR 33
#define NAS_ERROR_NOTCORRECTDIR 34
#define NAS_ERROR_NOTCORRECTDSCP 35
#define NAS_ERROR_NOTCORRECTVERSION 36
#define NAS_ERROR_NOTCORRECTRABI 37
/**********************************************************/
/* Constants related with IP protocols */
/**********************************************************/
//#define NAS_PORT_CONTROL __constant_htons(0xc45)
//#define NAS_PORT_AUTHENTICATION __constant_htons(1811)
#define NAS_TRAFFICCLASS_MASK __constant_htonl(0x0fc00000)
// Network control codepoint 111000 + IP version 6
#define NAS_FLOWINFO_NCONTROL __constant_htonl(0x6e000000)
// network control codepoint 111000
#define NAS_DSCP_NCONTROL 56 //0x38
// default codepoint 1000000
#define NAS_DSCP_DEFAULT 64
#define NAS_DSCP_MAX 193
#define NAS_PROTOCOL_DEFAULT 0
#define NAS_PROTOCOL_TCP IPPROTO_TCP
#define NAS_PROTOCOL_UDP IPPROTO_UDP
#define NAS_PROTOCOL_ICMP4 IPPROTO_ICMP
#define NAS_PROTOCOL_ICMP6 IPPROTO_ICMPV6
#define NAS_PORT_DEFAULT __constant_htons(65535)
#define NAS_PORT_HTTP __constant_htons(80)
#define NAS_VERSION_DEFAULT 0
#define NAS_VERSION_4 4
#define NAS_VERSION_6 0 //?MW
#define NAS_DEFAULT_IPV4_ADDR 0
#define NAS_DEFAULT_IPV6_ADDR0 0
#define NAS_DEFAULT_IPV6_ADDR1 0
#define NAS_DEFAULT_IPV6_ADDR2 0
#define NAS_DEFAULT_IPV6_ADDR3 0
#define NAS_MPLS_VERSION_CODE 99
#define NB_INSTANCES_MAX 64 //16
#endif
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/*! \file device.c
* \brief Networking Device Driver for OpenAirInterface MESH
* \author navid.nikaein, yan.moret(no longer valid), michelle.wetterwald, raymond.knopp
* \company Eurecom
* \email: raymond.knopp@eurecom.fr, navid.nikaein@eurecom.fr, michelle.wetterwald@eurecom.fr,
*/
/*******************************************************************************/
#include "constant.h"
#include "local.h"
#include "proto_extern.h"
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/version.h>
#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/moduleparam.h>
#include <asm/io.h>
#include <asm/bitops.h>
#include <asm/uaccess.h>
#include <asm/segment.h>
#include <asm/page.h>
#include <asm/delay.h>
#include <asm/unistd.h>
//#define DEBUG_DEVICE 1
//#define DEBUG_INTERRUPT 1
struct net_device *nasdev[NB_INSTANCES_MAX];
extern void nas_netlink_release(void);
extern int nas_netlink_init(void);
//int bytes_wrote;
//int bytes_read;
uint8_t NULL_IMEI[14]= {0x05, 0x04, 0x03, 0x01, 0x02 ,0x00, 0x00, 0x00, 0x05, 0x04, 0x03 ,0x00, 0x01, 0x08};
static unsigned int nas_IMEI[6]= {0x03, 0x01, 0x02 ,0x00, 0x00, 0x00}; // may change to char
static int m_arg=0;
static unsigned int nas_is_clusterhead=0;
int find_inst(struct net_device *dev)
{
int i;
for (i=0; i<NB_INSTANCES_MAX; i++)
if (nasdev[i] == dev)
return(i);
return(-1);
}
//---------------------------------------------------------------------------
// Called by ifconfig when the device is activated by ifconfig
int nas_open(struct net_device *dev)
{
//---------------------------------------------------------------------------
printk("OPEN: begin\n");
// MOD_INC_USE_COUNT;
// Address has already been set at init
/*
netif_start_queue(dev);
//
init_timer(&priv->timer);
(priv->timer).expires=jiffies+NAS_TIMER_TICK;
(priv->timer).data=0L;
(priv->timer).function=nas_mesh_timer;
// add_timer(&priv->timer);
//
*/
printk("OPEN: name = %s, end\n", dev->name);
return 0;
}
//---------------------------------------------------------------------------
// Called by ifconfig when the device is desactivated
int nas_stop(struct net_device *dev)
{
//---------------------------------------------------------------------------
struct nas_priv *priv = netdev_priv(dev);
printk("STOP: begin\n");
del_timer(&(priv->timer));
netif_stop_queue(dev);
// MOD_DEC_USE_COUNT;
printk("STOP: name = %s, end\n", dev->name);
return 0;
}
//---------------------------------------------------------------------------
void nas_teardown(struct net_device *dev)
{
//---------------------------------------------------------------------------
int cxi;
struct nas_priv *priv;
int inst;
if (dev) {
priv = netdev_priv(dev);
inst = find_inst(dev);
if (inst<0) {
printk("nas_teardown: ERROR, couldn't find instance\n");
}
printk("nas_teardown instance %d: begin\n",inst);
nas_CLASS_flush_rclassifier(priv);
for (cxi=0; cxi<NAS_CX_MAX; cxi++) {
nas_COMMON_flush_rb(priv->cx+cxi);
nas_CLASS_flush_sclassifier(priv->cx+cxi);
}
printk("nas_teardown: end\n");
} // check dev
else {
printk("nas_teardown: Device is null\n");
}
}
//---------------------------------------------------------------------------
int nas_set_config(struct net_device *dev, struct ifmap *map)
{
//---------------------------------------------------------------------------
printk("SET_CONFIG: begin\n");
if (dev->flags & IFF_UP)
return -EBUSY;
if (map->base_addr != dev->base_addr) {
printk(KERN_WARNING "SET_CONFIG: Can't change I/O address\n");
return -EOPNOTSUPP;
}
if (map->irq != dev->irq)
dev->irq = map->irq;
return 0;
}
//---------------------------------------------------------------------------
//
int nas_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
//---------------------------------------------------------------------------
// Start debug information
int inst;
if (dev)
inst = find_inst(dev);
else {
printk("nas_hard_start_xmit: ERROR, device is null\n");
return -1;
}
if (inst>=0) {
#ifdef DEBUG_DEVICE
printk("HARD_START_XMIT: inst %d, begin\n",inst);
#endif
if (!skb) {
printk("HARD_START_XMIT - input parameter skb is NULL \n");
return -1;
}
// End debug information
netif_stop_queue(dev);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,7,0) \
|| (defined RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= 1796 && RHEL_RELEASE_CODE != 2403)
netif_trans_update(dev);
#else
dev->trans_start = jiffies;
#endif
#ifdef DEBUG_DEVICE
printk("HARD_START_XMIT: step 1\n");
#endif
nas_CLASS_send(skb,inst);
#ifdef DEBUG_DEVICE
printk("HARD_START_XMIT: step 2\n");
#endif
// if (skb==NULL){
// printk("HARD_START_XMIT - parameter skb is NULL \n");
// return -1;
// }else
dev_kfree_skb(skb);
#ifdef DEBUG_DEVICE
printk("HARD_START_XMIT: step 3\n");
#endif
netif_wake_queue(dev);
#ifdef DEBUG_DEVICE
printk("HARD_START_XMIT: end\n");
#endif
} else {
printk("nas_hard_start_xmit: ERROR, couldn't find instnace\n");
return(-1);
}
return 0;
}
//---------------------------------------------------------------------------
struct net_device_stats *nas_get_stats(struct net_device *dev)
{
//---------------------------------------------------------------------------
// return &((struct nas_priv *)dev->priv)->stats;
struct nas_priv *priv = netdev_priv(dev);
return &priv->stats;
}
//---------------------------------------------------------------------------
int nas_change_mtu(struct net_device *dev, int mtu)
{
//---------------------------------------------------------------------------
printk("CHANGE_MTU: begin\n");
if ((mtu<50) || (mtu>1500))
return -EINVAL;
dev->mtu = mtu;
return 0;
}
//---------------------------------------------------------------------------
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,6,0)
void nas_tx_timeout(struct net_device *dev, unsigned int txqueue)
#else
void nas_tx_timeout(struct net_device *dev)
#endif
{
//---------------------------------------------------------------------------
// Transmitter timeout, serious problems.
struct nas_priv *priv = netdev_priv(dev);
printk("TX_TIMEOUT: begin\n");
// (struct nas_priv *)(dev->priv)->stats.tx_errors++;
(priv->stats).tx_errors++;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,7,0) \
|| (defined RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= 1796 && RHEL_RELEASE_CODE != 2403)
netif_trans_update(dev);
#else
dev->trans_start = jiffies;
#endif
netif_wake_queue(dev);
printk("TX_TIMEOUT: transmit timed out %s\n",dev->name);
}
static const struct net_device_ops nasmesh_netdev_ops = {
.ndo_open = nas_open,
.ndo_stop = nas_stop,
.ndo_start_xmit = nas_hard_start_xmit,
.ndo_validate_addr = NULL,
.ndo_set_mac_address = NULL,
.ndo_set_config = nas_set_config,
.ndo_do_ioctl = nas_CTL_ioctl,
#if LINUX_VERSION_CODE <= KERNEL_VERSION(3,11,0) \
|| (defined RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= 1797 && RHEL_RELEASE_CODE != 2403)
.extended.ndo_change_mtu = nas_change_mtu,
#else
.ndo_change_mtu = nas_change_mtu,
#endif
.ndo_tx_timeout = nas_tx_timeout,
};
//---------------------------------------------------------------------------
// Initialisation of the network device
void nas_init(struct net_device *dev)
{
//---------------------------------------------------------------------------
uint8_t cxi, dscpi;
struct nas_priv *priv;
// int inst;
if (dev) {
priv = netdev_priv(dev);
//memset(dev->priv, 0, sizeof(struct nas_priv));
memset(priv, 0, sizeof(struct nas_priv));
// priv=(struct nas_priv *)(dev->priv);
priv=netdev_priv(dev);
//
dev->netdev_ops = &nasmesh_netdev_ops;
// dev->type = ARPHRD_EUROPENAIRMESH;
//dev->type = ARPHRD_ETHER;
// dev->features = NETIF_F_NO_CSUM;
dev->hard_header_len = 0;
dev->addr_len = NAS_ADDR_LEN;
dev->flags = IFF_BROADCAST|IFF_MULTICAST|IFF_NOARP;
dev->tx_queue_len = NAS_TX_QUEUE_LEN;
dev->mtu = NAS_MTU;
//
// Initialize private structure
// priv->sap[NAS_GC_SAPI] = RRC_DEVICE_GC;
// priv->sap[NAS_NT_SAPI] = RRC_DEVICE_NT;
priv->sap[NAS_RAB_INPUT_SAPI] = PDCP2PDCP_USE_RT_FIFO;//QOS_DEVICE_CONVERSATIONAL_INPUT;
priv->sap[NAS_RAB_OUTPUT_SAPI] = NAS2PDCP_FIFO;//QOS_DEVICE_STREAMING_INPUT;
// priv->retry_limit=RETRY_LIMIT_DEFAULT;
// priv->timer_establishment=TIMER_ESTABLISHMENT_DEFAULT;
// priv->timer_release=TIMER_RELEASE_DEFAULT;
for (dscpi=0; dscpi<65; ++dscpi)
priv->rclassifier[dscpi]=NULL;
priv->nrclassifier=0;
//
for (cxi=0; cxi<NAS_CX_MAX; cxi++) {
#ifdef DEBUG_DEVICE
printk("INIT: init classifiers, state and timer for MT %u\n", cxi);
#endif
// priv->cx[cxi].sap[NAS_DC_INPUT_SAPI] = RRC_DEVICE_DC_INPUT0;
// priv->cx[cxi].sap[NAS_DC_OUTPUT_SAPI] = RRC_DEVICE_DC_OUTPUT0;
priv->cx[cxi].state=NAS_IDLE;
priv->cx[cxi].countimer=NAS_TIMER_IDLE;
priv->cx[cxi].retry=0;
priv->cx[cxi].lcr=cxi;
priv->cx[cxi].rb=NULL;
priv->cx[cxi].num_rb=0;
// initialisation of the classifier
for (dscpi=0; dscpi<65; ++dscpi) {
priv->cx[cxi].sclassifier[dscpi]=NULL;
priv->cx[cxi].fclassifier[dscpi]=NULL;
}
priv->cx[cxi].nsclassifier=0;
priv->cx[cxi].nfclassifier=0;
// initialisation of the IP address
// TOOL_imei2iid(IMEI, (uint8_t *)priv->cx[cxi].iid6);
priv->cx[cxi].iid4=0;
//
}
spin_lock_init(&priv->lock);
//this requires kernel patch for OAI driver: typically for RF/hard realtime emu experimentation
#ifdef ADDRCONF
#ifdef NETLINK
nas_TOOL_imei2iid(IMEI, dev->dev_addr);// IMEI to device address (for stateless autoconfiguration address)
nas_TOOL_imei2iid(IMEI, (uint8_t *)priv->cx[0].iid6);
#else
nas_TOOL_imei2iid((uint8_t *)nas_IMEI, dev->dev_addr); // IMEI to device address (for stateless autoconfiguration address)
nas_TOOL_imei2iid((uint8_t *)nas_IMEI, (uint8_t *)priv->cx[0].iid6);
#endif
// this is more appropriate for user space soft realtime emulation
#else
memcpy(dev->dev_addr,&nas_IMEI[0],8);
printk("Setting HW addr to : %X%X\n",*((unsigned int *)&dev->dev_addr[0]),*((unsigned int *)&dev->dev_addr[4]));
((unsigned char*)dev->dev_addr)[7] = (unsigned char)find_inst(dev);
memcpy((uint8_t *)priv->cx[0].iid6,&nas_IMEI[0],8);
printk("INIT: init IMEI to IID\n");
#endif
printk("INIT: end\n");
return;
} // instance value check
else {
printk("nas_init(): ERROR, Device is NULL!!\n");
return;
}
}
//---------------------------------------------------------------------------
int init_module (void)
{
//---------------------------------------------------------------------------
int err,inst;
struct nas_priv *priv;
char devicename[100];
// Initialize parameters shared with RRC
printk("Starting NASMESH, number of IMEI paramters %d, IMEI %X%X\n",m_arg,nas_IMEI[0],nas_IMEI[1]);
for (inst=0; inst<NB_INSTANCES_MAX; inst++) {
printk("[NAS][INIT] nasmesh_init_module: begin init instance %d\n",inst);
sprintf(devicename,"oai%d",inst);
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0)
nasdev[inst] = alloc_netdev(sizeof(struct nas_priv),devicename, nas_init);
#else
nasdev[inst] = alloc_netdev(sizeof(struct nas_priv),devicename, NET_NAME_PREDICTABLE, nas_init);
#endif
priv = netdev_priv(nasdev[inst]);
if (nasdev[inst]) {
nas_mesh_init(inst);
//memcpy(nasdev[inst]->dev_addr,&nas_IMEI[0],8);
nas_TOOL_imei2iid((uint8_t *)nas_IMEI, nasdev[inst]->dev_addr);// IMEI to device address (for stateless autoconfiguration address)
nas_TOOL_imei2iid((uint8_t *)nas_IMEI, (uint8_t *)priv->cx[0].iid6);
// TO HAVE DIFFERENT HW @
((unsigned char*)nasdev[inst]->dev_addr)[7] = ((unsigned char*)nasdev[inst]->dev_addr)[7] + (unsigned char)inst + 1;
printk("Setting HW addr for INST %d to : %X%X\n",inst,*((unsigned int *)&nasdev[inst]->dev_addr[0]),*((unsigned int *)&nasdev[inst]->dev_addr[4]));
}
err= register_netdev(nasdev[inst]);
if (err) {
printk("[NAS][INIT] nasmesh_init_module (inst %d): error %i registering device %s\n", inst,err, nasdev[inst]->name);
} else {
printk("nasmesh_init_module: registering device %s, ifindex = %d\n\n",nasdev[inst]->name, nasdev[inst]->ifindex);
}
}
if ((err=nas_netlink_init()) == -1)
printk("[NAS][INIT] NETLINK failed\n");
printk("[NAS][INIT] NETLINK INIT\n");
return err;
}
//---------------------------------------------------------------------------
void cleanup_module(void)
{
//---------------------------------------------------------------------------
int inst;
printk("[NAS][CLEANUP]nasmesh_cleanup_module: begin\n");
for (inst=0; inst<NB_INSTANCES_MAX; inst++) {
#ifdef DEBUG_DEVICE
printk("nasmesh_cleanup_module: unregister and free net device instance %d\n",inst);
#endif
unregister_netdev(nasdev[inst]);
nas_teardown(nasdev[inst]);
free_netdev(nasdev[inst]);
}
nas_netlink_release();
printk("nasmesh_cleanup_module: end\n");
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,0)
#define DRV_NAME "NASMESH"
#define DRV_VERSION "3.0.2"DRV_NAME
#define DRV_DESCRIPTION "OPENAIR MESH Device Driver"
#define DRV_COPYRIGHT "-Copyright(c) GNU GPL Eurecom 2009"
#define DRV_AUTHOR "Raymond Knopp, and Navid Nikaein: <firstname.name@eurecom.fr>"DRV_COPYRIGHT
module_param_array(nas_IMEI,uint,&m_arg,0444);
MODULE_PARM_DESC(nas_IMEI,"The IMEI Hardware address (64-bit, decimal nibbles)");
module_param(nas_is_clusterhead,uint,0444);
MODULE_PARM_DESC(nas_is_clusterhead,"The Clusterhead Indicator");
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,1)
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION(DRV_DESCRIPTION);
MODULE_AUTHOR(DRV_AUTHOR);
#endif
#endif
/*
//---------------------------------------------------------------------------
//module_init(init_nasmesh);
//module_exit(exit_nasmesh);
//---------------------------------------------------------------------------
*/
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#include "local.h"
#include "ioctl.h"
#include "proto_extern.h"
//#include <linux/in.h>
#include <asm/uaccess.h>
#include <asm/checksum.h>
#include <asm/uaccess.h>
// Statistic
//---------------------------------------------------------------------------
void nas_set_msg_statistic_reply(struct nas_msg_statistic_reply *msgrep,
struct nas_priv *priv)
{
//---------------------------------------------------------------------------
msgrep->rx_packets=priv->stats.rx_packets;
msgrep->tx_packets=priv->stats.tx_packets;
msgrep->rx_bytes=priv->stats.rx_bytes;
msgrep->tx_bytes=priv->stats.tx_bytes;
msgrep->rx_errors=priv->stats.rx_errors;
msgrep->tx_errors=priv->stats.tx_errors;
msgrep->rx_dropped=priv->stats.rx_dropped;
msgrep->tx_dropped=priv->stats.tx_dropped;
}
//---------------------------------------------------------------------------
int nas_ioCTL_statistic_request(struct nas_ioctl *gifr,
struct nas_priv *priv)
{
//---------------------------------------------------------------------------
struct nas_msg_statistic_reply msgrep;
printk("NAS_IOCTL_STATISTIC: stat requested\n");
nas_set_msg_statistic_reply(&msgrep,priv);
if (copy_to_user(gifr->msg, &msgrep, sizeof(msgrep))) {
printk("NAS_IOCTL_STATISTIC: copy_to_user failure\n");
return -EFAULT;
}
return 0;
}
///////////////////////////////////////////////////////////////////////////////
// Connections List
//---------------------------------------------------------------------------
void nas_set_msg_cx_list_reply(uint8_t *msgrep,
struct nas_priv *priv)
{
//---------------------------------------------------------------------------
struct cx_entity *cx;
nasLocalConnectionRef_t lcr;
struct nas_msg_cx_list_reply *list;
msgrep[0]=NAS_CX_MAX;
list=(struct nas_msg_cx_list_reply *)(msgrep+1);
for(lcr=0; lcr<NAS_CX_MAX; ++lcr) {
cx=nas_COMMON_search_cx(lcr,priv);
list[lcr].lcr=lcr;
list[lcr].state=cx->state;
list[lcr].cellid=cx->cellid;
list[lcr].iid4=cx->iid4;
list[lcr].iid6[0]=cx->iid6[0];
list[lcr].iid6[1]=cx->iid6[1];
list[lcr].num_rb=cx->num_rb;
list[lcr].nsclassifier=cx->nsclassifier;
printk("NAS_SET_MSG_CX_LIST_REPLY: nsc=%u\n",cx->nsclassifier);
}
}
//---------------------------------------------------------------------------
int nas_ioCTL_cx_list_request(struct nas_ioctl *gifr,
struct nas_priv *priv)
{
//---------------------------------------------------------------------------
uint8_t msgrep[NAS_CX_MAX*sizeof(struct nas_msg_cx_list_reply)+1];
printk("NAS_IOCTL_CX_LIST: connection list requested\n");
nas_set_msg_cx_list_reply(msgrep,priv);
if (copy_to_user(gifr->msg, msgrep, NAS_CX_MAX*sizeof(struct nas_msg_cx_list_reply)+1)) {
printk("NAS_IOCTL_CX_LIST: copy_to_user failure\n");
return -EFAULT;
}
printk("NAS_IOCTL_CX_LIST: end\n");
return 0;
}
///////////////////////////////////////////////////////////////////////////////
// Connection Establishment
//---------------------------------------------------------------------------
void nas_set_msg_cx_establishment_reply(struct nas_msg_cx_establishment_reply *msgrep,
struct nas_msg_cx_establishment_request *msgreq,
struct nas_priv *priv)
{
//---------------------------------------------------------------------------
struct cx_entity *cx;
cx=nas_COMMON_search_cx(msgreq->lcr,priv);
if (cx!=NULL) {
cx->cellid=msgreq->cellid;
msgrep->status=nas_mesh_DC_send_cx_establish_request(cx,priv);
} else
msgrep->status=-NAS_ERROR_NOTCORRECTLCR;
}
//---------------------------------------------------------------------------
int nas_ioCTL_cx_establishment_request(struct nas_ioctl *gifr,
struct nas_priv *priv)
{
//---------------------------------------------------------------------------
struct nas_msg_cx_establishment_request msgreq;
struct nas_msg_cx_establishment_reply msgrep;
printk("NAS_IOCTL_ESTABLISHMENT: connection establishment requested\n");
if (copy_from_user(&msgreq, gifr->msg, sizeof(msgreq))) {
printk("NAS_IOCTL_CX_ESTABLISHMENT: copy_from_user failure\n");
return -EFAULT;
}
nas_set_msg_cx_establishment_reply(&msgrep, &msgreq,priv);
if (copy_to_user(gifr->msg, &msgrep, sizeof(msgrep))) {
printk("NAS_IOCTL_CX_ESTABLISHMENT: copy_to_user failure\n");
return -EFAULT;
}
return 0;
}
///////////////////////////////////////////////////////////////////////////////
// Connection Release
//---------------------------------------------------------------------------
void nas_set_msg_cx_release_reply(struct nas_msg_cx_release_reply *msgrep,
struct nas_msg_cx_release_request *msgreq,
struct nas_priv *priv)
{
//---------------------------------------------------------------------------
struct cx_entity *cx;
cx=nas_COMMON_search_cx(msgreq->lcr,priv);
if (cx!=NULL)
msgrep->status=nas_mesh_DC_send_cx_release_request(cx,priv);
else
msgrep->status=-NAS_ERROR_NOTCORRECTLCR;
}
//---------------------------------------------------------------------------
// Request the release of a connection
int nas_ioCTL_cx_release_request(struct nas_ioctl *gifr,struct nas_priv *priv)
{
//---------------------------------------------------------------------------
struct nas_msg_cx_release_request msgreq;
struct nas_msg_cx_release_reply msgrep;
printk("NAS_IOCTL_CX_RELEASE: connection release requested\n");
if (copy_from_user(&msgreq, gifr->msg, sizeof(msgreq))) {
printk("NAS_IOCTL_CX_RELEASE: copy_from_user failure\n");
return -EFAULT;
}
nas_set_msg_cx_release_reply(&msgrep, &msgreq,priv);
if (copy_to_user(gifr->msg, &msgrep, sizeof(msgrep))) {
printk("NAS_IOCTL_CX_RELEASE: copy_to_user failure\n");
return -EFAULT;
}
printk("NAS_IOCTL_CX_RELEASE: end\n");
return 0;
}
///////////////////////////////////////////////////////////////////////////////
// Radio Bearer List
//---------------------------------------------------------------------------
void nas_set_msg_rb_list_reply(uint8_t *msgrep,
struct nas_msg_rb_list_request *msgreq,
struct nas_priv *priv)
{
//---------------------------------------------------------------------------
struct cx_entity *cx;
cx=nas_COMMON_search_cx(msgreq->lcr,priv);
if (cx!=NULL) {
uint8_t rbi;
struct rb_entity *rb;
struct nas_msg_rb_list_reply *list;
if (cx->num_rb > NAS_LIST_RB_MAX)
msgrep[0] = NAS_LIST_RB_MAX;
else
msgrep[0] = cx->num_rb;
list=(struct nas_msg_rb_list_reply *)(msgrep+1);
for (rb=cx->rb, rbi=0; (rb!=NULL)&&(rbi<msgrep[0]); rb=rb->next, ++rbi) {
list[rbi].state=rb->state;
list[rbi].rab_id=rb->rab_id;
list[rbi].sapi=rb->sapi;
list[rbi].qos=rb->qos;
}
} else
msgrep[0]=0;
}
//---------------------------------------------------------------------------
int nas_ioCTL_rb_list_request(struct nas_ioctl *gifr,
struct nas_priv *priv)
{
//---------------------------------------------------------------------------
uint8_t msgrep[NAS_LIST_RB_MAX*sizeof(struct nas_msg_rb_list_reply)+1];
struct nas_msg_rb_list_request msgreq;
printk("NAS_IOCTL_RB_LIST: Radio Bearer list requested\n");
if (copy_from_user(&msgreq, gifr->msg, sizeof(msgreq))) {
printk("NAS_IOCTL_RB_LIST: copy_from_user failure\n");
return -EFAULT;
}
nas_set_msg_rb_list_reply(msgrep, &msgreq,priv);
if (copy_to_user(gifr->msg, msgrep, NAS_LIST_RB_MAX*sizeof(struct nas_msg_rb_list_reply)+1)) {
printk("NAS_IOCTL_RB_LIST: copy_to_user failure\n");
return -EFAULT;
}
printk("NAS_IOCTL_CX_LIST: end\n");
return 0;
}
///////////////////////////////////////////////////////////////////////////////
// Radio Bearer Establishment
//---------------------------------------------------------------------------
void nas_set_msg_rb_establishment_reply(struct nas_msg_rb_establishment_reply *msgrep,
struct nas_msg_rb_establishment_request *msgreq,
struct nas_priv *priv)
{
//---------------------------------------------------------------------------
// if ((msgreq->rab_id<3)||(msgreq->rab_id>127))
if ((msgreq->rab_id<1)||(msgreq->rab_id>MAX_RABS)) // navid : increase the number
msgrep->status=-NAS_ERROR_NOTCORRECTRABI;
else {
struct cx_entity *cx;
cx=nas_COMMON_search_cx(msgreq->lcr,priv);
if (cx==NULL)
msgrep->status=-NAS_ERROR_NOTCORRECTLCR;
else {
struct rb_entity *rb;
rb=nas_COMMON_add_rb(cx, msgreq->rab_id, msgreq->qos);
if (rb!=NULL) {
// rb->cnxid = msgreq->cnxid;
// msgrep->status=nas_rg_DC_send_rb_establish_request(cx, rb);
} else
msgrep->status=-NAS_ERROR_NOMEMORY;
// msgrep->cnxid = msgreq->cnxid;
}
}
}
//---------------------------------------------------------------------------
int nas_ioCTL_rb_establishment_request(struct nas_ioctl *gifr,
struct nas_priv *priv)
{
//---------------------------------------------------------------------------
struct nas_msg_rb_establishment_request msgreq;
struct nas_msg_rb_establishment_reply msgrep;
printk("NAS_IOCTL_RB_ESTABLISHMENT: Radio bearer establishment requested\n");
if (copy_from_user(&msgreq, gifr->msg, sizeof(msgreq))) {
printk("NAS_IOCTL_RB_ESTABLISHMENT: copy_from_user failure\n");
return -EFAULT;
}
nas_set_msg_rb_establishment_reply(&msgrep, &msgreq,priv);
if (copy_to_user(gifr->msg, &msgrep, sizeof(msgrep))) {
printk("NAS_IOCTL_RB_ESTABLISHMENT: copy_to_user failure\n");
return -EFAULT;
}
return 0;
}
///////////////////////////////////////////////////////////////////////////////
// Radio Bearer Release
//---------------------------------------------------------------------------
void nas_set_msg_rb_release_reply(struct nas_msg_rb_release_reply *msgrep,
struct nas_msg_rb_release_request *msgreq,
struct nas_priv *priv)
{
//---------------------------------------------------------------------------
if (msgreq->lcr<NAS_CX_MAX) {
struct rb_entity *rb;
struct cx_entity *cx;
cx=nas_COMMON_search_cx(msgreq->lcr,priv);
rb=nas_COMMON_search_rb(cx, msgreq->rab_id);
if (rb!=NULL) {
//msgrep->status=nas_rg_DC_send_rb_release_request(cx, rb);
} else
msgrep->status=-NAS_ERROR_NOTCONNECTED;
// msgrep->cnxid = msgreq->cnxid;
} else
msgrep->status=-NAS_ERROR_NOTCORRECTLCR;
}
//---------------------------------------------------------------------------
int nas_ioCTL_rb_release_request(
struct nas_ioctl *gifr,
struct nas_priv *priv)
{
//---------------------------------------------------------------------------
struct nas_msg_rb_release_request msgreq;
struct nas_msg_rb_release_reply msgrep;
printk("NAS_IOCTL_RB_RELEASE: Radio bearer release requested\n");
if (copy_from_user(&msgreq, gifr->msg, sizeof(msgreq))) {
printk("NAS_IOCTL_RB_RELEASE: copy_from_user failure\n");
return -EFAULT;
}
nas_set_msg_rb_release_reply(&msgrep, &msgreq, priv);
if (copy_to_user(gifr->msg, &msgrep, sizeof(msgrep))) {
printk("NAS_IOCTL_RB_RELEASE: copy_to_user failure\n");
return -EFAULT;
}
return 0;
}
///////////////////////////////////////////////////////////////////////////////
// Classifier List
//---------------------------------------------------------------------------
void nas_set_msg_class_list_reply(
uint8_t *msgrep,
struct nas_msg_class_list_request *msgreq,
struct nas_priv *priv)
{
//---------------------------------------------------------------------------
struct cx_entity *cx;
struct classifier_entity *gc;
struct nas_msg_class_list_reply *list;
uint8_t cli;
list=(struct nas_msg_class_list_reply *)(msgrep+1);
switch(msgreq->dir) {
case NAS_DIRECTION_SEND:
cx=nas_COMMON_search_cx(msgreq->lcr,priv);
if (cx==NULL) {
msgrep[0]=0;
return;
}
gc=cx->sclassifier[msgreq->dscp];
break;
case NAS_DIRECTION_RECEIVE:
cx=NULL;
gc=priv->rclassifier[msgreq->dscp];
break;
default:
cx=NULL;
msgrep[0]=0;
return;
}
for (cli=0; (gc!=NULL)&&(cli<NAS_LIST_CLASS_MAX); gc=gc->next, ++cli) {
list[cli].classref=gc->classref;
list[cli].lcr=msgreq->lcr;
list[cli].dir=msgreq->dir;
list[cli].dscp=msgreq->dscp;
list[cli].rab_id=gc->rab_id;
list[cli].version=gc->version;
switch(gc->version) {
case 4:
list[cli].saddr.ipv4 = gc->saddr.ipv4;
list[cli].daddr.ipv4 = gc->daddr.ipv4;
break;
case 6:
list[cli].saddr.ipv6 = gc->saddr.ipv6;
list[cli].daddr.ipv6 = gc->daddr.ipv6;
break;
}
list[cli].protocol=gc->protocol;
list[cli].sport=ntohs(gc->sport);
list[cli].dport=ntohs(gc->dport);
list[cli].splen=gc->splen;
list[cli].dplen=gc->dplen;
list[cli].fct=nas_TOOL_invfct(gc);
}
msgrep[0]=cli;
}
//---------------------------------------------------------------------------
int nas_ioCTL_class_list_request(
struct nas_ioctl *gifr,
struct nas_priv *priv)
{
//---------------------------------------------------------------------------
uint8_t msgrep[NAS_LIST_CLASS_MAX*sizeof(struct nas_msg_class_list_reply)+1];
struct nas_msg_class_list_request msgreq;
printk("NAS_IOCTL_CLASS_LIST: classifier list requested\n");
if (copy_from_user(&msgreq, gifr->msg, sizeof(msgreq))) {
printk("NAS_IOCTL_CLASS_LIST: copy_from_user failure\n");
return -EFAULT;
}
nas_set_msg_class_list_reply(msgrep, &msgreq,priv);
if (copy_to_user(gifr->msg, msgrep, NAS_LIST_CLASS_MAX*sizeof(struct nas_msg_class_list_reply)+1)) {
printk("NAS_IOCTL_CLASS_LIST: copy_to_user failure\n");
return -EFAULT;
}
return 0;
}
///////////////////////////////////////////////////////////////////////////////
// Request the addition of a classifier rule
//---------------------------------------------------------------------------
void nas_set_msg_class_add_reply(
struct nas_msg_class_add_reply *msgrep,
struct nas_msg_class_add_request *msgreq,
struct nas_priv *priv)
{
//---------------------------------------------------------------------------
struct classifier_entity *gc,*gc2;
unsigned char *saddr,*daddr;
unsigned int *saddr32,*daddr32;
printk("[NAS][CLASS] nas_set_msg_class_add_reply\n");
if (msgreq->dscp>NAS_DSCP_MAX) {
printk("NAS_SET_MSG_CLASS_ADD_REPLY: Incoherent parameter value\n");
msgrep->status=-NAS_ERROR_NOTCORRECTDSCP;
return;
}
if (msgreq->dir==NAS_DIRECTION_SEND) {
struct cx_entity *cx;
cx=nas_COMMON_search_cx(msgreq->lcr,priv);
if (cx!=NULL) {
printk("NAS_SET_MSG_CLASS_ADD_REPLY: DSCP/EXP %d, Classref %d, RB %u\n", msgreq->dscp, msgreq->classref,msgreq->rab_id );
gc=nas_CLASS_add_sclassifier(cx, msgreq->dscp, msgreq->classref);
printk("NAS_SET_MSG_CLASS_ADD_REPLY: %p %p\n" , msgreq, gc);
if (gc==NULL) {
msgrep->status=-NAS_ERROR_NOMEMORY;
return;
}
} else {
msgrep->status=-NAS_ERROR_NOTCORRECTLCR;
return;
}
gc->rab_id=msgreq->rab_id;
gc->rb=nas_COMMON_search_rb(cx, gc->rab_id);
printk("NAS_SET_MSG_CLASS_ADD_REPLY: gc_rb %p %u \n", gc->rb, gc->rab_id);
} else {
if (msgreq->dir==NAS_DIRECTION_RECEIVE) {
gc=nas_CLASS_add_rclassifier(msgreq->dscp,
msgreq->classref,
priv);
if (gc==NULL) {
msgrep->status=-NAS_ERROR_NOMEMORY;
return;
}
gc->rab_id=msgreq->rab_id;
} else {
msgrep->status=-NAS_ERROR_NOTCORRECTDIR;
return;
}
for (gc2 = priv->rclassifier[msgreq->dscp]; gc2!=NULL ; gc2 = gc2->next)
printk("[NAS][CLASS] Add Receive Classifier dscp %d: rab_id %d (%p,next %p)\n",msgreq->dscp,gc2->rab_id,gc2,gc2->next);
}
printk("[NAS][CLASS] Getting addresses ...\n");
nas_TOOL_fct(gc, msgreq->fct);
gc->version=msgreq->version;
switch(gc->version) {
case 4:
gc->saddr.ipv4=msgreq->saddr.ipv4;
gc->daddr.ipv4=msgreq->daddr.ipv4;
// #ifdef NAS_CLASS_DEBUG
saddr = (unsigned char *)&gc->saddr.ipv4;
daddr = (unsigned char *)&gc->daddr.ipv4;
printk("[NAS][CLASS] Adding IPv4 %d.%d.%d.%d -> %d.%d.%d.%d\n",
saddr[0],saddr[1],saddr[2],saddr[3],
daddr[0],daddr[1],daddr[2],daddr[3]);
//#endif
gc->splen=msgreq->splen;
gc->dplen=msgreq->dplen;
break;
case 6:
memcpy(&gc->saddr.ipv6,&msgreq->saddr.ipv6,16);
memcpy(&gc->daddr.ipv6,&msgreq->daddr.ipv6,16);
saddr32 = (unsigned int *)&gc->saddr.ipv6;
daddr32 = (unsigned int *)&gc->daddr.ipv6;
printk("[NAS][CLASS] Adding IPv6 %X:%X:%X:%X -> %X.%X.%X.%X\n",
saddr32[0],saddr32[1],saddr32[2],saddr32[3],
daddr32[0],daddr32[1],daddr32[2],daddr32[3]);
gc->splen=msgreq->splen;
gc->dplen=msgreq->dplen;
break;
case NAS_MPLS_VERSION_CODE:
printk("[NAS][CLASS] Adding MPLS label %d with exp %d\n",
msgreq->daddr.mpls_label,msgreq->dscp);
gc->daddr.mpls_label = msgreq->daddr.mpls_label;
break;
case 0:
gc->saddr.ipv6.s6_addr32[0]=0;
gc->daddr.ipv6.s6_addr32[1]=0;
gc->saddr.ipv6.s6_addr32[2]=0;
gc->daddr.ipv6.s6_addr32[3]=0;
gc->splen=0;
gc->dplen=0;
break;
default:
msgrep->status=-NAS_ERROR_NOTCORRECTVERSION;
kfree(gc);
return;
}
gc->protocol=msgreq->protocol;
gc->protocol_message_type=msgreq->protocol_message_type;
gc->sport=htons(msgreq->sport);
gc->dport=htons(msgreq->dport);
msgrep->status=0;
}
//---------------------------------------------------------------------------
int nas_ioCTL_class_add_request(struct nas_ioctl *gifr,
struct nas_priv *priv)
{
//---------------------------------------------------------------------------
struct nas_msg_class_add_request msgreq;
struct nas_msg_class_add_reply msgrep;
printk("NAS_IOCTL_CLASS_ADD: Add classifier components requested\n");
printk("NAS_IOCTL_CLASS_ADD: size of gifr msg %zd\n", sizeof(gifr->msg));
if (copy_from_user(&msgreq, gifr->msg, sizeof(msgreq))) {
printk("NAS_IOCTL_CLASS_ADD: copy_from_user failure\n");
return -EFAULT;
}
nas_set_msg_class_add_reply(&msgrep, &msgreq,priv);
if (copy_to_user(gifr->msg, &msgrep, sizeof(msgrep))) {
printk("NAS_IOCTL_CLASS_ADD: copy_to_user failure\n");
return -EFAULT;
}
return 0;
}
///////////////////////////////////////////////////////////////////////////////
// Request the deletion of a classifier rule
//---------------------------------------------------------------------------
void nas_set_msg_class_del_reply(struct nas_msg_class_del_reply *msgrep,
struct nas_msg_class_del_request *msgreq,
struct nas_priv *priv)
{
//---------------------------------------------------------------------------
if (msgreq->dscp>NAS_DSCP_DEFAULT) {
printk("NAS_SET_MSG_CLASS_DEL_REPLY: Incoherent parameter value\n");
msgrep->status=-NAS_ERROR_NOTCORRECTDSCP;
return;
}
if (msgreq->dir==NAS_DIRECTION_SEND) {
struct cx_entity *cx;
cx=nas_COMMON_search_cx(msgreq->lcr,priv);
if (cx!=NULL)
nas_CLASS_del_sclassifier(cx, msgreq->dscp, msgreq->classref);
else {
msgrep->status=-NAS_ERROR_NOTCORRECTLCR;
return;
}
} else {
if (msgreq->dir==NAS_DIRECTION_RECEIVE)
nas_CLASS_del_rclassifier(msgreq->dscp, msgreq->classref,priv);
else {
msgrep->status=-NAS_ERROR_NOTCORRECTDIR;
return;
}
}
msgrep->status=0;
}
//---------------------------------------------------------------------------
int nas_ioCTL_class_del_request(struct nas_ioctl *gifr,
struct nas_priv *priv)
{
//---------------------------------------------------------------------------
struct nas_msg_class_del_request msgreq;
struct nas_msg_class_del_reply msgrep;
printk("NAS_IOCTL_CLASS_DEL: Del classifier components requested\n");
if (copy_from_user(&msgreq, gifr->msg, sizeof(msgreq))) {
printk("NAS_IOCTL_CLASS_DEL: copy_from_user failure\n");
return -EFAULT;
}
nas_set_msg_class_del_reply(&msgrep, &msgreq,priv);
if (copy_to_user(gifr->msg, &msgrep, sizeof(msgrep))) {
printk("NAS_IOCTL_CLASS_DEL: copy_to_user failure\n");
return -EFAULT;
}
return 0;
}
///////////////////////////////////////////////////////////////////////////////
// Measurement
// Messages for Measurement transfer
//---------------------------------------------------------------------------
void nas_set_msg_measure_reply(struct nas_msg_measure_reply *msgrep, struct nas_msg_measure_request *msgreq,
struct nas_priv *priv)
{
//---------------------------------------------------------------------------
struct cx_entity *cx;
int lcr=0; // Temp lcr->mt =0
int i;
cx=nas_COMMON_search_cx(lcr,priv);
if (cx!=NULL) {
msgrep->num_cells = cx->num_measures;
for (i=0; i<cx->num_measures; i++) {
msgrep-> measures[i].cell_id = cx->meas_cell_id[i];
msgrep-> measures[i].level = cx->meas_level[i];
msgrep-> measures[i].provider_id = cx->provider_id[i];
}
msgrep->signal_lost_flag = 0;
}
}
//---------------------------------------------------------------------------
int nas_ioCTL_measure_request(struct nas_ioctl *gifr,
struct nas_priv *priv)
{
//---------------------------------------------------------------------------
struct nas_msg_measure_request msgreq;
struct nas_msg_measure_reply msgrep;
printk("NAS_IOCTL_MEASURE: Measurement requested\n");
if (copy_from_user(&msgreq, gifr->msg, sizeof(msgreq))) {
printk("NAS_IOCTL_MEASURE: copy_from_user failure\n");
return -EFAULT;
}
nas_set_msg_measure_reply(&msgrep, &msgreq,priv);
if (copy_to_user(gifr->msg, &msgrep, sizeof(msgrep))) {
printk("NAS_IOCTL_MEASURE: copy_to_user failure\n");
return -EFAULT;
}
return 0;
}
///////////////////////////////////////////////////////////////////////////////
// IMEI
// Messages for IMEI transfer
//---------------------------------------------------------------------------
void nas_set_msg_imei_reply(struct nas_msg_l2id_reply *msgrep,
struct nas_priv *priv)
{
//---------------------------------------------------------------------------
struct cx_entity *cx;
int lcr=0; // Temp lcr->mt =0
cx=nas_COMMON_search_cx(lcr,priv);
if (cx!=NULL) {
msgrep->l2id[0] = cx->iid6[0];
msgrep->l2id[1] = cx->iid6[1];
}
}
//---------------------------------------------------------------------------
int nas_ioCTL_imei_request(struct nas_ioctl *gifr,
struct nas_priv *priv)
{
//---------------------------------------------------------------------------
struct nas_msg_l2id_reply msgrep;
printk("NAS_IOCTL_IMEI: IMEI requested\n");
nas_set_msg_imei_reply(&msgrep,priv);
if (copy_to_user(gifr->msg, &msgrep, sizeof(msgrep))) {
printk("NAS_IOCTL_IMEI: copy_to_user failure\n");
return -EFAULT;
}
return 0;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// IOCTL command
//---------------------------------------------------------------------------
int nas_CTL_ioctl(struct net_device *dev,
struct ifreq *ifr,
int cmd)
{
//---------------------------------------------------------------------------
struct nas_ioctl *gifr;
struct nas_priv *priv=netdev_priv(dev);
int r;
// printk("NAS_CTL_IOCTL: begin ioctl for instance %d\n",find_inst(dev));
switch(cmd) {
case NAS_IOCTL_RRM:
gifr=(struct nas_ioctl *)ifr;
switch(gifr->type) {
case NAS_MSG_STATISTIC_REQUEST:
r=nas_ioCTL_statistic_request(gifr,priv);
break;
case NAS_MSG_CX_ESTABLISHMENT_REQUEST:
r=nas_ioCTL_cx_establishment_request(gifr,priv);
break;
case NAS_MSG_CX_RELEASE_REQUEST:
r=nas_ioCTL_cx_release_request(gifr,priv);
break;
case NAS_MSG_CX_LIST_REQUEST:
r=nas_ioCTL_cx_list_request(gifr,priv);
break;
case NAS_MSG_RB_ESTABLISHMENT_REQUEST:
r=nas_ioCTL_rb_establishment_request(gifr,priv);
break;
case NAS_MSG_RB_RELEASE_REQUEST:
r= nas_ioCTL_rb_release_request(gifr,priv);
break;
case NAS_MSG_RB_LIST_REQUEST:
r=nas_ioCTL_rb_list_request(gifr,priv);
break;
case NAS_MSG_CLASS_ADD_REQUEST:
r=nas_ioCTL_class_add_request(gifr,priv);
break;
case NAS_MSG_CLASS_LIST_REQUEST:
r=nas_ioCTL_class_list_request(gifr,priv);
break;
case NAS_MSG_CLASS_DEL_REQUEST:
r=nas_ioCTL_class_del_request(gifr,priv);
break;
case NAS_MSG_MEAS_REQUEST:
r=nas_ioCTL_measure_request(gifr,priv);
break;
case NAS_MSG_IMEI_REQUEST:
r=nas_ioCTL_imei_request(gifr,priv);
break;
default:
// printk("NAS_IOCTL_RRM: unkwon request type, type=%x\n", gifr->type);
r=-EFAULT;
}
break;
default:
// printk("NAS_CTL_IOCTL: Unknown ioctl command, cmd=%x\n", cmd);
r=-EFAULT;
}
// printk("NAS_CTL_IOCTL: end\n");
return r;
}
//---------------------------------------------------------------------------
void nas_CTL_send(struct sk_buff *skb,
struct cx_entity *cx,
struct classifier_entity *gc, int inst, struct nas_priv *gpriv)
{
//---------------------------------------------------------------------------
printk("NAS_CTL_SEND - void \n");
}
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#ifndef NAS_CTL_H
#define NAS_CTL_H
#include <asm/byteorder.h>
#include <asm/types.h>
#include <linux/udp.h>
#include <linux/tcp.h>
#include <linux/if.h>
//#include <linux/ipv6.h>
#define NAS_MSG_MAXLEN 1100/// change???
// type of CTL message
#define NAS_MSG_STATISTIC_REQUEST 1
#define NAS_MSG_STATISTIC_REPLY 2
#define NAS_MSG_ECHO_REQUEST 3
#define NAS_MSG_ECHO_REPLY 4
#define NAS_MSG_CX_ESTABLISHMENT_REQUEST 5
#define NAS_MSG_CX_ESTABLISHMENT_REPLY 6
#define NAS_MSG_CX_RELEASE_REQUEST 7
#define NAS_MSG_CX_RELEASE_REPLY 8
#define NAS_MSG_CX_LIST_REQUEST 9
#define NAS_MSG_CX_LIST_REPLY 10
#define NAS_MSG_RB_ESTABLISHMENT_REQUEST 11
#define NAS_MSG_RB_ESTABLISHMENT_REPLY 12
#define NAS_MSG_RB_RELEASE_REQUEST 13
#define NAS_MSG_RB_RELEASE_REPLY 14
#define NAS_MSG_RB_LIST_REQUEST 15
#define NAS_MSG_RB_LIST_REPLY 16
#define NAS_MSG_CLASS_ADD_REQUEST 17
#define NAS_MSG_CLASS_ADD_REPLY 18
#define NAS_MSG_CLASS_DEL_REQUEST 19
#define NAS_MSG_CLASS_DEL_REPLY 20
#define NAS_MSG_CLASS_LIST_REQUEST 21
#define NAS_MSG_CLASS_LIST_REPLY 22
#define NAS_MSG_MEAS_REQUEST 23
#define NAS_MSG_MEAS_REPLY 24
#define NAS_MSG_IMEI_REQUEST 25
#define NAS_MSG_IMEI_REPLY 26
// Max number of entry of a message list
#define NAS_LIST_CX_MAX 32
#define NAS_LIST_RB_MAX 32
#define NAS_LIST_CLASS_MAX 16 // 32 is too high!!:
/* risk of stack problems: KEEP ATTENTION TO COMPILATION WARNINGS */
typedef unsigned short nasMsgType_t;
struct nas_ioctl {
char name[IFNAMSIZ];
nasMsgType_t type;
char *msg;
};
struct nas_msg_statistic_reply {
unsigned int rx_packets;
unsigned int tx_packets;
unsigned int rx_bytes;
unsigned int tx_bytes;
unsigned int rx_errors;
unsigned int tx_errors;
unsigned int rx_dropped;
unsigned int tx_dropped;
};
struct nas_msg_cx_list_reply {
nasLocalConnectionRef_t lcr; // Local Connection reference
unsigned char state;
nasCellID_t cellid; // cell identification
unsigned int iid6[2]; // IPv6 interface identification
unsigned char iid4; // IPv4 interface identification
unsigned short num_rb;
unsigned short nsclassifier;
};
struct nas_msg_cx_establishment_reply {
int status;
};
struct nas_msg_cx_establishment_request {
nasLocalConnectionRef_t lcr; // Local Connection reference
nasCellID_t cellid; // Cell identification
};
struct nas_msg_cx_release_reply {
int status;
};
struct nas_msg_cx_release_request {
nasLocalConnectionRef_t lcr; // Local Connection reference
};
struct nas_msg_rb_list_reply {
nasRadioBearerId_t rab_id;
nasSapId_t sapi;
nasQoSTrafficClass_t qos;
unsigned char state;
};
struct nas_msg_rb_list_request {
nasLocalConnectionRef_t lcr; // Local Connection reference
};
struct nas_msg_rb_establishment_reply {
int status;
};
struct nas_msg_rb_establishment_request {
nasLocalConnectionRef_t lcr; // Local Connection reference
nasRadioBearerId_t rab_id;
nasQoSTrafficClass_t qos;
};
struct nas_msg_rb_release_reply {
int status;
};
struct nas_msg_rb_release_request {
nasLocalConnectionRef_t lcr; // Local Connection reference
nasRadioBearerId_t rab_id;
};
/*
struct saddr {
struct in6_addr ipv6;
unsigned int ipv4;
};
struct daddr {
struct in6_addr ipv6;
unsigned int ipv4;
unsigned int mpls_label;
};
*/
struct nas_msg_class_add_request {
nasLocalConnectionRef_t lcr; // Local Connection reference
nasRadioBearerId_t rab_id;
nasRadioBearerId_t rab_id_rx;
unsigned char dir; // direction (send or receive, forward)
unsigned char dscp; // codepoint
unsigned char fct;
unsigned short classref;
unsigned char version;
//struct daddr daddr;
//struct saddr saddr;
unsigned char splen; // prefix length
union {
struct in6_addr ipv6;
// begin navid
//in_addr_t ipv4;
unsigned int ipv4;
//end navid
unsigned int mpls_label;
} daddr; // IP destination address
union {
struct in6_addr ipv6;
// begin navid
//in_addr_t ipv4;
unsigned int ipv4;
//end navid
} saddr; // IP source address
unsigned char dplen; // prefix length
unsigned char protocol; //!< transport layer protocol type (ANY,TCP,UDP,ICMPv4,ICMPv6)
unsigned char protocol_message_type; //!< transport layer protocol message (ROUTER_ADV, ROUTER_SOLL, etc.)
unsigned short sport; //!< source port
unsigned short dport; //!< destination port
};
struct nas_msg_class_add_reply {
int status;
};
struct nas_msg_class_del_request {
nasLocalConnectionRef_t lcr; // Local Connection reference
unsigned char dir; // direction (send or receive)
unsigned char dscp; // codepoint
unsigned short classref;
};
struct nas_msg_class_del_reply {
int status;
};
#define nas_msg_class_list_reply nas_msg_class_add_request
struct nas_msg_class_list_request {
nasLocalConnectionRef_t lcr; // Local Connection reference
unsigned char dir;
unsigned char dscp;
};
// Messages for Measurement transfer - MW 01/04/2005
typedef unsigned int nioctlProviderId_t;
typedef unsigned short nioctlSignalLoss_t;
typedef struct nioctlMeasures {
nasCellID_t cell_id;
nasSigLevel_t level;
nioctlProviderId_t provider_id;
} nioctlMeasures_t;
struct nas_msg_measure_request {
nasNumRGsMeas_t num_cells;
nasCellID_t cellid[MAX_MEASURE_NB]; // Cell identification
unsigned short num_providers;
nioctlProviderId_t provider_id[MAX_MEASURE_NB]; // Provider identification
};
struct nas_msg_measure_reply {
nasNumRGsMeas_t num_cells;
nioctlMeasures_t measures[MAX_MEASURE_NB];
nioctlSignalLoss_t signal_lost_flag;
};
// Messages for Measurement transfer - MW 01/04/2005
typedef unsigned int nioctlL2Id_t[2];
struct nas_msg_l2id_reply {
nioctlL2Id_t l2id;
};
#endif
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/***************************************************************************
local.h - description
-------------------
copyright : (C) 2002 by Eurecom
email : navid.nikaein@eurecom.fr
lionel.gauthier@eurecom.fr
knopp@eurecom.fr
***************************************************************************
***************************************************************************/
#ifndef LOCAL_H
#define LOCAL_H
#include <linux/if_arp.h>
#include <linux/types.h>
#include <linux/spinlock.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/ipv6.h>
#include <linux/ip.h>
#include <linux/sysctl.h>
#include <linux/timer.h>
#include <linux/unistd.h>
#include <asm/param.h>
//#include <sys/sysctl.h>
#include <linux/udp.h>
#include <linux/tcp.h>
#include <linux/icmp.h>
#include <linux/icmpv6.h>
#include <linux/in.h>
#include <net/ndisc.h>
//#include "rrc_nas_primitives.h"
//#include "rrc_sap.h"
#define PDCP2PDCP_USE_RT_FIFO 21
#define NAS2PDCP_FIFO 22
#include "constant.h"
#include "sap.h"
#include "rrc_nas_primitives.h"
#include "common/platform_types.h"
struct rb_entity {
nasRadioBearerId_t rab_id;
nasSapId_t sapi;
nasQoSTrafficClass_t qos;
uint8_t state;
uint8_t retry;
uint32_t countimer;
struct rb_entity *next;
};
struct cx_entity {
int sap[NAS_SAPI_CX_MAX];
uint8_t state; // state of the connection
nasLocalConnectionRef_t lcr; // Local connection reference
nasCellID_t cellid; // cell identification
uint32_t countimer; // timeout's counter
uint8_t retry; // number of retransmission
struct classifier_entity *sclassifier[NAS_DSCP_MAX]; // send classifier;
struct classifier_entity *fclassifier[NAS_DSCP_MAX]; // send classifier;
uint16_t nsclassifier;
uint16_t nfclassifier;
uint32_t iid6[2]; // IPv6 interface identification
uint8_t iid4; // IPv4 interface identification
struct rb_entity *rb;
uint16_t num_rb;
int lastRRCprimitive;
//measures
int req_prov_id[MAX_MEASURE_NB];
int num_measures;
int meas_cell_id[MAX_MEASURE_NB];
int meas_level[MAX_MEASURE_NB];
int provider_id[MAX_MEASURE_NB];
};
//#define NAS_RETRY_LIMIT_DEFAULT 5
struct nas_priv {
int irq;
struct timer_list timer;
spinlock_t lock;
struct net_device_stats stats;
uint8_t retry_limit;
uint32_t timer_establishment;
uint32_t timer_release;
struct cx_entity cx[NAS_CX_MAX];
struct classifier_entity *rclassifier[NAS_DSCP_MAX]; // receive classifier
uint16_t nrclassifier;
int sap[NAS_SAPI_MAX];
struct sock *nl_sk;
uint8_t nlmsg[NAS_MAX_LENGTH+sizeof(struct nlmsghdr)];
uint8_t xbuffer[NAS_MAX_LENGTH]; // transmition buffer
uint8_t rbuffer[NAS_MAX_LENGTH]; // reception buffer
};
struct classifier_entity {
uint32_t classref;
struct classifier_entity *next;
uint8_t version;
union {
struct in6_addr ipv6;
uint32_t ipv4;
} saddr; // IP source address
uint8_t splen; // prefix length
union {
struct in6_addr ipv6;
uint32_t ipv4;
unsigned int mpls_label;
} daddr; // IP destination address
uint8_t dplen; // prefix length
uint8_t protocol; // high layer protocol type
unsigned char protocol_message_type;
uint16_t sport; // source port
uint16_t dport; // destination port
struct rb_entity *rb; //pointer to rb_entity for sending function or receiving in case of forwarding rule
struct rb_entity *rb_rx; //pointer to rb_entity for receiving (in case of forwarding rule)
nasRadioBearerId_t rab_id; // RAB identification for sending
nasRadioBearerId_t rab_id_rx; // RAB identification for receiving (in case of forwarding rule)
void (*fct)(struct sk_buff *skb, struct cx_entity *cx, struct classifier_entity *gc,int inst, struct nas_priv *gpriv);
};
struct ipversion {
#if defined(__LITTLE_ENDIAN_BITFIELD)
uint8_t reserved:4,
version:4;
#else
uint8_t version:4,
reserved:4;
#endif
};
typedef struct pdcp_data_req_header_s {
rb_id_t rb_id;
sdu_size_t data_size;
signed int inst;
ip_traffic_type_t traffic_type;
uint32_t sourceL2Id;
uint32_t destinationL2Id;
} pdcp_data_req_header_t;
typedef struct pdcp_data_ind_header_s {
rb_id_t rb_id;
sdu_size_t data_size;
signed int inst;
ip_traffic_type_t dummy_traffic_type;
uint32_t sourceL2Id;
uint32_t destinationL2Id;
} pdcp_data_ind_header_t;
extern struct net_device *nasdev[NB_INSTANCES_MAX];
extern uint8_t NAS_NULL_IMEI[14];
#endif
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/***************************************************************************
nas_mesh.c - description
-------------------
copyright : (C) 2003-2008 by Eurecom
email : navid.nikaein@eurecom.fr
lionel.gauthier@eurecom.fr
raymond.knopp@eurecom.fr
***************************************************************************/
#include <linux/version.h>
#include "local.h"
#include "proto_extern.h"
//---------------------------------------------------------------------------
void nas_mesh_init(int inst)
{
//---------------------------------------------------------------------------
// struct cx_entity *cx;
printk("NAS_MESH_INIT Complete\n");
// Request the establishment of a connexion
// cx=nas_COMMON_search_cx(0);
// if (cx==NULL)
// {
// printk("NAS_MESH_INIT: connexion failure\n");
// return;
// }
// cx->countimer=5;
// cx->state=NAS_CX_CONNECTING;
// cx->retry=0;
// cx->cellid=25;
}
//---------------------------------------------------------------------------
//For demo, add automatically a classifier
//Equivalent to class add send 0 -f qos <x> -cr 0
void nas_mesh_start_broadcast_sclassifier(struct cx_entity *cx,struct rb_entity *rb)
{
struct classifier_entity *gc;
// Start debug information
#ifdef NAS_DEBUG_CLASS
printk("NAS_MESH_START_BROADCAST_SCLASS - begin \n");
#endif
if (cx==NULL) {
#ifdef NAS_DEBUG_CLASS
printk("NAS_MESH_START_DEFAULT_SCLASS - input parameter cx is NULL \n");
#endif
return;
}
if (rb==NULL) {
#ifdef NAS_DEBUG_CLASS
printk("NAS_MESH_START_DEFAULT_SCLASS - input parameter rb is NULL \n");
#endif
return;
}
// End debug information
gc=nas_CLASS_add_sclassifier(cx, NAS_DSCP_DEFAULT, 6);
// gc=nas_CLASS_add_sclassifier(cx, 5, 0);
if (gc==NULL) {
#ifdef NAS_DEBUG_CLASS
printk("NAS_MESH_START_DEFAULT_SCLASS - Classifier not added \n");
#endif
return;
}
gc->fct = nas_COMMON_QOS_send;
gc->rab_id =rb->rab_id; //5
gc->rb= rb;
gc->version = NAS_VERSION_DEFAULT;
gc->protocol= NAS_PROTOCOL_ICMP6;
// gc->sport = NAS_PORT_DEFAULT;
// gc->dport = NAS_PORT_DEFAULT;
#ifdef NAS_DEBUG_CLASS
printk("NAS_MESH_START_DEFAULT_SCLASS - end \n");
nas_print_classifier(gc);
#endif
}
void nas_mesh_start_default_sclassifier(struct cx_entity *cx,struct rb_entity *rb)
{
//---------------------------------------------------------------------------
#ifdef DEMO_3GSM
struct classifier_entity *gc;
// Start debug information
#ifdef NAS_DEBUG_CLASS
printk("NAS_MESH_START_DEFAULT_SCLASS - begin \n");
#endif
if (cx==NULL) {
#ifdef NAS_DEBUG_CLASS
printk("NAS_MESH_START_DEFAULT_SCLASS - input parameter cx is NULL \n");
#endif
return;
}
if (rb==NULL) {
#ifdef NAS_DEBUG_CLASS
printk("NAS_MESH_START_DEFAULT_SCLASS - input parameter rb is NULL \n");
#endif
return;
}
// End debug information
gc=nas_CLASS_add_sclassifier(cx, NAS_DSCP_DEFAULT, 5);
// gc=nas_CLASS_add_sclassifier(cx, 5, 0);
if (gc==NULL) {
#ifdef NAS_DEBUG_CLASS
printk("NAS_MESH_START_DEFAULT_SCLASS - Classifier not added \n");
#endif
return;
}
gc->fct = nas_COMMON_QOS_send;
gc->rab_id =rb->rab_id; //5
gc->rb= rb;
gc->version = NAS_VERSION_DEFAULT;
gc->protocol= NAS_PROTOCOL_DEFAULT;
// gc->sport = NAS_PORT_DEFAULT;
// gc->dport = NAS_PORT_DEFAULT;
#ifdef NAS_DEBUG_CLASS
printk("NAS_MESH_START_DEFAULT_SCLASS - end \n");
nas_print_classifier(gc);
#endif
#endif
}
//---------------------------------------------------------------------------
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0))
void nas_mesh_timer(struct timer_list *t)
#else
void nas_mesh_timer(unsigned long data)
#endif
{
//---------------------------------------------------------------------------
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0))
struct nas_priv *gpriv=from_timer(gpriv, t, timer);
#else
struct nas_priv *gpriv=(struct nas_priv *) data;
#endif
uint8_t cxi;
struct cx_entity *cx;
struct rb_entity *rb;
// spin_lock(&gpriv->lock);
#ifdef NAS_DEBUG_TIMER
printk("NAS_MESH_TIMER - begin \n");
#endif
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0))
timer_setup(&gpriv->timer, nas_mesh_timer, 0);
mod_timer(&gpriv->timer, jiffies+NAS_TIMER_TICK);
#else
(gpriv->timer).function=nas_mesh_timer;
(gpriv->timer).expires=jiffies+NAS_TIMER_TICK;
(gpriv->timer).data=data;
#endif
return;
for (cxi=0; cxi<NAS_CX_MAX; ++cxi) {
cx=gpriv->cx+cxi;
if (cx==NULL) {
#ifdef NAS_DEBUG_TIMER
printk("NAS_MESH_TIMER - No pointer for connection %d \n", cxi);
#endif
continue;
}
if (cx->countimer!=NAS_TIMER_IDLE) {
#ifdef NAS_DEBUG_TIMER
printk("NAS_MESH_TIMER: lcr %u, countimer %u\n", cx->lcr, cx->countimer);
#endif
if (cx->countimer==0) {
switch (cx->state) {
case NAS_CX_CONNECTING:
case NAS_CX_CONNECTING_FAILURE:
if (cx->retry<gpriv->retry_limit)
nas_mesh_DC_send_cx_establish_request(cx,gpriv);
else {
printk("NAS_MESH_TIMER: Establishment failure\n");
cx->state=NAS_IDLE;
cx->retry=0;
cx->countimer=NAS_TIMER_IDLE;
}
break;
case NAS_CX_RELEASING_FAILURE:
nas_mesh_DC_send_cx_release_request(cx,gpriv);
break;
default:
printk("NAS_MESH_TIMER: default value\n");
cx->countimer=NAS_TIMER_IDLE;
}
} else
--cx->countimer;
}
for (rb=cx->rb; rb!=NULL; rb=rb->next) {
if (rb->countimer!=NAS_TIMER_IDLE) {
#ifdef NAS_DEBUG_TIMER
printk("NAS_MESH_TIMER : rb countimer %d, rb state %d\n", rb->countimer, rb->state);
#endif
if (rb->countimer==0) {
switch (rb->state) {
case NAS_RB_DCH:
nas_mesh_start_default_sclassifier(cx, rb);
rb->countimer=NAS_TIMER_IDLE;
break;
default:
rb->countimer=NAS_TIMER_IDLE;
}
} else {
--rb->countimer;
printk("NAS_MESH_TIMER : rb countimer-- %d, rb state %d\n", rb->countimer, rb->state);
}
}
}
}
// add_timer(&gpriv->timer);
// spin_unlock(&gpriv->lock);
}
//---------------------------------------------------------------------------
// Request the establishment of a connexion (DC channel)
int nas_mesh_DC_send_cx_establish_request(struct cx_entity *cx,struct nas_priv *gpriv)
{
//---------------------------------------------------------------------------
struct nas_ue_dc_element *p;
int bytes_wrote=0;
// Start debug information
#ifdef NAS_DEBUG_DC
printk("NAS_MESH_DC_SEND_CX_ESTABLISH - begin \n");
#endif
if (cx==NULL) {
#ifdef NAS_DEBUG_DC
printk("NAS_MESH_DC_SEND_CX_ESTABLISH - input parameter cx is NULL \n");
#endif
return NAS_ERROR_NOTCORRECTVALUE;
}
// End debug information
switch (cx->state) {
case NAS_CX_CONNECTING:
case NAS_CX_CONNECTING_FAILURE:
case NAS_IDLE:
p= (struct nas_ue_dc_element *)(gpriv->xbuffer);
p->type = CONN_ESTABLISH_REQ;
p->length = NAS_TL_SIZE + sizeof(struct NASConnEstablishReq);
p->nasUEDCPrimitive.conn_establish_req.localConnectionRef = cx->lcr;
p->nasUEDCPrimitive.conn_establish_req.cellId = cx->cellid;
#ifdef NAS_DEBUG_DC
printk ("\nCONN_ESTABLISH_REQ Buffer to Xmit: ");
nas_tool_print_buffer((char *)p,p->length);
#endif
++cx->retry;
cx->countimer=gpriv->timer_establishment;
if (bytes_wrote==p->length) {
cx->state=NAS_CX_CONNECTING;
#ifdef NAS_DEBUG_DC
printk("nas_mesh_DC_send_cx_establish_req: Message sent successfully in DC-FIFO\n");
printk(" Local Connection reference %u\n", p->nasUEDCPrimitive.conn_establish_req.localConnectionRef);
printk(" Cell Identification %u\n", p->nasUEDCPrimitive.conn_establish_req.cellId);
print_TOOL_state(cx->state);
#endif
} else {
cx->state=NAS_CX_CONNECTING_FAILURE;
printk("NAS_MESH_DC_SEND_CX_ESTABLISHMENT_REQUEST: Message sent failure in DC-FIFO\n");
print_TOOL_state(cx->state);
}
return bytes_wrote;
default:
return -NAS_ERROR_NOTIDLE;
#ifdef NAS_DEBUG_DC
printk("NAS_MESH_DC_SEND_CX_ESTABLISH - NAS_ERROR_NOTIDLE \n");
#endif
}
}
//---------------------------------------------------------------------------
// Request the release of a connexion (DC channel)
int nas_mesh_DC_send_cx_release_request(struct cx_entity *cx,
struct nas_priv *gpriv)
{
//---------------------------------------------------------------------------
struct nas_ue_dc_element *p;
int bytes_wrote=0;
// Start debug information
#ifdef NAS_DEBUG_DC
printk("NAS_MESH_DC_SEND_CX_RELEASE - begin \n");
#endif
if (cx==NULL) {
#ifdef NAS_DEBUG_DC
printk("NAS_MESH_DC_SEND_CX_RELEASE - input parameter cx is NULL \n");
#endif
return NAS_ERROR_NOTCORRECTVALUE;
}
// End debug information
switch (cx->state) {
case NAS_CX_RELEASING_FAILURE:
case NAS_CX_DCH:
p= (struct nas_ue_dc_element *)(gpriv->xbuffer);
p->type = CONN_RELEASE_REQ;
p->length = NAS_TL_SIZE + sizeof(struct NASConnReleaseReq);
p->nasUEDCPrimitive.conn_release_req.localConnectionRef = cx->lcr;
p->nasUEDCPrimitive.conn_release_req.releaseCause = NAS_CX_RELEASE_UNDEF_CAUSE;
if (bytes_wrote==p->length) {
cx->state=NAS_IDLE;
cx->iid4=0;
// nas_TOOL_imei2iid(NAS_NULL_IMEI, (uint8_t *)cx->iid6);
nas_COMMON_flush_rb(cx);
#ifdef NAS_DEBUG_DC
printk("NAS_MESH_DC_SEND_CX_RELEASE_REQUEST: Message sent successfully in DC-FIFO\n");
printk(" Local Connection Reference %u\n", p->nasUEDCPrimitive.conn_release_req.localConnectionRef);
printk(" Release Cause %u\n", p->nasUEDCPrimitive.conn_release_req.releaseCause);
print_TOOL_state(cx->state);
#endif
} else {
++cx->retry;
cx->countimer=gpriv->timer_release;
cx->state=NAS_CX_RELEASING_FAILURE;
printk("NAS_MESH_DC_SEND_CX_RELEASE_REQUEST: Message sent failure in DC-FIFO\n");
print_TOOL_state(cx->state);
}
return bytes_wrote;
default:
return -NAS_ERROR_NOTCONNECTED;
#ifdef NAS_DEBUG_DC
printk("NAS_MESH_DC_SEND_CX_RELEASE_REQUEST - NAS_ERROR_NOTCONNECTED \n");
#endif
}
}
//---------------------------------------------------------------------------
// Request the transfer of data (DC SAP)
void nas_mesh_DC_send_sig_data_request(struct sk_buff *skb,
struct cx_entity *cx,
struct classifier_entity *gc,
int inst,
struct nas_priv *gpriv)
{
//---------------------------------------------------------------------------
struct nas_ue_dc_element *p;
//char data_type = 'A';
int bytes_wrote=0;
// Start debug information
#ifdef NAS_DEBUG_DC
printk("NAS_MESH_DC_SEND_SIG - begin \n");
#endif
if (skb==NULL) {
#ifdef NAS_DEBUG_DC
printk("NAS_MESH_DC_SEND_SIG - input parameter skb is NULL \n");
#endif
return;
}
if (gc==NULL) {
#ifdef NAS_DEBUG_DC
printk("NAS_MESH_DC_SEND_SIG - input parameter gc is NULL \n");
#endif
return;
}
if (cx==NULL) {
#ifdef NAS_DEBUG_DC
printk("NAS_MESH_DC_SEND_SIG - input parameter cx is NULL \n");
#endif
return;
}
// End debug information
if (cx->state!=NAS_CX_DCH) {
printk("NAS_MESH_DC_SEND_SIG: Not connected, so the message is dropped\n");
++gpriv->stats.tx_dropped;
return;
}
p = (struct nas_ue_dc_element *)(gpriv->xbuffer);
p->type = DATA_TRANSFER_REQ;
p->length = NAS_TL_SIZE + sizeof(struct NASDataReq);
p->nasUEDCPrimitive.data_transfer_req.localConnectionRef = cx->lcr;
p->nasUEDCPrimitive.data_transfer_req.priority = 3; // TBD
p->nasUEDCPrimitive.data_transfer_req.nasDataLength = (skb->len)+1; //adds category character
if (bytes_wrote!=p->length) {
printk("NAS_MESH_DC_SEND_SIG: Header sent failure in DC-FIFO\n");
return;
}
if (bytes_wrote != p->length + skb->len + 1) {
printk("NAS_MESH_DC_SEND_SIG: Data sent failure in DC-FIFO\n");
return;
}
gpriv->stats.tx_bytes += skb->len;
gpriv->stats.tx_packets ++;
#ifdef NAS_DEBUG_DC
printk("NAS_MESH_DC_SEND_SIG - end \n");
#endif
}
//---------------------------------------------------------------------------
// Request the transfer of data (DC SAP)
void nas_mesh_DC_send_peer_sig_data_request(struct cx_entity *cx, uint8_t sig_category,
struct nas_priv *gpriv)
{
//---------------------------------------------------------------------------
struct nas_ue_dc_element *p;
uint8_t nas_data[10];
unsigned int nas_length;
//char data_type = 'Z';
int bytes_wrote=0;
// Start debug information
#ifdef NAS_DEBUG_DC
printk("NAS_MESH_DC_PEER_SEND_SIG - begin \n");
#endif
if (cx==NULL) {
#ifdef NAS_DEBUG_DC
printk("NAS_MESH_DC_PEER_SEND_SIG - input parameter cx is NULL \n");
#endif
return;
}
// End debug information
if (cx->state!=NAS_CX_DCH) {
printk("NAS_MESH_DC_PEER_SEND_SIG: Not connected, so the message is dropped\n");
return;
}
// Initialize peer message
nas_length = 10;
memset (nas_data, 0, nas_length);
nas_data[0]= sig_category;
//
p = (struct nas_ue_dc_element *)(gpriv->xbuffer);
p->type = DATA_TRANSFER_REQ;
p->length = NAS_TL_SIZE + sizeof(struct NASDataReq);
p->nasUEDCPrimitive.data_transfer_req.localConnectionRef = cx->lcr;
p->nasUEDCPrimitive.data_transfer_req.priority = 3; // TBD
p->nasUEDCPrimitive.data_transfer_req.nasDataLength = (nas_length)+1; //adds category character
if (bytes_wrote!=p->length) {
printk("NAS_MESH_DC_PEER_SEND_SIG: Header sent failure in DC-FIFO\n");
return;
}
if (bytes_wrote != p->length + nas_length + 1) {
printk("NAS_MESH_DC_PEER_SEND_SIG: Data sent failure in DC-FIFO\n");
return;
}
#ifdef NAS_DEBUG_DC
printk("NAS_MESH_DC_PEER_SEND_SIG - end \n");
#endif
}
//---------------------------------------------------------------------------
// Decode CONN_ESTABLISH_RESP message from RRC
void nas_mesh_DC_decode_cx_establish_resp(struct cx_entity *cx, struct nas_ue_dc_element *p,struct nas_priv *gpriv)
{
//---------------------------------------------------------------------------
uint8_t sig_category;
// Start debug information
#ifdef NAS_DEBUG_DC
printk("NAS_MESH_DC_DECODE_CX_ESTABLISH - begin \n");
#endif
if (cx==NULL) {
#ifdef NAS_DEBUG_DC
printk("NAS_MESH_DC_DECODE_CX_ESTABLISH - input parameter cx is NULL \n");
#endif
return;
}
if (p==NULL) {
#ifdef NAS_DEBUG_DC
printk("NAS_MESH_DC_DECODE_CX_ESTABLISH - input parameter p is NULL \n");
#endif
return;
}
// End debug information
cx->retry=0;
if (p->nasUEDCPrimitive.conn_establish_resp.status == TERMINATED) {
cx->state=NAS_CX_DCH; //to be changed to NAS_CX_FACH
cx->iid4=1;
//nas_TOOL_imei2iid(NAS_RG_IMEI, (uint8_t *)cx->iid6);
sig_category = NAS_CMD_OPEN_RB;
//For demo, add automatically a radio bearer
#ifdef DEMO_3GSM
printk("NAS_MESH_DC_DECODE_CX_ESTABLISH - sig_category %u \n", sig_category);
nas_mesh_DC_send_peer_sig_data_request(cx, sig_category,gpriv);
#endif
} else {
cx->state=NAS_IDLE;
}
#ifdef NAS_DEBUG_DC
printk("NAS_MESH_DC_RECEIVE: CONN_ESTABLISH_RESP\n");
printk("Local Connection reference %u\n",p->nasUEDCPrimitive.conn_establish_resp.localConnectionRef);
printk("Connection Establishment status %u\n",p->nasUEDCPrimitive.conn_establish_resp.status);
print_TOOL_state(cx->state);
#endif
}
//---------------------------------------------------------------------------
// Decode CONN_LOSS_IND message from RRC
void nas_mesh_DC_decode_cx_loss_ind(struct cx_entity *cx, struct nas_ue_dc_element *p)
{
//---------------------------------------------------------------------------
// Start debug information
#ifdef NAS_DEBUG_DC
printk("NAS_MESH_DC_DECODE_CX_LOSS - begin \n");
#endif
if (cx==NULL) {
#ifdef NAS_DEBUG_DC
printk("NAS_MESH_DC_DECODE_CX_LOSS - input parameter cx is NULL \n");
#endif
return;
}
if (p==NULL) {
#ifdef NAS_DEBUG_DC
printk("NAS_MESH_DC_DECODE_CX_LOSS - input parameter p is NULL \n");
#endif
return;
}
// End debug information
cx->state=NAS_IDLE;
cx->iid4=0;
//nas_TOOL_imei2iid(NAS_NULL_IMEI, (uint8_t *)cx->iid6);
nas_COMMON_flush_rb(cx);
#ifdef NAS_DEBUG_DC
printk("NAS_MESH_DC_RECEIVE: CONN_LOSS_IND reception\n");
printk(" Local Connection reference %u\n", p->nasUEDCPrimitive.conn_loss_ind.localConnectionRef);
print_TOOL_state(cx->state);
#endif
}
//---------------------------------------------------------------------------
// Decode CONN_RELEASE_IND message from RRC
//void nas_mesh_DC_decode_cx_release_ind(struct cx_entity *cx, struct nas_ue_dc_element *p){
//---------------------------------------------------------------------------
// printk("\t\tCONN_RELEASE_IND\n");
// printk("\t\tLocal Connection reference %u\n", p->nasUEDCPrimitive.conn_release_ind.localConnectionRef);
// printk("\t\tRelease cause %u\n", p->nasRGDCPrimitive.conn_release_ind.releaseCause);
// if (gpriv->cx[cxi].state==NAS_CX_DCH)
// {
// gpriv->cx[cxi].state=NAS_IDLE;
// printk("\t\tMobile no more connected\n");
// return bytes_read;
// }
// printk("\t\tIncoherent state %u\n", gpriv->cx[cxi].state);
// return bytes_read;
//}
//---------------------------------------------------------------------------
// Decode DATA_TRANSFER_IND message from RRC
void nas_mesh_DC_decode_sig_data_ind(struct cx_entity *cx, struct nas_ue_dc_element *p)
{
//---------------------------------------------------------------------------
// Start debug information
#ifdef NAS_DEBUG_DC
printk("NAS_MESH_DC_DECODE_SIG_DATA_IND - begin \n");
#endif
if (cx==NULL) {
#ifdef NAS_DEBUG_DC
printk("NAS_MESH_DC_DECODE_SIG_DATA_IND - input parameter cx is NULL \n");
#endif
return;
}
if (p==NULL) {
#ifdef NAS_DEBUG_DC
printk("NAS_MESH_DC_DECODE_SIG_DATA_IND - input parameter p is NULL \n");
#endif
return;
}
// End debug information
#ifdef NAS_DEBUG_DC
printk("NAS_MESH_DC_RECEIVE: DATA_TRANSFER_IND reception\n");
printk(" Local Connection reference %u\n",p->nasUEDCPrimitive.data_transfer_ind.localConnectionRef);
printk(" Signaling Priority %u\n",p->nasUEDCPrimitive.data_transfer_ind.priority);
printk(" NAS Data length %u\n",p->nasUEDCPrimitive.data_transfer_ind.nasDataLength);
printk(" NAS Data string %s\n", (uint8_t *)p+p->length);
#endif
}
//---------------------------------------------------------------------------
// Decode RB_ESTABLISH_IND message from RRC
void nas_mesh_DC_decode_rb_establish_ind(struct cx_entity *cx, struct nas_ue_dc_element *p,struct nas_priv *gpriv)
{
//---------------------------------------------------------------------------
struct rb_entity *rb;
// Start debug information
#ifdef NAS_DEBUG_DC
printk("NAS_MESH_DC_DECODE_RB_ESTABLISH_IND - begin \n");
#endif
if (cx==NULL) {
#ifdef NAS_DEBUG_DC
printk("NAS_MESH_DC_DECODE_RB_ESTABLISH_IND - input parameter cx is NULL \n");
#endif
return;
}
if (p==NULL) {
#ifdef NAS_DEBUG_DC
printk("NAS_MESH_DC_DECODE_RB_ESTABLISH_IND - input parameter p is NULL \n");
#endif
return;
}
// End debug information
rb=nas_COMMON_search_rb(cx, p->nasUEDCPrimitive.rb_release_ind.rbId);
if (rb==NULL) {
rb=nas_COMMON_add_rb(cx, p->nasUEDCPrimitive.rb_establish_ind.rbId, p->nasUEDCPrimitive.rb_establish_ind.QoSclass);
rb->state=NAS_RB_DCH;
cx->state=NAS_CX_DCH;
//For demo, add automatically a classifier
#ifdef DEMO_3GSM
rb->countimer=gpriv->timer_establishment+10;
#endif
#ifdef NAS_DEBUG_DC
printk("NAS_MESH_DC_DECODE_RB_ESTABLISH_IND: RB_ESTABLISH_IND reception\n");
printk(" Local Connection reference %u\n",p->nasUEDCPrimitive.rb_establish_ind.localConnectionRef);
printk(" Radio Bearer Identity %u \n",p->nasUEDCPrimitive.rb_establish_ind.rbId);
printk(" QoS Traffic Class %u\n",p->nasUEDCPrimitive.rb_establish_ind.QoSclass);
printk(" DSCP Code %u\n",p->nasUEDCPrimitive.rb_establish_ind.dscp);
printk(" SAP Id %u\n",p->nasUEDCPrimitive.rb_establish_ind.sapId);
print_TOOL_state(cx->state);
nas_print_rb_entity(rb);
#endif
} else
printk("NAS_MESH_DC_DECODE_RB_ESTABLISH_IND: RB_ESTABLISH_IND reception, Radio bearer already opened\n");
}
//---------------------------------------------------------------------------
// Decode RB_RELEASE_IND message from RRC
void nas_mesh_DC_decode_rb_release_ind(struct cx_entity *cx, struct nas_ue_dc_element *p)
{
//---------------------------------------------------------------------------
struct rb_entity *rb;
// Start debug information
#ifdef NAS_DEBUG_DC
printk("NAS_MESH_DC_DECODE_RB_RELEASE_IND - begin \n");
#endif
if (cx==NULL) {
#ifdef NAS_DEBUG_DC
printk("NAS_MESH_DC_DECODE_RB_RELEASE_IND - input parameter cx is NULL \n");
#endif
return;
}
if (p==NULL) {
#ifdef NAS_DEBUG_DC
printk("NAS_MESH_DC_DECODE_RB_RELEASE_IND - input parameter p is NULL \n");
#endif
return;
}
// End debug information
rb=nas_COMMON_search_rb(cx, p->nasUEDCPrimitive.rb_release_ind.rbId);
if (rb!=NULL) {
rb->state=NAS_IDLE;
//needs also to flush corresponding control block to be coherent with add_rb
#ifdef NAS_DEBUG_DC
printk("NAS_MESH_DC_DECODE_RB_RELEASE_IND: RB_RELEASE_IND reception\n");
printk("Local Connection reference %u\n",p->nasUEDCPrimitive.rb_release_ind.localConnectionRef);
printk("Radio Bearer Identity %u\n",p->nasUEDCPrimitive.rb_release_ind.rbId);
print_TOOL_state(cx->state);
#endif
} else
printk("NAS_DC_RG_RECEIVE: RB_RELEASE_IND reception, No corresponding radio bearer\n");
}
//---------------------------------------------------------------------------
// Decode MEASUREMENT_IND message from RRC
void nas_mesh_DC_decode_measurement_ind(struct cx_entity *cx, struct nas_ue_dc_element *p)
{
//---------------------------------------------------------------------------
uint8_t i;
// Start debug information
#ifdef NAS_DEBUG_DC
printk("NAS_MESH_DC_DECODE_MEASUREMENT_IND - begin \n");
#endif
if (cx==NULL) {
#ifdef NAS_DEBUG_DC
printk("NAS_MESH_DC_DECODE_MEASUREMENT_IND - input parameter cx is NULL \n");
#endif
return;
}
if (p==NULL) {
#ifdef NAS_DEBUG_DC
printk("NAS_MESH_DC_DECODE_MEASUREMENT_IND - input parameter p is NULL \n");
#endif
return;
}
// End debug information
#ifdef NAS_DEBUG_DC_MEASURE
printk("NAS_MESH_DC_RECEIVE: MEASUREMENT_IND reception\n");
printk(" Local Connection reference: %u\n", p->nasUEDCPrimitive.measurement_ind.localConnectionRef);
printk(" Number of RGs: %u\n", p->nasUEDCPrimitive.measurement_ind.nb_rg);
print_TOOL_state(cx->state);
for (i=0; i<p->nasUEDCPrimitive.measurement_ind.nb_rg; ++i) {
printk(" RG[%u]: Cell_Id %u, Level: %u\n", i,
p->nasUEDCPrimitive.measurement_ind.measures[i].cell_id,
p->nasUEDCPrimitive.measurement_ind.measures[i].level);
}
#endif //NAS_DEBUG_DC_MEASURE
cx->num_measures = p->nasUEDCPrimitive.measurement_ind.nb_rg;
for (i=0; i<cx->num_measures; i++) {
cx->meas_cell_id[i]= (int)(p->nasUEDCPrimitive.measurement_ind.measures[i].cell_id);
cx->meas_level[i] = (int)(p->nasUEDCPrimitive.measurement_ind.measures[i].level);
//npriv->provider_id[i]=;
}
cx->provider_id[0]=25;
cx->provider_id[1]=1;
cx->provider_id[2]=25;
}
//---------------------------------------------------------------------------
// Check if anything in DC FIFO and decode it (MESH)
int nas_mesh_DC_receive(struct cx_entity *cx,struct nas_priv *gpriv)
{
//---------------------------------------------------------------------------
// Start debug information
int bytes_read=0;
#ifdef NAS_DEBUG_DC
printk("NAS_MESH_DC_RECEIVE - begin \n");
#endif
if (cx==NULL) {
#ifdef NAS_DEBUG_DC
printk("NAS_MESH_DC_RECEIVE - input parameter cx is NULL \n");
#endif
return NAS_ERROR_NOTCORRECTVALUE;
}
// End debug information
if (bytes_read>0) {
struct nas_ue_dc_element *p;
p= (struct nas_ue_dc_element *)(gpriv->rbuffer);
//get the rest of the primitive
if (bytes_read!=p->length) {
printk("NAS_MESH_DC_RECEIVE: Problem while reading primitive header\n");
return bytes_read;
}
switch (p->type) {
case CONN_ESTABLISH_RESP :
if (p->nasUEDCPrimitive.conn_establish_resp.localConnectionRef!=cx->lcr)
printk("NAS_MESH_DC_RECEIVE: CONN_ESTABLISH_RESP, Local connection reference not correct %u\n",p->nasUEDCPrimitive.conn_establish_resp.localConnectionRef);
else {
switch (cx->state) {
case NAS_CX_CONNECTING:
nas_mesh_DC_decode_cx_establish_resp(cx,p,gpriv); // process message
break;
default:
printk("NAS_MESH_DC_RECEIVE: CONN_ESTABLISH_RESP reception, Invalid state %u\n", cx->state);
}
}
break;
case CONN_LOSS_IND :
if (p->nasUEDCPrimitive.conn_loss_ind.localConnectionRef!=cx->lcr)
printk("NAS_MESH_DC_RECEIVE: CONN_LOSS_IND reception, Local connection reference not correct %u\n", p->nasUEDCPrimitive.conn_loss_ind.localConnectionRef);
else {
switch (cx->state) {
case NAS_CX_RELEASING_FAILURE:
cx->retry=0;
/* fallthrough */
case NAS_CX_DCH:
nas_mesh_DC_decode_cx_loss_ind(cx,p); // process message
break;
default:
printk("NAS_MESH_DC_RECEIVE: CONN_LOSS_IND reception, Invalid state %u", cx->state);
}
}
break;
// case CONN_RELEASE_IND :
// break;
case DATA_TRANSFER_IND :
if (p->nasUEDCPrimitive.data_transfer_ind.localConnectionRef!=cx->lcr)
printk("NAS_MESH_DC_RECEIVE: DATA_TRANSFER_IND reception, Local connection reference not correct %u\n", p->nasUEDCPrimitive.conn_loss_ind.localConnectionRef);
else {
switch (cx->state) {
case NAS_CX_FACH:
case NAS_CX_DCH:
nas_mesh_DC_decode_sig_data_ind(cx,p); // process message
break;
default:
printk("NAS_MESH_DC_RECEIVE: DATA_TRANSFER_IND reception, Invalid state %u", cx->state);
}
}
break;
case RB_ESTABLISH_IND :
if (p->nasUEDCPrimitive.rb_establish_ind.localConnectionRef!=cx->lcr)
printk("NAS_MESH_DC_RECEIVE: RB_ESTABLISH_IND reception, Local connexion reference not correct %u\n", p->nasUEDCPrimitive.rb_establish_ind.localConnectionRef);
else {
switch (cx->state) {
case NAS_CX_FACH:
case NAS_CX_DCH:
nas_mesh_DC_decode_rb_establish_ind(cx,p,gpriv); // process message
break;
default:
printk("NAS_MESH_DC_RECEIVE: RB_ESTABLISH_IND reception, Invalid state %u", cx->state);
}
}
break;
case RB_RELEASE_IND :
if (p->nasUEDCPrimitive.rb_release_ind.localConnectionRef!=cx->lcr)
printk("NAS_DC_MESH_RECEIVE: RB_RELEASE_IND reception, Local connection reference not correct %u\n", p->nasUEDCPrimitive.rb_release_ind.localConnectionRef);
else {
switch (cx->state) {
case NAS_CX_DCH:
nas_mesh_DC_decode_rb_release_ind(cx,p); // process message
break;
default:
printk("NAS_MESH_DC_RECEIVE: RB_RELEASE_IND reception, Invalid state %u", cx->state);
}
}
break;
case MEASUREMENT_IND :
if (p->nasUEDCPrimitive.measurement_ind.localConnectionRef!=cx->lcr)
printk("NAS_MESH_DC_RECEIVE: MEASUREMENT_IND reception, Local connection reference not correct %u\n", p->nasUEDCPrimitive.measurement_ind.localConnectionRef);
else {
nas_mesh_DC_decode_measurement_ind(cx,p);
}
break;
default :
printk("NAS_MESH_DC_RECEIVE: Invalid message received\n");
}
}
#ifdef NAS_DEBUG_DC
printk("NAS_MESH_DC_RECEIVE - end \n");
#endif
return bytes_read;
}
//---------------------------------------------------------------------------
// Check if anything in GC FIFO and decode it (MESH)
int nas_mesh_GC_receive(struct nas_priv *gpriv)
{
//---------------------------------------------------------------------------
int bytes_read=0;
#ifdef NAS_DEBUG_GC
printk("NAS_MESH_GC_RECEIVE - begin \n");
#endif
if (bytes_read>0) {
struct nas_ue_gc_element *p;
p= (struct nas_ue_gc_element *)(gpriv->rbuffer);
//get the rest of the primitive
if (bytes_read!=p->length) {
printk("NAS_MESH_GC_RECEIVE: Problem while reading primitive's header\n");
return bytes_read;
}
// start decoding message
switch (p->type) {
case INFO_BROADCAST_IND :
if (bytes_read!=p->length+p->nasUEGCPrimitive.broadcast_ind.nasDataLength) {
printk("NAS_MESH_GC_RECEIVE: INFO_BROADCAST_IND reception, Problem while reading primitive's data\n");
return bytes_read;
}
#ifdef NAS_DEBUG_GC
printk("NAS_MESH_GC_RECEIVE: INFO_BROADCAST_IND reception\n");
printk(" Primitive length %d \n", (int)(p->type));
printk(" Data length %u\n", p->nasUEGCPrimitive.broadcast_ind.nasDataLength);
printk(" Data string %s\n", (uint8_t *)p+p->length);
#endif //NAS_DEBUG_GC
return bytes_read;
default :
printk("NAS_MESH_GC_RECEIVE: Invalid message received\n");
return -1;
}
} else
return -1;
}
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/*! \file netlink.c
* \brief establish a netlink
* \author Navid Nikaein, Lionel Gauthier, and Raymond knopp
* \company Eurecom
* \email:navid.nikaein@eurecom.fr, lionel.gauthier@eurecom.fr, knopp@eurecom.fr
*/
//#include <linux/config.h>
#include <linux/version.h>
#include <linux/socket.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/netlink.h>
#include <net/sock.h>
#include <linux/kthread.h>
#include <linux/mutex.h>
#include "local.h"
#include "proto_extern.h"
//#include "common/platform_constants.h"
//#define NETLINK_DEBUG 1
#define OAI_IP_DRIVER_NETLINK_ID 31
#define NL_DEST_PID 1
static struct sock *nas_nl_sk = NULL;
static int exit_netlink_thread=0;
//static int nas_netlink_rx_thread(void *);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0)
struct netlink_kernel_cfg oai_netlink_cfg;
#endif
static DEFINE_MUTEX(nasmesh_mutex);
static inline void nasmesh_lock(void)
{
mutex_lock(&nasmesh_mutex);
}
static inline void nasmesh_unlock(void)
{
mutex_unlock(&nasmesh_mutex);
}
// This can also be implemented using thread to get the data from PDCP without blocking.
static void nas_nl_data_ready (struct sk_buff *skb)
{
// wake_up_interruptible(skb->sk->sk_sleep);
//nasmesh_lock();
//netlink_rcv_skb(skb, &my_rcv_msg);// my_rcv_msg is the call back func>
//nasmesh_unlock();
struct nlmsghdr *nlh = NULL;
//int j;
if (skb) {
#ifdef NETLINK_DEBUG
printk("[NAS][NETLINK] Received socket from PDCP\n");
#endif //NETLINK_DEBUG
nlh = (struct nlmsghdr *)skb->data;
nas_COMMON_QOS_receive(nlh);
//kfree_skb(skb); // not required,
}
}
int nas_netlink_init()
{
printk("[NAS][NETLINK] Running init ...\n");
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0)
oai_netlink_cfg.groups = 0;
oai_netlink_cfg.input = nas_nl_data_ready;
oai_netlink_cfg.cb_mutex = &nasmesh_mutex;
oai_netlink_cfg.bind = NULL;
nas_nl_sk = netlink_kernel_create(
&init_net,
OAI_IP_DRIVER_NETLINK_ID,
# if LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0)
THIS_MODULE,
# endif
&oai_netlink_cfg);
#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0) */
nas_nl_sk = netlink_kernel_create(
&init_net,
OAI_IP_DRIVER_NETLINK_ID,
0,
nas_nl_data_ready,
&nasmesh_mutex, // NULL
THIS_MODULE);
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0) */
if (nas_nl_sk == NULL) {
printk("[NAS][NETLINK] netlink_kernel_create failed \n");
return(-1);
}
return(0);
}
void nas_netlink_release(void)
{
exit_netlink_thread=1;
printk("[NAS][NETLINK] Releasing netlink socket\n");
if(nas_nl_sk) {
netlink_kernel_release(nas_nl_sk); //or skb->sk
}
// printk("[NAS][NETLINK] Removing netlink_rx_thread\n");
//kthread_stop(netlink_rx_thread);
}
int nas_netlink_send(unsigned char *data,unsigned int len)
{
struct sk_buff *nl_skb = alloc_skb(NLMSG_SPACE(len),GFP_ATOMIC);
struct nlmsghdr *nlh = (struct nlmsghdr *)nl_skb->data;
int status;
//printk("[NAS][NETLINK] Sending %d bytes (%d)\n",len,NLMSG_SPACE(len));
skb_put(nl_skb, NLMSG_SPACE(len));
memcpy(NLMSG_DATA(nlh),data,len);
nlh->nlmsg_len = NLMSG_SPACE(len);
nlh->nlmsg_pid = 0; /* from kernel */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
NETLINK_CB(nl_skb).portid = 0;
#else
NETLINK_CB(nl_skb).pid = 0;
#endif
#ifdef NETLINK_DEBUG
printk("[NAS][NETLINK] In nas_netlink_send, nl_skb %p, nl_sk %x, nlh %p, nlh->nlmsg_len %d (OAI_IP_DRIVER_NETLINK_ID %d)\n",
nl_skb,nas_nl_sk,nlh,nlh->nlmsg_len,
OAI_IP_DRIVER_NETLINK_ID);
#endif //DEBUG_NETLINK
if (nas_nl_sk) {
// nasmesh_lock();
status = netlink_unicast(nas_nl_sk, nl_skb, NL_DEST_PID, MSG_DONTWAIT);
// mutex_unlock(&nasmesh_mutex);
if (status < 0) {
printk("[NAS][NETLINK] SEND status is %d\n",status);
return(0);
} else {
#ifdef NETLINK_DEBUG
printk("[NAS][NETLINK] SEND status is %d\n",status);
#endif
return len;
}
} else {
printk("[NAS][SEND] socket is NULL\n");
return(0);
}
/*
nlmsg_failure: // Used by NLMSG_PUT
if (nl_skb)
kfree_skb(nl_skb);
*/
}
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/***************************************************************************
nas_proto_extern.h - description
-------------------
copyright : (C) 2002 by Eurecom
email : navid.nikaein@eurecom.fr
lionel.gauthier@eurecom.fr
knopp@eurecom.fr
***************************************************************************/
#ifndef __NETWORK_DRIVER_MESH_PROTO_EXTERN__H__
#define __NETWORK_DRIVER_MESH_PROTO_EXTERN__H__
#include <linux/if_arp.h>
#include <linux/types.h>
#include <linux/spinlock.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/ipv6.h>
#include <linux/ip.h>
#include <linux/sysctl.h>
#include <linux/timer.h>
#include <asm/param.h>
//#include <sys/sysctl.h>
#include <linux/udp.h>
#include <linux/tcp.h>
#include <linux/icmp.h>
#include <linux/icmpv6.h>
#include <linux/in.h>
#include <net/ndisc.h>
//#include "rrc_nas_primitives.h"
//#include "protocol_vars_extern.h"
//#include "as_sap.h"
//#include "rrc_qos.h"
//#include "rrc_sap.h"
#include "local.h"
// device.c
/** @defgroup _nas_mesh_impl_ NAS Mesh Network Device
* @ingroup _ref_implementation_
* @{
\fn int find_inst(struct net_device *dev)
\brief This function determines the instance id for a particular device pointer.
@param dev Pointer to net_device structure
*/
int find_inst(struct net_device *dev);
// nas_common.c
/**
\fn void nas_COMMON_receive(unsigned short dlen, void* pdcp_sdu,int inst,struct classifier_entity *rclass,nasRadioBearerId_t rb_id)
\brief Receive data from FIFO (QOS)
@param dlen Length of SDU in bytes
@param pdcp_sdu Pointer to received SDU
@param inst Instance number
@param rclass RX Classifier entity
@param rb_id Radio Bearer Id
*/
void nas_COMMON_receive(unsigned short dlen,
void *pdcp_sdu,
int inst,
struct classifier_entity *rclass,
nasRadioBearerId_t rb_id);
/**
\fn void nas_COMMON_QOS_send(struct sk_buff *skb, struct cx_entity *cx, struct classifier_entity *gc,int inst)
\brief Request the transfer of data (QoS SAP)
@param skb pointer to socket buffer
@param cx pointer to connection entity for SDU
@param gc pointer to classifier entity for SDU
@param inst device instance
*/
void nas_COMMON_QOS_send(struct sk_buff *skb,
struct cx_entity *cx,
struct classifier_entity *gc,int inst, struct nas_priv *gpriv);
/**
\fn void nas_COMMON_del_send(struct sk_buff *skb, struct cx_entity *cx, struct classifier_entity *gc,int inst)
\brief Delete the data
@param skb pointer to socket buffer
@param cx pointer to connection entity for SDU
@param gc pointer to classifier entity for SDU
@param inst device instance
*/
void nas_COMMON_del_send(struct sk_buff *skb,
struct cx_entity *cx,
struct classifier_entity *gc,int inst, struct nas_priv *gpriv);
/**
\fn struct rb_entity *nas_COMMON_add_rb(struct cx_entity *cx, nasRadioBearerId_t rabi, nasQoSTrafficClass_t qos)
\brief Add a radio-bearer descriptor
@param cx pointer to connection entity
@param rabi radio-bearer index
@param qos NAS QOS traffic class
*/
struct rb_entity *nas_COMMON_add_rb(
struct cx_entity *cx, nasRadioBearerId_t rabi,
nasQoSTrafficClass_t qos);
/**
\fn struct rb_entity *nas_COMMON_search_rb(struct cx_entity *cx, nasRadioBearerId_t rabi)
\brief Search for a radio-bearer entity for a particular connection and radio-bearer index
@param cx pointer to connection entity
@param rabi radio-bearer index
@returns A pointer to the radio-bearer entity
*/
struct rb_entity *nas_COMMON_search_rb(
struct cx_entity *cx, nasRadioBearerId_t rabi);
/**
\fn struct cx_entity *nas_COMMON_search_cx(nasLocalConnectionRef_t lcr,struct nas_priv *gpriv)
\brief Search for a connection entity based on its index and pointer to nas_priv
@param lcr index of local connection
@param gpriv pointer to nas_priv for device
@returns A pointer to the connection entity
*/
struct cx_entity *nas_COMMON_search_cx(
nasLocalConnectionRef_t lcr,
struct nas_priv *gpriv);
/**
\fn struct classifier_entity *nas_COMMON_search_class_for_rb(nasRadioBearerId_t rab_id,struct nas_priv *priv)
\brief Search for an RX classifier entity based on a RB id and pointer to nas_priv
@param rab_id Index of RAB for search
@param priv pointer to nas_priv for device
@returns A pointer to the corresponding RX classifier entity
*/
struct classifier_entity
*nas_COMMON_search_class_for_rb(nasRadioBearerId_t
rab_id,struct nas_priv *priv);
/**
\fn void nas_COMMON_flush_rb(struct cx_entity *cx)
\brief Clear all RB's for a particular connection
@param cx pointer to connection entity
*/
void nas_COMMON_flush_rb(struct cx_entity *cx);
/**
\fn int nas_netlink_send(unsigned char *data,unsigned int len)
\brief Request the transfer of data by PDCP via netlink socket
@param data pointer to SDU
@param len length of SDU in bytes
@returns Numeber of bytes transfered by netlink socket
*/
int nas_netlink_send(unsigned char *data,unsigned int len);
/**
\fn void nas_COMMON_QOS_receive(struct nlmsghdr *nlh)
\brief Request a PDU from PDCP
@param nlh pointer to netlink message header
*/
void nas_COMMON_QOS_receive(struct nlmsghdr *nlh);
//nasmesh.c
/**
\brief Initialize an interface for a particular instance ID.
*/
void nas_mesh_init(int inst //!< Instance ID
);
int nas_mesh_DC_receive(struct cx_entity *cx,struct nas_priv *gpriv);
int nas_mesh_GC_receive(struct nas_priv *gpriv);
int nas_mesh_DC_send_cx_establish_request(struct cx_entity *cx,struct nas_priv *gpriv);
int nas_mesh_DC_send_cx_release_request(struct cx_entity *cx,struct nas_priv *gpriv);
void nas_mesh_DC_send_sig_data_request(struct sk_buff *skb, struct cx_entity *cx, struct classifier_entity *gc,int inst, struct nas_priv *gpriv);
// iocontrol.c
void nas_CTL_send(struct sk_buff *skb,
struct cx_entity *cx,
struct classifier_entity *gc,int inst, struct nas_priv *gpriv);
//int nas_CTL_receive_authentication(struct ipv6hdr *iph, struct cx-entity *cx, unsigned char sapi);
int nas_CTL_ioctl(struct net_device *dev,
struct ifreq *ifr, int cmd);
// classifier.c
/**
\brief Send a socket received from IP to classifier for a particular instance ID.
*/
void nas_CLASS_send(struct sk_buff *skb, //!< Pointer to socket buffer
int inst //!< Instance ID
);
/**
\brief
*/
struct classifier_entity *nas_CLASS_add_sclassifier(struct cx_entity *cx, unsigned char dscp, unsigned short classref);
/**
\brief Send a socket received from IP to classifier for a particular instance ID.
*/
struct classifier_entity
*nas_CLASS_add_fclassifier(struct cx_entity *cx,
unsigned char dscp,
unsigned short classref
);
/**
\brief Send a socket received from IP to classifier for a particular instance ID.
*/
struct classifier_entity
*nas_CLASS_add_rclassifier(unsigned char dscp,
unsigned short classref,
struct nas_priv*
);
/**
\brief
*/
void nas_CLASS_del_sclassifier(struct cx_entity *cx,
unsigned char dscp,
unsigned short classref
);
/**
\brief
*/
void nas_CLASS_del_fclassifier(struct cx_entity *cx,
unsigned char dscp,
unsigned short classref
);
/**
\brief
*/
void nas_CLASS_del_rclassifier(unsigned char dscp,
unsigned short classref,
struct nas_priv*
);
/**
\brief
*/
void nas_CLASS_flush_sclassifier(struct cx_entity *cx
);
/**
\brief
*/
void nas_CLASS_flush_fclassifier(struct cx_entity *cx
);
/**
\brief
*/
void nas_CLASS_flush_rclassifier(struct nas_priv *gpriv
);
// nas_tool.c
unsigned char nas_TOOL_invfct(struct classifier_entity *gc);
void nas_TOOL_fct(struct classifier_entity *gc, unsigned char fct);
void nas_TOOL_imei2iid(unsigned char *imei, unsigned char *iid);
unsigned char nas_TOOL_get_dscp6(struct ipv6hdr *iph);
unsigned char nas_TOOL_get_dscp4(struct iphdr *iph);
unsigned char *nas_TOOL_get_protocol6(struct ipv6hdr *iph, unsigned char *protocol);
unsigned char *nas_TOOL_get_protocol4(struct iphdr *iph, unsigned char *protocol);
char *nas_TOOL_get_udpmsg(struct udphdr *udph);
unsigned short nas_TOOL_udpcksum(struct in6_addr *saddr, struct in6_addr *daddr, unsigned char proto, unsigned int udplen, void *data);
int nas_TOOL_network6(struct in6_addr *addr, struct in6_addr *prefix, unsigned char plen);
int nas_TOOL_network4(unsigned int *addr, unsigned int *prefix, unsigned char plen);
void print_TOOL_pk_icmp6(struct icmp6hdr *icmph);
void print_TOOL_pk_all(struct sk_buff *skb);
void print_TOOL_pk_ipv6(struct ipv6hdr *iph);
void print_TOOL_state(unsigned char state);
void nas_tool_print_buffer(char * buffer,int length);
void nas_print_rb_entity(struct rb_entity *rb);
void nas_print_classifier(struct classifier_entity *gc);
// nas_netlink.c
void nas_netlink_release(void);
int nas_netlink_init(void);
/** @} */
#endif
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/*********************************************************************
rrc_nas_primitives.h - description
-------------------
begin : Jan 11, 2002
copyright : (C) 2001 by Eurecom
email : navid.nikaein@eurecom.fr
lionel.gauthier@eurecom.fr
knopp@eurecom.fr
*********************************************************************
Define RRC external interface primitives
********************************************************************/
#ifndef __RRC_NASPRIM_H__
# define __RRC_NASPRIM_H__
//----------------------------------------------------------
// Primitives
//----------------------------------------------------------
# define INFO_BROADCAST_REQ 1
# define INFO_BROADCAST_IND 2
# define CONN_ESTABLISH_REQ 3
# define CONN_ESTABLISH_IND 4
# define CONN_ESTABLISH_RESP 5
# define CONN_ESTABLISH_CNF 6
# define CONN_RELEASE_REQ 7
# define CONN_RELEASE_IND 8
# define DATA_TRANSFER_REQ 9
# define DATA_TRANSFER_IND 10
# define RB_ESTABLISH_REQ 11
# define RB_ESTABLISH_IND 12
# define RB_ESTABLISH_CNF 14
# define RB_RELEASE_REQ 15
# define RB_RELEASE_IND 16
# define MEASUREMENT_IND 17
# define CONN_LOSS_IND 18
# define PAGING_REQ 19
# define NOTIFICATION_IND 20
//----------------------------------------------------------
// Constants
//----------------------------------------------------------
// Define max length authorized (to be updated later)
# define NAS_MAX_LENGTH 180 // maximum length of a NAS primitive
# define NAS_TL_SIZE 4 // size of the Type+Length fields of the primitive
# define NAS_DATA_MAX_LENGTH NAS_MAX_LENGTH - NAS_TL_SIZE //remaining bytes for the message
# define MAX_RABS 8 * 64 //NB_RAB_MAX * MAX_MOBILES_PER_RG //27 // = MAXURAB
# define MAX_MEASURE_NB 5
//Connection Establishment status
// UE
# define TERMINATED 0
# define ABORTED 1
# define ALREADY_CONNECTED 2
// RG + RB Establishment Confirm
# define ACCEPTED 0
# define FAILURE 1
//----------------------------------------------------------
// Parameter types
//----------------------------------------------------------
typedef unsigned int nasPeriod_t; // Broadcast repetition period
typedef unsigned short nasBroadcastCategory_t; // identifies the type of data to broadcast (IP signalling/ List of neighbors)
typedef unsigned char nasIMEI_t[14]; // 14 digits of IMEI
typedef unsigned short nasDataLength_t; // Length of the data in the primitive
typedef unsigned short nasCellID_t; // ID of the cell for connection
typedef unsigned int nasLocalConnectionRef_t; // local identifier
typedef unsigned short nasConnectionStatus_t; // connection establishment status
typedef unsigned short nasReleaseCause_t; // connection release cause
typedef unsigned short nasSignalingPriority_t; // priority to use srb3 or srb4
typedef unsigned short nasRadioBearerId_t;
typedef unsigned short nasQoSTrafficClass_t; //QoS traffic class requested
typedef unsigned short nasIPdscp_t; // DSCP code transported to service NAS
typedef struct nasRBDef {
nasRadioBearerId_t rbId;
nasQoSTrafficClass_t QoSclass;
nasIPdscp_t dscp;
} nasrbParms_t;
typedef unsigned int nasSapId_t; // Id of the QoS SAP to use
typedef unsigned short nasRBEstablishStatus_t; // radio bearer establishment status
typedef unsigned short nasNumRBsInList_t; // number of RBs defined in the list
typedef nasrbParms_t nasRBList_t[MAX_RABS]; // List of Rbs for handover
typedef unsigned short nasNumRGsMeas_t; // number of RGs that could be measured
typedef unsigned int nasPagingUEId_t; // Cell_Id of the mobile, = Local Conn Ref
typedef unsigned int nasSigLevel_t; // Signal level measured
typedef struct nasMeasures {
nasCellID_t cell_id;
nasSigLevel_t level;
} nasMeasures_t;
//----------------------------------------------------------
// Primitive definitions
//----------------------------------------------------------
// -- SAP-GC
struct NASInfoBroadcastReq {
nasPeriod_t period; // 0 = one-shot, otherwise in x 10 ms
nasBroadcastCategory_t category;
nasDataLength_t nasDataLength;
};
struct NASInfoBroadcastInd {
nasDataLength_t nasDataLength;
};
struct nas_ue_gc_element {
unsigned short type;
unsigned short length;
union {
struct NASInfoBroadcastInd broadcast_ind;
} nasUEGCPrimitive;
};
struct nas_rg_gc_element {
unsigned short type;
unsigned short length;
union {
struct NASInfoBroadcastReq broadcast_req;
} nasRGGCPrimitive;
};
// -- SAP-DC
struct NASConnEstablishReq {
nasLocalConnectionRef_t localConnectionRef; //provided by NAS
nasCellID_t cellId;
};
struct NASConnEstablishInd {
nasLocalConnectionRef_t localConnectionRef;
nasIMEI_t InterfaceIMEI;
};
struct NASConnEstablishConf {
nasLocalConnectionRef_t localConnectionRef;
nasConnectionStatus_t status; // can be : Accepted, Failure
nasNumRBsInList_t num_RBs; // actual number of RBs in the list
nasRBList_t RB_List;
};
struct NASConnEstablishResp {
nasLocalConnectionRef_t localConnectionRef;
nasIMEI_t InterfaceIMEI;
nasConnectionStatus_t status; // can be : Terminated, Aborted , Already_Connected
};
struct NASConnReleaseReq {
nasLocalConnectionRef_t localConnectionRef;
nasReleaseCause_t releaseCause;
};
struct NASConnReleaseInd {
nasLocalConnectionRef_t localConnectionRef;
nasReleaseCause_t releaseCause;
};
struct NASConnLossInd {
nasLocalConnectionRef_t localConnectionRef;
};
struct NASDataReq {
nasLocalConnectionRef_t localConnectionRef;
nasSignalingPriority_t priority;
nasDataLength_t nasDataLength;
};
struct NASDataInd {
nasLocalConnectionRef_t localConnectionRef;
nasSignalingPriority_t priority;
nasDataLength_t nasDataLength;
};
struct NASrbEstablishReq {
nasLocalConnectionRef_t localConnectionRef;
nasRadioBearerId_t rbId;
nasQoSTrafficClass_t QoSclass;
nasIPdscp_t dscp;
};
struct NASrbEstablishInd {
nasLocalConnectionRef_t localConnectionRef;
nasRadioBearerId_t rbId;
nasQoSTrafficClass_t QoSclass;
nasIPdscp_t dscp;
nasSapId_t sapId;
};
struct NASrbEstablishConf {
nasLocalConnectionRef_t localConnectionRef;
nasRadioBearerId_t rbId;
nasSapId_t sapId;
nasRBEstablishStatus_t status; // can be : Accepted, Failure
};
struct NASrbReleaseReq {
nasLocalConnectionRef_t localConnectionRef;
nasRadioBearerId_t rbId;
};
struct NASrbReleaseInd {
nasLocalConnectionRef_t localConnectionRef;
nasRadioBearerId_t rbId;
};
struct NASMeasureReq {
nasLocalConnectionRef_t localConnectionRef;
};
struct NASMeasureInd {
nasLocalConnectionRef_t localConnectionRef;
nasNumRGsMeas_t nb_rg;
nasMeasures_t measures[MAX_MEASURE_NB];
};
/*****
* UE Primitives
*****/
struct nas_ue_dc_element {
unsigned short type;
unsigned short length;
union {
struct NASConnEstablishReq conn_establish_req;
struct NASConnEstablishResp conn_establish_resp;
// struct NASConnReleaseInd conn_release_ind;
struct NASConnReleaseReq conn_release_req;
struct NASConnLossInd conn_loss_ind;
struct NASDataReq data_transfer_req;
struct NASDataInd data_transfer_ind;
struct NASrbEstablishInd rb_establish_ind;
struct NASrbReleaseInd rb_release_ind;
struct NASMeasureInd measurement_ind;
struct NASMeasureReq measurement_req;
} nasUEDCPrimitive;
};
/*****
* RG Primitives
*****/
struct nas_rg_dc_element {
unsigned short type;
unsigned short length;
union {
struct NASConnEstablishInd conn_establish_ind;
struct NASConnEstablishConf conn_establish_conf;
struct NASConnReleaseInd conn_release_ind;
// struct NASConnReleaseReq conn_release_req;
struct NASConnLossInd conn_loss_ind;
struct NASDataReq data_transfer_req;
struct NASDataInd data_transfer_ind;
struct NASrbEstablishReq rb_establish_req;
struct NASrbEstablishConf rb_establish_conf;
struct NASrbReleaseReq rb_release_req;
} nasRGDCPrimitive;
};
// -- SAP-NT
struct NASPagingReq {
nasPagingUEId_t UeId;
nasDataLength_t nasDataLength;
};
struct NASNotificationInd {
nasDataLength_t nasDataLength;
};
struct nas_ue_nt_element {
unsigned short type;
unsigned short length;
union {
struct NASNotificationInd notification_ind;
} nasUENTPrimitive;
};
struct nas_rg_nt_element {
unsigned short type;
unsigned short length;
union {
struct NASPagingReq paging_req;
} nasRGNTPrimitive;
};
#endif
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/***************************************************************************
graal_sap.h - description
-------------------
copyright : (C) 2002 by Eurecom
email : michelle.wetterwald@eurecom.fr
yan.moret@eurecom.fr
***************************************************************************
***************************************************************************/
#ifndef _NAS_SAP_H
#define _NAS_SAP_H
// RT-FIFO identifiers ** must be identical to Access Stratum as_sap.h and rrc_sap.h
#define RRC_DEVICE_GC RRC_SAPI_GCSAP
#define RRC_DEVICE_NT RRC_SAPI_NTSAP
#define RRC_DEVICE_DC_INPUT0 RRC_SAPI_DCSAP_IN
#define RRC_DEVICE_DC_OUTPUT0 RRC_SAPI_DCSAP_OUT
//FIFO indexes in control blocks
#define NAS_DC_INPUT_SAPI 0
#define NAS_DC_OUTPUT_SAPI 1
#define NAS_SAPI_CX_MAX 2
#define NAS_GC_SAPI 0
#define NAS_NT_SAPI 1
#define NAS_RAB_INPUT_SAPI 2
#define NAS_RAB_OUTPUT_SAPI 3
#define NAS_SAPI_MAX 4
#endif
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#include "local.h"
#include "proto_extern.h"
//#include <linux/in.h>
//#include <net/ndisc.h>
//#include <linux/icmpv6.h>
//#include <linux/icmp.h>
//#include <linux/udp.h>
//#include <linux/tcp.h>
//#define NAS_DEBUG_TOOL 1
//---------------------------------------------------------------------------
//
void nas_TOOL_fct(struct classifier_entity *gc, uint8_t fct)
{
//---------------------------------------------------------------------------
// Start debug information
#ifdef NAS_DEBUG_TOOL
printk("NAS_TOOL_FCT - begin \n");
#endif
if (gc==NULL) {
#ifdef NAS_DEBUG_TOOL
printk("NAS_TOOL_FCT - input parameter gc is NULL \n");
#endif
return;
}
// End debug information
switch(fct) {
case NAS_FCT_QOS_SEND:
gc->fct=nas_COMMON_QOS_send;
break;
case NAS_FCT_CTL_SEND:
gc->fct=nas_CTL_send;
break;
case NAS_FCT_DC_SEND:
gc->fct=nas_mesh_DC_send_sig_data_request;
break;
case NAS_FCT_DEL_SEND:
gc->fct=nas_COMMON_del_send;
break;
default:
gc->fct=nas_COMMON_del_send;
}
}
//---------------------------------------------------------------------------
uint8_t nas_TOOL_invfct(struct classifier_entity *gc)
{
//---------------------------------------------------------------------------
// Start debug information
#ifdef NAS_DEBUG_TOOL
printk("NAS_TOOL_INVFCT - begin \n");
#endif
if (gc==NULL) {
#ifdef NAS_DEBUG_TOOL
printk("NAS_TOOL_INVFCT - input parameter gc is NULL \n");
#endif
return 0;
}
// End debug information
if (gc->fct==nas_COMMON_QOS_send)
return NAS_FCT_QOS_SEND;
if (gc->fct==nas_CTL_send)
return NAS_FCT_CTL_SEND;
if (gc->fct==nas_COMMON_del_send)
return NAS_FCT_DEL_SEND;
if (gc->fct==nas_mesh_DC_send_sig_data_request)
return NAS_FCT_DC_SEND;
return 0;
}
//---------------------------------------------------------------------------
uint8_t nas_TOOL_get_dscp6(struct ipv6hdr *iph)
{
//---------------------------------------------------------------------------
// Start debug information
#ifdef NAS_DEBUG_TOOL
printk("NAS_TOOL_GET_DSCP6 - begin \n");
#endif
if (iph==NULL) {
#ifdef NAS_DEBUG_TOOL
printk("NAS_TOOL_GET_DSCP6 - input parameter iph is NULL \n");
#endif
return 0;
}
// End debug information
return (ntohl(((*(__u32 *)iph)&NAS_TRAFFICCLASS_MASK)))>>22;
//return ntohs(*(const __be16 *)iph) >> 4; // see linux/dsfield.h
}
//---------------------------------------------------------------------------
uint8_t nas_TOOL_get_dscp4(struct iphdr *iph)
{
//---------------------------------------------------------------------------
// Start debug information
#ifdef NAS_DEBUG_TOOL
printk("NAS_TOOL_GET_DSCP4 - begin \n");
#endif
if (iph==NULL) {
#ifdef NAS_DEBUG_TOOL
printk("NAS_TOOL_GET_DSCP4 - input parameter iph is NULL \n");
#endif
return 0;
}
// End debug information
return (iph->tos);
}
//---------------------------------------------------------------------------
int nas_TOOL_network6(struct in6_addr *addr, struct in6_addr *prefix, uint8_t plen)
{
//---------------------------------------------------------------------------
// Start debug information
#ifdef NAS_DEBUG_TOOL
printk("NAS_TOOL_NETWORK6 - begin \n");
#endif
if (addr==NULL) {
#ifdef NAS_DEBUG_TOOL
printk("NAS_TOOL_NETWORK6 - input parameter addr is NULL \n");
#endif
return 0;
}
if (prefix==NULL) {
#ifdef NAS_DEBUG_TOOL
printk("NAS_TOOL_NETWORK6 - input parameter prefix is NULL \n");
#endif
return 0;
}
// End debug information
switch(plen/32) {
case 0:
return (((addr->s6_addr32[0]>>(32-plen))<<(32-plen))==prefix->s6_addr[0]);
case 1:
return ((addr->s6_addr32[0]==prefix->s6_addr[0])&&
(((addr->s6_addr32[1]>>(64-plen))<<(64-plen))==prefix->s6_addr[1]));
case 2:
return ((addr->s6_addr32[0]==prefix->s6_addr[0])&&
(addr->s6_addr32[1]==prefix->s6_addr[1])&&
(((addr->s6_addr32[2]>>(96-plen))<<(96-plen))==prefix->s6_addr[2]));
case 3:
return ((addr->s6_addr32[0]==prefix->s6_addr[0])&&
(addr->s6_addr32[1]==prefix->s6_addr[1])&&
(addr->s6_addr32[2]==prefix->s6_addr[2])&&
(((addr->s6_addr32[3]>>(128-plen))<<(128-plen))==prefix->s6_addr[3]));
default:
return ((addr->s6_addr32[0]==prefix->s6_addr[0])&&
(addr->s6_addr32[1]==prefix->s6_addr[1])&&
(addr->s6_addr32[2]==prefix->s6_addr[2])&&
(addr->s6_addr32[3]==prefix->s6_addr[3]));
}
}
//---------------------------------------------------------------------------
int nas_TOOL_network4(uint32_t *addr, uint32_t *prefix, uint8_t plen)
{
//---------------------------------------------------------------------------
// Start debug information
#ifdef NAS_DEBUG_TOOL
printk("NAS_TOOL_NETWORK4 - begin \n");
#endif
if (addr==NULL) {
#ifdef NAS_DEBUG_TOOL
printk("NAS_TOOL_NETWORK4 - input parameter addr is NULL \n");
#endif
return 0;
}
if (prefix==NULL) {
#ifdef NAS_DEBUG_TOOL
printk("NAS_TOOL_NETWORK4 - input parameter prefix is NULL \n");
#endif
return 0;
}
// End debug information
if (plen>=32)
return (*addr==*prefix);
else
return (((*addr>>(32-plen))<<(32-plen))==*prefix);
}
//---------------------------------------------------------------------------
//struct udphdr *nas_TOOL_get_udp6(struct ipv6hdr *iph){
//---------------------------------------------------------------------------
// return (struct udphdr *)((char *)iph+NAS_IPV6_SIZE); // to modify
//}
//---------------------------------------------------------------------------
uint8_t *nas_TOOL_get_protocol6(struct ipv6hdr *iph, uint8_t *protocol)
{
//---------------------------------------------------------------------------
uint16_t size;
// Start debug information
#ifdef NAS_DEBUG_TOOL
printk("NAS_TOOL_GET_PROTOCOL6 - begin \n");
#endif
if (iph==NULL) {
#ifdef NAS_DEBUG_TOOL
printk("NAS_TOOL_GET_PROTOCOL6 - input parameter iph is NULL \n");
#endif
return NULL;
}
if (protocol==NULL) {
#ifdef NAS_DEBUG_TOOL
printk("NAS_TOOL_GET_PROTOCOL6 - input parameter protocol is NULL \n");
#endif
return NULL;
}
// End debug information
*protocol=iph->nexthdr;
size=NAS_IPV6_SIZE;
while (1) {
switch(*protocol) {
case IPPROTO_UDP:
case IPPROTO_TCP:
case IPPROTO_ICMPV6:
return (uint8_t *)((uint8_t *)iph+size);
case IPPROTO_HOPOPTS:
case IPPROTO_ROUTING:
case IPPROTO_DSTOPTS:
*protocol=((uint8_t *)iph+size)[0];
size+=((uint8_t *)iph+size)[1]*8+8;
break;
case IPPROTO_FRAGMENT:
*protocol=((uint8_t *)iph+size)[0];
size+=((uint8_t *)iph+size)[1]+8;
break;
case IPPROTO_NONE:
case IPPROTO_AH:
case IPPROTO_ESP:
default:
return NULL;
}
}
}
//---------------------------------------------------------------------------
uint8_t *nas_TOOL_get_protocol4(struct iphdr *iph, uint8_t *protocol)
{
//---------------------------------------------------------------------------
// Start debug information
#ifdef NAS_DEBUG_TOOL
printk("NAS_TOOL_GET_PROTOCOL4 - begin \n");
#endif
if (iph==NULL) {
#ifdef NAS_DEBUG_TOOL
printk("NAS_TOOL_GET_PROTOCOL4 - input parameter iph is NULL \n");
#endif
return NULL;
}
if (protocol==NULL) {
#ifdef NAS_DEBUG_TOOL
printk("NAS_TOOL_GET_PROTOCOL4 - input parameter protocol is NULL \n");
#endif
return NULL;
}
// End debug information
*protocol=iph->protocol;
switch(*protocol) {
case IPPROTO_UDP:
case IPPROTO_TCP:
case IPPROTO_ICMP:
return (uint8_t *)((uint8_t *)iph+iph->tot_len);
default:
return NULL;
}
}
//---------------------------------------------------------------------------
// Convert the IMEI to iid
void nas_TOOL_imei2iid(uint8_t *imei, uint8_t *iid)
{
//---------------------------------------------------------------------------
// Start debug information
#ifdef NAS_DEBUG_TOOL
printk("NAS_TOOL_IMEI2IID - begin \n");
#endif
if (imei==NULL) {
#ifdef NAS_DEBUG_TOOL
printk("NAS_TOOL_IMEI2IID - input parameter imei is NULL \n");
#endif
return;
}
if (iid==NULL) {
#ifdef NAS_DEBUG_TOOL
printk("NAS_TOOL_IMEI2IID - input parameter iid is NULL \n");
#endif
return;
}
// End debug information
memset(iid, 0, NAS_ADDR_LEN);
iid[0] = 0x03;
iid[1] = 16*imei[0]+imei[1];
iid[2] = 16*imei[2]+imei[3];
iid[3] = 16*imei[4]+imei[5];
iid[4] = 16*imei[6]+imei[7];
iid[5] = 16*imei[8]+imei[9];
iid[6] = 16*imei[10]+imei[11];
iid[7] = 16*imei[12]+imei[13];
}
//struct udphdr *nas_TOOL_get_udp4(struct iphdr *iph)
//{
// return (struct udphdr *)((char *)iph+NAS_IPV4_SIZE); // to modify
//}
//---------------------------------------------------------------------------
char *nas_TOOL_get_udpmsg(struct udphdr *udph)
{
//---------------------------------------------------------------------------
// Start debug information
#ifdef NAS_DEBUG_TOOL
printk("NAS_TOOL_GET_UDPMSG - begin \n");
#endif
if (udph==NULL) {
#ifdef NAS_DEBUG_TOOL
printk("NAS_TOOL_GET_UDPMSG - input parameter udph is NULL \n");
#endif
return NULL;
}
// End debug information
return ((char *)udph+sizeof(struct udphdr));
}
//---------------------------------------------------------------------------
// Compute the UDP checksum (the data size must be odd)
uint16_t nas_TOOL_udpcksum(struct in6_addr *saddr, struct in6_addr *daddr, uint8_t proto, uint32_t udplen, void *data)
{
//---------------------------------------------------------------------------
uint32_t i;
uint16_t *data16;
uint32_t csum=0;
// Start debug information
#ifdef NAS_DEBUG_TOOL
printk("NAS_TOOL_UDPCKSUM - begin \n");
#endif
if (saddr==NULL) {
#ifdef NAS_DEBUG_TOOL
printk("NAS_TOOL_UDPCKSUM - input parameter saddr is NULL \n");
#endif
return 0;
}
if (daddr==NULL) {
#ifdef NAS_DEBUG_TOOL
printk("NAS_TOOL_UDPCKSUM - input parameter daddr is NULL \n");
#endif
return 0;
}
if (data==NULL) {
#ifdef NAS_DEBUG_TOOL
printk("NAS_TOOL_UDPCKSUM - input parameter data is NULL \n");
#endif
return 0;
}
// End debug information
data16=data;
for (i=0; i<8; ++i) {
csum+=ntohs(saddr->s6_addr16[i]);
if (csum>0xffff)
csum-=0xffff;
}
for (i=0; i<8; ++i) {
csum+=ntohs(daddr->s6_addr16[i]);
if (csum>0xffff)
csum-=0xffff;
}
csum+=(udplen>>16); // udplen checksum
if (csum>0xffff)
csum -= 0xffff;
csum+=udplen & 0xffff;
if (csum>0xffff)
csum -= 0xffff;
csum+=proto; // protocol checksum
if (csum>0xffff)
csum-=0xffff;
for (i = 0; 2*i < udplen; i++) {
csum+=ntohs(data16[i]);
if (csum>0xffff)
csum-=0xffff;
}
return htons((uint16_t)(~csum)&0xffff);
}
//---------------------------------------------------------------------------
void print_TOOL_pk_udp(struct udphdr *udph)
{
//---------------------------------------------------------------------------
// Start debug information
#ifdef NAS_DEBUG_TOOL
printk("PRINT_TOOL_PK_UDP - begin \n");
#endif
if (udph==NULL) {
#ifdef NAS_DEBUG_TOOL
printk("NAS_TOOL_PK_UDP - input parameter udph is NULL \n");
#endif
return;
}
// End debug information
if (udph!=NULL) {
printk("UDP:\t source = %u, dest = %u, len = %u, check = %x\n", ntohs(udph->source), ntohs(udph->dest), ntohs(udph->len), udph->check);
}
}
//---------------------------------------------------------------------------
void print_TOOL_pk_tcp(struct tcphdr *tcph)
{
//---------------------------------------------------------------------------
// Start debug information
#ifdef NAS_DEBUG_TOOL
printk("PRINT_TOOL_PK_TDP - begin \n");
#endif
if (tcph==NULL) {
#ifdef NAS_DEBUG_TOOL
printk("NAS_TOOL_PK_TDP - input parameter tcph is NULL \n");
#endif
return;
}
// End debug information
if (tcph!=NULL) {
printk("TCP:\t source = %u, dest = %u\n", tcph->source, tcph->dest);
}
}
//---------------------------------------------------------------------------
void print_TOOL_pk_icmp6(struct icmp6hdr *icmph)
{
//---------------------------------------------------------------------------
// Start debug information
#ifdef NAS_DEBUG_TOOL
printk("PRINT_TOOL_PK_ICMP6 - begin \n");
#endif
if (icmph==NULL) {
#ifdef NAS_DEBUG_TOOL
printk("NAS_TOOL_PK_ICMP6 - input parameter icmph is NULL \n");
#endif
return;
}
// End debug information
if (icmph!=NULL) {
printk("ICMPv6:\t type= %d, code = %d\n", icmph->icmp6_type, icmph->icmp6_code);
switch(icmph->icmp6_type) {
case ICMPV6_DEST_UNREACH:
printk("Destination unreachable\n");
break;
case ICMPV6_PKT_TOOBIG:
printk("Packet too big\n");
break;
case ICMPV6_TIME_EXCEED:
printk("Time exceeded\n");
break;
case ICMPV6_PARAMPROB:
printk("Parameter problem\n");
break;
case ICMPV6_ECHO_REQUEST:
printk("Echo request\n");
break;
case ICMPV6_ECHO_REPLY:
printk("Echo reply\n");
break;
case ICMPV6_MGM_QUERY:
printk("Multicast listener query\n");
break;
case ICMPV6_MGM_REPORT:
printk("Multicast listener report\n");
break;
case ICMPV6_MGM_REDUCTION:
printk("Multicast listener done\n");
break;
case NDISC_ROUTER_SOLICITATION:
printk("Router solicitation\n");
break;
case NDISC_ROUTER_ADVERTISEMENT:
printk("Router advertisment\n");
break;
case NDISC_NEIGHBOUR_SOLICITATION:
printk("Neighbour solicitation\n");
break;
case NDISC_NEIGHBOUR_ADVERTISEMENT:
printk("Neighbour advertisment\n");
break;
case NDISC_REDIRECT:
printk("redirect message\n");
break;
}
}
}
//---------------------------------------------------------------------------
void print_TOOL_pk_ipv6(struct ipv6hdr *iph)
{
//---------------------------------------------------------------------------
// Start debug information
#ifdef NAS_DEBUG_TOOL
printk("PRINT_TOOL_PK_IPv6 - begin \n");
#endif
if (iph==NULL) {
#ifdef NAS_DEBUG_TOOL
printk("NAS_TOOL_PK_IPv6 - input parameter iph is NULL \n");
#endif
return;
}
// End debug information
if (iph!=NULL) {
// char addr[NAS_INET6_ADDRSTRLEN];
printk("IP:\t version = %u, priority = %u, payload_len = %u\n", iph->version, iph->priority, ntohs(iph->payload_len));
printk("\t fl0 = %u, fl1 = %u, fl2 = %u\n",iph->flow_lbl[0],iph->flow_lbl[1],iph->flow_lbl[2]);
printk("\t next header = %u, hop_limit = %u\n", iph->nexthdr, iph->hop_limit);
// inet_ntop(AF_INET6, (void *)(&iph->saddr), addr, NAS_INET6_ADDRSTRLEN);
// printk("\t saddr = %s",addr);
// inet_ntop(AF_INET6, (void *)(&iph->daddr), addr, NAS_INET6_ADDRSTRLEN);
// printk(", daddr = %s\n",addr);
switch(iph->nexthdr) {
case IPPROTO_UDP:
print_TOOL_pk_udp((struct udphdr *)((char *)iph+sizeof(struct ipv6hdr)));
break;
case IPPROTO_TCP:
print_TOOL_pk_tcp((struct tcphdr *)((char *)iph+sizeof(struct ipv6hdr)));
break;
case IPPROTO_ICMPV6:
print_TOOL_pk_icmp6((struct icmp6hdr *)((char *)iph+sizeof(struct ipv6hdr)));
break;
case IPPROTO_IPV6:
print_TOOL_pk_ipv6((struct ipv6hdr *)((char *)iph+sizeof(struct ipv6hdr)));
break;
default:
printk("Unknown upper layer\n");
}
}
}
//---------------------------------------------------------------------------
void print_TOOL_pk_ipv4(struct iphdr *iph)
{
//---------------------------------------------------------------------------
// Start debug information
#ifdef NAS_DEBUG_TOOL
printk("PRINT_TOOL_PK_IPv4 - begin \n");
#endif
if (iph==NULL) {
#ifdef NAS_DEBUG_TOOL
printk("NAS_TOOL_PK_IPv4 - input parameter iph is NULL \n");
#endif
return;
}
// End debug information
if (iph!=NULL) {
// char addr[NAS_INET_ADDRSTRLEN];
printk("IP:\t version = %u, IP length = %u\n", iph->version, iph->ihl);
// inet_ntop(AF_INET, (void *)(&iph->saddr), addr, NAS_INET_ADDRSTRLEN);
// printk("\t saddr = %s", addr);
// inet_ntop(AF_INET, (void *)(&iph->saddr), addr, NAS_INET_ADDRSTRLEN);
// printk("\t saddr = %s", addr);
}
}
//---------------------------------------------------------------------------
void print_TOOL_pk_all(struct sk_buff *skb)
{
//---------------------------------------------------------------------------
printk("Skb:\t %p, len = %u\n", skb, skb->len);
//navid: need to calculate the current used space: fixme?
printk("Skb:\t available buf space = %u \n", skb->truesize);
switch (ntohs(skb->protocol)) {
case ETH_P_IPV6:
print_TOOL_pk_ipv6((struct ipv6hdr *)skb_network_header(skb));
break;
case ETH_P_IP:
print_TOOL_pk_ipv4((struct iphdr *)skb_network_header(skb));
break;
}
}
//---------------------------------------------------------------------------
/*int isdigit(char c)
{
switch(c)
{
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
return 1;
default:
return 0;
}
}*/
/*int nas_TOOL_inet_pton4(char *src, uint32_t *dst)
{
uint32_t val;
int n;
uint8_t c;
uint32_t parts[4];
c = *src;
val=0;
n=0
for (;;)
{
for (;;)
{
if (isdigit(c))
{
val = (val * 10) + c - '0';
c = *++src;
}
else
break;
}
if (c == '.')
{
if (n>4)
return -1;
parts[n]=val;
c = *++src;
++n;
}
else
break;
}
if ((c != '\0')||(n!=3))
return (0);
if ((parts[0] | parts[1] | parts[2] | val) > 256)
return (0);
val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
if (dst)
dst = htonl(val);
return (1);
}*/
//---------------------------------------------------------------------------
void print_TOOL_state(uint8_t state)
{
//---------------------------------------------------------------------------
// case NAS_STATE_IDLE:printk(" State NAS_STATE_IDLE\n");return;
// case NAS_STATE_CONNECTED:printk(" State NAS_STATE_CONNECTED\n");return;
// case NAS_STATE_ESTABLISHMENT_REQUEST:printk(" State NAS_STATE_ESTABLISHMENT_REQUEST\n");return;
// case NAS_STATE_ESTABLISHMENT_FAILURE:printk(" State NAS_STATE_ESTABLISHMENT_FAILURE\n");return;
// case NAS_STATE_RELEASE_FAILURE:printk(" State NAS_STATE_RELEASE_FAILURE\n");return;
switch(state) {
case NAS_IDLE:
printk("NAS_IDLE\n");
return;
case NAS_CX_FACH:
printk("NAS_CX_FACH\n");
return;
case NAS_CX_DCH:
printk("NAS_CX_DCH\n");
return;
case NAS_CX_RECEIVED:
printk("NAS_CX_RECEIVED\n");
return;
case NAS_CX_CONNECTING:
printk("NAS_CX_CONNECTING\n");
return;
case NAS_CX_RELEASING:
printk("NAS_CX_RELEASING\n");
return;
case NAS_CX_CONNECTING_FAILURE:
printk("NAS_CX_CONNECTING_FAILURE\n");
return;
case NAS_CX_RELEASING_FAILURE:
printk("NAS_CX_RELEASING_FAILURE\n");
return;
case NAS_RB_ESTABLISHING:
printk("NAS_RB_ESTABLISHING\n");
return;
case NAS_RB_RELEASING:
printk("NAS_RB_RELEASING\n");
return;
case NAS_RB_DCH:
printk("NAS_RB_DCH\n");
return;
default:
printk(" Unknown state\n");
}
}
//-----------------------------------------------------------------------------
// Print the content of a buffer in hexadecimal
void nas_tool_print_buffer(char * buffer,int length)
{
//-----------------------------------------------------------------------------
int i;
// Start debug information
#ifdef NAS_DEBUG_TOOL
printk("NAS_TOOL_PRINT_BUFFER - begin \n");
#endif
if (buffer==NULL) {
#ifdef NAS_DEBUG_TOOL
printk("NAS_TOOL_PRINT_BUFFER - input parameter buffer is NULL \n");
#endif
return;
}
// End debug information
printk("\nBuffer content: ");
for (i=0; i<length; i++)
printk("-%hx-",buffer[i]);
printk(",\t length %d\n", length);
}
//-----------------------------------------------------------------------------
void nas_print_rb_entity(struct rb_entity *rb)
{
//-----------------------------------------------------------------------------
// Start debug information
#ifdef NAS_DEBUG_TOOL
printk("NAS_PRINT_RB_ENTITY - begin \n");
#endif
if (rb==NULL) {
#ifdef NAS_DEBUG_TOOL
printk("NAS_PRINT_RB_ENTITY - input parameter rb is NULL \n");
#endif
return;
}
// End debug information
printk("\nrb_entity content: rab_id %d, sapi %d, qos %d, \n", rb->rab_id, rb->sapi, rb->qos);
printk("state %d, retry %d, countimer %d\n",rb->state, rb->retry, rb->countimer);
};
//-----------------------------------------------------------------------------
void nas_print_classifier(struct classifier_entity *gc)
{
//-----------------------------------------------------------------------------
// Start debug information
#ifdef NAS_DEBUG_TOOL
printk("NAS_PRINT_GC_ENTITY - begin \n");
#endif
if (gc==NULL) {
#ifdef NAS_DEBUG_TOOL
printk("NAS_PRINT_GC_ENTITY - input parameter gc is NULL \n");
#endif
return;
}
// End debug information
printk("\nClassifier content: classref %d, version %d, splen %d, dplen %d,\n", gc->classref, gc->version, gc->splen, gc->dplen);
printk("protocol %d, sport %d, dport %d, rab_id %d\n", gc->protocol, gc->sport, gc->dport, gc->rab_id);
if (gc->rb != NULL) {
nas_print_rb_entity(gc->rb);
}
};
This the driver for the UE when NAS layer is running in the UE (EPC setting).
\ No newline at end of file
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/*! \file common.c
* \brief
* \author Navid Nikaein and Raymond Knopp, Lionel GAUTHIER
* \date 2013
* \version 1.0
* \company Eurecom
* \email: navid.nikaein@eurecom.fr, lionel.gauthier@eurecom.fr
*/
#include "local.h"
#include "proto_extern.h"
#ifndef OAI_NW_DRIVER_USE_NETLINK
#include "rtai_fifos.h"
#endif
#include <linux/inetdevice.h>
#include <net/tcp.h>
#include <net/udp.h>
#define NIPADDR(addr) \
(uint8_t)(addr & 0x000000FF), \
(uint8_t)((addr & 0x0000FF00) >> 8), \
(uint8_t)((addr & 0x00FF0000) >> 16), \
(uint8_t)((addr & 0xFF000000) >> 24)
#define NIP6ADDR(addr) \
ntohs((addr)->s6_addr16[0]), \
ntohs((addr)->s6_addr16[1]), \
ntohs((addr)->s6_addr16[2]), \
ntohs((addr)->s6_addr16[3]), \
ntohs((addr)->s6_addr16[4]), \
ntohs((addr)->s6_addr16[5]), \
ntohs((addr)->s6_addr16[6]), \
ntohs((addr)->s6_addr16[7])
//#define OAI_DRV_DEBUG_SEND
//#define OAI_DRV_DEBUG_RECEIVE
void
ue_ip_common_class_wireless2ip(
sdu_size_t data_lenP,
void *pdcp_sdu_pP,
int instP,
rb_id_t rb_idP) {
//---------------------------------------------------------------------------
struct sk_buff *skb_p = NULL;
ipversion_t *ipv_p = NULL;
ue_ip_priv_t *gpriv_p = netdev_priv(ue_ip_dev[instP]);
unsigned int hard_header_len = 0;
#ifdef OAI_DRV_DEBUG_RECEIVE
int i;
unsigned char *addr_p = 0;
#endif
unsigned char protocol;
struct iphdr *network_header_p = NULL;
#ifdef OAI_DRV_DEBUG_RECEIVE
printk("[UE_IP_DRV][%s] begin RB %d Inst %d Length %d bytes\n",__FUNCTION__, rb_idP,instP,data_lenP);
#endif
skb_p = dev_alloc_skb( data_lenP + 2 );
if(!skb_p) {
printk("[UE_IP_DRV][%s] low on memory\n",__FUNCTION__);
++gpriv_p->stats.rx_dropped;
return;
}
skb_reserve(skb_p,2);
memcpy(skb_put(skb_p, data_lenP), pdcp_sdu_pP,data_lenP);
skb_p->dev = ue_ip_dev[instP];
hard_header_len = ue_ip_dev[instP]->hard_header_len;
skb_set_mac_header(skb_p, 0);
skb_set_network_header(skb_p, hard_header_len);
skb_p->mark = rb_idP;
//printk("[NAC_COMMIN_RECEIVE]: Packet Type %d (%d,%d)",skb_p->pkt_type,PACKET_HOST,PACKET_BROADCAST);
skb_p->pkt_type = PACKET_HOST;
#ifdef OAI_DRV_DEBUG_RECEIVE
printk("[UE_IP_DRV][%s] Receiving packet of size %d from PDCP \n",__FUNCTION__, skb_p->len);
for (i=0; i<skb_p->len; i++) {
printk("%2x ",((unsigned char *)(skb_p->data))[i]);
}
printk("\n");
#endif
#ifdef OAI_DRV_DEBUG_RECEIVE
printk("[UE_IP_DRV][%s] skb_p->data @ %p\n",__FUNCTION__, skb_p->data);
printk("[UE_IP_DRV][%s] skb_p->mac_header @ %p\n",__FUNCTION__, skb_p->mac_header);
#endif
// LG TEST skb_p->ip_summed = CHECKSUM_NONE;
skb_p->ip_summed = CHECKSUM_UNNECESSARY;
ipv_p = (ipversion_t *)((void *)&(skb_p->data[hard_header_len]));
switch (ipv_p->version) {
case 6:
#ifdef OAI_DRV_DEBUG_RECEIVE
printk("[UE_IP_DRV][%s] receive IPv6 message\n",__FUNCTION__);
#endif
skb_set_network_header(skb_p, hard_header_len);
//skb_p->network_header_p = &skb_p->data[hard_header_len];
if (hard_header_len == 0) {
skb_p->protocol = htons(ETH_P_IPV6);
} else {
#ifdef OAI_NW_DRIVER_TYPE_ETHERNET
skb_p->protocol = eth_type_trans(skb_p, ue_ip_dev[instP]);
#else
#endif
}
//printk("Writing packet with protocol %x\n",ntohs(skb_p->protocol));
break;
case 4:
#ifdef OAI_DRV_DEBUG_RECEIVE
//printk("NAS_TOOL_RECEIVE: receive IPv4 message\n");
addr_p = (unsigned char *)&((struct iphdr *)&skb_p->data[hard_header_len])->saddr;
if (addr_p) {
printk("[UE_IP_DRV][%s] Source %d.%d.%d.%d\n",__FUNCTION__, addr_p[0],addr_p[1],addr_p[2],addr_p[3]);
}
addr_p = (unsigned char *)&((struct iphdr *)&skb_p->data[hard_header_len])->daddr;
if (addr_p) {
printk("[UE_IP_DRV][%s] Dest %d.%d.%d.%d\n",__FUNCTION__, addr_p[0],addr_p[1],addr_p[2],addr_p[3]);
}
printk("[UE_IP_DRV][%s] protocol %d\n",__FUNCTION__, ((struct iphdr *)&skb_p->data[hard_header_len])->protocol);
#endif
skb_set_network_header(skb_p, hard_header_len);
//network_header_p = (struct iphdr *)skb_network_header(skb_p);
network_header_p = (struct iphdr *)skb_network_header(skb_p);
protocol = network_header_p->protocol;
#ifdef OAI_DRV_DEBUG_RECEIVE
switch (protocol) {
case IPPROTO_IP:
printk("[UE_IP_DRV][%s] Received Raw IPv4 packet\n",__FUNCTION__);
break;
case IPPROTO_IPV6:
printk("[UE_IP_DRV][%s] Received Raw IPv6 packet\n",__FUNCTION__);
break;
case IPPROTO_ICMP:
printk("[UE_IP_DRV][%s] Received Raw ICMP packet\n",__FUNCTION__);
break;
case IPPROTO_TCP:
printk("[UE_IP_DRV][%s] Received TCP packet\n",__FUNCTION__);
break;
case IPPROTO_UDP:
printk("[UE_IP_DRV][%s] Received UDP packet\n",__FUNCTION__);
break;
default:
break;
}
#endif
if (hard_header_len == 0) {
skb_p->protocol = htons(ETH_P_IP);
}
//printk("[UE_IP_DRV][COMMON] Writing packet with protocol %x\n",ntohs(skb_p->protocol));
break;
default:
printk("[UE_IP_DRV][%s] begin RB %ld Inst %d Length %d bytes\n",__FUNCTION__,rb_idP,instP,data_lenP);
printk("[UE_IP_DRV][%s] Inst %d: receive unknown message (version=%d)\n",__FUNCTION__,instP,ipv_p->version);
}
++gpriv_p->stats.rx_packets;
gpriv_p->stats.rx_bytes += data_lenP;
#ifdef OAI_DRV_DEBUG_RECEIVE
printk("[UE_IP_DRV][%s] sending packet of size %d to kernel\n",__FUNCTION__,skb_p->len);
for (i=0; i<skb_p->len; i++) {
printk("%2x ",((unsigned char *)(skb_p->data))[i]);
}
printk("\n");
#endif //OAI_DRV_DEBUG_RECEIVE
netif_rx_ni(skb_p);
#ifdef OAI_DRV_DEBUG_RECEIVE
printk("[UE_IP_DRV][%s] end\n",__FUNCTION__);
#endif
}
//---------------------------------------------------------------------------
// Delete the data
void ue_ip_common_ip2wireless_drop(struct sk_buff *skb_pP, int instP) {
//---------------------------------------------------------------------------
ue_ip_priv_t *priv_p=netdev_priv(ue_ip_dev[instP]);
++priv_p->stats.tx_dropped;
}
//---------------------------------------------------------------------------
// Request the transfer of data (QoS SAP)
void
ue_ip_common_ip2wireless(
struct sk_buff *skb_pP,
int instP
) {
//---------------------------------------------------------------------------
struct pdcp_data_req_header_s pdcph;
ue_ip_priv_t *priv_p=netdev_priv(ue_ip_dev[instP]);
ipversion_t *ipv_p = NULL;
unsigned int hard_header_len = 0;
unsigned char *src_addr = 0;
unsigned char *dst_addr = 0;
#ifdef LOOPBACK_TEST
int i;
#endif
#ifdef OAI_DRV_DEBUG_SEND
int j;
#endif
unsigned int bytes_wrote;
// Start debug information
#ifdef OAI_DRV_DEBUG_SEND
printk("[UE_IP_DRV][%s] inst %d begin \n",__FUNCTION__,instP);
#endif
if (skb_pP==NULL) {
#ifdef OAI_DRV_DEBUG_SEND
printk("[UE_IP_DRV][%s] input parameter skb is NULL \n",__FUNCTION__);
#endif
return;
}
pdcph.data_size = skb_pP->len;
if (skb_pP->mark) {
pdcph.rb_id = skb_pP->mark;
} else {
pdcph.rb_id = UE_IP_DEFAULT_RAB_ID;
}
pdcph.inst = instP;
//pass source/destination IP addresses to PDCP header
hard_header_len = ue_ip_dev[instP]->hard_header_len;
ipv_p = (ipversion_t *)((void *)&(skb_pP->data[hard_header_len]));
switch (ipv_p->version) {
case 6:
printk("[UE_IP_DRV][%s] receive IPv6 message\n",__FUNCTION__);
//TODO
break;
case 4:
src_addr = (unsigned char *)&((struct iphdr *)&skb_pP->data[hard_header_len])->saddr;
if (src_addr) {
printk("[UE_IP_DRV][%s] Source %d.%d.%d.%d\n",__FUNCTION__, src_addr[0],src_addr[1],src_addr[2],src_addr[3]);
}
dst_addr = (unsigned char *)&((struct iphdr *)&skb_pP->data[hard_header_len])->daddr;
if (dst_addr) {
printk("[UE_IP_DRV][%s] Dest %d.%d.%d.%d\n",__FUNCTION__, dst_addr[0],dst_addr[1],dst_addr[2],dst_addr[3]);
}
//get Ipv4 address and pass to PCDP header
printk("[UE_IP_DRV] source Id: 0x%08x\n",pdcph.sourceL2Id );
printk("[UE_IP_DRV] destinationL2Id Id: 0x%08x\n",pdcph.destinationL2Id );
pdcph.sourceL2Id = ntohl( ((struct iphdr *)&skb_pP->data[hard_header_len])->saddr) & 0x00FFFFFF;
pdcph.destinationL2Id = ntohl( ((struct iphdr *)&skb_pP->data[hard_header_len])->daddr) & 0x00FFFFFF;
break;
default:
break;
}
bytes_wrote = ue_ip_netlink_send((char *)&pdcph,UE_IP_PDCPH_SIZE);
#ifdef OAI_DRV_DEBUG_SEND
printk("[UE_IP_DRV][%s] Wrote %d bytes (header for %d byte skb) to PDCP via netlink\n",__FUNCTION__,
bytes_wrote,skb_pP->len);
#endif
if (bytes_wrote != UE_IP_PDCPH_SIZE) {
printk("[UE_IP_DRV][%s] problem while writing PDCP's header (bytes wrote = %d)\n",__FUNCTION__,bytes_wrote);
printk("rb_id %ld, Wrote %d, Header Size %d \n", pdcph.rb_id, bytes_wrote, UE_IP_PDCPH_SIZE);
priv_p->stats.tx_dropped ++;
return;
}
bytes_wrote += ue_ip_netlink_send((char *)skb_pP->data,skb_pP->len);
if (bytes_wrote != skb_pP->len+UE_IP_PDCPH_SIZE) {
printk("[UE_IP_DRV][%s] Inst %d, RB_ID %ld: problem while writing PDCP's data, bytes_wrote = %d, Data_len %d, PDCPH_SIZE %d\n",
__FUNCTION__,
instP,
pdcph.rb_id,
bytes_wrote,
skb_pP->len,
UE_IP_PDCPH_SIZE); // congestion
priv_p->stats.tx_dropped ++;
return;
}
#ifdef OAI_DRV_DEBUG_SEND
printk("[UE_IP_DRV][%s] Sending packet of size %d to PDCP \n",__FUNCTION__,skb_pP->len);
for (j=0; j<skb_pP->len; j++) {
printk("%2x ",((unsigned char *)(skb_pP->data))[j]);
}
printk("\n");
#endif
priv_p->stats.tx_bytes += skb_pP->len;
priv_p->stats.tx_packets ++;
#ifdef OAI_DRV_DEBUG_SEND
printk("[UE_IP_DRV][%s] end \n",__FUNCTION__);
#endif
}
//---------------------------------------------------------------------------
void ue_ip_common_wireless2ip(struct nlmsghdr *nlh_pP) {
//---------------------------------------------------------------------------
struct pdcp_data_ind_header_s *pdcph_p = (struct pdcp_data_ind_header_s *)NLMSG_DATA(nlh_pP);
ue_ip_priv_t *priv_p;
priv_p = netdev_priv(ue_ip_dev[pdcph_p->inst]);
#ifdef OAI_DRV_DEBUG_RECEIVE
printk("[UE_IP_DRV][%s] QOS receive from PDCP, size %d, rab %d, inst %d\n",__FUNCTION__,
pdcph_p->data_size,pdcph_p->rb_id,pdcph_p->inst);
#endif
ue_ip_common_class_wireless2ip(pdcph_p->data_size,
(unsigned char *)NLMSG_DATA(nlh_pP) + UE_IP_PDCPH_SIZE,
pdcph_p->inst,
pdcph_p->rb_id);
}
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#include "common/openairinterface5g_limits.h"
#ifndef _UE_IP_CST
#define _UE_IP_CST
#define UE_IP_MAX_LENGTH 180
// General Constants
#define UE_IP_MTU 1500
#define UE_IP_TX_QUEUE_LEN 100
#define UE_IP_ADDR_LEN 8
#define UE_IP_INET6_ADDRSTRLEN 46
#define UE_IP_INET_ADDRSTRLEN 16
#define UE_IP_DEFAULT_RAB_ID 1
#define UE_IP_RESET_RX_FLAGS 0
#define UE_IP_RETRY_LIMIT_DEFAULT (int)5
#define UE_IP_MESSAGE_MAXLEN (int)5004
#define UE_IP_TIMER_ESTABLISHMENT_DEFAULT (int)12
#define UE_IP_TIMER_RELEASE_DEFAULT (int)2
#define UE_IP_TIMER_IDLE UINT_MAX
#define UE_IP_TIMER_TICK HZ
#define UE_IP_PDCPH_SIZE (int)sizeof(struct pdcp_data_req_header_s)
#define UE_IP_IPV4_SIZE (int)20
#define UE_IP_IPV6_SIZE (int)40
#define UE_IP_NB_INSTANCES_MAX NUMBER_OF_UE_MAX /*MAX_MOBILES_PER_ENB*/
#endif
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/*! \file device.c
* \brief Networking Device Driver for OpenAirInterface
* \author navid nikaein, Lionel Gauthier, raymond knopp
* \company Eurecom
* \email: raymond.knopp@eurecom.fr, navid.nikaein@eurecom.fr, lionel.gauthier@eurecom.fr
*/
/*******************************************************************************/
#include "constant.h"
#include "local.h"
#include "proto_extern.h"
#include <linux/kernel.h>
#include <linux/version.h>
#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/moduleparam.h>
#include <asm/io.h>
#include <asm/bitops.h>
#include <asm/uaccess.h>
#include <asm/segment.h>
#include <asm/page.h>
#include <asm/delay.h>
#include <asm/unistd.h>
#include <linux/netdevice.h>
struct net_device *ue_ip_dev[UE_IP_NB_INSTANCES_MAX];
#ifdef OAI_NW_DRIVER_USE_NETLINK
extern void ue_ip_netlink_release(void);
extern int ue_ip_netlink_init(void);
#endif
//---------------------------------------------------------------------------
int ue_ip_find_inst(struct net_device *dev_pP) {
//---------------------------------------------------------------------------
int i;
for (i=0; i<UE_IP_NB_INSTANCES_MAX; i++)
if (ue_ip_dev[i] == dev_pP) {
return(i);
}
return(-1);
}
//---------------------------------------------------------------------------
#ifndef OAI_NW_DRIVER_USE_NETLINK
void *ue_ip_interrupt(void) {
//---------------------------------------------------------------------------
uint8_t cxi;
// ue_ip_priv_t *priv_p=netdev_priv(dev_id);
// unsigned int flags;
// priv_p->lock = SPIN_LOCK_UNLOCKED;
#ifdef OAI_DRV_DEBUG_INTERRUPT
printk("INTERRUPT - begin\n");
#endif
// spin_lock_irqsave(&priv_p->lock,flags);
cxi=0;
// mesh_GC_receive();
// mesh_DC_receive(naspriv->cx+cxi);
#ifndef OAI_NW_DRIVER_USE_NETLINK
ue_ip_common_wireless2ip();
#endif
// spin_unlock_irqrestore(&priv_p->lock,flags);
#ifdef OAI_DRV_DEBUG_INTERRUPT
printk("INTERRUPT: end\n");
#endif
// return 0;
}
#endif //NETLINK
//---------------------------------------------------------------------------
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0))
void ue_ip_timer(struct timer_list *t)
#else
void ue_ip_timer(unsigned long dataP)
#endif
{
//---------------------------------------------------------------------------
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0))
ue_ip_priv_t *priv_p = from_timer(priv_p, t, timer);
#else
ue_ip_priv_t *priv_p = (ue_ip_priv_t *)dataP;
#endif
spin_lock(&priv_p->lock);
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0))
mod_timer(&priv_p->timer, jiffies + UE_IP_TIMER_TICK);
#else
(priv_p->timer).function = ue_ip_timer;
(priv_p->timer).expires = jiffies + UE_IP_TIMER_TICK;
(priv_p->timer).data = dataP;
add_timer(&priv_p->timer);
#endif
spin_unlock(&priv_p->lock);
return;
// add_timer(&gpriv->timer);
// spin_unlock(&gpriv->lock);
}
//---------------------------------------------------------------------------
// Called by ifconfig when the device is activated by ifconfig
int ue_ip_open(struct net_device *dev_pP) {
//---------------------------------------------------------------------------
ue_ip_priv_t *priv_p=netdev_priv(dev_pP);
// Address has already been set at init
#ifndef OAI_NW_DRIVER_USE_NETLINK
if (pdcp_2_ue_ip_irq==-EBUSY) {
printk("[UE_IP_DRV][%s] : irq failure\n", __FUNCTION__);
return -EBUSY;
}
#endif //OAI_NW_DRIVER_USE_NETLINK
if(!netif_queue_stopped(dev_pP)) {
netif_start_queue(dev_pP);
} else {
netif_wake_queue(dev_pP);
}
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0))
timer_setup(&(priv_p->timer), ue_ip_timer, 0);
(priv_p->timer).expires = jiffies+UE_IP_TIMER_TICK;
#else
init_timer(&priv_p->timer);
(priv_p->timer).expires = jiffies+UE_IP_TIMER_TICK;
(priv_p->timer).data = (unsigned long)priv_p;
(priv_p->timer).function = ue_ip_timer;
#endif
//add_timer(&priv_p->timer);
printk("[UE_IP_DRV][%s] name = %s\n", __FUNCTION__, dev_pP->name);
return 0;
}
//---------------------------------------------------------------------------
// Called by ifconfig when the device is desactivated
int ue_ip_stop(struct net_device *dev_pP) {
//---------------------------------------------------------------------------
ue_ip_priv_t *priv_p = netdev_priv(dev_pP);
printk("[UE_IP_DRV][%s] Begin\n", __FUNCTION__);
del_timer(&(priv_p->timer));
netif_stop_queue(dev_pP);
// MOD_DEC_USE_COUNT;
printk("[UE_IP_DRV][%s] End\n", __FUNCTION__);
return 0;
}
//---------------------------------------------------------------------------
void ue_ip_teardown(struct net_device *dev_pP) {
//---------------------------------------------------------------------------
ue_ip_priv_t *priv_p;
int inst;
printk("[UE_IP_DRV][%s] Begin\n", __FUNCTION__);
if (dev_pP) {
priv_p = netdev_priv(dev_pP);
inst = ue_ip_find_inst(dev_pP);
if ((inst<0) || (inst>=UE_IP_NB_INSTANCES_MAX)) {
printk("[UE_IP_DRV][%s] ERROR, couldn't find instance\n", __FUNCTION__);
return;
}
printk("[UE_IP_DRV][%s] End\n", __FUNCTION__);
} // check dev_pP
else {
printk("[UE_IP_DRV][%s] Device is null\n", __FUNCTION__);
}
}
//---------------------------------------------------------------------------
int ue_ip_set_config(struct net_device *dev_pP, struct ifmap *map_pP) {
//---------------------------------------------------------------------------
printk("[UE_IP_DRV][%s] Begin\n", __FUNCTION__);
if (dev_pP->flags & IFF_UP) {
return -EBUSY;
}
if (map_pP->base_addr != dev_pP->base_addr) {
printk(KERN_WARNING "[UE_IP_DRV][%s] Can't change I/O address\n", __FUNCTION__);
return -EOPNOTSUPP;
}
if (map_pP->irq != dev_pP->irq) {
dev_pP->irq = map_pP->irq;
}
printk("[UE_IP_DRV][%s] End\n", __FUNCTION__);
return 0;
}
//---------------------------------------------------------------------------
//
int ue_ip_hard_start_xmit(struct sk_buff *skb_pP, struct net_device *dev_pP) {
//---------------------------------------------------------------------------
int inst;
if (dev_pP) {
inst = ue_ip_find_inst(dev_pP);
} else {
printk("[UE_IP_DRV][%s] ERROR, device is null\n", __FUNCTION__);
return -1;
}
if ((inst>=0) && (inst<UE_IP_NB_INSTANCES_MAX)) {
#ifdef OAI_DRV_OAI_DRV_DEBUG_DEVICE
printk("[UE_IP_DRV][%s] inst %d, begin\n", __FUNCTION__,inst);
#endif
if (!skb_pP) {
printk("[UE_IP_DRV][%s] input parameter skb is NULL\n", __FUNCTION__);
return -1;
}
// End debug information
netif_stop_queue(dev_pP);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,7,0) \
|| (defined RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= 1796 && RHEL_RELEASE_CODE != 2403)
netif_trans_update(dev_pP);
#else
dev_pP->trans_start = jiffies;
#endif
#ifdef OAI_DRV_DEBUG_DEVICE
printk("[UE_IP_DRV][%s] step 1\n", __FUNCTION__);
#endif
ue_ip_common_ip2wireless(skb_pP,inst);
#ifdef OAI_DRV_DEBUG_DEVICE
printk("[UE_IP_DRV][%s] step 2\n", __FUNCTION__);
#endif
dev_kfree_skb(skb_pP);
#ifdef OAI_DRV_DEBUG_DEVICE
printk("[UE_IP_DRV][%s] step 3\n", __FUNCTION__);
#endif
netif_wake_queue(dev_pP);
#ifdef OAI_DRV_DEBUG_DEVICE
printk("[UE_IP_DRV][%s] end\n", __FUNCTION__);
#endif
} else {
printk("[UE_IP_DRV][%s] ERROR, couldn't find instance\n", __FUNCTION__);
return(-1);
}
return 0;
}
//---------------------------------------------------------------------------
struct net_device_stats *ue_ip_get_stats(struct net_device *dev_pP) {
//---------------------------------------------------------------------------
ue_ip_priv_t *priv_p = netdev_priv(dev_pP);
return &priv_p->stats;
}
//---------------------------------------------------------------------------
int ue_ip_set_mac_address(struct net_device *dev_pP, void *mac_pP) {
//---------------------------------------------------------------------------
//struct sockaddr *addr = mac_pP;
printk("[UE_IP_DRV][%s] CHANGE MAC ADDRESS UNSUPPORTED\n", __FUNCTION__);
//memcpy(dev_pP->dev_addr, addr->sa_data, dev_pP->addr_len);
return 0;
}
//---------------------------------------------------------------------------
int ue_ip_change_mtu(struct net_device *dev_pP, int mtuP) {
//---------------------------------------------------------------------------
printk("[UE_IP_DRV][%s] CHANGE MTU %d bytes\n", __FUNCTION__, mtuP);
if ((mtuP<50) || (mtuP>1500)) {
return -EINVAL;
}
dev_pP->mtu = mtuP;
return 0;
}
//---------------------------------------------------------------------------
void ue_ip_change_rx_flags(struct net_device *dev_pP, int flagsP) {
//---------------------------------------------------------------------------
ue_ip_priv_t *priv_p = netdev_priv(dev_pP);
printk("[UE_IP_DRV][%s] CHANGE RX FLAGS %08X\n", __FUNCTION__, flagsP);
priv_p->rx_flags ^= flagsP;
}
//---------------------------------------------------------------------------
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,6,0) || (defined RHEL_RELEASE_CODE && RHEL_RELEASE_CODE == 2055)
void ue_ip_tx_timeout(struct net_device *dev_pP, unsigned int txqueue)
#else
void ue_ip_tx_timeout(struct net_device *dev_pP)
#endif
{
//---------------------------------------------------------------------------
// Transmitter timeout, serious problems.
ue_ip_priv_t *priv_p = netdev_priv(dev_pP);
printk("[UE_IP_DRV][%s] begin\n", __FUNCTION__);
// (ue_ip_priv_t *)(dev_pP->priv_p)->stats.tx_errors++;
(priv_p->stats).tx_errors++;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,7,0) \
|| (defined RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= 1796 && RHEL_RELEASE_CODE != 2403)
netif_trans_update(dev_pP);
#else
dev_pP->trans_start = jiffies;
#endif
netif_wake_queue(dev_pP);
printk("[UE_IP_DRV][%s] transmit timed out %s\n", __FUNCTION__,dev_pP->name);
}
static const struct net_device_ops ue_ip_netdev_ops = {
.ndo_open = ue_ip_open,
.ndo_stop = ue_ip_stop,
.ndo_start_xmit = ue_ip_hard_start_xmit,
.ndo_validate_addr = NULL,
.ndo_get_stats = ue_ip_get_stats,
.ndo_set_mac_address = ue_ip_set_mac_address,
.ndo_set_config = ue_ip_set_config,
.ndo_do_ioctl = NULL,
#if defined(RHEL_RELEASE_CODE)
#if (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7, 5)) && (RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(8, 0))
.extended.ndo_change_mtu = ue_ip_change_mtu,
#else
.ndo_change_mtu = ue_ip_change_mtu,
#endif
#else
.ndo_change_mtu = ue_ip_change_mtu,
#endif
.ndo_tx_timeout = ue_ip_tx_timeout,
.ndo_change_rx_flags = ue_ip_change_rx_flags,
};
/*.ndo_set_multicast_list = NULL,*/
//---------------------------------------------------------------------------
// Initialisation of the network device
void ue_ip_init(struct net_device *dev_pP) {
//---------------------------------------------------------------------------
ue_ip_priv_t *priv_p = NULL;
if (dev_pP) {
priv_p = netdev_priv(dev_pP);
memset(priv_p, 0, sizeof(ue_ip_priv_t));
spin_lock_init(&priv_p->lock);
dev_pP->netdev_ops = &ue_ip_netdev_ops;
dev_pP->hard_header_len = 0;
dev_pP->addr_len = UE_IP_ADDR_LEN;
dev_pP->flags = IFF_BROADCAST|IFF_MULTICAST|IFF_NOARP;
dev_pP->tx_queue_len = UE_IP_TX_QUEUE_LEN;
dev_pP->mtu = UE_IP_MTU;
} else {
printk("[UE_IP_DRV][%s] ERROR, Device is NULL!!\n", __FUNCTION__);
return;
}
}
//---------------------------------------------------------------------------
int init_module (void) {
//---------------------------------------------------------------------------
int err,inst;
char devicename[100];
// Initialize parameters shared with RRC
printk("[UE_IP_DRV][%s] Starting OAI IP driver", __FUNCTION__);
for (inst=0; inst<UE_IP_NB_INSTANCES_MAX; inst++) {
printk("[UE_IP_DRV][%s] begin init instance %d\n", __FUNCTION__,inst);
sprintf(devicename,"oip%d",inst+1);
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0)
ue_ip_dev[inst] = alloc_netdev(sizeof(ue_ip_priv_t),devicename, ue_ip_init);
#else
ue_ip_dev[inst] = alloc_netdev(sizeof(ue_ip_priv_t),devicename, NET_NAME_PREDICTABLE,ue_ip_init);
#endif
//netif_stop_queue(ue_ip_dev[inst]);
if (ue_ip_dev[inst] == NULL) {
printk("[UE_IP_DRV][%s][INST %02d] alloc_netdev FAILED\n", __FUNCTION__,inst);
} else {
// linux/net/core/dev.c line 4767
err= register_netdev(ue_ip_dev[inst]);
if (err) {
printk("[UE_IP_DRV][%s] (inst %d): error %i registering device %s\n", __FUNCTION__, inst,err, ue_ip_dev[inst]->name);
} else {
printk("[UE_IP_DRV][%s] registering device %s, ifindex = %d\n\n", __FUNCTION__,ue_ip_dev[inst]->name, ue_ip_dev[inst]->ifindex);
}
}
}
printk("[UE_IP_DRV][%s] NETLINK INIT\n", __FUNCTION__);
if ((err=ue_ip_netlink_init()) == -1) {
printk("[UE_IP_DRV][%s] NETLINK failed\n", __FUNCTION__);
}
return err;
}
//---------------------------------------------------------------------------
void cleanup_module(void) {
//---------------------------------------------------------------------------
int inst;
printk("[UE_IP_DRV][CLEANUP] begin\n");
for (inst=0; inst<UE_IP_NB_INSTANCES_MAX; inst++) {
#ifdef OAI_DRV_DEBUG_DEVICE
printk("[UE_IP_DRV][CLEANUP] unregister and free net device instance %d\n",inst);
#endif
if (ue_ip_dev[inst]) {
unregister_netdev(ue_ip_dev[inst]);
ue_ip_teardown(ue_ip_dev[inst]);
free_netdev(ue_ip_dev[inst]);
}
}
ue_ip_netlink_release();
printk("[UE_IP_DRV][CLEANUP] end\n");
}
#define DRV_NAME "ue_ip"
#define DRV_VERSION "1.0"DRV_NAME
#define DRV_DESCRIPTION "OPENAIR UE IP Device Driver"
#define DRV_COPYRIGHT "-Copyright(c) GNU GPL Eurecom 2013"
#define DRV_AUTHOR "Lionel GAUTHIER: <firstname.name@eurecom.fr>"DRV_COPYRIGHT
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/***************************************************************************
local.h - description
-------------------
copyright : (C) 2002 by Eurecom
email : navid.nikaein@eurecom.fr
lionel.gauthier@eurecom.fr,
knopp@eurecom.fr
***************************************************************************/
#ifndef UE_IP_LOCAL_H
#define UE_IP_LOCAL_H
#include <linux/if_arp.h>
#include <linux/types.h>
#include <linux/spinlock.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/ipv6.h>
#include <linux/ip.h>
#include <linux/sysctl.h>
#include <linux/timer.h>
#include <linux/unistd.h>
#include <asm/param.h>
//#include <sys/sysctl.h>
#include <linux/udp.h>
#include <linux/tcp.h>
#include <linux/icmp.h>
#include <linux/icmpv6.h>
#include <linux/in.h>
#include <net/ndisc.h>
#include "constant.h"
#include "common/platform_types.h"
#include "sap.h"
typedef struct ue_ip_priv_s {
int irq;
int rx_flags;
struct timer_list timer;
spinlock_t lock;
struct net_device_stats stats;
uint8_t retry_limit;
uint32_t timer_establishment;
uint32_t timer_release;
struct sock *nl_sk;
uint8_t nlmsg[UE_IP_PRIMITIVE_MAX_LENGTH+sizeof(struct nlmsghdr)];
uint8_t xbuffer[UE_IP_PRIMITIVE_MAX_LENGTH]; // transmission buffer
uint8_t rbuffer[UE_IP_PRIMITIVE_MAX_LENGTH]; // reception buffer
} ue_ip_priv_t;
typedef struct ipversion_s {
#if defined(__LITTLE_ENDIAN_BITFIELD)
uint8_t reserved:4,
version:4;
#else
uint8_t version:4,
reserved:4;
#endif
} ipversion_t;
typedef struct pdcp_data_req_header_s {
rb_id_t rb_id;
sdu_size_t data_size;
signed int inst;
ip_traffic_type_t traffic_type;
uint32_t sourceL2Id;
uint32_t destinationL2Id;
} pdcp_data_req_header_t;
typedef struct pdcp_data_ind_header_s {
rb_id_t rb_id;
sdu_size_t data_size;
signed int inst;
ip_traffic_type_t dummy_traffic_type;
uint32_t sourceL2Id;
uint32_t destinationL2Id;
} pdcp_data_ind_header_t;
extern struct net_device *ue_ip_dev[UE_IP_NB_INSTANCES_MAX];
#endif
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/*! \file netlink.c
* \brief establish a netlink
* \author Navid Nikaein, Lionel Gauthier, Raymond knopp
* \company Eurecom
* \email: navid.nikaein@eurecom.fr, lionel.gauthier@eurecom.fr, knopp@eurecom.fr
*/
//#include <linux/config.h>
#include <linux/socket.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/netlink.h>
#include <net/sock.h>
#include <linux/kthread.h>
#include <linux/mutex.h>
#include <linux/version.h>
#include "local.h"
#include "proto_extern.h"
MODULE_LICENSE("OAI");
#define OAI_IP_DRIVER_NETLINK_ID 31
#define NL_DEST_PID 1
/*******************************************************************************
Prototypes
*******************************************************************************/
static inline void nasmesh_lock(void);
static inline void nasmesh_unlock(void);
static void nas_nl_data_ready (struct sk_buff *skb);
int ue_ip_netlink_init(void);
static struct sock *nas_nl_sk = NULL;
static int exit_netlink_thread=0;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
struct netlink_kernel_cfg cfg = {
.input = nas_nl_data_ready,
};
#endif
static DEFINE_MUTEX(nasmesh_mutex);
static inline void nasmesh_lock(void)
{
mutex_lock(&nasmesh_mutex);
}
static inline void nasmesh_unlock(void)
{
mutex_unlock(&nasmesh_mutex);
}
// This can also be implemented using thread to get the data from PDCP without blocking.
static void nas_nl_data_ready (struct sk_buff *skb)
{
// wake_up_interruptible(skb->sk->sk_sleep);
//nasmesh_lock();
//netlink_rcv_skb(skb, &my_rcv_msg);// my_rcv_msg is the call back func>
//nasmesh_unlock();
struct nlmsghdr *nlh = NULL;
if (skb) {
#ifdef NETLINK_DEBUG
printk("[UE_IP_DRV][NETLINK] Received socket from PDCP\n");
#endif //NETLINK_DEBUG
nlh = (struct nlmsghdr *)skb->data;
ue_ip_common_wireless2ip(nlh);
//kfree_skb(skb); // not required,
}
}
int ue_ip_netlink_init(void)
{
printk("[UE_IP_DRV][NETLINK] Running init ...\n");
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0)
cfg.groups = 0;
cfg.input = nas_nl_data_ready;
cfg.cb_mutex = &nasmesh_mutex;
cfg.bind = NULL;
nas_nl_sk = netlink_kernel_create(
&init_net,
OAI_IP_DRIVER_NETLINK_ID,
# if LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0)
THIS_MODULE,
# endif
&cfg);
#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0) */
nas_nl_sk = netlink_kernel_create(
&init_net,
OAI_IP_DRIVER_NETLINK_ID,
0,
nas_nl_data_ready,
&nasmesh_mutex, // NULL
THIS_MODULE);
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0) */
if (nas_nl_sk == NULL) {
printk("[UE_IP_DRV][NETLINK] netlink_kernel_create failed \n");
return(-1);
}
return(0);
}
void ue_ip_netlink_release(void)
{
exit_netlink_thread=1;
printk("[UE_IP_DRV][NETLINK] Releasing netlink socket\n");
if(nas_nl_sk) {
netlink_kernel_release(nas_nl_sk); //or skb->sk
}
// printk("[UE_IP_DRV][NETLINK] Removing netlink_rx_thread\n");
//kthread_stop(netlink_rx_thread);
}
int ue_ip_netlink_send(unsigned char *data,unsigned int len)
{
struct sk_buff *nl_skb = alloc_skb(NLMSG_SPACE(len),GFP_ATOMIC);
struct nlmsghdr *nlh = (struct nlmsghdr *)nl_skb->data;
int status;
// printk("[UE_IP_DRV][NETLINK] Sending %d bytes (%d)\n",len,NLMSG_SPACE(len));
skb_put(nl_skb, NLMSG_SPACE(len));
memcpy(NLMSG_DATA(nlh),data,len);
nlh->nlmsg_len = NLMSG_SPACE(len);
nlh->nlmsg_pid = 0; /* from kernel */
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
NETLINK_CB(nl_skb).pid = 0;
#endif
#ifdef NETLINK_DEBUG
printk("[UE_IP_DRV][NETLINK] In nas_netlink_send, nl_skb %p, nl_sk %x, nlh %p, nlh->nlmsg_len %d\n",nl_skb,nas_nl_sk,nlh,nlh->nlmsg_len);
#endif //DEBUG_NETLINK
if (nas_nl_sk) {
// nasmesh_lock();
status = netlink_unicast(nas_nl_sk, nl_skb, NL_DEST_PID, MSG_DONTWAIT);
// mutex_unlock(&nasmesh_mutex);
if (status < 0) {
printk("[UE_IP_DRV][NETLINK] SEND status is %d\n",status);
return(0);
} else {
#ifdef NETLINK_DEBUG
printk("[UE_IP_DRV][NETLINK] SEND status is %d\n",status);
#endif
return len;
}
} else {
printk("[UE_IP_DRV][SEND] socket is NULL\n");
return(0);
}
}
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/***************************************************************************
proto_extern.h - description
-------------------
copyright : (C) 2002 by Eurecom
email : navid.nikaein@eurecom.fr
lionel.gauthier@eurecom.fr
knopp@eurecom.fr
***************************************************************************/
#ifndef _UE_IP_PROTO_H
#define _UE_IP_PROTO_H
#include <linux/if_arp.h>
#include <linux/types.h>
#include <linux/spinlock.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/ipv6.h>
#include <linux/ip.h>
#include <linux/sysctl.h>
#include <linux/timer.h>
#include <asm/param.h>
//#include <sys/sysctl.h>
#include <linux/udp.h>
#include <linux/tcp.h>
#include <linux/icmp.h>
#include <linux/icmpv6.h>
#include <linux/in.h>
#include <net/ndisc.h>
#include "local.h"
// device.c
/** @defgroup _ue_ip_impl_ OAI Network Device for RRC Lite
* @ingroup _ref_implementation_
* @{
\fn int ue_ip_find_inst(struct net_device *dev)
\brief This function determines the instance id for a particular device pointer.
@param dev Pointer to net_device structure
*/
int ue_ip_find_inst(struct net_device *dev);
// common.c
/**
\fn void ue_ip_common_class_wireless2ip(unsigned short dlen, void* pdcp_sdu,int inst,struct classifier_entity *rclass,OaiNwDrvRadioBearerId_t rb_id)
\brief Receive classified LTE packet, build skbuff struct with it and deliver it to the OS network layer.
@param dlen Length of SDU in bytes
@param pdcp_sdu Pointer to received SDU
@param inst Instance number
@param rb_id Radio Bearer Id
*/
void ue_ip_common_class_wireless2ip(sdu_size_t dlen,
void *pdcp_sdu,
int inst,
rb_id_t rb_id);
/**
\fn void ue_ip_common_ip2wireless(struct sk_buff *skb, struct cx_entity *cx, struct classifier_entity *gc,int inst)
\brief Request the transfer of data (QoS SAP)
@param skb pointer to socket buffer
@param inst device instance
*/
void ue_ip_common_ip2wireless(struct sk_buff *skb, int inst);
/**
\fn void ue_ip_common_ip2wireless_drop(struct sk_buff *skb, struct cx_entity *cx, struct classifier_entity *gc,int inst)
\brief Drop the IP packet comming from the OS network layer.
@param skb pointer to socket buffer
@param inst device instance
*/
void ue_ip_common_ip2wireless_drop(struct sk_buff *skb, int inst);
#ifndef OAI_NW_DRIVER_USE_NETLINK
/**
\fn void ue_ip_common_wireless2ip()
\brief Retrieve PDU from PDCP through RT-fifos for delivery to the IP stack.
*/
void ue_ip_common_wireless2ip(void);
#else
/**
\fn void ue_ip_common_wireless2ip(struct nlmsghdr *nlh)
\brief Retrieve PDU from PDCP through netlink sockets for delivery to the IP stack.
*/
void ue_ip_common_wireless2ip(struct nlmsghdr *nlh);
#endif //OAI_NW_DRIVER_USE_NETLINK
#ifdef OAI_NW_DRIVER_USE_NETLINK
/**
\fn int ue_ip_netlink_send(unsigned char *data,unsigned int len)
\brief Request the transfer of data by PDCP via netlink socket
@param data pointer to SDU
@param len length of SDU in bytes
@returns Numeber of bytes transfered by netlink socket
*/
int ue_ip_netlink_send(unsigned char *data,unsigned int len);
/**
\fn void ue_ip_COMMON_QOS_receive(struct nlmsghdr *nlh)
\brief Request a PDU from PDCP
@param nlh pointer to netlink message header
*/
void ue_ip_COMMON_QOS_receive(struct nlmsghdr *nlh);
#endif //OAI_NW_DRIVER_USE_NETLINK
// netlink.c
void ue_ip_netlink_release(void);
int ue_ip_netlink_init(void);
/** @} */
#endif
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#ifndef UE_IP_SAP_H
#define UE_IP_SAP_H
typedef unsigned short OaiNwDrvRadioBearerId_t;
#define UE_IP_PRIMITIVE_MAX_LENGTH 180 // maximum length of a NAS primitive
#endif
......@@ -13,9 +13,6 @@ cd cmake_targets
#Execution instuctions (Currently running eNB (VNF) and UE side (PNF) on the same machine using the loopback interface)
cd cmake_targets/tools
# Loading nasmesh
source init_nas_nos1
# Add a new loopback interface address
sudo ifconfig lo: 127.0.0.2 netmask 255.0.0.0 up
......
include $(OPENAIR_DIR)/common/utils/Makefile.inc
TOP_DIR = $(OPENAIR1_DIR)
OPENAIR1_TOP = $(OPENAIR1_DIR)
OPENAIR2_TOP = $(OPENAIR2_DIR)
OPENAIR3_TOP = $(OPENAIR3_DIR)
OPENAIR3 = $(OPENAIR3_DIR)
CFLAGS += -m32 -DPHYSIM -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TX=2 -I/usr/include/X11
ASN1_MSG_INC = $(OPENAIR2_DIR)/RRC/LITE/MESSAGES
CFLAGS += -DOPENAIR_LTE #-DOFDMA_ULSCH -DIFFT_FPGA -DIFFT_FPGA_UE
CFLAGS += -DMAC_CONTEXT=1 -DPHY_CONTEXT=1
CFLAGS += -DEMIT_ASN_DEBUG=1
ifndef OPENAIR2
OPENAIR2=1
endif
# activate OCG and libxml only under linux
ifeq ($(linux),1)
CFLAGS += -I/usr/include/libxml2 -L/usr/local/lib -I/usr/include/atlas -L/usr/X11R6/lib
CFLAGS += -DLINUX
endif
ifndef rrc_cellular
rrc_cellular = 0
rrc_cellular_eNB = 0
rrc_cellular_UE = 0
else
ifeq ($(eNB_flag),1)
rrc_cellular_eNB=1
endif
ifeq ($(UE_flag),1)
rrc_cellular_UE=1
endif
endif
ifdef DEBUG_PHY
CFLAGS += -DDEBUG_PHY
endif
#CFLAGS += -DPDCP_USE_NETLINK -DLINUX
#NAS_FLAG=1
#require kernel patch for oai driver to enable address autoconfiguration (IPv6 only)
ifdef ADDCONF
CFLAGS+=-DADDRCONF
endif
ifdef TRAFFIC_TM5
CFLAGS += -DRLC_UM_TEST_TRAFFIC=1 -DFULL_BUFFER=1
endif
include $(OPENAIR1_DIR)/PHY/Makefile.inc
include $(OPENAIR1_DIR)/SCHED/Makefile.inc
include $(OPENAIR2_DIR)/LAYER2/Makefile.inc
include $(OPENAIR1_DIR)/SIMULATION/ETH_TRANSPORT/Makefile.inc
include $(OPENAIR2_DIR)/RRC/LITE/MESSAGES/Makefile.inc
include $(OPENAIR2_DIR)/RRC/NAS/Makefile.inc
include $(OPENAIR2_DIR)/UTIL/Makefile.inc
ASN1_MSG_OBJS1=$(addprefix $(OPENAIR2_DIR)/RRC/LITE/MESSAGES/, $(ASN1_MSG_OBJS))
#L2_OBJS =
#EXTRA_CFLAGS =
export IS_REL10=$(shell if [ -f .lock-rel10 ] ; then echo "1" ; else echo "0" ; fi)
export IS_REL8=$(shell if [ -f .lock-rel8 ] ; then echo "1" ; else echo "0" ; fi)
ifdef Rel10
CFLAGS += -DRel10
ifeq ($(IS_REL10), 0)
$(shell cd $(OPENAIR2_DIR)/RRC/LITE/MESSAGES/asn1c/ASN1_files/ ; rm EUTRA-RRC-Definitions.asn ; ln -s EUTRA-RRC-Definitions-a20.asn EUTRA-RRC-Definitions.asn ; cd $(OPENAIR_TARGETS)/TEST/PACKET_TRACER/ ; rm -f $(ASN1_MSG_OBJS1) ; rm -f $(OPENAIR2_DIR)/RRC/LITE/MESSAGES/Makefile.inc.generated ; rm -f $(L2_OBJS) ; touch .lock-rel10 ; rm .lock-rel8 ;)
endif
else # default is rel 8
ifeq ($(IS_REL8), 0)
$(shell cd $(OPENAIR2_DIR)/RRC/LITE/MESSAGES/asn1c/ASN1_files/ ; rm EUTRA-RRC-Definitions.asn ; ln -s EUTRA-RRC-Definitions-86.asn EUTRA-RRC-Definitions.asn ; cd $(OPENAIR_TARGETS)/TEST/PACKET_TRACER/ ; rm -f $(ASN1_MSG_OBJS1) ; rm -f $(OPENAIR2_DIR)/RRC/LITE/MESSAGES/Makefile.inc.generated ; rm -f $(L2_OBJS); rm -f *.o ; rm -f oaisim ; touch .lock-rel8 ; rm .lock-rel10 ; )
endif
endif
export IS_REL10=$(shell if [ -f .lock-rel10 ] ; then echo "1" ; else echo "0" ; fi)
export IS_REL8=$(shell if [ -f .lock-rel8 ] ; then echo "1" ; else echo "0" ; fi)
PT_OBJS = pt.o
SIMULATION_OBJS += $(TOP_DIR)/SIMULATION/TOOLS/taus.o
SIMULATION_OBJS += $(TOP_DIR)/SIMULATION/TOOLS/rangen_double.o
OBJ = $(PHY_OBJS) $(SIMULATION_OBJS) $(SCHED_OBJS) $(L2_OBJS) $(TOOLS_OBJS) $(STATS_OBJS) $(ASN1_MSG_OBJS1) $(NAS_OBJS) $(INT_OBJS) $(UTIL_OBJ)
OBJ += $(OPENAIR_TARGETS)/SIMU/USER/init_lte.o
all: pt
printvars:
@echo LINUX variable is $(linux)
@echo rrc_cellular variable is $(rrc_cellular)
@echo EXTRA_CFLAGS = $(EXTRA_CFLAGS)
@echo OAI NETLINK FLAG is $(NAS_FLAG)
@echo SSE3 proc is $(SSE3PROC)
@echo IS_REL_8 is $(IS_REL_8)
@echo IS_REL_10 is $(IS_REL_10)
$(OBJ): %.o : %.c
@echo Compiling $<
$(CC) -c $(CFLAGS) $(EXTRA_CFLAGS) -DPHY_CONTEXT=1 -I$(TOP_DIR) $(L2_incl) $(UTIL_incl) -I$(ASN1_MSG_INC) -o $@ $<
pt: $(OBJ) pt.c
@echo "Compiling pt.c ..."
@$(CC) pt.c -I$(TOP_DIR) $(L2_incl) $(UTIL_incl) -I$(ASN1_MSG_INC) -o pt $(CFLAGS) $(EXTRA_CFLAGS) $(OBJ) -lm -lblas -lpthread -lxml2 -lX11 -lXpm -lrt -lforms -llapack_atlas
ifeq ($(rrc_cellular_eNB),1)
mv oaisim oaisim_eNB
endif
ifeq ($(rrc_cellular_UE),1)
mv oaisim oaisim_UE
endif
nasmesh_fix:
(cd $(OPENAIR2_DIR) && make nasmesh_netlink_address_fix.ko)
(sudo insmod $(OPENAIR2_DIR)/NAS/DRIVER/MESH/nasmesh.ko)
nasmesh_nl:
(cd $(OPENAIR2_DIR) && make nasmesh_netlink.ko)
(sudo insmod $(OPENAIR2_DIR)/NAS/DRIVER/MESH/nasmesh.ko)
rb_tool:
(cd $(OPENAIR2_DIR)/NAS/DRIVER/MESH/RB_TOOL && make)
nasmesh_install:
(sudo rmmod nasmesh)
(sudo insmod $(OPENAIR2_DIR)/NAS/DRIVER/MESH/nasmesh.ko)
clean:
rm -f oaisim
rm -f $(OBJ)
rm -f *.o
rm -f *.exe*
cleanl1:
rm -f oaisim
rm -f $(PHY_OBJS) $(SCHED_OBJS)
rm -f *.o
rm -f *.exe
cleanl2:
rm -f $(L2_OBJS)
cleanasn1:
rm -f $(ASN1_MSG_OBJS1)
rm -f $(OPENAIR2_DIR)/RRC/LITE/MESSAGES/Makefile.inc.generated
print:
@echo $(CFLAGS)
@echo $(EXTRA_CFLAGS)
@echo $(OBJ)
showcflags:
@echo $(CFLAGS)
This utility allows you to inject packets into the Openair4G stack (UE for the moment) or generate packets
from different parts of the stack.
To compile:
make pt
To get help
./pt --help
Some pregenerated messages (RRC and MAC) can be found in the PACKET_TRACER/messages directory. Here are some
usage examples:
To generate RRC messages (e.g. SIBx)
./pt --eNB_RRC --RRCSIB2_3
./pt --eNB_RRC --RRCConnectionReconfiguration
./pt --UE_RRC --RRCConnectionRequest
To inject packets into the OpenAir4G stack (This works for UE receiver only for now, with control-plane messasges)
./pt --eNB_MAC -I messages/Msg4.txt
./pt -I messages/rrcconnectionsetup.txt -J messages/rrcconnectionreconfiguration.txt --eNB_RRC --RRCConnectionReconfiguration
./pt -I messages/rrcconnectionsetup.txt --eNB_RRC --RRCConnectionSetup
To be done:
- user-plane tests, in particular out-of-order segments to (MAC->RLC)
21591FA00404200602013D2C3FAC50083A101700300007888000080102900E08484A0202020000000000605A0AA1A3BB4B932B632B9B982808A0A0A322805FB007888000080891A2B3C353E0FA897844866E926E0D80100021F756A900
5040040300010000001C1650902080850000
00000C60FD6C8160C002A00200141000029AA55696D0C72944C1C000
00800f5995648000020a580020000804012f395796dec00a111fe807c1
010101eb32ac900000414b00040001008025e72af2dbd800115542023fd00f83020c000802200000
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#include <string.h>
#include <math.h>
#include <execinfo.h>
#include <signal.h>
#include <unistd.h>
#include <getopt.h>
//#include "SIMULATION/TOOLS/defs.h"
#include "PHY/types.h"
#include "PHY/defs.h"
#include "PHY/vars.h"
#include "MAC_INTERFACE/vars.h"
#include "SCHED/defs.h"
#include "SCHED/vars.h"
#include "LAYER2/MAC/defs.h"
#include "LAYER2/MAC/vars.h"
#include "RRC/LTE/vars.h"
#include "PHY_INTERFACE/vars.h"
#include "UTIL/LOG/log.h"
#include "UTIL/OTG/otg_tx.h"
#include "UTIL/OTG/otg.h"
#include "UTIL/OTG/otg_vars.h"
char binary_table[16][5] = {{"0000\0"},{"0001\0"},{"0010\0"},{"0011\0"},{"0100\0"},{"0101\0"},{"0110\0"},{"0111\0"},{"1000\0"},{"1001\0"},{"1010\0"},{"1011\0"},{"1100\0"},{"1101\0"},{"1110\0"},{"1111\0"}};
typedef enum {
RRCConnectionRequest=0,
RRCConnectionSetup,
RRCConnectionSetupComplete,
RRCConnectionReconfiguration,
RRCConnectionReconfigurationComplete,
RRCSIB1,
RRCSIB2_3
} RRC_MESSAGES_t;
typedef enum {
eNB_RRC=0,
eNB_S1U,
eNB_PDCP,
eNB_RLC_UM,
eNB_RLC_AM,
eNB_RLC_TM,
eNB_MAC,
UE_RRC,
UE_S1U,
UE_PDCP,
UE_RLC_UM,
UE_RLC_AM,
UE_RLC_TM,
eNB_SI
} SDUsource_t;
typedef struct {
int verbose;
int RRCmessage;
int lcid;
int rbid;
int SDUsize;
int TBsize;
SDUsource_t SDUsource;
char input1_file[128];
char input2_file[128];
char output_file[128];
unsigned char input1_sdu[1024];
unsigned char input2_sdu[1024];
int input1_sdu_flag;
unsigned short input1_sdu_len;
int input2_sdu_flag;
unsigned short input2_sdu_len;
int frame;
int input_sib;
int input_eNB_MAC;
} args_t;
int input_text(char *file,char *sdu)
{
FILE *fd;
int i,b_ind=0;
char c,c0,c1;
unsigned char byte;
fd = fopen(file,"r");
while (!feof(fd)) {
c0 = fgetc(fd);
if (!feof(fd))
c1 = fgetc(fd);
else
return(-1);
byte = 0;
for (i=0,c=c0; i<2; i++,c=c1)
switch(c) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
byte += (c-'0')<<(4*(1-i));
break;
case 'A':
case 'B':
case 'C':
case 'D':
case 'E':
case 'F':
byte += (10+c-'A')<<(4*(1-i));
break;
case 'a':
case 'b':
case 'c':
case 'd':
case 'e':
case 'f':
byte += (10+c-'a')<<(4*(1-i));
break;
case '\n':
case '\0':
return(b_ind);
break;
default:
printf("Unknown hex character %c in file\n",c);
return(-1);
break;
}
sdu[b_ind]=byte;
printf("byte %d: %x (%s%s)\n",b_ind,byte,binary_table[byte>>4],binary_table[byte&0xf]);
b_ind++;
}
if (fd)
fclose(fd);
return(b_ind);
}
int parse_args(int argc, char** argv, args_t* args)
{
int c;
int k;
const struct option long_options[] = {
{"lcid", required_argument, NULL, 256},
{"rbid", required_argument, NULL, 257},
{"TBsize", required_argument, NULL, 258},
{"SDUsize", required_argument, NULL, 259},
{"eNB_RRC", no_argument, NULL, 260},
{"eNB_S1U", no_argument, NULL, 261},
{"eNB_PDCP", no_argument, NULL, 262},
{"eNB_RLC_UM", no_argument, NULL, 263},
{"eNB_RLC_AM", no_argument, NULL, 264},
{"eNB_RLC_TM", no_argument, NULL, 265},
{"eNB_MAC" , no_argument, NULL, 266},
{"UE_RRC", no_argument, NULL, 267},
{"UE_S1U", no_argument, NULL, 268},
{"UE_PDCP", no_argument, NULL, 269},
{"UE_RLC_UM", no_argument, NULL, 270},
{"UE_RLC_AM", no_argument, NULL, 271},
{"UE_RLC_TM", no_argument, NULL, 272},
{"RRCConnectionRequest", no_argument, NULL, 273},
{"RRCConnectionSetup", no_argument, NULL, 274},
{"RRCConnectionSetupComplete", no_argument, NULL, 275},
{"RRCConnectionReconfiguration", no_argument, NULL, 276},
{"RRCConnectionReconfigurationComplete", no_argument, NULL, 277},
{"RRCSIB1", no_argument, NULL, 278},
{"RRCSIB2_3", no_argument, NULL, 279},
{NULL, 0, NULL, 0}
};
args->frame = 0;
while((c = getopt_long(argc, argv, "ho:I:J:v", long_options, NULL)) != -1) {
switch(c) {
case 'h':
return 1;
case 'o':
strcpy(args->output_file,optarg);
break;
case 'f':
args->frame = atoi(optarg);
break;
case 'I':
strcpy(args->input1_file,optarg);
args->input1_sdu_len = input_text(args->input1_file,args->input1_sdu);
printf("Got sdu1 of length %u bytes\n",args->input1_sdu_len);
args->input1_sdu_flag=1;
break;
case 'J':
strcpy(args->input2_file,optarg);
args->input2_sdu_len = input_text(args->input2_file,args->input2_sdu);
printf("Got sdu2 of length %u bytes\n",args->input2_sdu_len);
args->input2_sdu_flag=1;
break;
case 'v':
args->verbose++;
break;
case 256: // lchan
args->lcid = atoi(optarg);
break;
case 257: //
args->rbid = atoi(optarg);
break;
case 258:
args->TBsize = atoi(optarg);
break;
case 259:
args->SDUsize = atoi(optarg);
break;
case 260: //eNB_RRC
case 261: //eNB_S1U
case 262: //eNB_PDCP
case 263: //eNB_RLC_UM
case 264: //eNB_RLC_AM
case 265: //eNB_RLC_TM
case 266: //eNB_MAC
case 267: //UE_RRC
case 268: //UE_S1U
case 269: //UE_PDCP
case 270: //UE_RLC_UM
case 271: //UE_RLC_AM
case 272: //UE_RLC_TM
args->SDUsource = c-260;
break;
case 273: //RRCConnectionRequest
case 274: //RRCConnectionSetup
case 275: //RRCConnectionSetupComplete
case 276: //RRCConnectionReconfiguration
case 277: //RRCConnectionReconfigurationComplete
case 278: //RRCSIB1
case 279: //RRCSIB2_3
args->RRCmessage = c-273;
break;
default:
return 1;
}
}
return 0;
}
void print_usage(const char* prog)
{
printf("Usage: %s [options]\n", prog);
printf("\n");
printf(" General options:\n");
printf(" -h : print usage\n");
printf(" -v : increase verbosity level [0]\n");
printf(" -o : output .dat file (binary packet data)\n");
printf(" -i : input .dat file (binary packet data)\n");
printf(" -I : input .txt file (ASCII packet data)\n");
printf("\n");
printf(" Packet options:\n");
printf(" --eNB_RRC : set source of packet to eNB_RRC\n");
printf(" --eNB_S1U : set source of packet to eNB_S1U (e.g. IP)\n");
printf(" --eNB_PDCP : set source of packet to eNB_PDCP\n");
printf(" --eNB_RLC_UM : set source of packet to eNB_RLC_UM\n");
printf(" --eNB_RLC_AM : set source of packet to eNB_RLC_AM\n");
printf(" --eNB_RLC_TM : set source of packet to eNB_RLC_TM\n");
printf(" --eNB_MAC : set source of packet to eNB_MAC\n");
printf(" --UE_RRC : set source of packet to UE_RRC\n");
printf(" --UE_S1U : set source of packet to UE_S1U (e.g. IP)\n");
printf(" --UE_PDCP : set source of packet to UE_PDCP\n");
printf(" --UE_RLC_UM : set source of packet to UE_RLC_UM\n");
printf(" --UE_RLC_AM : set source of packet to UE RLC_AM\n");
printf(" --UE_RLC_TM : set source of packet to UE RLC_TM\n");
printf(" --lchan : set logical channel id\n");
printf(" --rbid : set radio bearer id\n");
printf(" --TBsize : set Transport Block Size at MAC layer\n");
printf(" --SDUsize : set the SDU size used by the originating entity (except RRC)\n");
printf(" --RRCConnectionSetup : set the SDU to be an RRCConnectionSetup\n");
printf(" --RRCConnectionSetupComplete : set the SDU to be an RRCConnectionSetupComplete\n");
printf(" --RRCConnectionRequest : set the SDU to be an RRCConnectionRequest\n");
printf(" --RRCConnectionReconfiguration : set the SDU to be an RRCConnectionReconfiguration\n");
printf(" --RRCConnectionReconfigurationComplete : set the SDU to be an RRCConnectionReconfigurationComplete\n");
printf(" --RRCSIB1 : set the SDU to be an RRCSIB1\n");
printf(" --RRCSIB2_3 : set the SDU to be an RRCSIB2_3\n");
}
u8 attach_ue0(char *sdu)
{
u8 Size;
u16 Size16;
u8 lcid=0;
UE_rrc_inst[0].Info[0].State = RRC_SI_RECEIVED;
rrc_ue_generate_RRCConnectionRequest(0,131,0);
Size = mac_rrc_data_req(0,
131,
CCCH,1,
&sdu[sizeof(SCH_SUBHEADER_FIXED)],0,
0);
Size16 = (u16)Size;
generate_ulsch_header((u8 *)sdu, // mac header
1, // num sdus
0, // short padding
&Size16, // sdu length
&lcid, // sdu lcid
NULL, // power headroom
NULL, // crnti
NULL, // truncated bsr
NULL, // short bsr
NULL,
0); // post padding
return(Size+sizeof(SCH_SUBHEADER_FIXED));
}
// This retrieves the RRCConnectionSetup RRC SDU
u8 attach_ue1(char *sdu)
{
// simulate reception of CCCH at eNB(RRCConnectionRequest)
mac_rrc_lite_data_ind(0,131,0,UE_rrc_inst[0].Srb0[0].Tx_buffer.Payload,
UE_rrc_inst[0].Srb0[0].Tx_buffer.payload_size,1,0);
return(mac_rrc_data_req(0,
132,
0,1,
sdu,
1,
0));
}
// This retrieves the RRCConnectionSetupComplete RRC SDU
u16 attach_ue2(char *dcch_sdu_eNB, char dcch_sdu_eNB_len, char *dcch_sdu)
{
mac_rlc_status_resp_t rlc_status;
u16 sdu_len;
printf("************* attach_ue2 (CCCH payload %d)\n",
eNB_rrc_inst[0].Srb0.Tx_buffer.payload_size);
// simulate reception of CCCH at UE (RRCConnectionSetup)
mac_rrc_lite_data_ind(0,132,0,dcch_sdu_eNB,dcch_sdu_eNB_len,0,0);
// simulate transmission of RRCConnectionSetupComplete
rlc_status = mac_rlc_status_ind(1,134,0,
DCCH,
100);
sdu_len = mac_rlc_data_req(1,133,
DCCH,
dcch_sdu);
return(sdu_len);
}
// This retrieves the RRCConnectionReconfiguration RRC SDU
u16 attach_ue3(char *dcch_sdu_ue, char dcch_sdu_ue_len, char *dcch_sdu_eNB)
{
mac_rlc_status_resp_t rlc_status;
u16 sdu_len;
// simulation reception of RRCConnectionSetupComplete
mac_rlc_data_ind(0,134,1,
DCCH,
dcch_sdu_ue,
dcch_sdu_ue_len,
1,
NULL);
/// ... and generation of RRCConnectionReconfiguration
/// First RLC-AM Control SDU (ACK)
rlc_status = mac_rlc_status_ind(0,135,1,
DCCH,
100);
sdu_len = mac_rlc_data_req(0,135,
DCCH,
dcch_sdu_eNB);
mac_rlc_data_ind(1,135,1,
DCCH,
dcch_sdu_eNB,
sdu_len,
1,
NULL);
// now RRC message
rlc_status = mac_rlc_status_ind(0,136,1,
DCCH,
100);
sdu_len = mac_rlc_data_req(0,136,
DCCH,
dcch_sdu_eNB);
return(sdu_len);
}
// This retrieves the RRCConnectionReconfigurationComplete RRC SDU
u16 attach_ue4(char *dcch_sdu_eNB, char dcch_sdu_eNB_len, char *dcch_sdu_ue)
{
mac_rlc_status_resp_t rlc_status;
u16 sdu_len;
// simulation UE reception of RRCConnectionReconfiguration ....
mac_rlc_data_ind(1,135,0,
DCCH,
dcch_sdu_eNB,
dcch_sdu_eNB_len,
1,
NULL);
// ... and generation of RRCConnectionReconfigurationComplete
rlc_status = mac_rlc_status_ind(1,135,0,
DCCH,
100);
sdu_len = mac_rlc_data_req(1,135,
DCCH,
dcch_sdu_ue);
rlc_status = mac_rlc_status_ind(1,136,0,
DCCH,
100);
sdu_len = mac_rlc_data_req(1,136,
DCCH,
dcch_sdu_ue);
return(sdu_len);
}
//u8 NB_INST=2;
const int NB_UE_INST = 1;
int main (int argc, char **argv)
{
args_t args;
LTE_DL_FRAME_PARMS frame_parms0;
LTE_DL_FRAME_PARMS *frame_parms=&frame_parms;
char sdu0[16],sdu1[64],sdu2[1024],sdu3[1024],sdu4[1024];
unsigned short sdu_len0,sdu_len1,sdu_len2,sdu_len3,sdu_len4;
char ulsch_buffer[1024],dlsch_buffer[1024];
u8 lcid;
u8 payload_offset;
int i,comp;
logInit();
// Parse arguments
if(parse_args(argc, argv, &args) > 0) {
print_usage(argv[0]);
exit(1);
}
set_taus_seed(0);
logInit();
set_glog(LOG_TRACE, 1);
for (comp = PHY; comp < MAX_LOG_COMPONENTS ; comp++)
set_comp_log(comp,
LOG_TRACE,
LOG_NONE,
1);
/*
set_log(OMG, LOG_INFO, 20);
set_log(EMU, LOG_INFO, 10);
set_log(MAC, LOG_TRACE, 1);
set_log(RLC, LOG_TRACE, 1);
set_log(PHY, LOG_DEBUG, 1);
set_log(PDCP, LOG_TRACE, 1);
set_log(RRC, LOG_TRACE, 1);
*/
mac_xface = (MAC_xface *)malloc(sizeof(MAC_xface));
init_lte_vars (&frame_parms, 0, 1, 0, 0, 25, 0, 0, 1, 1);
l2_init(frame_parms);
// Generate eNB SI
if (args.input_sib == 0) {
openair_rrc_lite_eNB_init(0);
} else {
printf("Got SI from files (%d,%d,%d)\n",
args.input_sib,args.input1_sdu_flag,args.input2_sdu_flag);
}
openair_rrc_on(0,0);
openair_rrc_lite_ue_init(0,0);
switch (args.SDUsource) {
case eNB_RRC:
if (args.RRCmessage == RRCSIB1) {
if (args.input1_sdu_flag == 1) {
for (i=0; i<args.input1_sdu_len; i++)
printf("%02x",args.input1_sdu[i]);
printf("\n");
ue_decode_si(0,142,0,args.input1_sdu,args.input1_sdu_len);
} else {
printf("\n\nSIB1\n\n");
for (i=0; i<eNB_rrc_inst[0].sizeof_SIB1; i++)
printf("%02x",eNB_rrc_inst[0].SIB1[i]);
printf("\n");
}
} else if (args.RRCmessage == RRCSIB2_3) {
if (args.input1_sdu_flag == 1) {
for (i=0; i<args.input2_sdu_len; i++)
printf("%02x",args.input2_sdu[i]);
printf("\n");
ue_decode_si(0,149,0,args.input1_sdu,args.input1_sdu_len);
} else {
printf("\n\nSIB2_3\n\n");
for (i=0; i<eNB_rrc_inst[0].sizeof_SIB23; i++)
printf("%02x",eNB_rrc_inst[0].SIB23[i]);
printf("\n");
}
} else if ((args.input1_sdu_flag == 1)&&
((args.RRCmessage == RRCConnectionSetup) ||
(args.RRCmessage == RRCConnectionReconfiguration))) {
sdu_len0 = attach_ue0(sdu0);
ue_send_sdu(0,143,args.input1_sdu,args.input1_sdu_len,0);
if (args.RRCmessage == RRCConnectionReconfiguration)
ue_send_sdu(0,144,args.input2_sdu,args.input2_sdu_len,0);
} else {
switch (args.RRCmessage) {
case RRCConnectionSetup:
printf("Doing eNB RRCConnectionSetup\n");
sdu_len0 = attach_ue0(sdu0);
sdu_len1 = attach_ue1(sdu1);
lcid = 0;
payload_offset = generate_dlsch_header(dlsch_buffer,
1, //num_sdus
&sdu_len1, //
&lcid, // sdu_lcid
255, // no drx
0, // no timing advance
sdu0, // contention res id
0,0);
memcpy(&dlsch_buffer[payload_offset],sdu1,sdu_len1);
printf("\nRRCConnectionSetup (DLSCH input / MAC output)\n\n");
for (i=0; i<sdu_len1+payload_offset; i++)
printf("%02x ",(unsigned char)sdu1[i]);
printf("\n");
break;
case RRCConnectionReconfiguration:
printf("Doing eNB RRCConnectionReconfiguration\n");
sdu_len0 = attach_ue0(sdu0);
sdu_len1 = attach_ue1(sdu1);
sdu_len2 = attach_ue2(sdu1,sdu_len1,sdu2);
sdu_len3 = attach_ue3(sdu2,sdu_len2,sdu3);
lcid=1;
payload_offset = generate_dlsch_header(dlsch_buffer,
// offset = generate_dlsch_header((unsigned char*)eNB_mac_inst[0].DLSCH_pdu[0][0].payload[0],
1, //num_sdus
&sdu_len3, //
&lcid,
255, // no drx
1, // timing advance
NULL, // contention res idk
0,0);
memcpy(&dlsch_buffer[payload_offset],sdu3,sdu_len3);
printf("\nRRCConnectionReconfiguration (DLSCH input / MAC output)\n\n");
for (i=0; i<sdu_len3+payload_offset; i++)
printf("%02x ",(unsigned char)dlsch_buffer[i]);
printf("\n");
break;
default:
printf("Unknown eNB_RRC SDU (%d), exiting\n",args.RRCmessage);
break;
}
break;
}
break;
case eNB_MAC:
sdu_len0 = attach_ue0(sdu0);
ue_send_sdu(0,143,args.input1_sdu,args.input1_sdu_len,0);
break;
case UE_RRC:
switch (args.RRCmessage) {
case RRCConnectionRequest:
sdu_len0 = attach_ue0(sdu0);
printf("\n\nRRCConnectionRequest\n\n");
for (i=0; i<sdu_len0; i++)
printf("%02x ",(unsigned char)sdu0[i]);
printf("\n");
break;
case RRCConnectionSetupComplete:
sdu_len0=attach_ue0(sdu0);
sdu_len1 = attach_ue1(sdu1);
sdu_len2 = attach_ue2(sdu1,sdu_len1,sdu2);
lcid=1;
printf("Got sdu of length %d\n",sdu_len2);
payload_offset = generate_ulsch_header((u8*)ulsch_buffer, // mac header
1, // num sdus
0, // short pading
&sdu_len2, // sdu length
&lcid, // sdu lcid
NULL, // power headroom
NULL, // crnti
NULL, // truncated bsr
NULL, // short bsr
NULL, // long_bsr
0);
printf("Got MAC header of length %d\n",payload_offset);
memcpy(&ulsch_buffer[payload_offset],sdu2,sdu_len2);
printf("\n\nRRCConnectionSetupComplete (ULSCH input / MAC output)\n\n");
for (i=0; i<sdu_len2+payload_offset; i++)
printf("%02x ",(unsigned char)ulsch_buffer[i]);
printf("\n");
break;
case RRCConnectionReconfigurationComplete:
sdu_len0=attach_ue0(sdu0);
sdu_len1=attach_ue1(sdu1);
sdu_len2 = attach_ue2(sdu1,sdu_len1,sdu2);
sdu_len3 = attach_ue3(sdu2,sdu_len2,sdu3);
sdu_len4 = attach_ue4(sdu3,sdu_len3,sdu4);
lcid=1;
printf("Got sdu of length %d\n",sdu_len4);
payload_offset = generate_ulsch_header((u8*)ulsch_buffer, // mac header
1, // num sdus
0, // short pading
&sdu_len4, // sdu length
&lcid, // sdu lcid
NULL, // power headroom
NULL, // crnti
NULL, // truncated bsr
NULL, // short bsr
NULL, // long_bsr
0);
printf("Got MAC header of length %d\n",payload_offset);
memcpy(&ulsch_buffer[payload_offset],sdu4,sdu_len4);
printf("\n\nRRCConnectionReconfigurationComplete (ULSCH input / MAC output)\n\n");
for (i=0; i<sdu_len4+payload_offset; i++)
printf("%02x ",(unsigned char)ulsch_buffer[i]);
printf("\n");
break;
default:
printf("Unknown UE_RRC SDU (%d), exiting\n",args.RRCmessage);
break;
}
break;
}
free(mac_xface);
return(0);
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment