device.c 14.1 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
Cedric Roux's avatar
Cedric Roux committed
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
 */

gauthier's avatar
gauthier committed
22
23
/*! \file device.c
* \brief Networking Device Driver for OpenAirInterface
nikaeinn's avatar
nikaeinn committed
24
* \author  navid nikaein,  Lionel Gauthier, raymond knopp
gauthier's avatar
gauthier committed
25
26
27
28
29
30
31
32
33
34
35
* \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>
thomasl's avatar
thomasl committed
36
#include <linux/version.h>
gauthier's avatar
gauthier committed
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#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

//---------------------------------------------------------------------------
59
60
61
int ue_ip_find_inst(struct net_device *dev_pP)
{
  //---------------------------------------------------------------------------
gauthier's avatar
gauthier committed
62
63
  int i;

64
  for (i=0; i<UE_IP_NB_INSTANCES_MAX; i++)
65
    if (ue_ip_dev[i] == dev_pP) {
gauthier's avatar
gauthier committed
66
      return(i);
67
    }
68

gauthier's avatar
gauthier committed
69
70
71
72
73
74
  return(-1);
}

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

#ifndef OAI_NW_DRIVER_USE_NETLINK
75
76
void *ue_ip_interrupt(void)
{
gauthier's avatar
gauthier committed
77
  //---------------------------------------------------------------------------
gauthier's avatar
gauthier committed
78
  uint8_t cxi;
gauthier's avatar
gauthier committed
79

gauthier's avatar
gauthier committed
80
  //  ue_ip_priv_t *priv_p=netdev_priv(dev_id);
gauthier's avatar
gauthier committed
81
  //  unsigned int flags;
gauthier's avatar
gauthier committed
82
  //  priv_p->lock = SPIN_LOCK_UNLOCKED;
gauthier's avatar
gauthier committed
83
84
85
86

#ifdef OAI_DRV_DEBUG_INTERRUPT
  printk("INTERRUPT - begin\n");
#endif
gauthier's avatar
gauthier committed
87
  //  spin_lock_irqsave(&priv_p->lock,flags);
gauthier's avatar
gauthier committed
88
89
90
91
92
93
  cxi=0;
  //    mesh_GC_receive();
  //    mesh_DC_receive(naspriv->cx+cxi);
#ifndef OAI_NW_DRIVER_USE_NETLINK
  ue_ip_common_wireless2ip();
#endif
gauthier's avatar
gauthier committed
94
  //  spin_unlock_irqrestore(&priv_p->lock,flags);
gauthier's avatar
gauthier committed
95
96
97
98
99
100
101
#ifdef OAI_DRV_DEBUG_INTERRUPT
  printk("INTERRUPT: end\n");
#endif
  //  return 0;
}
#endif //NETLINK
//---------------------------------------------------------------------------
102
103
104
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0))
void ue_ip_timer(struct timer_list *t)
#else
105
void ue_ip_timer(unsigned long dataP)
106
#endif
107
{
gauthier's avatar
gauthier committed
108
  //---------------------------------------------------------------------------
109
110
111
112
113
114
#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

gauthier's avatar
gauthier committed
115
  spin_lock(&priv_p->lock);
116
117
118
119
120
121
#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;
gauthier's avatar
gauthier committed
122
  add_timer(&priv_p->timer);
123
124
#endif

gauthier's avatar
gauthier committed
125
  spin_unlock(&priv_p->lock);
gauthier's avatar
gauthier committed
126
  return;
127
128
  //  add_timer(&gpriv->timer);
  //  spin_unlock(&gpriv->lock);
gauthier's avatar
gauthier committed
129
130
131
132
}

//---------------------------------------------------------------------------
// Called by ifconfig when the device is activated by ifconfig
133
134
int ue_ip_open(struct net_device *dev_pP)
{
gauthier's avatar
gauthier committed
135
  //---------------------------------------------------------------------------
gauthier's avatar
gauthier committed
136
  ue_ip_priv_t *priv_p=netdev_priv(dev_pP);
gauthier's avatar
gauthier committed
137
138
139

  // Address has already been set at init
#ifndef OAI_NW_DRIVER_USE_NETLINK
140
141
142
143

  if (pdcp_2_ue_ip_irq==-EBUSY) {
    printk("[UE_IP_DRV][%s] : irq failure\n", __FUNCTION__);
    return -EBUSY;
gauthier's avatar
gauthier committed
144
  }
145

gauthier's avatar
gauthier committed
146
147
#endif //OAI_NW_DRIVER_USE_NETLINK

148
  if(!netif_queue_stopped(dev_pP)) {
149
    netif_start_queue(dev_pP);
150
  } else {
151
    netif_wake_queue(dev_pP);
152
  }
gauthier's avatar
gauthier committed
153

154
155
156
157
#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
gauthier's avatar
gauthier committed
158
159
160
161
  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;
162
#endif
gauthier's avatar
gauthier committed
163
  //add_timer(&priv_p->timer);
gauthier's avatar
gauthier committed
164

gauthier's avatar
gauthier committed
165
  printk("[UE_IP_DRV][%s] name = %s\n", __FUNCTION__, dev_pP->name);
gauthier's avatar
gauthier committed
166
167
168
169
170
  return 0;
}

//---------------------------------------------------------------------------
// Called by ifconfig when the device is desactivated
171
172
int ue_ip_stop(struct net_device *dev_pP)
{
gauthier's avatar
gauthier committed
173
  //---------------------------------------------------------------------------
gauthier's avatar
gauthier committed
174
  ue_ip_priv_t *priv_p = netdev_priv(dev_pP);
gauthier's avatar
gauthier committed
175
176

  printk("[UE_IP_DRV][%s] Begin\n", __FUNCTION__);
gauthier's avatar
gauthier committed
177
178
  del_timer(&(priv_p->timer));
  netif_stop_queue(dev_pP);
gauthier's avatar
gauthier committed
179
180
181
182
183
184
  //    MOD_DEC_USE_COUNT;
  printk("[UE_IP_DRV][%s] End\n", __FUNCTION__);
  return 0;
}

//---------------------------------------------------------------------------
185
186
void ue_ip_teardown(struct net_device *dev_pP)
{
gauthier's avatar
gauthier committed
187
  //---------------------------------------------------------------------------
gauthier's avatar
gauthier committed
188
  ue_ip_priv_t    *priv_p;
gauthier's avatar
gauthier committed
189
190
191
  int              inst;

  printk("[UE_IP_DRV][%s] Begin\n", __FUNCTION__);
192

gauthier's avatar
gauthier committed
193
  if (dev_pP) {
194
195
    priv_p = netdev_priv(dev_pP);
    inst = ue_ip_find_inst(dev_pP);
gauthier's avatar
gauthier committed
196

197
198
199
200
    if ((inst<0) || (inst>=UE_IP_NB_INSTANCES_MAX)) {
      printk("[UE_IP_DRV][%s] ERROR, couldn't find instance\n", __FUNCTION__);
      return;
    }
gauthier's avatar
gauthier committed
201

202
203

    printk("[UE_IP_DRV][%s] End\n", __FUNCTION__);
gauthier's avatar
gauthier committed
204
  } // check dev_pP
gauthier's avatar
gauthier committed
205
  else {
206
    printk("[UE_IP_DRV][%s] Device is null\n", __FUNCTION__);
gauthier's avatar
gauthier committed
207
208
209
  }
}
//---------------------------------------------------------------------------
210
211
int ue_ip_set_config(struct net_device *dev_pP, struct ifmap *map_pP)
{
gauthier's avatar
gauthier committed
212
213
  //---------------------------------------------------------------------------
  printk("[UE_IP_DRV][%s] Begin\n", __FUNCTION__);
214

215
  if (dev_pP->flags & IFF_UP) {
216
    return -EBUSY;
217
  }
218

gauthier's avatar
gauthier committed
219
  if (map_pP->base_addr != dev_pP->base_addr) {
220
221
    printk(KERN_WARNING "[UE_IP_DRV][%s] Can't change I/O address\n", __FUNCTION__);
    return -EOPNOTSUPP;
gauthier's avatar
gauthier committed
222
  }
223

224
  if (map_pP->irq != dev_pP->irq) {
225
    dev_pP->irq = map_pP->irq;
226
  }
227

gauthier's avatar
gauthier committed
228
229
230
231
232
233
  printk("[UE_IP_DRV][%s] End\n", __FUNCTION__);
  return 0;
}

//---------------------------------------------------------------------------
//
234
235
int ue_ip_hard_start_xmit(struct sk_buff *skb_pP, struct net_device *dev_pP)
{
gauthier's avatar
gauthier committed
236
237
238
  //---------------------------------------------------------------------------
  int inst;

gauthier's avatar
gauthier committed
239
  if (dev_pP) {
240
    inst = ue_ip_find_inst(dev_pP);
gauthier's avatar
gauthier committed
241
  } else {
242
243
    printk("[UE_IP_DRV][%s] ERROR, device is null\n", __FUNCTION__);
    return -1;
gauthier's avatar
gauthier committed
244
245
246
  }

  if ((inst>=0) && (inst<UE_IP_NB_INSTANCES_MAX)) {
247
248
249
#ifdef OAI_DRV_OAI_DRV_DEBUG_DEVICE
    printk("[UE_IP_DRV][%s] inst %d,  begin\n", __FUNCTION__,inst);
#endif
gauthier's avatar
gauthier committed
250

251
252
253
254
255
256
257
    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);
oai's avatar
oai committed
258
#if  LINUX_VERSION_CODE >= KERNEL_VERSION(4,7,0) || (defined RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= 1796)
Cedric Roux's avatar
Cedric Roux committed
259
260
    netif_trans_update(dev_pP);
#else
261
    dev_pP->trans_start = jiffies;
Cedric Roux's avatar
Cedric Roux committed
262
#endif
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
#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
gauthier's avatar
gauthier committed
278
  } else {
279
280
    printk("[UE_IP_DRV][%s] ERROR, couldn't find instance\n", __FUNCTION__);
    return(-1);
gauthier's avatar
gauthier committed
281
  }
282

gauthier's avatar
gauthier committed
283
284
285
286
  return 0;
}

//---------------------------------------------------------------------------
287
288
289
struct net_device_stats *ue_ip_get_stats(struct net_device *dev_pP)
{
  //---------------------------------------------------------------------------
gauthier's avatar
gauthier committed
290
291
  ue_ip_priv_t *priv_p = netdev_priv(dev_pP);
  return &priv_p->stats;
gauthier's avatar
gauthier committed
292
293
}
//---------------------------------------------------------------------------
294
295
296
int ue_ip_set_mac_address(struct net_device *dev_pP, void *mac_pP)
{
  //---------------------------------------------------------------------------
gauthier's avatar
gauthier committed
297
  //struct sockaddr *addr = mac_pP;
gauthier's avatar
gauthier committed
298
  printk("[UE_IP_DRV][%s] CHANGE MAC ADDRESS UNSUPPORTED\n", __FUNCTION__);
gauthier's avatar
gauthier committed
299
  //memcpy(dev_pP->dev_addr, addr->sa_data, dev_pP->addr_len);
gauthier's avatar
gauthier committed
300
301
302
  return 0;
}
//---------------------------------------------------------------------------
303
304
int ue_ip_change_mtu(struct net_device *dev_pP, int mtuP)
{
gauthier's avatar
gauthier committed
305
  //---------------------------------------------------------------------------
gauthier's avatar
gauthier committed
306
  printk("[UE_IP_DRV][%s] CHANGE MTU %d bytes\n", __FUNCTION__, mtuP);
307

308
  if ((mtuP<50) || (mtuP>1500)) {
309
    return -EINVAL;
310
  }
311

gauthier's avatar
gauthier committed
312
  dev_pP->mtu = mtuP;
gauthier's avatar
gauthier committed
313
314
315
  return 0;
}
//---------------------------------------------------------------------------
316
317
void ue_ip_change_rx_flags(struct net_device *dev_pP, int flagsP)
{
gauthier's avatar
gauthier committed
318
  //---------------------------------------------------------------------------
gauthier's avatar
gauthier committed
319
320
321
  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;
gauthier's avatar
gauthier committed
322
323
324
}

//---------------------------------------------------------------------------
325
326
void ue_ip_tx_timeout(struct net_device *dev_pP)
{
gauthier's avatar
gauthier committed
327
328
  //---------------------------------------------------------------------------
  // Transmitter timeout, serious problems.
gauthier's avatar
gauthier committed
329
  ue_ip_priv_t *priv_p =  netdev_priv(dev_pP);
gauthier's avatar
gauthier committed
330
331

  printk("[UE_IP_DRV][%s] begin\n", __FUNCTION__);
gauthier's avatar
gauthier committed
332
333
  //  (ue_ip_priv_t *)(dev_pP->priv_p)->stats.tx_errors++;
  (priv_p->stats).tx_errors++;
oai's avatar
oai committed
334
#if  LINUX_VERSION_CODE >= KERNEL_VERSION(4,7,0) || (defined RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= 1796)
Cedric Roux's avatar
Cedric Roux committed
335
336
  netif_trans_update(dev_pP);
#else
gauthier's avatar
gauthier committed
337
  dev_pP->trans_start = jiffies;
Cedric Roux's avatar
Cedric Roux committed
338
#endif
gauthier's avatar
gauthier committed
339
340
  netif_wake_queue(dev_pP);
  printk("[UE_IP_DRV][%s] transmit timed out %s\n", __FUNCTION__,dev_pP->name);
gauthier's avatar
gauthier committed
341
342
343
}

static const struct net_device_ops ue_ip_netdev_ops = {
344
345
346
347
348
349
350
351
352
353
354
  .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,
  .ndo_change_mtu         = ue_ip_change_mtu,
  .ndo_tx_timeout         = ue_ip_tx_timeout,
  .ndo_change_rx_flags    = ue_ip_change_rx_flags,
gauthier's avatar
gauthier committed
355
};
356
/*.ndo_set_multicast_list = NULL,*/
gauthier's avatar
gauthier committed
357
358
359

//---------------------------------------------------------------------------
// Initialisation of the network device
360
361
void ue_ip_init(struct net_device *dev_pP)
{
gauthier's avatar
gauthier committed
362
  //---------------------------------------------------------------------------
gauthier's avatar
gauthier committed
363
  ue_ip_priv_t *priv_p = NULL;
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378

  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;
  }
gauthier's avatar
gauthier committed
379
380
}
//---------------------------------------------------------------------------
381
382
383
int init_module (void)
{
  //---------------------------------------------------------------------------
gauthier's avatar
gauthier committed
384
385
386
387
388
389
390
  int err,inst;
  char devicename[100];


  // Initialize parameters shared with RRC
  printk("[UE_IP_DRV][%s] Starting OAI IP driver", __FUNCTION__);

391
  for (inst=0; inst<UE_IP_NB_INSTANCES_MAX; inst++) {
gauthier's avatar
gauthier committed
392
393
    printk("[UE_IP_DRV][%s] begin init instance %d\n", __FUNCTION__,inst);
    sprintf(devicename,"oip%d",inst);
thomasl's avatar
thomasl committed
394
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0)
gauthier's avatar
gauthier committed
395
    ue_ip_dev[inst]  = alloc_netdev(sizeof(ue_ip_priv_t),devicename, ue_ip_init);
thomasl's avatar
thomasl committed
396
397
398
#else
    ue_ip_dev[inst]  = alloc_netdev(sizeof(ue_ip_priv_t),devicename, NET_NAME_PREDICTABLE,ue_ip_init);
#endif
399

gauthier's avatar
gauthier committed
400
401
    //netif_stop_queue(ue_ip_dev[inst]);
    if (ue_ip_dev[inst] == NULL) {
402
      printk("[UE_IP_DRV][%s][INST %02d] alloc_netdev FAILED\n", __FUNCTION__,inst);
gauthier's avatar
gauthier committed
403
    } else {
404
405
406
407
408
409
410
411
      // 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);
      }
gauthier's avatar
gauthier committed
412
413
414
415
    }
  }

  printk("[UE_IP_DRV][%s] NETLINK INIT\n", __FUNCTION__);
416

417
  if ((err=ue_ip_netlink_init()) == -1) {
gauthier's avatar
gauthier committed
418
    printk("[UE_IP_DRV][%s] NETLINK failed\n", __FUNCTION__);
419
  }
gauthier's avatar
gauthier committed
420
421
422
423
424
425

  return err;

}

//---------------------------------------------------------------------------
426
427
428
429
void cleanup_module(void)
{
  //---------------------------------------------------------------------------
  int inst;
gauthier's avatar
gauthier committed
430

431
  printk("[UE_IP_DRV][CLEANUP] begin\n");
gauthier's avatar
gauthier committed
432

433
  for (inst=0; inst<UE_IP_NB_INSTANCES_MAX; inst++) {
gauthier's avatar
gauthier committed
434
#ifdef OAI_DRV_DEBUG_DEVICE
435
    printk("[UE_IP_DRV][CLEANUP]  unregister and free net device instance %d\n",inst);
gauthier's avatar
gauthier committed
436
#endif
437
438
439
440
441

    if (ue_ip_dev[inst]) {
      unregister_netdev(ue_ip_dev[inst]);
      ue_ip_teardown(ue_ip_dev[inst]);
      free_netdev(ue_ip_dev[inst]);
gauthier's avatar
gauthier committed
442
    }
443
444
445
  }

  ue_ip_netlink_release();
446
  printk("[UE_IP_DRV][CLEANUP] end\n");
gauthier's avatar
gauthier committed
447
448
449
450
451
452
453
454
455
}

#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