device.c 20.5 KB
Newer Older
1 2 3 4 5
/*
 * 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
6
 * the OAI Public License, Version 1.1  (the "License"); you may not use this file
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
 * 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
 */

22 23
/*! \file device.c
* \brief Networking Device Driver for OpenAirInterface Ethernet
24
* \author  navid.nikaein,  Lionel Gauthier, raymond.knopp,
25
* \company Eurecom
26
* \email:navid.nikaein@eurecom.fr, lionel.gauthier@eurecom.fr,  raymond.knopp@eurecom.fr
27 28 29 30 31 32 33 34 35 36

*/
/*******************************************************************************/

#include "constant.h"
#include "local.h"
#include "proto_extern.h"

//#include <linux/module.h>
#include <linux/kernel.h>
37
#include <linux/version.h>
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
#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

64
uint8_t NULL_IMEI[14]= {0x05, 0x04, 0x03, 0x01, 0x02 ,0x00, 0x00, 0x00, 0x05, 0x04, 0x03 ,0x00, 0x01, 0x08};
65 66 67 68 69

static unsigned char oai_nw_drv_IMEI[14];
static int           m_arg=0;
static unsigned int  oai_nw_drv_is_clusterhead=0;
//---------------------------------------------------------------------------
70 71 72
int oai_nw_drv_find_inst(struct net_device *dev)
{
  //---------------------------------------------------------------------------
73 74
  int i;

75
  for (i=0; i<OAI_NW_DRV_NB_INSTANCES_MAX; i++)
76 77
    if (oai_nw_drv_dev[i] == dev)
      return(i);
78

79 80 81 82 83 84
  return(-1);
}

//---------------------------------------------------------------------------

#ifndef OAI_NW_DRIVER_USE_NETLINK
85 86
void *oai_nw_drv_interrupt(void)
{
87
  //---------------------------------------------------------------------------
88
  uint8_t cxi;
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111

  //  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
//---------------------------------------------------------------------------
112 113
void oai_nw_drv_timer(unsigned long data)
{
114 115 116 117 118 119 120 121 122
  //---------------------------------------------------------------------------
  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;
123 124
  //  add_timer(&gpriv->timer);
  //  spin_unlock(&gpriv->lock);
125 126 127 128
}

//---------------------------------------------------------------------------
// Called by ifconfig when the device is activated by ifconfig
129 130
int oai_nw_drv_open(struct net_device *dev)
{
131 132 133 134 135
  //---------------------------------------------------------------------------
  struct oai_nw_drv_priv *priv=netdev_priv(dev);

  // Address has already been set at init
#ifndef OAI_NW_DRIVER_USE_NETLINK
136 137 138 139

  if (pdcp_2_oai_nw_drv_irq==-EBUSY) {
    printk("[OAI_IP_DRV][%s] : irq failure\n", __FUNCTION__);
    return -EBUSY;
140
  }
141

142 143 144
#endif //OAI_NW_DRIVER_USE_NETLINK

  if(!netif_queue_stopped(dev))
145
    netif_start_queue(dev);
146
  else
147
    netif_wake_queue(dev);
148 149 150 151 152 153 154 155 156 157 158 159 160

  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
161 162
int oai_nw_drv_stop(struct net_device *dev)
{
163 164 165 166 167 168 169 170 171 172 173 174
  //---------------------------------------------------------------------------
  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;
}

//---------------------------------------------------------------------------
175 176
void oai_nw_drv_teardown(struct net_device *dev)
{
177 178 179 180 181
  //---------------------------------------------------------------------------
  struct oai_nw_drv_priv *priv;
  int              inst;

  printk("[OAI_IP_DRV][%s] Begin\n", __FUNCTION__);
182

183
  if (dev) {
184 185
    priv = netdev_priv(dev);
    inst = oai_nw_drv_find_inst(dev);
186

187 188 189 190 191 192 193 194 195 196 197 198
    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__);
199 200
  } // check dev
  else {
201
    printk("[OAI_IP_DRV][%s] Device is null\n", __FUNCTION__);
202 203 204
  }
}
//---------------------------------------------------------------------------
205 206
int oai_nw_drv_set_config(struct net_device *dev, struct ifmap *map)
{
207 208
  //---------------------------------------------------------------------------
  printk("[OAI_IP_DRV][%s] Begin\n", __FUNCTION__);
209

210
  if (dev->flags & IFF_UP)
211 212
    return -EBUSY;

213
  if (map->base_addr != dev->base_addr) {
214 215
    printk(KERN_WARNING "[OAI_IP_DRV][%s] Can't change I/O address\n", __FUNCTION__);
    return -EOPNOTSUPP;
216
  }
217

218
  if (map->irq != dev->irq)
219 220
    dev->irq = map->irq;

221 222 223 224 225 226
  printk("[OAI_IP_DRV][%s] End\n", __FUNCTION__);
  return 0;
}

//---------------------------------------------------------------------------
//
227 228
int oai_nw_drv_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
229 230 231 232 233 234 235 236 237 238 239
  //---------------------------------------------------------------------------
  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)) {
240 241 242
#ifdef OAI_DRV_OAI_DRV_DEBUG_DEVICE
    printk("[OAI_IP_DRV][%s] inst %d,  begin\n", __FUNCTION__,inst);
#endif
243

244 245 246 247 248 249 250
    if (!skb) {
      printk("[OAI_IP_DRV][%s] input parameter skb is NULL\n", __FUNCTION__);
      return -1;
    }

    // End debug information
    netif_stop_queue(dev);
251 252 253
#if  LINUX_VERSION_CODE >= KERNEL_VERSION(4,7,0)
    netif_trans_update(dev);
#else
254
    dev->trans_start = jiffies;
255
#endif
256 257 258 259 260 261 262 263 264 265 266 267 268 269 270
#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
271
  } else {
272 273
    printk("[OAI_IP_DRV][%s] ERROR, couldn't find instance\n", __FUNCTION__);
    return(-1);
274
  }
275

276 277 278 279
  return 0;
}

//---------------------------------------------------------------------------
280 281 282
struct net_device_stats *oai_nw_drv_get_stats(struct net_device *dev)
{
  //---------------------------------------------------------------------------
283 284 285 286 287 288
  //    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;
}
//---------------------------------------------------------------------------
289 290 291
int oai_nw_drv_set_mac_address(struct net_device *dev, void *mac)
{
  //---------------------------------------------------------------------------
292 293 294 295 296 297
  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;
}
//---------------------------------------------------------------------------
298 299
int oai_nw_drv_change_mtu(struct net_device *dev, int mtu)
{
300 301
  //---------------------------------------------------------------------------
  printk("[OAI_IP_DRV][%s] CHANGE MTU %d bytes\n", __FUNCTION__, mtu);
302

303
  if ((mtu<50) || (mtu>1500))
304 305
    return -EINVAL;

306 307 308 309
  dev->mtu = mtu;
  return 0;
}
//---------------------------------------------------------------------------
310 311
void oai_nw_drv_change_rx_flags(struct net_device *dev, int flags)
{
312 313 314 315 316 317 318
  //---------------------------------------------------------------------------
  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;
}

//---------------------------------------------------------------------------
319 320 321
#if  LINUX_VERSION_CODE >= KERNEL_VERSION(5,6,0)
void oai_nw_drv_tx_timeout(struct net_device *dev, unsigned int txqueue)
#else
322
void oai_nw_drv_tx_timeout(struct net_device *dev)
323
#endif
324
{
325 326 327 328 329 330 331
  //---------------------------------------------------------------------------
  // 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++;
332 333 334
#if  LINUX_VERSION_CODE >= KERNEL_VERSION(4,7,0)
  netif_trans_update(dev);
#else
335
  dev->trans_start = jiffies;
336
#endif
337 338 339 340 341
  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 = {
342 343 344 345 346 347 348 349 350 351 352
  .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,
353
};
354
/*.ndo_set_multicast_list = NULL,*/
355 356 357

//---------------------------------------------------------------------------
// Initialisation of the network device
358 359
void oai_nw_drv_init(struct net_device *dev)
{
360
  //---------------------------------------------------------------------------
361
  uint8_t               cxi;
362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392
  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;
393
#ifdef OAI_NW_DRIVER_TYPE_ETHERNET
394 395 396 397 398 399 400 401 402 403 404 405
    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;
406
    //344
407 408 409
    //345         memset(dev->broadcast, 0xFF, ETH_ALEN);
    //346 }
    ether_setup(dev);
410
#endif
411 412 413 414 415 416 417 418 419 420
    //
    // 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;

421
    /*for (dscpi=0; dscpi<OAI_NW_DRV_DSCP_MAX; ++dscpi) {
422 423
        priv->rclassifier[dscpi]=NULL;
    }
424
    priv->nrclassifier=0;*/
425
    //
426
    for (cxi=0; cxi<OAI_NW_DRV_CX_MAX; cxi++) {
427
#ifdef OAI_DRV_DEBUG_DEVICE
428
      printk("[OAI_IP_DRV][%s] init classifiers, state and timer for MT %u\n", __FUNCTION__, cxi);
429 430
#endif

431 432 433 434 435 436 437 438 439 440 441 442 443
      //    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;
      }
444

445 446 447 448 449 450 451
      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;
      //
452
    }
453

454
    spin_lock_init(&priv->lock);
455
    //this requires kernel patch for OAI driver: typically for RF/hard realtime emu experimentation
456 457 458
#define ADDRCONF
#ifdef ADDRCONF

459
#ifdef OAI_NW_DRIVER_USE_NETLINK
460 461
    oai_nw_drv_TOOL_eNB_imei2iid(oai_nw_drv_IMEI, dev->dev_addr, dev->addr_len);// IMEI to device address (for stateless autoconfiguration address)

462
    oai_nw_drv_TOOL_eNB_imei2iid(oai_nw_drv_IMEI, (uint8_t *)priv->cx[0].iid6, dev->addr_len);
463
#else
464
    oai_nw_drv_TOOL_imei2iid(oai_nw_drv_IMEI, dev->dev_addr);// IMEI to device address (for stateless autoconfiguration address)
465
    oai_nw_drv_TOOL_imei2iid(oai_nw_drv_IMEI, (uint8_t *)priv->cx[0].iid6);
466 467
#endif
    // this is more appropriate for user space soft realtime emulation
468
#else
469 470

    // LG: strange
471
    for (index = 0; index < dev->addr_len;  index++) {
472
      dev->dev_addr[index] = 16*oai_nw_drv_IMEI[index]+oai_nw_drv_IMEI[index+1]);
473
    }
474

475
    memcpy((uint8_t *)priv->cx[0].iid6,&oai_nw_drv_IMEI[0],dev->addr_len);
476 477 478 479

    printk("INIT: init IMEI to IID\n");
#endif
    printk("[OAI_IP_DRV][%s] Setting HW addr to : ", __FUNCTION__);
480

481
    for (index = 0; index < dev->addr_len;  index++) {
482
      printk("%02X", dev->dev_addr[index]);
483
    }
484 485 486 487 488 489 490

    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]);
    }

491 492 493
    printk("\n");
    printk("[OAI_IP_DRV][%s] INIT: end\n", __FUNCTION__);
    return;
494
  } else {
495 496 497 498 499
    printk("[OAI_IP_DRV][%s] ERROR, Device is NULL!!\n", __FUNCTION__);
    return;
  }
}
//---------------------------------------------------------------------------
500 501 502
int init_module (void)
{
  //---------------------------------------------------------------------------
503 504 505 506 507 508 509
  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);
510

511
  for (index = 0; index < m_arg;  index++) {
512
    printk("%02X", oai_nw_drv_IMEI[index]);
513
  }
514

515 516 517 518
  printk("\n");

#ifndef OAI_NW_DRIVER_USE_NETLINK

519
  if (pdcp_2_oai_nw_drv_irq == -EBUSY || pdcp_2_oai_nw_drv_irq == -EINVAL) {
520 521
    printk("[OAI_IP_DRV][%s] No interrupt resource available\n", __FUNCTION__);
    return -EBUSY;
522
  } else
523
    printk("[OAI_IP_DRV][%s] Interrupt %d\n", __FUNCTION__, pdcp_2_oai_nw_drv_irq);
524

525 526
#endif //NETLINK

527
  for (inst=0; inst<OAI_NW_DRV_NB_INSTANCES_MAX; inst++) {
528 529 530 531 532
    printk("[OAI_IP_DRV][%s] begin init instance %d\n", __FUNCTION__,inst);


    sprintf(devicename,"oai%d",inst);

533
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0)
534
    oai_nw_drv_dev[inst]  = alloc_netdev(sizeof(struct oai_nw_drv_priv),devicename, oai_nw_drv_init);
535
#else
thomasl's avatar
thomasl committed
536
    oai_nw_drv_dev[inst]  = alloc_netdev(sizeof(struct oai_nw_drv_priv),devicename, NET_NAME_PREDICTABLE, oai_nw_drv_init);
537
#endif
538 539 540
    //netif_stop_queue(oai_nw_drv_dev[inst]);

    if (oai_nw_drv_dev[inst] == NULL) {
541
      printk("[OAI_IP_DRV][%s][INST %02d] alloc_netdev FAILED\n", __FUNCTION__,inst);
542 543
    } else {

544 545 546 547
      priv = netdev_priv(oai_nw_drv_dev[inst]);

      if (oai_nw_drv_dev[inst]) {
        oai_nw_drv_IMEI[9] += 1;
548

549 550 551
        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;
552
        }
553
      }
554

555 556
      // linux/net/core/dev.c line 4767
      err= register_netdev(oai_nw_drv_dev[inst]);
557

558 559 560 561 562
      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);
      }
563 564 565 566 567
    }
  }

#ifdef OAI_NW_DRIVER_USE_NETLINK
  printk("[OAI_IP_DRV][%s] NETLINK INIT\n", __FUNCTION__);
568

569 570 571 572 573 574 575 576 577 578
  if ((err=oai_nw_drv_netlink_init()) == -1)
    printk("[OAI_IP_DRV][%s] NETLINK failed\n", __FUNCTION__);

#endif //NETLINK

  return err;

}

//---------------------------------------------------------------------------
579 580 581 582
void cleanup_module(void)
{
  //---------------------------------------------------------------------------
  int inst;
583

584
  printk("[OAI_IP_DRV][CLEANUP]nasmesh_cleanup_module: begin\n");
585 586

#ifndef OAI_NW_DRIVER_USE_NETLINK
587 588 589 590 591 592 593 594

  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
  }

595 596 597
#else // NETLINK
#endif //NETLINK

598
  for (inst=0; inst<OAI_NW_DRV_NB_INSTANCES_MAX; inst++) {
599
#ifdef OAI_DRV_DEBUG_DEVICE
600
    printk("nasmesh_cleanup_module: unregister and free net device instance %d\n",inst);
601
#endif
602 603 604 605 606

    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]);
607
    }
608 609
  }

610
#ifdef OAI_NW_DRIVER_USE_NETLINK
611
  oai_nw_drv_netlink_release();
612
#endif //OAI_NW_DRIVER_USE_NETLINK
613
  printk("nasmesh_cleanup_module: end\n");
614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635
}

#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);