OpenCores
URL https://opencores.org/ocsvn/or1k_old/or1k_old/trunk

Subversion Repositories or1k_old

[/] [or1k_old/] [trunk/] [uclinux/] [uClinux-2.0.x/] [net/] [core/] [net_alias.c] - Blame information for rev 1782

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 200 simons
/*
2
 *              NET_ALIAS network device aliasing module.
3
 *
4
 *
5
 * Version:     @(#)net_alias.c 0.50   4/20/97
6
 *
7
 *
8
 * Authors:     Juan Jose Ciarlante, <jjciarla@raiz.uncu.edu.ar>
9
 *              Marcelo Fabian Roccasalva, <mfroccas@raiz.uncu.edu.ar>
10
 *
11
 * Features:
12
 *      -       AF_ independent: net_alias_type objects
13
 *      -       AF_INET optimized
14
 *      -       ACTUAL alias devices inserted in dev chain
15
 *      -       fast hashed alias address lookup
16
 *      -       net_alias_type objs registration/unreg., module-ables.
17
 *      -       /proc/net/aliases & /proc/net/alias_types entries
18
 *      -       tx and rx stats
19
 *      -       /proc/sys/net/core/net_alias_max entry
20
 * Fixes:
21
 *      Juan Jose Ciarlante     :       several net_alias_type func. renamed.
22
 *      Juan Jose Ciarlante     :       net_alias_type object methods now pass
23
 *                                      *this.
24
 *      Juan Jose Ciarlante     :       xxx_rcv device selection based on <src,dst> addrs
25
 *              Andreas Schultz :       Kerneld support.
26
 *      Juan Jose Ciarlante     :       Added tx/rx stats for aliases.
27
 *      Juan Jose Ciarlante     :       Added sysctl interface for max aliases per device
28
 *
29
 * FIXME:
30
 *      - User calls sleep/wake_up locking.
31
 *
32
 *
33
 *      This program is free software; you can redistribute it and/or
34
 *      modify it under the terms of the GNU General Public License
35
 *      as published by the Free Software Foundation; either version
36
 *      2 of the License, or (at your option) any later version.
37
 *
38
 */
39
 
40
#include <linux/config.h>
41
#include <linux/types.h>
42
#include <linux/errno.h>
43
#include <linux/netdevice.h>
44
#include <linux/notifier.h>
45
#include <linux/if.h>
46
#include <linux/if_ether.h>
47
#include <linux/inet.h>
48
#include <linux/in.h>
49
#include <linux/proc_fs.h>
50
#include <linux/stat.h>
51
#include <linux/sysctl.h>
52
 
53
#ifdef ALIAS_USER_LAND_DEBUG
54
#include "net_alias.h"
55
#include "user_stubs.h"
56
#endif
57
 
58
#include <linux/net_alias.h>
59
 
60
#ifdef CONFIG_KERNELD
61
#include <linux/kerneld.h>
62
#endif
63
 
64
 
65
/*
66
 *      NET_ALIAS_MAX_DEFAULT: max. alias slot number allowed by default,
67
 *              can be changed by sysctl
68
 *      NET_ALIAS_HASH_TAB_SIZE: hash table size (addr lookup), 1 per aliased
69
 *              device, due to hash optimizations, MUST be 16 or 256 only.
70
 */
71
 
72
#define NET_ALIAS_MAX_DEFAULT           256
73
 
74
/* DO NOT CHANGE the line below ! */
75
#define NET_ALIAS_HASH_TAB_SIZE(n)  ( ((n)>=NET_ALIAS_MAX_DEFAULT) ? 256 : 16 )
76
 
77
/*
78
 *      set default max_aliases per device
79
 */
80
int sysctl_net_alias_max = NET_ALIAS_MAX_DEFAULT;
81
 
82
/*
83
 *      Only allow the following flags to pass from main device to aliases
84
 *      Note that IFF_BROADCAST is not passed by default, this make sense
85
 *      because:
86
 *      a) if same-net alias: broadcasts are already handled by main device
87
 *      b) if diff-net alias: bcasts will be set by 'broadcast' ifconfig opt.
88
 *      I prefer this approach instead of setting '-broadcast' for each
89
 *      same-net alias device  --JJC.
90
 */
91
 
92
#define  NET_ALIAS_IFF_MASK   (IFF_SOFTHEADERS|IFF_NOARP|IFF_LOOPBACK|IFF_POINTOPOINT)
93
 
94
static struct net_alias_type * nat_getbytype(int type);
95
static int nat_attach_chg(struct net_alias_type *nat, int delta);
96
static int nat_bind(struct net_alias_type *nat,struct net_alias *alias, struct sockaddr *sa);
97
static int nat_unbind(struct net_alias_type *nat, struct net_alias *alias);
98
 
99
 
100
static int net_alias_devinit(struct device *dev);
101
static struct enet_statistics *net_alias_dev_stats(struct device *dev);
102
static int net_alias_hard_start_xmit(struct sk_buff *skb, struct device *dev);
103
static int net_alias_devsetup(struct net_alias *alias, struct net_alias_type *nat, struct sockaddr *sa);
104
static struct net_alias **net_alias_slow_findp(struct net_alias_info *alias_info, struct net_alias *alias);
105
static struct device *net_alias_dev_create(struct device *main_dev, int slot, int *err, struct sockaddr *sa, void *data);
106
static struct device *net_alias_dev_delete(struct device *main_dev, int slot, int *err);
107
static void net_alias_free(struct device *dev);
108
 
109
/*
110
 * net_alias_type base array, will hold net_alias_type obj hashed list heads.
111
 */
112
 
113
struct net_alias_type *net_alias_type_base[16];
114
 
115
 
116
/*
117
 *      get_stats function: return rx/tx pkts based on lookups
118
 */
119
static struct enet_statistics *net_alias_dev_stats(struct device *dev)
120
{
121
        static struct enet_statistics alias_stats;
122
        struct net_alias *alias = dev->my_alias;
123
 
124
        memset (&alias_stats, 0, sizeof (alias_stats));
125
        alias_stats.rx_packets        = alias->rx_lookups;
126
        alias_stats.tx_packets        = alias->tx_lookups;
127
        return &alias_stats;
128
}
129
 
130
 
131
/*
132
 * get net_alias_type ptr by type
133
 */
134
 
135
static __inline__ struct net_alias_type *
136
nat_getbytype(int type)
137
{
138
  struct net_alias_type *nat;
139
  for(nat = net_alias_type_base[type & 0x0f]; nat ; nat = nat->next)
140
  {
141
    if (nat->type == type) return nat;
142
  }
143
  return NULL;
144
}
145
 
146
 
147
/*
148
 * get addr32 representation (pre-hashing) of address.
149
 * if NULL nat->get_addr32, assume sockaddr_in struct (IP-ish).
150
 */
151
 
152
static __inline__ __u32
153
nat_addr32(struct net_alias_type *nat, struct sockaddr *sa)
154
{
155
  if (nat->get_addr32)
156
    return nat->get_addr32(nat, sa);
157
  else
158
    return (*(struct sockaddr_in *)sa).sin_addr.s_addr;
159
}
160
 
161
 
162
/*
163
 * hashing code for alias_info->hash_tab entries
164
 * 4 bytes -> 1/2 byte using xor complemented by af
165
 */
166
 
167
static __inline__ unsigned
168
hash_key(unsigned hsize, __u32 addr)
169
{
170
  unsigned tmp = addr ^ (addr>>16); /* 4 -> 2 */
171
  tmp ^= (tmp>>8);                  /* 2 -> 1 */
172
  if (hsize == 256)
173
    return (tmp & 0xff);
174
  else
175
    return (tmp^(tmp>>4)) & 0x0f;           /* 1 -> 1/2 */
176
}
177
 
178
 
179
/*
180
 * get hash key for supplied net alias type and address
181
 * nat must be !NULL
182
 * the purpose here is to map a net_alias_type and a generic
183
 * address to a hash code.
184
 */
185
 
186
static __inline__ int
187
nat_hash_key(struct net_alias_type *nat, unsigned hsize, struct sockaddr *sa)
188
{
189
  return hash_key(hsize, nat_addr32(nat,sa));
190
}
191
 
192
 
193
/*
194
 * change net_alias_type number of attachments (bindings)
195
 */
196
 
197
static int
198
nat_attach_chg(struct net_alias_type *nat, int delta)
199
{
200
  unsigned long flags;
201
  int n_at;
202
  if (!nat) return -1;
203
  save_flags(flags);
204
  cli();
205
  n_at = nat->n_attach + delta;
206
  if (n_at < 0)
207
  {
208
    restore_flags(flags);
209
    printk(KERN_WARNING "net_alias: tried to set n_attach < 0 for (family==%d) nat object.\n",
210
           nat->type);
211
    return -1;
212
  }
213
  nat->n_attach = n_at;
214
  restore_flags(flags);
215
  return 0;
216
}
217
 
218
 
219
/*
220
 * bind alias to its type (family) object and call initialization hook
221
 */
222
 
223
static __inline__ int
224
nat_bind(struct net_alias_type *nat,struct net_alias *alias, struct sockaddr *sa)
225
{
226
  if (nat->alias_init_1) nat->alias_init_1(nat, alias, sa);
227
  return nat_attach_chg(nat, +1);
228
}
229
 
230
 
231
/*
232
 * unbind alias from type object and call alias destructor
233
 */
234
 
235
static __inline__ int
236
nat_unbind(struct net_alias_type *nat, struct net_alias *alias)
237
{
238
  if (nat->alias_done_1) nat->alias_done_1(nat, alias);
239
  return nat_attach_chg(nat, -1);
240
}
241
 
242
 
243
/*
244
 * compare device address with given. if NULL nat->dev_addr_chk,
245
 * compare dev->pa_addr with (sockaddr_in) 32 bits address (IP-ish)
246
 */
247
 
248
static __inline__ int nat_dev_addr_chk_1(struct net_alias_type *nat,
249
                                   struct device *dev, struct sockaddr *sa)
250
{
251
  if (nat->dev_addr_chk)
252
    return nat->dev_addr_chk(nat, dev, sa);
253
  else
254
    return (dev->pa_addr == (*(struct sockaddr_in *)sa).sin_addr.s_addr);
255
}
256
 
257
 
258
/*
259
 * alias device init()
260
 * do nothing.
261
 */
262
 
263
static int
264
net_alias_devinit(struct device *dev)
265
{
266
#ifdef ALIAS_USER_LAND_DEBUG
267
  printk("net_alias_devinit(%s) called.\n", dev->name);
268
#endif
269
  return 0;
270
}
271
 
272
 
273
/*
274
 * hard_start_xmit() should not be called.
275
 * ignore ... but shout!.
276
 */
277
 
278
static int
279
net_alias_hard_start_xmit(struct sk_buff *skb, struct device *dev)
280
{
281
  printk(KERN_WARNING "net_alias: net_alias_hard_start_xmit() for %s called (ignored)!!\n", dev->name);
282
  dev_kfree_skb(skb, FREE_WRITE);
283
  return 0;
284
}
285
 
286
 
287
static int
288
net_alias_dev_open(struct device * dev)
289
{
290
  return 0;
291
}
292
 
293
static int
294
net_alias_dev_close(struct device * dev)
295
{
296
  return 0;
297
}
298
 
299
/*
300
 * setups a new (alias) device
301
 */
302
 
303
static int
304
net_alias_devsetup(struct net_alias *alias, struct net_alias_type *nat,
305
                struct sockaddr *sa)
306
{
307
  struct device *main_dev;
308
  struct device *dev;
309
  int family;
310
  int i;
311
 
312
  /*
313
   *
314
   * generic device setup based on main_dev info
315
   *
316
   * FIXME: is NULL bitwise 0 for all Linux platforms?
317
   */
318
 
319
  main_dev = alias->main_dev;
320
  dev = &alias->dev;
321
  memset(dev, '\0', sizeof(struct device));
322
  family = (sa)? sa->sa_family : main_dev->family;
323
  alias->rx_lookups = 0;
324
  alias->tx_lookups = 0;
325
  dev->alias_info = NULL;       /* no aliasing recursion */
326
  dev->my_alias = alias;        /* point to alias */
327
  dev->name = alias->name;
328
  dev->type = main_dev->type;
329
  dev->open = net_alias_dev_open;
330
  dev->stop = net_alias_dev_close;
331
  dev->get_stats = net_alias_dev_stats;
332
 
333
  dev->hard_header_len = main_dev->hard_header_len;
334
  memcpy(dev->broadcast, main_dev->broadcast, MAX_ADDR_LEN);
335
  memcpy(dev->dev_addr, main_dev->dev_addr, MAX_ADDR_LEN);
336
  dev->addr_len = main_dev->addr_len;
337
  dev->init = net_alias_devinit;
338
  dev->hard_start_xmit = net_alias_hard_start_xmit;
339
  dev->flags = main_dev->flags & NET_ALIAS_IFF_MASK & ~IFF_UP;
340
 
341
  /*
342
   * only makes sense if same family
343
   */
344
 
345
  if (family == main_dev->family)
346
  {
347
    dev->metric = main_dev->metric;
348
    dev->mtu = main_dev->mtu;
349
    dev->pa_alen = main_dev->pa_alen;
350
    dev->hard_header = main_dev->hard_header;
351
    dev->rebuild_header = main_dev->rebuild_header;
352
  }
353
 
354
  /*
355
   *    Fill in the generic fields of the device structure.
356
   *    not actually used, avoids some dev.c #ifdef's
357
   */
358
 
359
  for (i = 0; i < DEV_NUMBUFFS; i++)
360
    skb_queue_head_init(&dev->buffs[i]);
361
 
362
  dev->family = family;
363
  return 0;
364
}
365
 
366
 
367
/*
368
 * slow alias find (parse the whole hash_tab)
369
 * returns: alias' pointer address
370
 */
371
 
372
static struct net_alias **
373
net_alias_slow_findp(struct net_alias_info *alias_info, struct net_alias *alias)
374
{
375
  unsigned idx, n_aliases;
376
  struct net_alias **aliasp;
377
 
378
  /*
379
   * for each alias_info's hash_tab entry, for every alias ...
380
   */
381
 
382
  n_aliases = alias_info->n_aliases;
383
  for (idx=0; idx < alias_info->hash_tab_size ; idx++)
384
    for (aliasp = &alias_info->hash_tab[idx];*aliasp;aliasp = &(*aliasp)->next)
385
      if (*aliasp == alias)
386
        return aliasp;
387
      else
388
        if (--n_aliases == 0) break; /* faster give up */
389
  return NULL;
390
}
391
 
392
 
393
/*
394
 * create alias device for main_dev with given slot num.
395
 * if sa==NULL will create a same_family alias device
396
 */
397
 
398
static struct device *
399
net_alias_dev_create(struct device *main_dev, int slot, int *err, struct sockaddr *sa, void *data)
400
{
401
  struct net_alias_info *alias_info;
402
  struct net_alias *alias, **aliasp;
403
  struct net_alias_type *nat;
404
  struct device *dev;
405
  unsigned long flags;
406
  int family;
407
  __u32 addr32;
408
  int max_aliases;
409
 
410
  /* FIXME: lock */
411
  alias_info = main_dev->alias_info;
412
 
413
  /*
414
   * if NULL address given, take family from main_dev
415
   */
416
 
417
  family = (sa)? sa->sa_family : main_dev->family;
418
 
419
  /*
420
   * check if wanted family has a net_alias_type object registered
421
   */
422
 
423
  nat = nat_getbytype(family);
424
  if (!nat) {
425
#ifdef CONFIG_KERNELD
426
    char modname[20];
427
    sprintf (modname,"netalias-%d", family);
428
    request_module(modname);
429
 
430
    nat = nat_getbytype(family);
431
    if (!nat) {
432
#endif
433
      printk(KERN_WARNING "net_alias_dev_create(%s:%d): unregistered family==%d\n",
434
             main_dev->name, slot, family);
435
      /* *err = -EAFNOSUPPORT; */
436
      *err = -EINVAL;
437
      return NULL;
438
#ifdef CONFIG_KERNELD
439
    }
440
#endif
441
  }
442
 
443
  *err = -EINVAL;
444
 
445
  if (!alias_info)
446
        /*
447
         *      At this point we take the sysctl value(s)
448
         */
449
        max_aliases = sysctl_net_alias_max;
450
  else
451
        max_aliases = alias_info->max_aliases;
452
 
453
  if (slot >= max_aliases )     /* 0-based (eth0:0 _IS_ valid) */
454
        return NULL;
455
 
456
  /*
457
   * do not allow creation over downed devices
458
   */
459
 
460
  *err = -EIO;
461
 
462
  if (! (main_dev->flags & IFF_UP) )
463
    return NULL;
464
 
465
  /*
466
   * if first alias, must also create alias_info
467
   */
468
 
469
  *err = -ENOMEM;
470
 
471
  if (!alias_info)
472
  {
473
          /*
474
           *    Allocate space for struct net_alias_info plus hash table
475
           */
476
          int truesize;
477
 
478
          /* net_alias_info size */
479
          truesize = sizeof(struct net_alias_info);
480
          /* add   hash_tab size * sizeof(elem)  */
481
          truesize += NET_ALIAS_HASH_TAB_SIZE(max_aliases) * sizeof (struct net_alias *);
482
 
483
          alias_info = kmalloc( truesize , GFP_KERNEL);
484
 
485
          if (!alias_info) return NULL; /* ENOMEM */
486
 
487
          memset(alias_info, 0, truesize);
488
          alias_info->truesize = truesize;
489
          alias_info->max_aliases = max_aliases;
490
          alias_info->hash_tab_size = NET_ALIAS_HASH_TAB_SIZE(max_aliases);
491
  }
492
 
493
  if (!(alias = kmalloc(sizeof(struct net_alias), GFP_KERNEL)))
494
    return NULL;                /* ENOMEM */
495
 
496
  /*
497
   * FIXME: is NULL bitwise 0 for all Linux platforms?
498
   */
499
 
500
  memset(alias, 0, sizeof(struct net_alias));
501
  alias->slot = slot;
502
  alias->main_dev = main_dev;
503
  alias->nat = nat;
504
  alias->next = NULL;
505
  alias->data = data;
506
  sprintf(alias->name, "%s:%d", main_dev->name, slot);
507
 
508
  /*
509
   * initialise alias' device structure
510
   */
511
 
512
  net_alias_devsetup(alias, nat, sa);
513
 
514
  dev = &alias->dev;
515
 
516
  save_flags(flags);
517
  cli();
518
 
519
  /*
520
   * bind alias to its object type
521
   * nat_bind calls nat->alias_init_1
522
   */
523
 
524
  nat_bind(nat, alias, sa);
525
 
526
  /*
527
   * if no address passed, take from device (could have been
528
   * set by nat->alias_init_1)
529
   */
530
 
531
  addr32 = (sa)? nat_addr32(nat, sa) : alias->dev.pa_addr;
532
 
533
  /*
534
   * store hash key in alias: will speed-up rehashing and deletion
535
   */
536
 
537
  alias->hash = hash_key(alias_info->hash_tab_size, addr32);
538
 
539
  /*
540
   * insert alias in hashed linked list
541
   */
542
 
543
  aliasp = &alias_info->hash_tab[alias->hash];
544
  alias->next = *aliasp;
545
  *aliasp = alias;
546
 
547
  /*
548
   * if first alias ...
549
   */
550
 
551
  if (!alias_info->n_aliases++)
552
  {
553
    alias_info->taildev = main_dev;
554
    main_dev->alias_info = alias_info;
555
  }
556
 
557
  /*
558
   * add device at tail (just after last main_dev alias)
559
   */
560
 
561
  dev->next = alias_info->taildev->next;
562
  alias_info->taildev->next = dev;
563
  alias_info->taildev = dev;
564
  restore_flags(flags);
565
  return dev;
566
}
567
 
568
 
569
/*
570
 * delete one main_dev alias (referred by its slot num)
571
 */
572
 
573
static struct device *
574
net_alias_dev_delete(struct device *main_dev, int slot, int *err)
575
{
576
  struct net_alias_info *alias_info;
577
  struct net_alias *alias, **aliasp;
578
  struct device *dev;
579
  unsigned n_aliases;
580
  unsigned long flags;
581
  struct net_alias_type *nat;
582
  struct device *prevdev;
583
 
584
  /* FIXME: lock */
585
  *err = -ENODEV;
586
 
587
  if (main_dev == NULL) return NULL;
588
 
589
  /*
590
   * does main_dev have aliases?
591
   */
592
 
593
  alias_info = main_dev->alias_info;
594
  if (!alias_info) return NULL; /* ENODEV */
595
 
596
  n_aliases = alias_info->n_aliases;
597
 
598
  /*
599
   * find device that holds the same slot number (could also
600
   * be strcmp() ala dev_get).
601
   */
602
 
603
  for (prevdev=main_dev, alias = NULL;prevdev->next && n_aliases; prevdev = prevdev->next)
604
  {
605
    if (!(alias = prevdev->next->my_alias))
606
    {
607
      printk(KERN_ERR "net_alias_dev_delete(): incorrect non-alias device after maindev\n");
608
      continue;                 /* or should give up? */
609
    }
610
    if (alias->slot == slot) break;
611
    alias = NULL;
612
    n_aliases--;
613
  }
614
 
615
  if (!alias) return NULL;      /* ENODEV */
616
 
617
  dev = &alias->dev;
618
 
619
  /*
620
   * find alias hashed entry
621
   */
622
 
623
  for(aliasp = &alias_info->hash_tab[alias->hash]; *aliasp; aliasp = &(*aliasp)->next)
624
    if(*aliasp == alias) break;
625
 
626
  /*
627
   * if not found (???), try a full search
628
   */
629
 
630
  if (*aliasp != alias)
631
    if ((aliasp = net_alias_slow_findp(alias_info, alias)))
632
      printk(KERN_WARNING "net_alias_dev_delete(%s): bad hashing recovered\n", alias->name);
633
    else
634
    {
635
      printk(KERN_ERR "net_alias_dev_delete(%s): unhashed alias!\n",alias->name);
636
      return NULL;              /* ENODEV */
637
    }
638
 
639
  nat = alias->nat;
640
 
641
  save_flags(flags);
642
  cli();
643
 
644
  /*
645
   * unbind alias from alias_type obj.
646
   */
647
 
648
  nat_unbind(nat, alias);
649
 
650
  /*
651
   * is alias at tail?
652
   */
653
 
654
  if ( dev == alias_info->taildev )
655
    alias_info->taildev = prevdev;
656
 
657
  /*
658
   * unlink and close device
659
   */
660
  prevdev->next = dev->next;
661
  dev_close(dev);
662
 
663
  /*
664
   * unlink alias
665
   */
666
 
667
  *aliasp = (*aliasp)->next;
668
 
669
  if (--alias_info->n_aliases == 0) /* last alias */
670
    main_dev->alias_info = NULL;
671
  restore_flags(flags);
672
 
673
  /*
674
   * now free structures
675
   */
676
 
677
  kfree_s(alias, sizeof(struct net_alias));
678
  if (main_dev->alias_info == NULL)
679
    kfree_s(alias_info, alias_info->truesize);
680
 
681
  /*
682
   * deletion ok (*err=0), NULL device returned.
683
   */
684
 
685
  *err = 0;
686
  return NULL;
687
}
688
 
689
/*
690
 * free all main device aliasing stuff
691
 * will be called on dev_close(main_dev)
692
 */
693
 
694
static void
695
net_alias_free(struct device *main_dev)
696
{
697
  struct net_alias_info *alias_info;
698
  struct net_alias *alias;
699
  struct net_alias_type *nat;
700
  struct device *dev;
701
  unsigned long flags;
702
 
703
  /*
704
   * do I really have aliases?
705
   */
706
 
707
  if (!(alias_info = main_dev->alias_info))    return;
708
 
709
  /*
710
   * fast device link "short-circuit": set main_dev->next to
711
   * device after last alias
712
   */
713
 
714
  save_flags(flags);
715
  cli();
716
 
717
  dev =  main_dev->next;
718
  main_dev->next = alias_info->taildev->next;
719
  main_dev->alias_info = NULL;
720
  alias_info->taildev->next = NULL;
721
 
722
  restore_flags(flags);
723
 
724
  /*
725
   * loop over alias devices, free and dev_close()
726
   */
727
 
728
  while (dev)
729
  {
730
    if (net_alias_is(dev))
731
    {
732
      alias = dev->my_alias;
733
      if (alias->main_dev == main_dev)
734
      {
735
        /*
736
         * unbind alias from alias_type object
737
         */
738
 
739
        nat = alias->nat;
740
        if (nat)
741
        {
742
          nat_unbind(nat, alias);
743
        } /*  else error/printk ??? */
744
 
745
        dev_close(dev);
746
        dev = dev->next;
747
 
748
        kfree_s(alias, sizeof(struct net_alias));
749
        continue;
750
      }
751
      else
752
        printk(KERN_ERR "net_alias_free(%s): '%s' is not my alias\n",
753
               main_dev->name, alias->name);
754
    }
755
    else
756
      printk(KERN_ERR "net_alias_free(%s): found a non-alias after device!\n",
757
             main_dev->name);
758
    dev = dev->next;
759
  }
760
 
761
  kfree_s(alias_info, sizeof(alias_info));
762
  return;
763
}
764
 
765
/*
766
 * dev_get() with added alias naming magic.
767
 */
768
 
769
struct device *
770
net_alias_dev_get(char *dev_name, int aliasing_ok, int *err,
771
                  struct sockaddr *sa, void *data)
772
{
773
  struct device *dev;
774
  char *sptr,*eptr;
775
  int slot = 0;
776
  int delete = 0;
777
 
778
  *err = -ENODEV;
779
  if ((dev=dev_get(dev_name)))
780
    return dev;
781
 
782
  /*
783
   * want alias naming magic?
784
   */
785
 
786
  if (!aliasing_ok) return NULL;
787
 
788
  if (!dev_name || !*dev_name)
789
    return NULL;
790
 
791
  /*
792
   * find the first ':' , must be followed by, at least, 1 char
793
   */
794
 
795
  for (sptr=dev_name ; *sptr ; sptr++) if(*sptr==':') break;
796
  if (!*sptr || !*(sptr+1))
797
    return NULL;
798
 
799
  /*
800
   * seems to be an alias name, fetch main device
801
   */
802
 
803
  *sptr='\0';
804
  if (!(dev=dev_get(dev_name)))
805
    return NULL;
806
  *sptr++=':';
807
 
808
  /*
809
   * fetch slot number
810
   */
811
 
812
  slot = simple_strtoul(sptr,&eptr,10);
813
 
814
  /*
815
   * if last char is '-', it is a deletion request
816
   */
817
 
818
  if (eptr[0] == '-' && !eptr[1] ) delete++;
819
  else if (eptr[0])
820
    return NULL;
821
 
822
  /*
823
   * well... let's work.
824
   */
825
 
826
  if (delete)
827
    return net_alias_dev_delete(dev, slot, err);
828
  else
829
    return net_alias_dev_create(dev, slot, err, sa, data);
830
}
831
 
832
 
833
/*
834
 * rehash alias device with address supplied.
835
 */
836
 
837
int
838
net_alias_dev_rehash(struct device *dev, struct sockaddr *sa)
839
{
840
  struct net_alias_info *alias_info;
841
  struct net_alias *alias, **aliasp;
842
  struct device *main_dev;
843
  unsigned long flags;
844
  struct net_alias_type *o_nat, *n_nat;
845
  unsigned n_hash;
846
 
847
  /*
848
   * defensive ...
849
   */
850
 
851
  if (dev == NULL) return -1;
852
  if ( (alias = dev->my_alias) == NULL ) return -1;
853
 
854
  if (!sa)
855
  {
856
    printk(KERN_ERR "net_alias_rehash(): NULL sockaddr passed\n");
857
    return -1;
858
  }
859
 
860
  /*
861
   * defensive. should not happen.
862
   */
863
 
864
  if ( (main_dev = alias->main_dev) == NULL )
865
  {
866
    printk(KERN_ERR "net_alias_rehash for %s: NULL maindev\n", alias->name);
867
    return -1;
868
  }
869
 
870
  /*
871
   * defensive. should not happen.
872
   */
873
 
874
  if (!(alias_info=main_dev->alias_info))
875
  {
876
    printk(KERN_ERR "net_alias_rehash for %s: NULL alias_info\n", alias->name);
877
    return -1;
878
  }
879
 
880
  /*
881
   * will the request also change device family?
882
   */
883
 
884
  o_nat = alias->nat;
885
  if (!o_nat)
886
  {
887
    printk(KERN_ERR "net_alias_rehash(%s): unbound alias.\n", alias->name);
888
    return -1;
889
  }
890
 
891
  /*
892
   * point to new alias_type obj.
893
   */
894
 
895
  if (o_nat->type == sa->sa_family)
896
    n_nat = o_nat;
897
  else
898
  {
899
    n_nat = nat_getbytype(sa->sa_family);
900
    if (!n_nat)
901
    {
902
      printk(KERN_ERR "net_alias_rehash(%s): unreg family==%d.\n", alias->name, sa->sa_family);
903
      return -1;
904
    }
905
  }
906
 
907
  /*
908
   * new hash key. if same as old AND same type (family) return;
909
   */
910
 
911
  n_hash = nat_hash_key(n_nat, alias_info->hash_tab_size, sa);
912
  if (n_hash == alias->hash && o_nat == n_nat )
913
    return 0;
914
 
915
  /*
916
   * find alias in hashed list
917
   */
918
 
919
  for (aliasp = &alias_info->hash_tab[alias->hash]; *aliasp; aliasp = &(*aliasp)->next)
920
    if (*aliasp == alias) break;
921
 
922
  /*
923
   * not found (???). try a full search
924
   */
925
 
926
  if(!*aliasp)
927
    if ((aliasp = net_alias_slow_findp(alias_info, alias)))
928
      printk(KERN_WARNING "net_alias_rehash(%s): bad hashing recovered\n", alias->name);
929
    else
930
    {
931
      printk(KERN_ERR "net_alias_rehash(%s): unhashed alias!\n", alias->name);
932
      return -1;
933
    }
934
 
935
  save_flags(flags);
936
  cli();
937
 
938
  /*
939
   * if type (family) changed, unlink from old type object (o_nat)
940
   * will call o_nat->alias_done_1()
941
   */
942
 
943
  if (o_nat != n_nat)
944
    nat_unbind(o_nat, alias);
945
 
946
  /*
947
   * if diff hash key, change alias position in hashed list
948
   */
949
 
950
  if (n_hash != alias->hash)
951
  {
952
    *aliasp = (*aliasp)->next;
953
    alias->hash = n_hash;
954
    aliasp = &alias_info->hash_tab[n_hash];
955
    alias->next = *aliasp;
956
    *aliasp = alias;
957
  }
958
 
959
  /*
960
   * if type (family) changed link to new type object (n_nat)
961
   * will call n_nat->alias_init_1()
962
   */
963
 
964
  if (o_nat != n_nat)
965
    nat_bind(n_nat, alias, sa);
966
 
967
  restore_flags(flags);
968
  return 0;
969
}
970
 
971
 
972
 
973
 
974
/*
975
 *  implements /proc/net/alias_types entry
976
 *  shows net_alias_type objects registered.
977
 */
978
 
979
int net_alias_types_getinfo(char *buffer, char **start, off_t offset, int length, int dummy)
980
{
981
  off_t pos=0, begin=0;
982
  int len=0;
983
  struct net_alias_type *nat;
984
  unsigned idx;
985
  len=sprintf(buffer,"type    name            n_attach\n");
986
  for (idx=0 ; idx < 16 ; idx++)
987
    for (nat = net_alias_type_base[idx]; nat ; nat = nat->next)
988
    {
989
      len += sprintf(buffer+len, "%-7d %-15s %-7d\n",
990
                     nat->type, nat->name,nat->n_attach);
991
      pos=begin+len;
992
      if(pos<offset)
993
      {
994
        len=0;
995
        begin=pos;
996
      }
997
      if(pos>offset+length)
998
        break;
999
    }
1000
  *start=buffer+(offset-begin);
1001
  len-=(offset-begin);
1002
  if(len>length)
1003
    len=length;
1004
  return len;
1005
}
1006
 
1007
 
1008
/*
1009
 *  implements /proc/net/aliases entry, shows alias devices.
1010
 *   calls alias nat->alias_print_1 if not NULL and formats everything
1011
 *   to a fixed rec. size without using local (stack) buffers
1012
 *
1013
 */
1014
 
1015
#define NET_ALIASES_RECSIZ 64
1016
int net_alias_getinfo(char *buffer, char **start, off_t offset, int length, int dummy)
1017
{
1018
  off_t pos=0, begin=0;
1019
  int len=0;
1020
  int dlen;
1021
  struct net_alias_type *nat;
1022
  struct net_alias *alias;
1023
  struct device *dev;
1024
 
1025
  len=sprintf(buffer,"%-*s\n",NET_ALIASES_RECSIZ-1,"device           family address");
1026
  for (dev = dev_base; dev ; dev = dev->next)
1027
    if (net_alias_is(dev))
1028
    {
1029
      alias = dev->my_alias;
1030
      nat = alias->nat;
1031
      dlen=sprintf(buffer+len, "%-16s %-6d ", alias->name, alias->dev.family);
1032
 
1033
      /*
1034
       * call alias_type specific print function.
1035
       */
1036
 
1037
      if (nat->alias_print_1)
1038
        dlen += nat->alias_print_1(nat, alias, buffer+len+dlen, NET_ALIASES_RECSIZ - dlen);
1039
      else
1040
        dlen += sprintf(buffer+len+dlen, "-");
1041
 
1042
      /*
1043
       * fill with spaces if needed
1044
       */
1045
 
1046
      if (dlen < NET_ALIASES_RECSIZ) memset(buffer+len+dlen, ' ', NET_ALIASES_RECSIZ - dlen);
1047
      /*
1048
       * truncate to NET_ALIASES_RECSIZ
1049
       */
1050
 
1051
      len += NET_ALIASES_RECSIZ;
1052
      buffer[len-1] = '\n';
1053
 
1054
      pos=begin+len;
1055
      if(pos<offset)
1056
      {
1057
        len=0;
1058
        begin=pos;
1059
      }
1060
      if(pos>offset+length)
1061
        break;
1062
    }
1063
  *start=buffer+(offset-begin);
1064
  len-=(offset-begin);
1065
  if(len>length)
1066
    len=length;
1067
  return len;
1068
}
1069
 
1070
 
1071
/*
1072
 * notifier for devices events
1073
 */
1074
 
1075
int net_alias_device_event(struct notifier_block *this, unsigned long event, void *ptr)
1076
{
1077
  struct device *dev = ptr;
1078
 
1079
  if (event == NETDEV_DOWN)
1080
  {
1081
#ifdef ALIAS_USER_LAND_DEBUG
1082
    printk("net_alias: NETDEV_DOWN for %s received\n", dev->name);
1083
#endif
1084
    if (net_alias_has(dev))
1085
      net_alias_free(dev);
1086
  }
1087
 
1088
  if (event == NETDEV_UP)
1089
  {
1090
#ifdef ALIAS_USER_LAND_DEBUG
1091
    printk("net_alias: NETDEV_UP for %s received\n", dev->name);
1092
#endif
1093
    dev->alias_info = 0;
1094
  }
1095
 
1096
  return NOTIFY_DONE;
1097
}
1098
 
1099
 
1100
/*
1101
 * device aliases address comparison workhorse
1102
 * no checks for nat and alias_info, must be !NULL
1103
 */
1104
 
1105
static __inline__ struct device *
1106
nat_addr_chk(struct net_alias_type *nat, struct net_alias_info *alias_info, struct sockaddr *sa, int flags_on, int flags_off)
1107
{
1108
  struct net_alias *alias;
1109
  unsigned hsize = alias_info->hash_tab_size;
1110
 
1111
  for(alias = alias_info->hash_tab[nat_hash_key(nat,hsize,sa)];
1112
      alias; alias = alias->next)
1113
  {
1114
    if (alias->dev.family != sa->sa_family) continue;
1115
 
1116
    /*
1117
     * nat_dev_addr_chk_1 will call type specific address cmp function.
1118
     */
1119
 
1120
    if (alias->dev.flags & flags_on && !(alias->dev.flags & flags_off) &&
1121
        nat_dev_addr_chk_1(nat,&alias->dev,sa))
1122
      return &alias->dev;
1123
  }
1124
  return NULL;
1125
}
1126
 
1127
/*
1128
 * nat_addr_chk enough for protocols whose addr is (fully) stored at pa_addr.
1129
 * note that nat pointer is ignored because of static comparison.
1130
 */
1131
 
1132
static __inline__ struct device *
1133
nat_addr_chk32(struct net_alias_type *nat, struct net_alias_info *alias_info, int family, __u32 addr32, int flags_on, int flags_off)
1134
{
1135
  struct net_alias *alias;
1136
  unsigned hsize = alias_info->hash_tab_size;
1137
 
1138
  for (alias=alias_info->hash_tab[hash_key(hsize, addr32)];
1139
       alias; alias=alias->next)
1140
  {
1141
    if (alias->dev.family != family) continue;
1142
 
1143
    /*
1144
     * "hard" (static) comparison between addr32 and pa_addr.
1145
     */
1146
 
1147
    if (alias->dev.flags & flags_on && !(alias->dev.flags & flags_off) &&
1148
        addr32 == alias->dev.pa_addr)
1149
      return &alias->dev;
1150
  }
1151
  return NULL;
1152
}
1153
 
1154
/*
1155
 * returns alias device with specified address AND flags_on AND flags_off,
1156
 * else NULL.
1157
 * intended for main devices.
1158
 */
1159
 
1160
struct device *
1161
net_alias_dev_chk(struct device *main_dev, struct sockaddr *sa,int flags_on, int flags_off)
1162
{
1163
  struct net_alias_info *alias_info = main_dev->alias_info;
1164
  struct net_alias_type *nat;
1165
 
1166
  /*
1167
   * only if main_dev has aliases
1168
   */
1169
 
1170
  if (!alias_info) return NULL;
1171
 
1172
  /*
1173
   * get alias_type object for sa->sa_family.
1174
   */
1175
 
1176
  nat = nat_getbytype(sa->sa_family);
1177
  if (!nat)
1178
    return NULL;
1179
 
1180
  return nat_addr_chk(nat, alias_info, sa, flags_on, flags_off);
1181
}
1182
 
1183
/*
1184
 * net_alias_dev_chk enough for protocols whose addr is (fully) stored
1185
 * at pa_addr.
1186
 */
1187
 
1188
struct device *
1189
net_alias_dev_chk32(struct device *main_dev, int family, __u32 addr32,
1190
                int flags_on, int flags_off)
1191
{
1192
  struct net_alias_info *alias_info = main_dev->alias_info;
1193
 
1194
  /*
1195
   * only if main_dev has aliases
1196
   */
1197
 
1198
  if (!alias_info) return NULL;
1199
 
1200
  return nat_addr_chk32(NULL, alias_info, family, addr32, flags_on, flags_off);
1201
}
1202
 
1203
 
1204
/*
1205
 * select closest (main or alias) device to <src,dst> addresses given. if no
1206
 * further info is available, return main_dev (for easier calling arrangement).
1207
 *
1208
 * Should be called early at xxx_rcv() time for device selection
1209
 */
1210
 
1211
struct device *
1212
net_alias_dev_rx(struct device *main_dev, struct sockaddr *sa_src, struct sockaddr *sa_dst)
1213
{
1214
  int family;
1215
  struct net_alias_type *nat;
1216
  struct net_alias_info *alias_info;
1217
  struct device *dev;
1218
 
1219
  if (main_dev == NULL) return NULL;
1220
 
1221
  /*
1222
   * if not aliased, don't bother any more
1223
   */
1224
 
1225
  if ((alias_info = main_dev->alias_info) == NULL)
1226
    return main_dev;
1227
 
1228
  /*
1229
   * find out family
1230
   */
1231
 
1232
  family = (sa_src)? sa_src->sa_family : ((sa_dst)? sa_dst->sa_family : AF_UNSPEC);
1233
  if (family == AF_UNSPEC) return main_dev;
1234
 
1235
  /*
1236
   * get net_alias_type object for this family
1237
   */
1238
 
1239
  if ( (nat = nat_getbytype(family)) == NULL ) return main_dev;
1240
 
1241
  /*
1242
   * first step: find out if dst addr is main_dev's or one of its aliases'
1243
   */
1244
 
1245
  if (sa_dst)
1246
  {
1247
    if (nat_dev_addr_chk_1(nat, main_dev,sa_dst))
1248
      return main_dev;
1249
 
1250
    dev = nat_addr_chk(nat, alias_info, sa_dst, IFF_UP, 0);
1251
 
1252
    if (dev != NULL) {
1253
            net_alias_inc_rx(dev->my_alias);
1254
            return dev;
1255
    }
1256
  }
1257
 
1258
  /*
1259
   * second step: find the rcv addr 'closest' alias through nat method call
1260
   */
1261
 
1262
  if ( sa_src == NULL || nat->dev_select == NULL) return main_dev;
1263
  dev = nat->dev_select(nat, main_dev, sa_src);
1264
 
1265
  if (dev == NULL || dev->family != family) return main_dev;
1266
 
1267
  /*
1268
   * dev ok only if it is alias of main_dev
1269
   */
1270
 
1271
  if (net_alias_is(dev)) {
1272
          struct net_alias *alias=dev->my_alias;
1273
          if (alias->main_dev == main_dev) {
1274
                  net_alias_inc_rx(alias);
1275
                  return dev;
1276
          }
1277
  }
1278
 
1279
  /*
1280
   * do not return NULL.
1281
   */
1282
 
1283
  return main_dev;
1284
 
1285
}
1286
 
1287
/*
1288
 * dev_rx32: dev_rx selection for 'pa_addr' protocols.
1289
 */
1290
 
1291
struct device *
1292
net_alias_dev_rx32(struct device *main_dev, int family, __u32 src, __u32 dst)
1293
{
1294
  struct net_alias_type *nat;
1295
  struct net_alias_info *alias_info;
1296
  struct sockaddr_in sin_src;
1297
  struct device *dev;
1298
 
1299
  if (main_dev == NULL) return NULL;
1300
 
1301
  /*
1302
   * if not aliased, don't bother any more
1303
   */
1304
 
1305
  if ((alias_info = main_dev->alias_info) == NULL)
1306
    return main_dev;
1307
 
1308
  /*
1309
   * early return if dst is main_dev's address
1310
   */
1311
 
1312
  if (dst == main_dev->pa_addr)
1313
    return main_dev;
1314
 
1315
  if (family == AF_UNSPEC) return main_dev;
1316
 
1317
  /*
1318
   * get net_alias_type object for this family
1319
   */
1320
 
1321
  if ( (nat = nat_getbytype(family)) == NULL ) return main_dev;
1322
 
1323
  /*
1324
   * first step: find out if dst address one of main_dev aliases'
1325
   */
1326
 
1327
  if (dst)
1328
  {
1329
    dev = nat_addr_chk32(nat, alias_info, family, dst, IFF_UP, 0);
1330
    if (dev) {
1331
            net_alias_inc_rx(dev->my_alias);
1332
            return dev;
1333
    }
1334
  }
1335
 
1336
  /*
1337
   * second step: find the rcv addr 'closest' alias through nat method call
1338
   */
1339
 
1340
  if ( src == 0 || nat->dev_select == NULL) return main_dev;
1341
 
1342
  sin_src.sin_family = family;
1343
  sin_src.sin_addr.s_addr = src;
1344
 
1345
  dev = nat->dev_select(nat, main_dev, (struct sockaddr *)&sin_src);
1346
 
1347
  if (dev == NULL || dev->family != family) return main_dev;
1348
 
1349
  /*
1350
   * dev ok only if it is alias of main_dev
1351
   */
1352
 
1353
  if (net_alias_is(dev)) {
1354
          struct net_alias *alias=dev->my_alias;
1355
          if (alias->main_dev == main_dev) {
1356
                  net_alias_inc_rx(alias);
1357
                  return dev;
1358
          }
1359
  }
1360
 
1361
  /*
1362
   * do not return NULL.
1363
   */
1364
 
1365
  return main_dev;
1366
 
1367
}
1368
 
1369
/*
1370
 * device event hook
1371
 */
1372
 
1373
static struct notifier_block net_alias_dev_notifier = {
1374
  net_alias_device_event,
1375
  NULL,
1376
 
1377
};
1378
 
1379
 
1380
/*
1381
 * net_alias initialisation
1382
 * called from net_dev_init().
1383
 */
1384
 
1385
#ifndef ALIAS_USER_LAND_DEBUG
1386
#ifdef CONFIG_PROC_FS
1387
static struct proc_dir_entry pde1 = {
1388
    PROC_NET_ALIAS_TYPES, 11, "alias_types",
1389
    S_IFREG | S_IRUGO, 1, 0, 0,
1390
    0, &proc_net_inode_operations,
1391
    net_alias_types_getinfo
1392
  };
1393
static struct proc_dir_entry pde2 = {
1394
    PROC_NET_ALIASES, 7, "aliases",
1395
    S_IFREG | S_IRUGO, 1, 0, 0,
1396
    0, &proc_net_inode_operations,
1397
    net_alias_getinfo
1398
  };
1399
#endif
1400
#endif
1401
 
1402
void net_alias_init(void)
1403
{
1404
 
1405
  /*
1406
   * register dev events notifier
1407
   */
1408
 
1409
  register_netdevice_notifier(&net_alias_dev_notifier);
1410
 
1411
  /*
1412
   * register /proc/net entries
1413
   */
1414
 
1415
#ifndef ALIAS_USER_LAND_DEBUG
1416
#ifdef CONFIG_PROC_FS
1417
  proc_net_register(&pde1);
1418
  proc_net_register(&pde2);
1419
#endif
1420
#endif
1421
 
1422
}
1423
 
1424
/*
1425
 * net_alias type object registering func.
1426
 */
1427
int register_net_alias_type(struct net_alias_type *nat, int type)
1428
{
1429
  unsigned hash;
1430
  unsigned long flags;
1431
  if (!nat)
1432
  {
1433
    printk(KERN_ERR "register_net_alias_type(): NULL arg\n");
1434
    return -EINVAL;
1435
  }
1436
  nat->type = type;
1437
  nat->n_attach = 0;
1438
  hash = nat->type & 0x0f;
1439
  save_flags(flags);
1440
  cli();
1441
  nat->next = net_alias_type_base[hash];
1442
  net_alias_type_base[hash] = nat;
1443
  restore_flags(flags);
1444
  return 0;
1445
}
1446
 
1447
/*
1448
 * net_alias type object unreg.
1449
 */
1450
int unregister_net_alias_type(struct net_alias_type *nat)
1451
{
1452
  struct net_alias_type **natp;
1453
  unsigned hash;
1454
  unsigned long flags;
1455
 
1456
  if (!nat)
1457
  {
1458
    printk(KERN_ERR "unregister_net_alias_type(): NULL arg\n");
1459
    return -EINVAL;
1460
  }
1461
 
1462
  /*
1463
   * only allow unregistration if it has no attachments
1464
   */
1465
  if (nat->n_attach)
1466
  {
1467
    printk(KERN_ERR "unregister_net_alias_type(): has %d attachments. failed\n",
1468
           nat->n_attach);
1469
    return -EINVAL;
1470
  }
1471
  hash = nat->type & 0x0f;
1472
  save_flags(flags);
1473
  cli();
1474
  for (natp = &net_alias_type_base[hash]; *natp ; natp = &(*natp)->next)
1475
  {
1476
    if (nat==(*natp))
1477
    {
1478
      *natp = nat->next;
1479
      restore_flags(flags);
1480
      return 0;
1481
    }
1482
  }
1483
  restore_flags(flags);
1484
  printk(KERN_ERR "unregister_net_alias_type(type=%d): not found!\n", nat->type);
1485
  return -EINVAL;
1486
}
1487
 
1488
/*
1489
 *      Log sysctl's net_alias_max changes.
1490
 */
1491
int proc_do_net_alias_max(ctl_table *ctl, int write, struct file *filp,
1492
                            void *buffer, size_t *lenp)
1493
{
1494
        int old = sysctl_net_alias_max;
1495
        int ret;
1496
 
1497
        ret = proc_dointvec(ctl, write, filp, buffer, lenp);
1498
        if (write) {
1499
                if (sysctl_net_alias_max != old) {
1500
                        printk(KERN_INFO "sysctl: net_alias_max changed (max.aliases=%d, hashsize=%d).\n",
1501
                               sysctl_net_alias_max,
1502
                               NET_ALIAS_HASH_TAB_SIZE(sysctl_net_alias_max));
1503
                        if (!sysctl_net_alias_max)
1504
                                printk(KERN_INFO "sysctl: net_alias creation disabled.\n");
1505
                        if (!old)
1506
                                printk(KERN_INFO "sysctl: net_alias creation enabled.\n");
1507
                }
1508
        }
1509
        return ret;
1510
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.