Files
openairinterface5g/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_device.c
T
2014-11-21 15:06:30 +00:00

527 lines
17 KiB
C
Executable File

/***************************************************************************
nasmt_device.c - description
***************************************************************************
Device Driver features for MT
***************************************************************************
Eurecom OpenAirInterface 2
Copyright(c) 1999 - 2013 Eurecom
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
version 2, as published by the Free Software Foundation.
This program is distributed in the hope it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
The full GNU General Public License is included in this distribution in
the file called "COPYING".
Contact Information
Openair Admin: openair_admin@eurecom.fr
Openair Tech : openair_tech@eurecom.fr
Forums : http://forums.eurecom.fsr/openairinterface
Address : Eurecom, 450 route des Chappes, 06410 Biot Sophia Antipolis, France
*******************************************************************************/
/*! \file nasmt_device.c
* \brief Networking Device Driver for OpenAirInterface CELLULAR version - MT
* \author michelle.wetterwald, navid.nikaein, raymond.knopp, Lionel Gauthier
* \company Eurecom
* \email: michelle.wetterwald@eurecom.fr, raymond.knopp@eurecom.fr, navid.nikaein@eurecom.fr, lionel.gauthier@eurecom.fr
*/
/*******************************************************************************/
#ifndef NAS_NETLINK
#ifdef RTAI
#include "rtai_posix.h"
#define RTAI_IRQ 30 //try to get this irq with RTAI
#endif // RTAI
#endif // NAS_NETLINK
//:::::::::::::::::::::::::::::::::::::::;;
#include "nasmt_variables.h"
#include "nasmt_proto.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 NAS_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 NAS_DRIVER_TYPE_ETHERNET
#include <linux/etherdevice.h>
#endif
//:::::::::::::::::::::::::::::::::::::::;;
struct net_device *gdev;
struct nas_priv *gpriv;
//int bytes_wrote;
//int bytes_read;
uint8_t NAS_NULL_IMEI[14]={0x00, 0x00, 0x00, 0x00, 0x00 ,0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ,0x00, 0x00, 0x00};
uint8_t NAS_RG_IMEI[14]={0x00, 0x00, 0x00, 0x00, 0x00 ,0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ,0x00, 0x00, 0x01};
// TEMP
//uint8_t nas_IMEI[14];
static unsigned char nas_IMEI[14];
static int m_arg=0;
#ifdef NAS_NETLINK
extern void nasmt_netlink_release(void);
extern int nasmt_netlink_init(void);
#endif
extern void nasmt_ASCTL_timer(unsigned long data);
#ifndef NAS_NETLINK
//---------------------------------------------------------------------------
//void nasmt_interrupt(void){
void *nasmt_interrupt(void){
//---------------------------------------------------------------------------
uint8_t cxi;
char *buffer = NULL;
#ifdef NAS_DEBUG_INTERRUPT
printk("nasmt_interrupt - begin\n");
#endif
//spin_lock(&gpriv->lock);
cxi=0;
nasmt_COMMON_QOS_receive(gpriv->cx+cxi);
nasmt_ASCTL_GC_receive(buffer);
nasmt_ASCTL_DC_receive(gpriv->cx+cxi, buffer);
//spin_unlock(&gpriv->lock);
#ifdef NAS_DEBUG_INTERRUPT
printk("nasmt_interrupt: end\n");
#endif
}
#endif //NETLINK
//---------------------------------------------------------------------------
// Called by ifconfig when the device is activated by ifconfig
int nasmt_open(struct net_device *dev){
//---------------------------------------------------------------------------
printk("nasmt_open: begin\n");
gpriv=netdev_priv(dev);
// Address has already been set at init
#ifndef NAS_NETLINK
if (gpriv->irq==-EBUSY){
printk("nasmt_open: irq failure\n");
return -EBUSY;
}
#endif //NETLINK
// next lines prevent compilation of the driver with kernel version under 2.6.29
// ATTENTION !!!!!! NASMT is not usable with these versions
if(!netif_queue_stopped(dev))
netif_start_queue(dev);
else
netif_wake_queue(dev);
//
init_timer(&gpriv->timer);
(gpriv->timer).expires=jiffies+NAS_TIMER_TICK;
(gpriv->timer).data=0L;
(gpriv->timer).function=nasmt_ASCTL_timer;
// ??LITE comments: add_timer(&gpriv->timer);
add_timer(&gpriv->timer);
//
printk("nasmt_open: name = %s, end\n", dev->name);
return 0;
}
//---------------------------------------------------------------------------
// Called by ifconfig when the device is desactivated by ifconfig
int nasmt_stop(struct net_device *dev){
//---------------------------------------------------------------------------
struct nas_priv *priv = netdev_priv(dev);
printk("nasmt_stop: begin\n");
del_timer(&priv->timer);
netif_stop_queue(dev);
printk("nasmt_stop: name = %s, end\n", dev->name);
return 0;
}
//---------------------------------------------------------------------------
void nasmt_teardown(struct net_device *dev){
//---------------------------------------------------------------------------
int cxi;
#ifndef NAS_NETLINK
struct nas_priv *priv = netdev_priv(dev);
#endif //NAS_NETLINK
printk("nasmt_teardown: begin\n");
// priv=(struct nas_priv *)(gdev.priv);
if (dev) {
#ifndef NAS_NETLINK
if (priv->irq!=-EBUSY){
*pt_nas_ue_irq=-1;
rt_free_srq(priv->irq);
}
#endif //NAS_NETLINK
#ifdef NAS_NETLINK
nasmt_netlink_release();
#endif //NAS_NETLINK
// for (sapi=0; sapi<NAS_SAPI_MAX; ++sapi)
// close(priv->sap[sapi]);
nasmt_CLASS_flush_rclassifier();
cxi=0;
nasmt_COMMON_flush_rb(gpriv->cx+cxi);
nasmt_CLASS_flush_sclassifier(gpriv->cx+cxi);
// for (sapi=0; sapi<NAS_SAPI_CX_MAX; ++sapi)
// close(priv->cx[cxi].sap[sapi]);
} // check dev
else {
printk("nasmt_teardown: Device is null\n");
}
printk("nasmt_teardown: end\n");
}
//---------------------------------------------------------------------------
int nasmt_set_config(struct net_device *dev, struct ifmap *map){
//---------------------------------------------------------------------------
printk("nasmt_set_config: begin\n");
if (dev->flags & IFF_UP)
return -EBUSY;
if (map->base_addr != dev->base_addr)
{
printk(KERN_WARNING "nasmt_set_config: Can't change I/O address\n");
return -EOPNOTSUPP;
}
if (map->irq != dev->irq)
dev->irq = map->irq;
printk("nasmt_set_config: end\n");
return 0;
}
//---------------------------------------------------------------------------
//
int nasmt_hard_start_xmit(struct sk_buff *skb, struct net_device *dev){
//---------------------------------------------------------------------------
// Start debug information
#ifdef NAS_DEBUG_DEVICE
printk("nasmt_hard_start_xmit: begin\n");
#endif
if ((!skb)||(!dev)){
printk("nasmt_hard_start_xmit - input parameter skb or dev is NULL \n");
return -1;
}
// End debug information
netif_stop_queue(dev);
dev->trans_start = jiffies;
#ifdef NAS_DEBUG_SEND_DETAIL
printk("nasmt_hard_start_xmit: step 1\n");
#endif
nasmt_CLASS_send(skb);
#ifdef NAS_DEBUG_SEND_DETAIL
printk("nasmt_hard_start_xmit: step 2\n");
#endif
dev_kfree_skb(skb);
#ifdef NAS_DEBUG_SEND_DETAIL
printk("nasmt_hard_start_xmit: step 3\n");
#endif
netif_wake_queue(dev);
#ifdef NAS_DEBUG_DEVICE
printk("nasmt_hard_start_xmit: end\n");
#endif
return 0;
}
//---------------------------------------------------------------------------
struct net_device_stats *nasmt_get_stats(struct net_device *dev){
//---------------------------------------------------------------------------
// return &((struct nas_priv *)dev->priv)->stats;
struct nas_priv *npriv = netdev_priv(dev);
return &npriv->stats;
}
//---------------------------------------------------------------------------
// New function from LITE DRIVER
int nasmt_set_mac_address(struct net_device *dev, void *mac) {
//---------------------------------------------------------------------------
struct sockaddr *addr = mac;
printk("nasmt_set_mac_address: begin\n");
memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
return 0;
}
//---------------------------------------------------------------------------
int nasmt_change_mtu(struct net_device *dev, int mtu){
//---------------------------------------------------------------------------
printk("nasmt_change_mtu: begin\n");
if ((mtu<50) || (mtu>1500))
// if ((mtu<1280) || (mtu>1500))
return -EINVAL;
dev->mtu = mtu;
return 0;
}
//---------------------------------------------------------------------------
int nasmt_change_rx_flags(struct net_device *dev, int flags){
//---------------------------------------------------------------------------
//struct nas_priv *priv = netdev_priv(dev);
printk("nasmt_change_rx_flags %08X\n", flags);
gpriv->rx_flags ^= flags;
return 0;
}
//---------------------------------------------------------------------------
void nasmt_tx_timeout(struct net_device *dev){
//---------------------------------------------------------------------------
/* Transmitter timeout, serious problems. */
printk("nasmt_tx_timeout: begin\n");
//((struct nas_priv *)(dev->priv))->stats.tx_errors++;
(gpriv->stats).tx_errors++;
dev->trans_start = jiffies;
netif_wake_queue(dev);
printk("nasmt_tx_timeout: transmit timed out %s\n",dev->name);
}
//---------------------------------------------------------------------------
// Define pointers for the module
static const struct net_device_ops nasmt_netdev_ops = {
// ?? nasmt_interrupt
//
.ndo_open = nasmt_open,
.ndo_stop = nasmt_stop,
.ndo_start_xmit = nasmt_hard_start_xmit,
.ndo_validate_addr = NULL,
.ndo_get_stats = nasmt_get_stats,
//#ifdef KERNEL_VERSION_GREATER_THAN_32
// .ndo_set_multicast_list = NULL,
.ndo_set_mac_address = nasmt_set_mac_address,
.ndo_set_config = nasmt_set_config,
.ndo_do_ioctl = nasmt_CTL_ioctl,
.ndo_change_mtu = nasmt_change_mtu,
.ndo_tx_timeout = nasmt_tx_timeout,
.ndo_change_rx_flags = nasmt_change_rx_flags,
//#endif
};
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// Initialisation of the network device
void nasmt_init(struct net_device *dev){
//---------------------------------------------------------------------------
uint8_t cxi, dscpi;
printk("nasmt_init: begin\n");
if (dev){
gpriv=netdev_priv(dev);
memset(gpriv, 0, sizeof(struct nas_priv));
// Initialize function pointers
dev->netdev_ops = &nasmt_netdev_ops;
#ifndef NAS_DRIVER_TYPE_ETHERNET
// Update driver properties
dev->type = ARPHRD_EURUMTS;
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;
#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);
#ifdef NAS_DRIVER_TYPE_ETHERNET
// overwrite values written above ( header_ops,type,hard_header_len,mtu,addr_len,tx_queue_len,flags,broadcast)
printk("\nnasmt_init: WARNING Driver type ETHERNET\n");
ether_setup(dev);
#endif
//
// Initialize private structure
gpriv->rx_flags = NAS_RESET_RX_FLAGS;
gpriv->sap[NAS_GC_SAPI] = RRC_DEVICE_GC;
gpriv->sap[NAS_NT_SAPI] = RRC_DEVICE_NT;
gpriv->cx[0].sap[NAS_DC_INPUT_SAPI] = RRC_DEVICE_DC_INPUT0;
gpriv->cx[0].sap[NAS_DC_OUTPUT_SAPI] = RRC_DEVICE_DC_OUTPUT0;
//gpriv->sap[NAS_CO_INPUT_SAPI] = QOS_DEVICE_CONVERSATIONAL_INPUT;
//gpriv->sap[NAS_CO_OUTPUT_SAPI] = QOS_DEVICE_CONVERSATIONAL_OUTPUT;
gpriv->sap[NAS_DRB_INPUT_SAPI] = PDCP2NAS_FIFO;//QOS_DEVICE_CONVERSATIONAL_INPUT;
gpriv->sap[NAS_DRB_OUTPUT_SAPI] = NAS2PDCP_FIFO;//QOS_DEVICE_STREAMING_INPUT;
gpriv->retry_limit = NAS_RETRY_LIMIT_DEFAULT;
gpriv->timer_establishment = NAS_TIMER_ESTABLISHMENT_DEFAULT;
gpriv->timer_release = NAS_TIMER_RELEASE_DEFAULT;
for (dscpi=0; dscpi<NAS_DSCP_MAX; ++dscpi)
gpriv->rclassifier[dscpi] = NULL;
gpriv->nrclassifier = 0;
//
cxi=0;
#ifdef NAS_DEBUG_DEVICE
printk("nasmt_init: init classifiers, state and timer for MT %u\n", cxi);
#endif
gpriv->cx[cxi].state = NAS_IDLE;
gpriv->cx[cxi].countimer = NAS_TIMER_IDLE;
gpriv->cx[cxi].retry = 0;
gpriv->cx[cxi].lcr = cxi;
gpriv->cx[cxi].rb = NULL;
gpriv->cx[cxi].num_rb = 0;
// initialisation of the classifiers
for (dscpi=0; dscpi<NAS_DSCP_MAX; ++dscpi){
gpriv->cx[cxi].sclassifier[dscpi]=NULL;
}
gpriv->cx[cxi].nsclassifier=0;
// initialisation of the IP address
nasmt_TOOL_imei2iid(NAS_NULL_IMEI, (uint8_t *)gpriv->cx[cxi].iid6);
gpriv->cx[cxi].iid4=0;
//
spin_lock_init(&gpriv->lock);
printk("nasmt_init: init IMEI to IID\n");
#ifdef NAS_DRIVER_TYPE_ETHERNET
nasmt_TOOL_eth_imei2iid(nas_IMEI, dev->dev_addr ,(uint8_t *)gpriv->cx[0].iid6, dev->addr_len);
#else
nasmt_TOOL_imei2iid(nas_IMEI, dev->dev_addr);// IMEI to device address (for stateless autoconfiguration address)
nasmt_TOOL_imei2iid(nas_IMEI, (uint8_t *)gpriv->cx[0].iid6);
#endif
nasmt_ASCTL_init();
} else {
printk("\n\nnasmt_init: ERROR, Device is NULL!!\n");
}
printk("nasmt_init: end\n");
return;
}
//---------------------------------------------------------------------------
int init_module (void) {
//---------------------------------------------------------------------------
int err;
int inst = 0;
int index;
struct nas_priv *priv;
char devicename[100];
printk("\n\n\ninit_module: begin \n");
// check IMEI parameter
printk("number of IMEI parameters %d, IMEI ", m_arg);
for (index = 0; index < m_arg; index++) {
printk("%02X ", nas_IMEI[index]);
}
printk("\n");
#ifndef NAS_NETLINK
// Initialize parameters shared with RRC (done first to avoid going further)
if (pt_nas_ue_irq==NULL){
printk("init_module: shared irq parameter not initialised\n");
err = -EBUSY;
printk("init_module: returning %d \n\n", err);
return err;
}
printk("init_module: pt_nas_ue_irq valid \n");
#endif
// Allocate device structure
sprintf(devicename,"oai%d",inst);
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0)
gdev = alloc_netdev(sizeof(struct nas_priv), devicename, nasmt_init);
#else
gdev = alloc_netdev(sizeof(struct nas_priv), devicename, NET_NAME_PREDICTABLE, nasmt_init);
#endif
priv = netdev_priv(gdev);
////
#ifndef NAS_NETLINK
priv->irq=rt_request_srq(0, nasmt_interrupt, NULL);
if (priv->irq == -EBUSY || priv->irq == -EINVAL){
printk("\n init_module: No interrupt resource available\n");
if (gdev){
free_netdev(gdev);
printk("init_module: free_netdev ..\n");
}
return -EBUSY;
}
else
printk("init_module: Interrupt %d, ret = %d \n", priv->irq , ret);
if (pt_nas_ue_irq==NULL){
printk("init_module: shared irq parameter has been reset\n");
}else{
*pt_nas_ue_irq=priv->irq;
}
#endif
#ifdef NAS_NETLINK
if ((err=nasmt_netlink_init()) == -1)
printk("init_module: NETLINK failed\n");
printk("init_module: NETLINK INIT successful\n");
#endif //NETLINK
//
err= register_netdev(gdev);
if (err){
printk("init_module: error %i registering device %s\n", err, gdev->name);
}else{
printk("init_module: registering device %s, ifindex = %d\n\n",gdev->name, gdev->ifindex);
}
return err;
}
//---------------------------------------------------------------------------
void cleanup_module(void){
//---------------------------------------------------------------------------
printk("nasmt_cleanup_module: begin\n");
unregister_netdev(gdev);
nasmt_teardown(gdev);
free_netdev(gdev);
printk("nasmt_cleanup_module: end\n\n\n\n");
}
//---------------------------------------------------------------------------
// Replaced by init_module and cleanup_module
//module_init (nasmt_init_module);
//module_exit (nasmt_cleanup_module);
//---------------------------------------------------------------------------
#define DRV_NAME "oai_nasmt"
#define DRV_VERSION "3.0.1"DRV_NAME
#define DRV_DESCRIPTION "OPENAIR CELLULAR LTE NASMT Device Driver"
#define DRV_COPYRIGHT "-Copyright(c) GNU GPL Eurecom 2013"
#define DRV_AUTHOR "Michelle Wetterwald <michelle.wetterwald@eurecom.fr>"DRV_COPYRIGHT
module_param_array_named(nas_IMEI,nas_IMEI,byte,&m_arg,0);
//module_param_array(oai_nw_drv_IMEI,byte,&m_arg,0444);
MODULE_PARM_DESC(nas_IMEI,"Terminal IMEI Identifier (14 digits, only first 10 significant if ETH option ON)");
// MODULE_LICENSE("GPL");
// MODULE_DESCRIPTION("LTE Driver for Mobile Terminal, playing as Non Access Stratum");
// MODULE_AUTHOR("Michelle Wetterwald <michelle.wetterwald@eurecom.fr>");