/*************************************************************************** nasrg_device.c - description *************************************************************************** Device Driver features for RG *************************************************************************** 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 - RG * \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 "nasrg_variables.h" #include "nasrg_proto.h" //:::::::::::::::::::::::::::::::::::::::;; //#include #include #include #include #include #ifdef NAS_DRIVER_TYPE_ETHERNET #include #endif #include #include #include #include #include #include #include #include #ifdef NAS_DRIVER_TYPE_ETHERNET #include #endif //:::::::::::::::::::::::::::::::::::::::;; /* Global variables */ struct net_device *gdev; struct nas_priv *gpriv; //int bytes_wrote; //int bytes_read; uint8_t NAS_RG_IMEI[14]={0x00, 0x00, 0x00, 0x00, 0x00 ,0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ,0x00, 0x00, 0x01}; uint8_t NAS_NULL_IMEI[14]={0x00, 0x00, 0x00, 0x00, 0x00 ,0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ,0x00, 0x00, 0x00}; uint16_t local_rg_cell_id; #ifdef NAS_NETLINK extern void nasrg_netlink_release(void); extern int nasrg_netlink_init(void); #endif extern void nasrg_ASCTL_timer(unsigned long data); #ifndef NAS_NETLINK //--------------------------------------------------------------------------- void *nasrg_interrupt(void){ //--------------------------------------------------------------------------- uint8_t cxi; #ifdef NAS_DEBUG_INTERRUPT printk("nasrg_interrupt - begin\n"); #endif //spin_lock(&gpriv->lock); for (cxi=0;cxicx+cxi); for (cxi=0;cxicx+cxi); //spin_unlock(&gpriv->lock); #ifdef NAS_DEBUG_INTERRUPT printk("nasrg_interrupt: end\n"); #endif // return 0; } #endif //NETLINK //--------------------------------------------------------------------------- // Called by ifconfig when the device is activated by ifconfig int nasrg_open(struct net_device *dev){ //--------------------------------------------------------------------------- printk("nasrg_open: begin\n"); gpriv=netdev_priv(dev); // Address has already been set at init #ifndef NAS_NETLINK if (gpriv->irq==-EBUSY){ printk("nasrg_open: irq failure\n"); return -EBUSY; } #endif //NETLINK 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=nasrg_ASCTL_timer; add_timer(&gpriv->timer); // printk("nasrg_open: name = %s, end\n", dev->name); return 0; } //--------------------------------------------------------------------------- // Called by ifconfig when the device is desactivated by ifconfig int nasrg_stop(struct net_device *dev){ //--------------------------------------------------------------------------- struct nas_priv *priv = netdev_priv(dev); printk("nasrg_stop: begin\n"); del_timer(&priv->timer); netif_stop_queue(dev); printk("nasrg_stop: name = %s, end\n", dev->name); return 0; } //--------------------------------------------------------------------------- void nasrg_teardown(struct net_device *dev){ //--------------------------------------------------------------------------- int cxi; #ifndef NAS_NETLINK struct nas_priv *priv = netdev_priv(dev); #endif //NAS_NETLINK printk("nasrg_teardown: begin\n"); if (dev) { #ifndef NAS_NETLINK if (priv->irq!=-EBUSY){ *pt_nas_rg_irq=-1; rt_free_srq(priv->irq); } #endif //NAS_NETLINK #ifdef NAS_NETLINK nasrg_netlink_release(); #endif //NAS_NETLINK // for (sapi=0; sapisap[sapi]); nasrg_CLASS_flush_rclassifier(); nasrg_CLASS_flush_mbmsclassifier(); for (cxi=0;cxicx+cxi); nasrg_CLASS_flush_sclassifier(gpriv->cx+cxi); //for (sapi=0; sapicx[cxi].sap[sapi]); } } // check dev else { printk("nasmt_teardown: Device is null\n"); } printk("nasrg_teardown: end\n"); } //--------------------------------------------------------------------------- int nasrg_set_config(struct net_device *dev, struct ifmap *map){ //--------------------------------------------------------------------------- printk("nasrg_set_config: begin\n"); if (dev->flags & IFF_UP) return -EBUSY; if (map->base_addr != dev->base_addr) { printk(KERN_WARNING "nasrg_set_config: Can't change I/O address\n"); return -EOPNOTSUPP; } if (map->irq != dev->irq) dev->irq = map->irq; return 0; } //--------------------------------------------------------------------------- int nasrg_hard_start_xmit(struct sk_buff *skb, struct net_device *dev){ //--------------------------------------------------------------------------- // Start debug information #ifdef NAS_DEBUG_DEVICE printk("nasrg_hard_start_xmit: begin\n"); #endif if ((!skb )||(!dev)){ printk("nasrg_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("nasrg_hard_start_xmit: step 1\n"); #endif nasrg_CLASS_send(skb); #ifdef NAS_DEBUG_SEND_DETAIL printk("nasrg_hard_start_xmit: step 2\n"); #endif dev_kfree_skb(skb); #ifdef NAS_DEBUG_SEND_DETAIL printk("nasrg_hard_start_xmit: step 3\n"); #endif netif_wake_queue(dev); #ifdef NAS_DEBUG_DEVICE printk("nasrg_hard_start_xmit: end\n"); #endif return 0; } //--------------------------------------------------------------------------- struct net_device_stats *nasrg_get_stats(struct net_device *dev){ //--------------------------------------------------------------------------- struct nas_priv *npriv = netdev_priv(dev); return &npriv->stats; } //--------------------------------------------------------------------------- // New function from LITE DRIVER int nasrg_set_mac_address(struct net_device *dev, void *mac) { //--------------------------------------------------------------------------- struct sockaddr *addr = mac; printk("nasrg_set_mac_address: begin\n"); memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); return 0; } //--------------------------------------------------------------------------- int nasrg_change_mtu(struct net_device *dev, int mtu){ //--------------------------------------------------------------------------- printk("nasrg_change_mtu: begin\n"); if ((mtu<50) || (mtu>1500)) // if ((mtu<1280) || (mtu>1500)) return -EINVAL; dev->mtu = mtu; return 0; } //--------------------------------------------------------------------------- int nasrg_change_rx_flags(struct net_device *dev, int flags){ //--------------------------------------------------------------------------- //struct nas_priv *priv = netdev_priv(dev); printk("nasrg_change_rx_flags %08X\n", flags); gpriv->rx_flags ^= flags; return 0; } //--------------------------------------------------------------------------- void nasrg_tx_timeout(struct net_device *dev){ //--------------------------------------------------------------------------- /* Transmitter timeout, serious problems. */ printk("nasrg_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("nasrg_tx_timeout: transmit timed out %s\n",dev->name); } //--------------------------------------------------------------------------- // Define pointers for the module static const struct net_device_ops nasrg_netdev_ops = { // ?? nasrg_ interrupt // .ndo_open = nasrg_open, .ndo_stop = nasrg_stop, .ndo_start_xmit = nasrg_hard_start_xmit, .ndo_validate_addr = NULL, .ndo_get_stats = nasrg_get_stats, //#ifdef KERNEL_VERSION_GREATER_THAN_32 // .ndo_set_multicast_list = NULL, .ndo_set_mac_address = nasrg_set_mac_address, .ndo_set_config = nasrg_set_config, .ndo_do_ioctl = nasrg_CTL_ioctl, .ndo_change_mtu = nasrg_change_mtu, .ndo_tx_timeout = nasrg_tx_timeout, .ndo_change_rx_flags = nasrg_change_rx_flags, //#endif }; //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- // Initialisation of the network device void nasrg_init(struct net_device *dev){ //--------------------------------------------------------------------------- uint8_t cxi, dscpi; printk("nasrg_init: begin\n"); if (dev){ gpriv=netdev_priv(dev); memset(gpriv, 0, sizeof(struct nas_priv)); // Initialize function pointers dev->netdev_ops = &nasrg_netdev_ops; #ifndef NAS_DRIVER_TYPE_ETHERNET 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("\nnasrg_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->cx[1].sap[NAS_DC_INPUT_SAPI] = RRC_DEVICE_DC_INPUT1; gpriv->cx[1].sap[NAS_DC_OUTPUT_SAPI] = RRC_DEVICE_DC_OUTPUT1; // 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; dscpirclassifier[dscpi]=NULL; gpriv->nrclassifier=0; // for(cxi=0; cxicx[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 classifier for (dscpi=0; dscpicx[cxi].sclassifier[dscpi]=NULL; gpriv->cx[cxi].nsclassifier=0; // initialisation of the IP address nasrg_TOOL_imei2iid(NAS_NULL_IMEI, (uint8_t *)gpriv->cx[cxi].iid6); gpriv->cx[cxi].iid4=0; } spin_lock_init(&gpriv->lock); nasrg_TOOL_RGimei2iid(NAS_RG_IMEI, dev->dev_addr);// IMEI to device address (for stateless autoconfiguration address) printk("nasrg_init: init IMEI to IID\n"); nasrg_ASCTL_init(); }else{ printk("\n\nnasmt_init: ERROR, Device is NULL!!\n"); } printk("nasrg_init: end\n"); return ; } //--------------------------------------------------------------------------- int init_module (void) { //--------------------------------------------------------------------------- int err; int inst = 0; struct nas_priv *priv; char devicename[100]; printk("\n\n\n\nnasrg_init_module: begin \n"); // Initialize parameters shared with RRC #ifndef NAS_NETLINK if (pt_nas_rg_irq==NULL){ printk("nasrg_init_module: shared irq parameter not initialised\n"); err = -EBUSY; printk("nasrg_init_module: returning %d \n\n", err); return err; } printk("nasrg_init_module: pt_nas_rg_irq valid \n"); #endif /* if (pt_rg_own_cell_id==NULL){ printk("nasrg_init_module: shared cell_id parameter not initialised\n"); err = -EBUSY; printk("nasrg_init_module: returning %d \n\n\n", err); return err; } printk("nasrg_init_module: pt_rg_own_cell_id valid \n"); *pt_rg_own_cell_id = NASRG_OWN_CELLID; */ local_rg_cell_id = NASRG_OWN_CELLID; // 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, nasrg_init); #else gdev = alloc_netdev(sizeof(struct nas_priv), devicename, NET_NAME_PREDICTABLE, nasrg_init); #endif printk("nasrg_init_module: after alloc_netdev \n"); priv = netdev_priv(gdev); //// // #ifndef NAS_NETLINK priv->irq=rt_request_srq(0, nasrg_interrupt, NULL); if (priv->irq == -EBUSY || priv->irq == -EINVAL){ printk("nasrg_init_module: No interrupt resource available\n"); if (gdev){ free_netdev(gdev); printk("nasrg_init_module: free_netdev ..\n"); } return -EBUSY; }else printk("nasrg_init_module: Interrupt %d, ret = %d \n", priv->irq , ret); if (pt_nas_rg_irq==NULL){ printk("nasmt_init_module: shared irq parameter has been reset\n"); }else{ *pt_nas_rg_irq=priv->irq; } #endif // ////// #ifdef NAS_NETLINK if ((err=nasrg_netlink_init()) < 0) printk("nasrg_init_module: NETLINK failed\n"); printk("nasrg_init_module: NETLINK INIT successful\n"); #endif //NETLINK err= register_netdev(gdev); if (err){ printk("nasrg_init_module: error %i registering device %s\n", err, gdev->name); }else{ printk("nasrg_init_module: registering device %s, ifindex = %d\n\n",gdev->name, gdev->ifindex); } return err; } //--------------------------------------------------------------------------- void cleanup_module(void){ //--------------------------------------------------------------------------- printk("nasrg_cleanup_module: begin\n"); unregister_netdev(gdev); nasrg_teardown(gdev); free_netdev(gdev); printk("nasrg_cleanup_module: end\n\n\n\n"); } //--------------------------------------------------------------------------- // Replaced by init_module and cleanup_module //module_init (nasrg_init_module); //module_exit (nasrg_cleanup_module); //--------------------------------------------------------------------------- #define DRV_NAME "oai_nasrg" #define DRV_VERSION "3.0.1"DRV_NAME #define DRV_DESCRIPTION "OPENAIR CELLULAR LTE NASRG (eNodeB) Device Driver" #define DRV_COPYRIGHT "-Copyright(c) GNU GPL Eurecom 2013" #define DRV_AUTHOR "Michelle Wetterwald "DRV_COPYRIGHT // MODULE_LICENSE("GPL"); // MODULE_DESCRIPTION("LTE Driver for eNodeB, playing as Non Access Stratum"); // MODULE_AUTHOR("Michelle Wetterwald ");