root/net/core/net_alias.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. nat_getbytype
  2. nat_addr32
  3. HASH
  4. nat_hash_key
  5. nat_attach_chg
  6. nat_bind
  7. nat_unbind
  8. nat_addr_chk
  9. net_alias_devinit
  10. net_alias_hard_start_xmit
  11. net_alias_devsetup
  12. net_alias_slow_findp
  13. net_alias_dev_create
  14. net_alias_dev_delete
  15. net_alias_dev_get
  16. net_alias_rehash
  17. net_alias_free
  18. net_alias_types_getinfo
  19. net_alias_getinfo
  20. net_alias_device_event
  21. net_alias_chk
  22. net_alias_chk32
  23. net_alias_init
  24. register_net_alias_type
  25. unregister_net_alias_type

   1 /*
   2  *              NET_ALIAS device aliasing module.
   3  *
   4  * Version:     @(#)net_alias.c 0.42   12/11/95
   5  *
   6  * Authors:     Juan Jose Ciarlante, <jjciarla@raiz.uncu.edu.ar>
   7  *              Marcelo Fabian Roccasalva, <mfroccas@raiz.uncu.edu.ar>
   8  *
   9  * Features:
  10  *      -       AF_ independent: net_alias_type objects
  11  *      -       AF_INET optimized
  12  *      -       ACTUAL alias devices inserted in dev chain
  13  *      -       fast hashed alias address lookup
  14  *      -       net_alias_type objs registration/unreg., module-ables.
  15  *      -       /proc/net/aliases & /proc/net/alias_types entries
  16  *
  17  * FIXME:
  18  *      - User calls sleep/wake_up locking.
  19  *      - Define a way to select the "best" alias device for an incoming
  20  *        packet to allow xxx_rcv() device switching based ALSO on pkt's
  21  *        src address (this would require a routing query).
  22  *        Related stuff:
  23  *              IP: Test routing between aliases (possible ICMP redirects).
  24  *              IP: ARP proxy entries attached to aliases are not visible.
  25  *
  26  *
  27  *      This program is free software; you can redistribute it and/or
  28  *      modify it under the terms of the GNU General Public License
  29  *      as published by the Free Software Foundation; either version
  30  *      2 of the License, or (at your option) any later version.
  31  *      
  32  */
  33 
  34 #include <linux/types.h>
  35 #include <linux/errno.h>
  36 #include <linux/netdevice.h>
  37 #include <linux/notifier.h>
  38 #include <linux/if.h>
  39 #include <linux/inet.h>
  40 #include <linux/proc_fs.h>
  41 #include <linux/stat.h>
  42 
  43 #ifdef ALIAS_USER_LAND_DEBUG
  44 #include "net_alias.h"
  45 #include "user_stubs.h"
  46 #endif
  47 
  48 #include <linux/net_alias.h>
  49 
  50 /*
  51  * Only allow the following flags to pass from main device to aliases
  52  */
  53 
  54 #define  NET_ALIAS_IFF_MASK   (IFF_UP|IFF_BROADCAST|IFF_RUNNING|IFF_NOARP|IFF_LOOPBACK|IFF_POINTOPOINT)
  55 
  56 static struct net_alias_type * nat_getbytype(int type);
  57 static int nat_attach_chg(struct net_alias_type *nat, int delta);
  58 static int nat_bind(struct net_alias_type *nat,struct net_alias *alias, struct sockaddr *sa);
  59 static int nat_unbind(struct net_alias_type *nat, struct net_alias *alias);
  60 
  61 
  62 static int net_alias_devinit(struct device *dev);
  63 static int net_alias_hard_start_xmit(struct sk_buff *skb, struct device *dev);
  64 static int net_alias_devsetup(struct net_alias *alias, struct net_alias_type *nat, struct sockaddr *sa);
  65 static struct net_alias **net_alias_slow_findp(struct net_alias_info *alias_info, struct net_alias *alias);
  66 static struct device *net_alias_dev_create(struct device *main_dev, int slot, int *err, struct sockaddr *sa, void *data);
  67 static struct device *net_alias_dev_delete(struct device *main_dev, int slot, int *err);
  68 static void net_alias_free(struct device *dev);
  69                                            
  70 /*
  71  * net_alias_type base array, will hold net_alias_type objects.
  72  */
  73 
  74 struct net_alias_type *nat_base[16];
  75 
  76 
  77 /*
  78  * get net_alias_type ptr by type
  79  */
  80 
  81 static __inline__ struct net_alias_type *
  82 nat_getbytype(int type)
     /* [previous][next][first][last][top][bottom][index][help] */
  83 {
  84   struct net_alias_type *nat;
  85   for(nat = nat_base[type & 0x0f]; nat ; nat = nat->next)
  86   {
  87     if (nat->type == type) return nat;
  88   }
  89   return NULL;
  90 }
  91 
  92 
  93 /*
  94  * get addr32 representation (pre-hashing) of address.
  95  * if NULL nat->get_addr32, assume sockaddr_in struct (IP-ish).
  96  */
  97 
  98 static __inline__ __u32
  99 nat_addr32(struct net_alias_type *nat, struct sockaddr *sa)
     /* [previous][next][first][last][top][bottom][index][help] */
 100 {
 101   if (nat->get_addr32)
 102     return nat->get_addr32(sa);
 103   else
 104     return (*(struct sockaddr_in *)sa).sin_addr.s_addr;
 105 }
 106 
 107 
 108 /*
 109  * hashing code for alias_info->hash_tab entries
 110  * 4 bytes -> 1/2 byte using xor condimented by af
 111  */
 112 
 113 static __inline__ unsigned
 114 HASH(__u32 addr, int af)
     /* [previous][next][first][last][top][bottom][index][help] */
 115 {
 116   unsigned tmp = addr ^ (addr>>16); /* 4 -> 2 */
 117   tmp ^= (tmp>>8);                  /* 2 -> 1 */
 118   return (tmp^(tmp>>4)^af) & 0x0f;          /* 1 -> 1/2 */
 119 }
 120 
 121 
 122 /*
 123  * get hash key for supplied net alias type and address
 124  * nat must be !NULL
 125  * the purpose here is to map an net_alias_type and a generic
 126  * address to a hash code.
 127  */
 128 
 129 static __inline__ int
 130 nat_hash_key(struct net_alias_type *nat, struct sockaddr *sa)
     /* [previous][next][first][last][top][bottom][index][help] */
 131 {
 132   return HASH(nat_addr32(nat,sa), sa->sa_family);
 133 }
 134 
 135 
 136 /*
 137  * change net_alias_type number of attachments (bindings)
 138  */
 139 
 140 static int
 141 nat_attach_chg(struct net_alias_type *nat, int delta)
     /* [previous][next][first][last][top][bottom][index][help] */
 142 {
 143   unsigned long flags;
 144   int n_at;
 145   if (!nat) return -1;
 146   save_flags(flags);
 147   cli();
 148   n_at = nat->n_attach + delta;
 149   if (n_at < 0)
 150   {
 151     restore_flags(flags);
 152     printk("net_alias: tried to set n_attach < 0 for (family==%d) nat object.\n",
 153            nat->type);
 154     return -1;
 155   }
 156   nat->n_attach = n_at;
 157   restore_flags(flags);
 158   return 0;
 159 }
 160 
 161 
 162 /*
 163  * bind alias to its type (family) object and call initialization hook
 164  */
 165 
 166 static __inline__ int
 167 nat_bind(struct net_alias_type *nat,struct net_alias *alias, struct sockaddr *sa)
     /* [previous][next][first][last][top][bottom][index][help] */
 168 {
 169   if (nat->alias_init_1) nat->alias_init_1(alias, sa);
 170   return nat_attach_chg(nat, +1);
 171 }
 172 
 173 
 174 /*
 175  * unbind alias from type object and call 'done' hook
 176  */
 177 
 178 static __inline__ int
 179 nat_unbind(struct net_alias_type *nat, struct net_alias *alias)
     /* [previous][next][first][last][top][bottom][index][help] */
 180 {
 181   if (nat->alias_done_1) nat->alias_done_1(alias);
 182   return nat_attach_chg(nat, -1);
 183 }
 184 
 185 
 186 /*
 187  * compare device address with given. if NULL nat->addr_chk,
 188  * compare dev->pa_addr with (sockaddr_in) 32 bits address (IP-ish)
 189  */
 190 
 191 static __inline__ int nat_addr_chk(struct net_alias_type *nat,
     /* [previous][next][first][last][top][bottom][index][help] */
 192                                    struct device *dev, struct sockaddr *sa)
 193 {
 194   if (nat->addr_chk)
 195     return nat->addr_chk(dev, sa);
 196   else
 197     return (dev->pa_addr == (*(struct sockaddr_in *)sa).sin_addr.s_addr);
 198 }
 199 
 200 
 201 /*
 202  * alias device init()
 203  * do nothing.
 204  */
 205 
 206 static int 
 207 net_alias_devinit(struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 208 {
 209 #ifdef ALIAS_USER_LAND_DEBUG
 210   printk("net_alias_devinit(%s) called.\n", dev->name);
 211 #endif
 212   return 0;
 213 }
 214 
 215 
 216 /*
 217  * hard_start_xmit() should not be called.
 218  * ignore ... but shout!.
 219  */
 220 
 221 static int
 222 net_alias_hard_start_xmit(struct sk_buff *skb, struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 223 {
 224   printk("net_alias: net_alias_hard_start_xmit() for %s called (ignored)!!\n", dev->name);
 225   dev_kfree_skb(skb, FREE_WRITE);
 226   return 0;
 227 }
 228 
 229 
 230 /*
 231  * setups a new (alias) device 
 232  */
 233 
 234 static int
 235 net_alias_devsetup(struct net_alias *alias, struct net_alias_type *nat,
     /* [previous][next][first][last][top][bottom][index][help] */
 236                 struct sockaddr *sa)
 237 {
 238   struct device *main_dev;
 239   struct device *dev;
 240   int family;
 241   int i;
 242 
 243   /*
 244    *
 245    * generic device setup based on main_dev info
 246    *
 247    * FIXME: is NULL bitwise 0 for all Linux platforms?
 248    */
 249   
 250   main_dev = alias->main_dev;
 251   dev = &alias->dev;
 252   memset(dev, '\0', sizeof(struct device));
 253   family = (sa)? sa->sa_family : main_dev->family;
 254 
 255   dev->alias_info = NULL;       /* no aliasing recursion */
 256   dev->my_alias = alias;        /* point to alias */
 257   dev->name = alias->name;
 258   dev->type = main_dev->type;
 259   dev->hard_header_len = main_dev->hard_header_len;
 260   memcpy(dev->broadcast, main_dev->broadcast, MAX_ADDR_LEN);
 261   memcpy(dev->dev_addr, main_dev->dev_addr, MAX_ADDR_LEN);
 262   dev->addr_len = main_dev->addr_len;
 263   dev->init = net_alias_devinit;
 264   dev->hard_start_xmit = net_alias_hard_start_xmit;
 265   dev->flags = main_dev->flags & NET_ALIAS_IFF_MASK & ~IFF_UP;
 266 
 267   /*
 268    * only makes sense if same family
 269    */
 270   
 271   if (family == main_dev->family)
 272   {
 273     dev->metric = main_dev->metric;
 274     dev->mtu = main_dev->mtu;
 275     dev->pa_alen = main_dev->pa_alen;
 276     dev->hard_header = main_dev->hard_header;
 277     dev->rebuild_header = main_dev->rebuild_header;
 278   }
 279   
 280   /*
 281    *    Fill in the generic fields of the device structure.
 282    *    not actually used, avoids some dev.c #ifdef's
 283    */
 284   
 285   for (i = 0; i < DEV_NUMBUFFS; i++)
 286     skb_queue_head_init(&dev->buffs[i]);
 287   
 288   dev->family = family;
 289   return 0;
 290 }
 291 
 292 
 293 /*
 294  * slow alias find (parse the whole hash_tab)
 295  * returns: alias' pointer address
 296  */
 297 
 298 static struct net_alias **
 299 net_alias_slow_findp(struct net_alias_info *alias_info, struct net_alias *alias)
     /* [previous][next][first][last][top][bottom][index][help] */
 300 {
 301   unsigned idx, n_aliases;
 302   struct net_alias **aliasp;
 303 
 304   /*
 305    * for each alias_info's hash_tab entry, for every alias ...
 306    */
 307   
 308   n_aliases = alias_info->n_aliases;
 309   for (idx=0; idx < 16 ; idx++)
 310     for (aliasp = &alias_info->hash_tab[idx];*aliasp;aliasp = &(*aliasp)->next)
 311       if (*aliasp == alias)
 312         return aliasp;
 313       else
 314         if (--n_aliases == 0) break; /* faster give up */
 315   return NULL;
 316 }
 317 
 318 
 319 /*
 320  * create alias device for main_dev with given slot num.
 321  * if sa==NULL will create a same_family alias device 
 322  */
 323 
 324 static struct device *
 325 net_alias_dev_create(struct device *main_dev, int slot, int *err, struct sockaddr *sa, void *data)
     /* [previous][next][first][last][top][bottom][index][help] */
 326 {
 327   struct net_alias_info *alias_info;
 328   struct net_alias *alias, **aliasp;
 329   struct net_alias_type *nat;
 330   struct device *dev;
 331   unsigned long flags;
 332   int family;
 333   __u32 addr32;
 334   
 335   /* FIXME: lock */
 336   alias_info = main_dev->alias_info;
 337 
 338   /*
 339    * if NULL address given, take family from main_dev
 340    */
 341   
 342   family = (sa)? sa->sa_family : main_dev->family;
 343   
 344   /*
 345    * check if wanted family has a net_alias_type object registered
 346    */
 347   
 348   nat = nat_getbytype(family);
 349   if (!nat)
 350   {
 351     printk("net_alias_dev_create(%s:%d): unregistered family==%d\n",
 352            main_dev->name, slot, family);
 353     /* *err = -EAFNOSUPPORT; */
 354     *err = -EINVAL;
 355     return NULL;
 356   }
 357   
 358   /*
 359    * do not allow creation over downed devices
 360    */
 361 
 362   *err = -EIO;
 363   
 364   if (! (main_dev->flags & IFF_UP) )
 365     return NULL;
 366   
 367   /*
 368    * if first alias, must also create alias_info
 369    */
 370       
 371   *err = -ENOMEM;
 372 
 373   if (!alias_info)
 374   { 
 375     alias_info = kmalloc(sizeof(struct net_alias_info), GFP_KERNEL);
 376     if (!alias_info) return NULL; /* ENOMEM */
 377     memset(alias_info, 0, sizeof(struct net_alias_info));
 378   }
 379   
 380   if (!(alias = kmalloc(sizeof(struct net_alias), GFP_KERNEL)))
 381     return NULL;                /* ENOMEM */
 382 
 383   /*
 384    * FIXME: is NULL bitwise 0 for all Linux platforms?
 385    */
 386   
 387   memset(alias, 0, sizeof(struct net_alias));
 388   alias->slot = slot;
 389   alias->main_dev = main_dev;
 390   alias->nat = nat;
 391   alias->next = NULL;
 392   alias->data = data;
 393   sprintf(alias->name, "%s:%d", main_dev->name, slot);
 394   
 395   /*
 396    * initialise alias' device structure
 397    */
 398   
 399   net_alias_devsetup(alias, nat, sa);
 400 
 401   dev = &alias->dev;
 402   
 403   save_flags(flags);
 404   cli();
 405 
 406   /*
 407    * bind alias to its object type
 408    * nat_bind calls nat->alias_init_1
 409    */
 410   
 411   nat_bind(nat, alias, sa);
 412 
 413   /*
 414    * if no address passed, take from device (could have been
 415    * set by nat->alias_init_1)
 416    */
 417   
 418   addr32 = (sa)? nat_addr32(nat, sa) : alias->dev.pa_addr;
 419   
 420   /*
 421    * store hash key in alias: will speed-up rehashing and deletion
 422    */
 423   
 424   alias->hash = HASH(addr32, family);
 425 
 426   /*
 427    * insert alias in hashed linked list
 428    */
 429   
 430   aliasp = &alias_info->hash_tab[alias->hash];
 431   alias->next = *aliasp;        
 432   *aliasp = alias;
 433 
 434   /*
 435    * if first alias ...
 436    */
 437   
 438   if (!alias_info->n_aliases++)
 439   {
 440     alias_info->taildev = main_dev;
 441     main_dev->alias_info = alias_info;
 442   }
 443   
 444   /*
 445    * add device at tail (just after last main_dev alias)
 446    */
 447   
 448   dev->next = alias_info->taildev->next;
 449   alias_info->taildev->next = dev;
 450   alias_info->taildev = dev;
 451   restore_flags(flags);
 452   return dev;
 453 }
 454 
 455 
 456 /*
 457  * delete one main_dev alias (referred by its slot num)
 458  */
 459 
 460 static struct device *
 461 net_alias_dev_delete(struct device *main_dev, int slot, int *err)
     /* [previous][next][first][last][top][bottom][index][help] */
 462 {
 463   struct net_alias_info *alias_info;
 464   struct net_alias *alias, **aliasp;
 465   struct device *dev;
 466   unsigned n_aliases;
 467   unsigned long flags;
 468   struct net_alias_type *nat;
 469   struct device *prevdev;
 470   
 471   /* FIXME: lock */
 472   *err = -ENODEV;
 473   
 474   if (main_dev == NULL) return NULL;
 475 
 476   /*
 477    * does main_dev have aliases?
 478    */
 479   
 480   alias_info = main_dev->alias_info;
 481   if (!alias_info) return NULL; /* ENODEV */
 482   
 483   n_aliases = alias_info->n_aliases;
 484   
 485   /*
 486    * find device that holds the same slot number (could also
 487    * be strcmp() ala dev_get).
 488    */
 489   
 490   for (prevdev=main_dev, alias = NULL;prevdev->next && n_aliases; prevdev = prevdev->next)
 491   {
 492     if (!(alias = prevdev->next->my_alias))
 493     {
 494       printk("ERROR: net_alias_dev_delete(): incorrect non-alias device after maindev\n");
 495       continue;                 /* or should give up? */
 496     }
 497     if (alias->slot == slot) break;
 498     alias = NULL;
 499     n_aliases--;
 500   }
 501   
 502   if (!alias) return NULL;      /* ENODEV */
 503   
 504   dev = &alias->dev;
 505   
 506   /*
 507    * find alias hashed entry
 508    */
 509   
 510   for(aliasp = &alias_info->hash_tab[alias->hash]; *aliasp; aliasp = &(*aliasp)->next)
 511     if(*aliasp == alias) break;
 512 
 513   /*
 514    * if not found (???), try a full search
 515    */
 516   
 517   if (*aliasp != alias)
 518     if ((aliasp = net_alias_slow_findp(alias_info, alias)))
 519       printk("net_alias_dev_delete(%s): bad hashing recovered\n", alias->name);
 520     else
 521     {
 522       printk("ERROR: net_alias_dev_delete(%s): unhashed alias!\n",alias->name);
 523       return NULL;              /* ENODEV */
 524     }
 525   
 526   nat = alias->nat;
 527 
 528   save_flags(flags);
 529   cli();
 530   
 531   /*
 532    * unbind alias from alias_type obj.
 533    */
 534   
 535   nat_unbind(nat, alias);
 536   
 537   /*
 538    * is alias at tail?
 539    */
 540   
 541   if ( dev == alias_info->taildev )
 542     alias_info->taildev = prevdev;
 543   
 544   /*
 545    * unlink and close device
 546    */
 547   prevdev->next = dev->next;
 548   dev_close(dev);
 549   
 550   /*
 551    * unlink alias
 552    */
 553   
 554   *aliasp = (*aliasp)->next;
 555 
 556   if (--alias_info->n_aliases == 0) /* last alias */
 557     main_dev->alias_info = NULL;
 558   restore_flags(flags);
 559 
 560   /*
 561    * now free structures
 562    */
 563   
 564   kfree_s(alias, sizeof(struct net_alias));
 565   if (main_dev->alias_info == NULL)
 566     kfree_s(alias_info, sizeof(struct net_alias_info));
 567 
 568   /*
 569    * deletion ok (*err=0), NULL device returned.
 570    */
 571   
 572   *err = 0;
 573   return NULL;
 574 }
 575 
 576 
 577 /*
 578  * dev_get() with added alias naming magic.
 579  */
 580 
 581 struct device *
 582 net_alias_dev_get(char *dev_name, int aliasing_ok, int *err,
     /* [previous][next][first][last][top][bottom][index][help] */
 583                   struct sockaddr *sa, void *data)
 584 {
 585   struct device *dev;
 586   char *sptr,*eptr;
 587   int slot = 0;
 588   int delete = 0;
 589   
 590   *err = -ENODEV;
 591   if ((dev=dev_get(dev_name)))
 592     return dev;
 593 
 594   /*
 595    * want alias naming magic?
 596    */
 597   
 598   if (!aliasing_ok) return NULL;
 599 
 600   if (!dev_name || !*dev_name)
 601     return NULL;
 602   
 603   /*
 604    * find the first ':' , must be followed by, at least, 1 char
 605    */
 606   
 607   for (sptr=dev_name ; *sptr ; sptr++) if(*sptr==':') break;
 608   if (!*sptr || !*(sptr+1))
 609     return NULL;
 610   
 611   /*
 612    * seems to be an alias name, fetch main device
 613    */
 614   
 615   *sptr='\0';
 616   if (!(dev=dev_get(dev_name)))
 617     return NULL;
 618   *sptr++=':';
 619   
 620   /*
 621    * fetch slot number
 622    */
 623   
 624   slot = simple_strtoul(sptr,&eptr,10);
 625   if (slot >= NET_ALIAS_MAX_SLOT)
 626     return NULL;
 627 
 628   /*
 629    * if last char is '-', it is a deletion request
 630    */
 631   
 632   if (eptr[0] == '-' && !eptr[1] ) delete++;
 633   else if (eptr[0])
 634     return NULL;
 635   
 636   /*
 637    * well... let's work.
 638    */
 639   
 640   if (delete)
 641     return net_alias_dev_delete(dev, slot, err);
 642   else
 643     return net_alias_dev_create(dev, slot, err, sa, data);
 644 }
 645 
 646 
 647 /*
 648  * rehash alias with address supplied. 
 649  */
 650 
 651 int
 652 net_alias_rehash(struct net_alias *alias, struct sockaddr *sa)
     /* [previous][next][first][last][top][bottom][index][help] */
 653 {
 654   struct net_alias_info *alias_info;
 655   struct net_alias **aliasp;
 656   struct device *dev;
 657   unsigned long flags;
 658   struct net_alias_type *o_nat, *n_nat;
 659   unsigned n_hash;
 660   
 661   /*
 662    * defensive ...
 663    */
 664   
 665   if (!sa)
 666   {
 667     printk("ERROR: net_alias_rehash(): NULL sockaddr passed\n");
 668     return -1;
 669   }
 670 
 671   /*
 672    * defensive. should not happen.
 673    */
 674   
 675   if (!(dev = alias->main_dev))
 676   {
 677     printk("ERROR: net_alias_rehash for %s: NULL maindev\n", alias->name);
 678     return -1;
 679   }
 680 
 681   /*
 682    * defensive. should not happen.
 683    */
 684 
 685   if (!(alias_info=dev->alias_info))
 686   {
 687     printk("ERROR: net_alias_rehash for %s: NULL alias_info\n", alias->name);
 688     return -1;
 689   }
 690   
 691   /*
 692    * will the request also change device family?
 693    */
 694   
 695   o_nat = alias->nat;
 696   if (!o_nat)
 697   {
 698     printk("ERROR: net_alias_rehash(%s): unbound alias.\n", alias->name);
 699     return -1;
 700   }
 701 
 702   /*
 703    * point to new alias_type obj.
 704    */
 705   
 706   if (o_nat->type == sa->sa_family)
 707     n_nat = o_nat;
 708   else
 709   {
 710     n_nat = nat_getbytype(sa->sa_family);
 711     if (!n_nat)
 712     {
 713       printk("ERROR: net_alias_rehash(%s): unreg family==%d.\n", alias->name, sa->sa_family);
 714       return -1;
 715     }
 716   }
 717   
 718   /*
 719    * new hash key. if same as old AND same type (family) return;
 720    */
 721   
 722   n_hash = nat_hash_key(n_nat, sa);
 723   if (n_hash == alias->hash && o_nat == n_nat )
 724     return 0;
 725 
 726   /*
 727    * find alias in hashed list
 728    */
 729   
 730   for (aliasp = &alias_info->hash_tab[alias->hash]; *aliasp; aliasp = &(*aliasp)->next)
 731     if (*aliasp == alias) break;
 732   
 733   /*
 734    * not found (???). try a full search
 735    */
 736   
 737   if(!*aliasp)
 738     if ((aliasp = net_alias_slow_findp(alias_info, alias)))
 739       printk("net_alias_rehash(%s): bad hashing recovered\n", alias->name);
 740     else
 741     {
 742       printk("ERROR: net_alias_rehash(%s): unhashed alias!\n", alias->name);
 743       return -1;
 744     }
 745   
 746   save_flags(flags);
 747   cli();
 748   
 749   /*
 750    * if type (family) changed unlink from old type object (o_nat)
 751    * will call o_nat->alias_done_1()
 752    */
 753   
 754   if (o_nat != n_nat)
 755     nat_unbind(o_nat, alias);
 756 
 757   /*
 758    * if diff hash key, change alias position in hashed list
 759    */
 760   
 761   if (n_hash != alias->hash)
 762   {
 763     *aliasp = (*aliasp)->next;
 764     alias->hash = n_hash;
 765     aliasp = &alias_info->hash_tab[n_hash];
 766     alias->next = *aliasp;
 767     *aliasp = alias;
 768   }
 769   
 770   /*
 771    * if type (family) changed link to new type object (n_nat)
 772    * will call n_nat->alias_init_1()
 773    */
 774   
 775   if (o_nat != n_nat)
 776     nat_bind(n_nat, alias, sa);
 777   
 778   restore_flags(flags);
 779   return 0;
 780 }
 781 
 782 
 783 /*
 784  * free all main device aliasing stuff
 785  * will be called on dev_close(main_dev)
 786  */
 787 
 788 static void
 789 net_alias_free(struct device *main_dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 790 {
 791   struct net_alias_info *alias_info;
 792   struct net_alias *alias;
 793   struct net_alias_type *nat;
 794   struct device *dev;
 795   unsigned long flags;
 796 
 797   /*
 798    * do I really have aliases?
 799    */
 800   
 801   if (!(alias_info = main_dev->alias_info))    return;
 802 
 803   /*
 804    * fast device link "short-circuit": set main_dev->next to
 805    * device after last alias
 806    */
 807   
 808   save_flags(flags);
 809   cli();
 810   
 811   dev =  main_dev->next;
 812   main_dev->next = alias_info->taildev->next;
 813   main_dev->alias_info = NULL;
 814   alias_info->taildev->next = NULL;
 815   
 816   restore_flags(flags);
 817 
 818   /*
 819    * loop over alias devices, free and dev_close()
 820    */
 821   
 822   while (dev)
 823   {
 824     if (net_alias_is(dev))
 825     {
 826       alias = dev->my_alias;
 827       if (alias->main_dev == main_dev)
 828       {
 829         /*
 830          * unbind alias from alias_type object
 831          */
 832         
 833         nat = alias->nat;
 834         if (nat)
 835         {
 836           nat_unbind(nat, alias);
 837         } /*  else error/printk ??? */
 838         
 839         dev_close(dev);
 840         dev = dev->next;
 841         
 842         kfree_s(alias, sizeof(struct net_alias));
 843         continue;
 844       }
 845       else
 846         printk("net_alias_free(%s): '%s' is not my alias\n",
 847                main_dev->name, alias->name);
 848     }
 849     else
 850       printk("net_alias_free(%s): found a non-alias after device!\n",
 851              main_dev->name);
 852     dev = dev->next;
 853   }
 854   
 855   kfree_s(alias_info, sizeof(alias_info));
 856   return;
 857 }
 858 
 859 
 860 /*
 861  *  implements /proc/net/alias_types entry
 862  *  shows net_alias_type objects registered.
 863  */
 864 
 865 int net_alias_types_getinfo(char *buffer, char **start, off_t offset, int length, int dummy)
     /* [previous][next][first][last][top][bottom][index][help] */
 866 {
 867   off_t pos=0, begin=0;
 868   int len=0;
 869   struct net_alias_type *nat;
 870   unsigned idx;
 871   len=sprintf(buffer,"type    name            n_attach\n");
 872   for (idx=0 ; idx < 16 ; idx++)
 873     for (nat = nat_base[idx]; nat ; nat = nat->next)
 874     {
 875       len += sprintf(buffer+len, "%-7d %-15s %-7d\n",
 876                      nat->type, nat->name,nat->n_attach);
 877       pos=begin+len;
 878       if(pos<offset)
 879       {
 880         len=0;
 881         begin=pos;
 882       }
 883       if(pos>offset+length)
 884         break;
 885     }
 886   *start=buffer+(offset-begin);
 887   len-=(offset-begin);
 888   if(len>length)
 889     len=length; 
 890   return len;
 891 }
 892 
 893 
 894 /*
 895  *  implements /proc/net/aliases entry, shows alias devices.
 896  *   calls alias nat->alias_print_1 if not NULL and formats everything
 897  *   to a fixed rec. size without using local (stack) buffers
 898  *
 899  */
 900 
 901 #define NAT_REC_SIZE 64
 902 int net_alias_getinfo(char *buffer, char **start, off_t offset, int length, int dummy)
     /* [previous][next][first][last][top][bottom][index][help] */
 903 {
 904   off_t pos=0, begin=0;
 905   int len=0;
 906   int dlen;
 907   struct net_alias_type *nat;
 908   struct net_alias *alias;
 909   struct device *dev;
 910 
 911   len=sprintf(buffer,"%-*s\n",NAT_REC_SIZE-1,"device           family address");
 912   for (dev = dev_base; dev ; dev = dev->next)
 913     if (net_alias_is(dev))
 914     {
 915       alias = dev->my_alias;
 916       nat = alias->nat;
 917       dlen=sprintf(buffer+len, "%-16s %-6d ", alias->name, alias->dev.family);
 918       
 919       /*
 920        * call alias_type specific print function.
 921        */
 922       
 923       if (nat->alias_print_1)
 924         dlen += nat->alias_print_1(buffer+len+dlen, NAT_REC_SIZE - dlen, alias);
 925       else
 926         dlen += sprintf(buffer+len+dlen, "-");
 927 
 928       /*
 929        * fill with spaces if needed 
 930        */
 931       
 932       if (dlen < NAT_REC_SIZE) memset(buffer+len+dlen, ' ', NAT_REC_SIZE - dlen);
 933       /*
 934        * truncate to NAT_REC_SIZE
 935        */
 936       
 937       len += NAT_REC_SIZE;
 938       buffer[len-1] = '\n';
 939       
 940       pos=begin+len;
 941       if(pos<offset)
 942       {
 943         len=0;
 944         begin=pos;
 945       }
 946       if(pos>offset+length)
 947         break;
 948     }
 949   *start=buffer+(offset-begin);
 950   len-=(offset-begin);
 951   if(len>length)
 952     len=length; 
 953   return len;
 954 }
 955 
 956 
 957 /*
 958  * notifier for devices events
 959  */
 960 
 961 int net_alias_device_event(struct notifier_block *this, unsigned long event, void *ptr)
     /* [previous][next][first][last][top][bottom][index][help] */
 962 {
 963   struct device *dev = ptr;
 964 
 965   if (event == NETDEV_DOWN)
 966   {
 967 #ifdef ALIAS_USER_LAND_DEBUG
 968     printk("net_alias: NETDEV_DOWN for %s received\n", dev->name);
 969 #endif
 970     if (net_alias_has(dev))
 971       net_alias_free(dev);
 972   }
 973 
 974   if (event == NETDEV_UP)
 975   {
 976 #ifdef ALIAS_USER_LAND_DEBUG
 977     printk("net_alias: NETDEV_UP for %s received\n", dev->name);
 978 #endif
 979     dev->alias_info = 0;
 980   }
 981 
 982   return NOTIFY_DONE;
 983 }
 984 
 985 
 986 /*
 987  * returns alias device with specified address AND flags_1 on AND flags_0 off.
 988  *   intended for main devices.
 989  *   typically called on xxx_rcv() to check if packet's dest address is one
 990  *   of main_dev's alias address.
 991  */
 992 
 993 struct device *
 994 net_alias_chk(struct device *dev, struct sockaddr *sa,int flags_1, int flags_0)
     /* [previous][next][first][last][top][bottom][index][help] */
 995 {
 996   struct net_alias_info *alias_info = dev->alias_info;
 997   struct net_alias_type *nat;
 998   struct net_alias *alias;
 999   
1000   if (!alias_info) return NULL; /* has aliases? */
1001   
1002   /*
1003    * get alias_type object for sa->sa_family.
1004    */
1005   
1006   nat = nat_getbytype(sa->sa_family);
1007   if (!nat)
1008     return 0;
1009   
1010   for(alias = alias_info->hash_tab[nat_hash_key(nat,sa)];
1011       alias; alias = alias->next)
1012   {
1013     if (alias->dev.family != sa->sa_family) continue;
1014 
1015     /*
1016      * nat_addr_chk will call type specific address cmp function.
1017      */
1018     
1019     if (alias->dev.flags & flags_1 && !(alias->dev.flags & flags_0) &&
1020         nat_addr_chk(nat,&alias->dev,sa))
1021       return &alias->dev;
1022   }
1023   return NULL;
1024 }
1025 
1026 /*
1027  * addr_chk enough for protocols whose addr is (fully) stored at pa_addr.
1028  */
1029 
1030 struct device *
1031 net_alias_chk32(struct device *dev, int family, __u32 addr32,
     /* [previous][next][first][last][top][bottom][index][help] */
1032                 int flags_1, int flags_0)
1033 {
1034   struct net_alias_info *alias_info = dev->alias_info;
1035   struct net_alias *alias;
1036   
1037   if (!alias_info) return NULL; /* has aliases? */
1038   
1039   for (alias=alias_info->hash_tab[HASH(addr32,family)];
1040        alias; alias=alias->next)
1041   {
1042     if (alias->dev.family != family) continue;
1043     
1044     /*
1045      * "hard" (static) comparison between addr32 and pa_addr.
1046      */
1047     
1048     if (alias->dev.flags & flags_1 && !(alias->dev.flags & flags_0) &&
1049         addr32 == alias->dev.pa_addr)
1050       return &alias->dev;
1051   }
1052   return NULL;
1053 }
1054 
1055 
1056 /*
1057  * device event hook
1058  */
1059 
1060 static struct notifier_block net_alias_dev_notifier = {
1061   net_alias_device_event,
1062   NULL,
1063   0
1064 };
1065 
1066 
1067 /*
1068  * net_alias initialisation
1069  * called from net_dev_init().
1070  */
1071 
1072 void net_alias_init(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1073 {
1074 
1075   /*
1076    * register dev events notifier
1077    */
1078   
1079   register_netdevice_notifier(&net_alias_dev_notifier);
1080 
1081   /*
1082    * register /proc/net entries
1083    */
1084   
1085 #ifndef ALIAS_USER_LAND_DEBUG
1086   proc_net_register(&(struct proc_dir_entry) {
1087     PROC_NET_ALIAS_TYPES, 11, "alias_types",
1088     S_IFREG | S_IRUGO, 1, 0, 0,
1089     0, &proc_net_inode_operations,
1090     net_alias_types_getinfo
1091   });
1092   proc_net_register(&(struct proc_dir_entry) {
1093     PROC_NET_ALIASES, 7, "aliases",
1094     S_IFREG | S_IRUGO, 1, 0, 0,
1095     0, &proc_net_inode_operations,
1096     net_alias_getinfo
1097   });
1098 #endif
1099   
1100 }
1101 
1102 /*
1103  * net_alias type object registering func.
1104  */
1105 int register_net_alias_type(struct net_alias_type *nat, int type)
     /* [previous][next][first][last][top][bottom][index][help] */
1106 {
1107   unsigned hash;
1108   unsigned long flags;
1109   if (!nat)
1110   {
1111     printk("register_net_alias_type(): NULL arg\n");
1112     return -EINVAL;
1113   }
1114   nat->type = type;
1115   nat->n_attach = 0;
1116   hash = nat->type & 0x0f;
1117   save_flags(flags);
1118   cli();
1119   nat->next = nat_base[hash];
1120   nat_base[hash] = nat;
1121   restore_flags(flags);
1122   return 0;
1123 }
1124 
1125 /*
1126  * net_alias type object unreg.
1127  */
1128 int unregister_net_alias_type(struct net_alias_type *nat)
     /* [previous][next][first][last][top][bottom][index][help] */
1129 {
1130   struct net_alias_type **natp;
1131   unsigned hash;
1132   unsigned long flags;
1133   
1134   if (!nat)
1135   {
1136     printk("unregister_net_alias_type(): NULL arg\n");
1137     return -EINVAL;
1138   }
1139 
1140   /*
1141    * only allow unregistration if it has no attachments
1142    */
1143   if (nat->n_attach)
1144   {
1145     printk("unregister_net_alias_type(): has %d attachments. failed\n",
1146            nat->n_attach);
1147     return -EINVAL;
1148   }
1149   hash = nat->type & 0x0f;
1150   save_flags(flags);
1151   cli();
1152   for (natp = &nat_base[hash]; *natp ; natp = &(*natp)->next)
1153   {
1154     if (nat==(*natp))
1155     {
1156       *natp = nat->next;
1157       restore_flags(flags);
1158       return 0;
1159     }
1160   }
1161   restore_flags(flags);
1162   printk("unregister_net_alias_type(type=%d): not found!\n", nat->type);
1163   return -EINVAL;
1164 }

/* [previous][next][first][last][top][bottom][index][help] */