device.c 16.2 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 24 25 26 27
/*! \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,

28
*/
29 30
/*******************************************************************************/

31
#include "constant.h"
32 33 34
#include "local.h"
#include "proto_extern.h"

35
#include <linux/module.h>
36
#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
#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];

56
#ifdef PDCP_USE_NETLINK
57
extern void nas_netlink_release(void);
58 59 60 61 62
extern int nas_netlink_init(void);
#endif

//int bytes_wrote;
//int bytes_read;
63
uint8_t NULL_IMEI[14]= {0x05, 0x04, 0x03, 0x01, 0x02 ,0x00, 0x00, 0x00, 0x05, 0x04, 0x03 ,0x00, 0x01, 0x08};
64 65


66
static unsigned int  nas_IMEI[6]= {0x03, 0x01, 0x02 ,0x00, 0x00, 0x00}; // may change to char
67 68 69 70
static int m_arg=0;
static unsigned int nas_is_clusterhead=0;


71 72
int find_inst(struct net_device *dev)
{
73 74 75

  int i;

76
  for (i=0; i<NB_INSTANCES_MAX; i++)
77 78
    if (nasdev[i] == dev)
      return(i);
79

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

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

85
#ifndef PDCP_USE_NETLINK
86
//void interrupt(void){
87 88
void *nas_interrupt(void)
{
89
  //---------------------------------------------------------------------------
90
  uint8_t cxi;
91 92 93

  //  struct nas_priv *priv=netdev_priv(dev_id);
  //  unsigned int flags;
94

95 96 97 98 99 100 101
  //  priv->lock = SPIN_LOCK_UNLOCKED;

#ifdef DEBUG_INTERRUPT
  printk("INTERRUPT - begin\n");
#endif
  //  spin_lock_irqsave(&priv->lock,flags);
  cxi=0;
102 103
  //  mesh_GC_receive();
  //  mesh_DC_receive(naspriv->cx+cxi);
104
#ifndef PDCP_USE_NETLINK
105 106 107 108 109 110 111
  nas_COMMON_QOS_receive();
#endif
  //  spin_unlock_irqrestore(&priv->lock,flags);
#ifdef DEBUG_INTERRUPT
  printk("INTERRUPT: end\n");
#endif
  //  return 0;
112
  return NULL;
113 114 115 116 117
}
#endif //NETLINK

//---------------------------------------------------------------------------
// Called by ifconfig when the device is activated by ifconfig
118 119
int nas_open(struct net_device *dev)
{
120 121
  //---------------------------------------------------------------------------
  printk("OPEN: begin\n");
122
  //  MOD_INC_USE_COUNT;
123
  // Address has already been set at init
124
#ifndef PDCP_USE_NETLINK
125 126 127 128

  if (pdcp_2_nas_irq==-EBUSY) {
    printk("OPEN: irq failure\n");
    return -EBUSY;
129
  }
130

131
#endif //PDCP_USE_NETLINK
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148

  /*
  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
149 150
int nas_stop(struct net_device *dev)
{
151 152 153 154 155
  //---------------------------------------------------------------------------
  struct nas_priv *priv = netdev_priv(dev);
  printk("STOP: begin\n");
  del_timer(&(priv->timer));
  netif_stop_queue(dev);
156
  //  MOD_DEC_USE_COUNT;
157 158 159 160 161
  printk("STOP: name = %s, end\n", dev->name);
  return 0;
}

//---------------------------------------------------------------------------
162 163
void nas_teardown(struct net_device *dev)
{
164 165 166 167 168 169 170 171 172
  //---------------------------------------------------------------------------
  int cxi;

  struct nas_priv *priv;
  int inst;

  if (dev) {
    priv = netdev_priv(dev);
    inst = find_inst(dev);
173

174 175 176
    if (inst<0) {
      printk("nas_teardown: ERROR, couldn't find instance\n");
    }
177

178 179
    printk("nas_teardown instance %d: begin\n",inst);

180 181


182
    nas_CLASS_flush_rclassifier(priv);
183 184

    for (cxi=0; cxi<NAS_CX_MAX; cxi++) {
185 186 187
      nas_COMMON_flush_rb(priv->cx+cxi);
      nas_CLASS_flush_sclassifier(priv->cx+cxi);
    }
188

189 190 191 192 193 194 195 196
    printk("nas_teardown: end\n");
  } // check dev
  else {
    printk("nas_teardown: Device is null\n");
  }
}

//---------------------------------------------------------------------------
197 198
int nas_set_config(struct net_device *dev, struct ifmap *map)
{
199 200
  //---------------------------------------------------------------------------
  printk("SET_CONFIG: begin\n");
201

202 203
  if (dev->flags & IFF_UP)
    return -EBUSY;
204 205 206 207 208 209

  if (map->base_addr != dev->base_addr) {
    printk(KERN_WARNING "SET_CONFIG: Can't change I/O address\n");
    return -EOPNOTSUPP;
  }

210 211
  if (map->irq != dev->irq)
    dev->irq = map->irq;
212

213 214 215 216 217
  return 0;
}

//---------------------------------------------------------------------------
//
218 219
int nas_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
220 221 222 223 224 225 226 227 228 229 230
  //---------------------------------------------------------------------------
  // Start debug information

  int inst;

  if (dev)
    inst = find_inst(dev);
  else {
    printk("nas_hard_start_xmit: ERROR, device is null\n");
    return -1;
  }
231

232 233 234 235
  if (inst>=0) {
#ifdef DEBUG_DEVICE
    printk("HARD_START_XMIT: inst %d,  begin\n",inst);
#endif
236 237

    if (!skb) {
238 239 240
      printk("HARD_START_XMIT - input parameter skb is NULL \n");
      return -1;
    }
241

242 243
    // End debug information
    netif_stop_queue(dev);
laurent's avatar
laurent committed
244
#if  LINUX_VERSION_CODE >= KERNEL_VERSION(4,7,0) ||  (defined RHEL_RELEASE_CODE && RHEL_RELEASE_CODE>=1796)
245 246
    netif_trans_update(dev);
#else
247
    dev->trans_start = jiffies;
248
#endif
249 250 251 252 253 254 255 256
#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){
257
    //    printk("HARD_START_XMIT - parameter skb is NULL \n");
258 259 260 261 262 263 264 265 266 267
    //    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
268 269
  } else {
    printk("nas_hard_start_xmit: ERROR, couldn't find instnace\n");
270 271
    return(-1);
  }
272

273 274 275 276
  return 0;
}

//---------------------------------------------------------------------------
277 278
struct net_device_stats *nas_get_stats(struct net_device *dev)
{
279
  //---------------------------------------------------------------------------
280
  //  return &((struct nas_priv *)dev->priv)->stats;
281 282 283 284 285
  struct nas_priv *priv = netdev_priv(dev);
  return &priv->stats;
}

//---------------------------------------------------------------------------
286 287
int nas_change_mtu(struct net_device *dev, int mtu)
{
288 289 290
  //---------------------------------------------------------------------------

  printk("CHANGE_MTU: begin\n");
291

292 293
  if ((mtu<50) || (mtu>1500))
    return -EINVAL;
294

295 296 297 298 299
  dev->mtu = mtu;
  return 0;
}

//---------------------------------------------------------------------------
300 301
void nas_tx_timeout(struct net_device *dev)
{
302 303 304
  //---------------------------------------------------------------------------
  // Transmitter timeout, serious problems.
  struct nas_priv *priv =  netdev_priv(dev);
305

306 307 308
  printk("TX_TIMEOUT: begin\n");
  //  (struct nas_priv *)(dev->priv)->stats.tx_errors++;
  (priv->stats).tx_errors++;
laurent's avatar
laurent committed
309
#if  LINUX_VERSION_CODE >= KERNEL_VERSION(4,7,0) ||  (defined RHEL_RELEASE_CODE && RHEL_RELEASE_CODE>=1796)
310 311
  netif_trans_update(dev);
#else
312
  dev->trans_start = jiffies;
313
#endif
314 315 316 317 318 319
  netif_wake_queue(dev);
  printk("TX_TIMEOUT: transmit timed out %s\n",dev->name);
}

static const struct net_device_ops nasmesh_netdev_ops = {

320 321 322 323 324 325 326
  .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,
laurent's avatar
laurent committed
327
#if  (defined RHEL_RELEASE_CODE && RHEL_RELEASE_CODE>=1797)
328 329
  .extended.ndo_change_mtu   = nas_change_mtu,
#else
330
  .ndo_change_mtu   = nas_change_mtu,
331
#endif
332
  .ndo_tx_timeout   = nas_tx_timeout,
333 334 335 336
};

//---------------------------------------------------------------------------
// Initialisation of the network device
337 338
void nas_init(struct net_device *dev)
{
339
  //---------------------------------------------------------------------------
340
  uint8_t cxi, dscpi;
341 342 343 344 345 346 347
  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));
348
    //  priv=(struct nas_priv *)(dev->priv);
349 350 351 352 353 354 355 356 357 358 359 360 361 362 363
    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;
364
    priv->sap[NAS_RAB_INPUT_SAPI] = PDCP2PDCP_USE_RT_FIFO;//QOS_DEVICE_CONVERSATIONAL_INPUT;
365
    priv->sap[NAS_RAB_OUTPUT_SAPI] = NAS2PDCP_FIFO;//QOS_DEVICE_STREAMING_INPUT;
366

367 368 369
    //  priv->retry_limit=RETRY_LIMIT_DEFAULT;
    //  priv->timer_establishment=TIMER_ESTABLISHMENT_DEFAULT;
    //  priv->timer_release=TIMER_RELEASE_DEFAULT;
370

371 372
    for (dscpi=0; dscpi<65; ++dscpi)
      priv->rclassifier[dscpi]=NULL;
373

374
    priv->nrclassifier=0;
375

376
    //
377
    for (cxi=0; cxi<NAS_CX_MAX; cxi++) {
378 379 380
#ifdef DEBUG_DEVICE
      printk("INIT: init classifiers, state and timer for MT %u\n", cxi);
#endif
381

382 383 384 385 386 387 388 389
      //    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;
390

391 392
      // initialisation of the classifier
      for (dscpi=0; dscpi<65; ++dscpi) {
393 394
        priv->cx[cxi].sclassifier[dscpi]=NULL;
        priv->cx[cxi].fclassifier[dscpi]=NULL;
395 396 397 398 399
      }

      priv->cx[cxi].nsclassifier=0;
      priv->cx[cxi].nfclassifier=0;
      // initialisation of the IP address
400
      //  TOOL_imei2iid(IMEI, (uint8_t *)priv->cx[cxi].iid6);
401 402 403
      priv->cx[cxi].iid4=0;
      //
    }
404

405
    spin_lock_init(&priv->lock);
406 407 408 409 410 411
    //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
412 413
    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);
414 415
#endif
    // this is more appropriate for user space soft realtime emulation
416
#else
417 418 419 420 421 422 423 424 425
    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
426 427 428 429 430 431 432 433 434 435

    printk("INIT: end\n");
    return;
  }  // instance value check
  else {
    printk("nas_init(): ERROR, Device is NULL!!\n");
    return;
  }
}
//---------------------------------------------------------------------------
436 437 438
int init_module (void)
{
  //---------------------------------------------------------------------------
439 440 441 442 443 444 445 446 447
  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]);

448
#ifndef PDCP_USE_NETLINK
449

450
  if (pdcp_2_nas_irq == -EBUSY || pdcp_2_nas_irq == -EINVAL) {
451 452
    printk("[NAS][INIT] No interrupt resource available\n");
    return -EBUSY;
453
  } else
454
    printk("[NAS][INIT]: Interrupt %d\n", pdcp_2_nas_irq);
455

456
#endif //NETLINK
457 458

  for (inst=0; inst<NB_INSTANCES_MAX; inst++) {
459 460 461 462
    printk("[NAS][INIT] nasmesh_init_module: begin init instance %d\n",inst);


    sprintf(devicename,"oai%d",inst);
463
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0)
464
    nasdev[inst]  = alloc_netdev(sizeof(struct nas_priv),devicename, nas_init);
465 466 467
#else
    nasdev[inst]  = alloc_netdev(sizeof(struct nas_priv),devicename, NET_NAME_PREDICTABLE, nas_init);
#endif
468 469
    priv = netdev_priv(nasdev[inst]);

470
    if (nasdev[inst]) {
471 472
      nas_mesh_init(inst);
      //memcpy(nasdev[inst]->dev_addr,&nas_IMEI[0],8);
473 474
      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);
475
      // TO HAVE DIFFERENT HW @
476 477 478 479 480 481 482 483
      ((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]);
484 485

    if (err) {
486
      printk("[NAS][INIT] nasmesh_init_module (inst %d): error %i registering device %s\n", inst,err, nasdev[inst]->name);
487
    } else {
488 489 490 491
      printk("nasmesh_init_module: registering device %s, ifindex = %d\n\n",nasdev[inst]->name, nasdev[inst]->ifindex);
    }
  }

492
#ifdef PDCP_USE_NETLINK
493

494 495
  if ((err=nas_netlink_init()) == -1)
    printk("[NAS][INIT] NETLINK failed\n");
496

497 498 499 500 501 502 503
  printk("[NAS][INIT] NETLINK INIT\n");

#endif //NETLINK

  return err;

}
504

505
//---------------------------------------------------------------------------
506 507 508
void cleanup_module(void)
{
  //---------------------------------------------------------------------------
509 510 511 512 513 514

  int inst;


  printk("[NAS][CLEANUP]nasmesh_cleanup_module: begin\n");

515
#ifndef PDCP_USE_NETLINK
516

517 518 519 520 521
  if (pdcp_2_nas_irq!=-EBUSY) {
    pdcp_2_nas_irq=0;
    // Start IRQ linux
    //    free_irq(priv->irq, NULL);
    // End IRQ linux
522

523
  }
524

525
#else // NETLINK
526 527 528



529 530
#endif //NETLINK

531 532 533 534 535 536 537 538
  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]);
  }
539

540
#ifdef PDCP_USE_NETLINK
541
  nas_netlink_release();
542
#endif //PDCP_USE_NETLINK
543 544 545 546 547
  printk("nasmesh_cleanup_module: end\n");
}



548
#if  LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,0)
549

550 551 552 553
#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"
554 555 556 557 558 559 560 561
#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");

562
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,1)
563 564 565 566 567 568 569 570 571 572 573 574 575 576 577
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION(DRV_DESCRIPTION);
MODULE_AUTHOR(DRV_AUTHOR);
#endif
#endif



/*
//---------------------------------------------------------------------------
//module_init(init_nasmesh);
//module_exit(exit_nasmesh);
//---------------------------------------------------------------------------

*/