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_dev_addr_chk_1
  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_free
  16. net_alias_dev_get
  17. net_alias_dev_rehash
  18. net_alias_types_getinfo
  19. net_alias_getinfo
  20. net_alias_device_event
  21. nat_addr_chk
  22. nat_addr_chk32
  23. net_alias_dev_chk
  24. net_alias_dev_chk32
  25. net_alias_dev_rcv_sel
  26. net_alias_dev_rcv_sel32
  27. net_alias_init
  28. register_net_alias_type
  29. unregister_net_alias_type

   1 /*
   2  *              NET_ALIAS network device aliasing module.
   3  *
   4  *
   5  * Version:     @(#)net_alias.c 0.43   12/20/95
   6  *
   7  * Authors:     Juan Jose Ciarlante, <jjciarla@raiz.uncu.edu.ar>
   8  *              Marcelo Fabian Roccasalva, <mfroccas@raiz.uncu.edu.ar>
   9  *
  10  * Features:
  11  *      -       AF_ independent: net_alias_type objects
  12  *      -       AF_INET optimized
  13  *      -       ACTUAL alias devices inserted in dev chain
  14  *      -       fast hashed alias address lookup
  15  *      -       net_alias_type objs registration/unreg., module-ables.
  16  *      -       /proc/net/aliases & /proc/net/alias_types entries
  17  * Fixes:
  18  *      JJC     :       several net_alias_type func. renamed.
  19  *      JJC     :       net_alias_type object methods now pass *this.
  20  *      JJC     :       xxx_rcv device selection based on <src,dst> addrs
  21  *
  22  * FIXME:
  23  *      - User calls sleep/wake_up locking.
  24  *
  25  *
  26  *      This program is free software; you can redistribute it and/or
  27  *      modify it under the terms of the GNU General Public License
  28  *      as published by the Free Software Foundation; either version
  29  *      2 of the License, or (at your option) any later version.
  30  *      
  31  */
  32 
  33 #include <linux/types.h>
  34 #include <linux/errno.h>
  35 #include <linux/netdevice.h>
  36 #include <linux/notifier.h>
  37 #include <linux/if.h>
  38 #include <linux/inet.h>
  39 #include <linux/in.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 obj hashed list heads.
  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(nat, 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 a 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(nat, alias, sa);
 170   return nat_attach_chg(nat, +1);
 171 }
 172 
 173 
 174 /*
 175  * unbind alias from type object and call alias destructor
 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(nat, alias);
 182   return nat_attach_chg(nat, -1);
 183 }
 184 
 185 
 186 /*
 187  * compare device address with given. if NULL nat->dev_addr_chk,
 188  * compare dev->pa_addr with (sockaddr_in) 32 bits address (IP-ish)
 189  */
 190 
 191 static __inline__ int nat_dev_addr_chk_1(struct net_alias_type *nat,
     /* [previous][next][first][last][top][bottom][index][help] */
 192                                    struct device *dev, struct sockaddr *sa)
 193 {
 194   if (nat->dev_addr_chk)
 195     return nat->dev_addr_chk(nat, 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  * free all main device aliasing stuff
 578  * will be called on dev_close(main_dev)
 579  */
 580 
 581 static void
 582 net_alias_free(struct device *main_dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 583 {
 584   struct net_alias_info *alias_info;
 585   struct net_alias *alias;
 586   struct net_alias_type *nat;
 587   struct device *dev;
 588   unsigned long flags;
 589 
 590   /*
 591    * do I really have aliases?
 592    */
 593   
 594   if (!(alias_info = main_dev->alias_info))    return;
 595 
 596   /*
 597    * fast device link "short-circuit": set main_dev->next to
 598    * device after last alias
 599    */
 600   
 601   save_flags(flags);
 602   cli();
 603   
 604   dev =  main_dev->next;
 605   main_dev->next = alias_info->taildev->next;
 606   main_dev->alias_info = NULL;
 607   alias_info->taildev->next = NULL;
 608   
 609   restore_flags(flags);
 610 
 611   /*
 612    * loop over alias devices, free and dev_close()
 613    */
 614   
 615   while (dev)
 616   {
 617     if (net_alias_is(dev))
 618     {
 619       alias = dev->my_alias;
 620       if (alias->main_dev == main_dev)
 621       {
 622         /*
 623          * unbind alias from alias_type object
 624          */
 625         
 626         nat = alias->nat;
 627         if (nat)
 628         {
 629           nat_unbind(nat, alias);
 630         } /*  else error/printk ??? */
 631         
 632         dev_close(dev);
 633         dev = dev->next;
 634         
 635         kfree_s(alias, sizeof(struct net_alias));
 636         continue;
 637       }
 638       else
 639         printk("net_alias_free(%s): '%s' is not my alias\n",
 640                main_dev->name, alias->name);
 641     }
 642     else
 643       printk("net_alias_free(%s): found a non-alias after device!\n",
 644              main_dev->name);
 645     dev = dev->next;
 646   }
 647   
 648   kfree_s(alias_info, sizeof(alias_info));
 649   return;
 650 }
 651 
 652 /*
 653  * dev_get() with added alias naming magic.
 654  */
 655 
 656 struct device *
 657 net_alias_dev_get(char *dev_name, int aliasing_ok, int *err,
     /* [previous][next][first][last][top][bottom][index][help] */
 658                   struct sockaddr *sa, void *data)
 659 {
 660   struct device *dev;
 661   char *sptr,*eptr;
 662   int slot = 0;
 663   int delete = 0;
 664   
 665   *err = -ENODEV;
 666   if ((dev=dev_get(dev_name)))
 667     return dev;
 668 
 669   /*
 670    * want alias naming magic?
 671    */
 672   
 673   if (!aliasing_ok) return NULL;
 674 
 675   if (!dev_name || !*dev_name)
 676     return NULL;
 677   
 678   /*
 679    * find the first ':' , must be followed by, at least, 1 char
 680    */
 681   
 682   for (sptr=dev_name ; *sptr ; sptr++) if(*sptr==':') break;
 683   if (!*sptr || !*(sptr+1))
 684     return NULL;
 685   
 686   /*
 687    * seems to be an alias name, fetch main device
 688    */
 689   
 690   *sptr='\0';
 691   if (!(dev=dev_get(dev_name)))
 692     return NULL;
 693   *sptr++=':';
 694   
 695   /*
 696    * fetch slot number
 697    */
 698   
 699   slot = simple_strtoul(sptr,&eptr,10);
 700   if (slot >= NET_ALIAS_MAX_SLOT)
 701     return NULL;
 702 
 703   /*
 704    * if last char is '-', it is a deletion request
 705    */
 706   
 707   if (eptr[0] == '-' && !eptr[1] ) delete++;
 708   else if (eptr[0])
 709     return NULL;
 710   
 711   /*
 712    * well... let's work.
 713    */
 714   
 715   if (delete)
 716     return net_alias_dev_delete(dev, slot, err);
 717   else
 718     return net_alias_dev_create(dev, slot, err, sa, data);
 719 }
 720 
 721 
 722 /*
 723  * rehash alias device with address supplied. 
 724  */
 725 
 726 int
 727 net_alias_dev_rehash(struct device *dev, struct sockaddr *sa)
     /* [previous][next][first][last][top][bottom][index][help] */
 728 {
 729   struct net_alias_info *alias_info;
 730   struct net_alias *alias, **aliasp;
 731   struct device *main_dev;
 732   unsigned long flags;
 733   struct net_alias_type *o_nat, *n_nat;
 734   unsigned n_hash;
 735 
 736   /*
 737    * defensive ...
 738    */
 739   
 740   if (dev == NULL) return -1;
 741   if ( (alias = dev->my_alias) == NULL ) return -1;
 742   
 743   if (!sa)
 744   {
 745     printk("ERROR: net_alias_rehash(): NULL sockaddr passed\n");
 746     return -1;
 747   }
 748 
 749   /*
 750    * defensive. should not happen.
 751    */
 752 
 753   if ( (main_dev = alias->main_dev) == NULL )
 754   {
 755     printk("ERROR: net_alias_rehash for %s: NULL maindev\n", alias->name);
 756     return -1;
 757   }
 758 
 759   /*
 760    * defensive. should not happen.
 761    */
 762 
 763   if (!(alias_info=main_dev->alias_info))
 764   {
 765     printk("ERROR: net_alias_rehash for %s: NULL alias_info\n", alias->name);
 766     return -1;
 767   }
 768   
 769   /*
 770    * will the request also change device family?
 771    */
 772   
 773   o_nat = alias->nat;
 774   if (!o_nat)
 775   {
 776     printk("ERROR: net_alias_rehash(%s): unbound alias.\n", alias->name);
 777     return -1;
 778   }
 779 
 780   /*
 781    * point to new alias_type obj.
 782    */
 783   
 784   if (o_nat->type == sa->sa_family)
 785     n_nat = o_nat;
 786   else
 787   {
 788     n_nat = nat_getbytype(sa->sa_family);
 789     if (!n_nat)
 790     {
 791       printk("ERROR: net_alias_rehash(%s): unreg family==%d.\n", alias->name, sa->sa_family);
 792       return -1;
 793     }
 794   }
 795   
 796   /*
 797    * new hash key. if same as old AND same type (family) return;
 798    */
 799   
 800   n_hash = nat_hash_key(n_nat, sa);
 801   if (n_hash == alias->hash && o_nat == n_nat )
 802     return 0;
 803 
 804   /*
 805    * find alias in hashed list
 806    */
 807   
 808   for (aliasp = &alias_info->hash_tab[alias->hash]; *aliasp; aliasp = &(*aliasp)->next)
 809     if (*aliasp == alias) break;
 810   
 811   /*
 812    * not found (???). try a full search
 813    */
 814   
 815   if(!*aliasp)
 816     if ((aliasp = net_alias_slow_findp(alias_info, alias)))
 817       printk("net_alias_rehash(%s): bad hashing recovered\n", alias->name);
 818     else
 819     {
 820       printk("ERROR: net_alias_rehash(%s): unhashed alias!\n", alias->name);
 821       return -1;
 822     }
 823   
 824   save_flags(flags);
 825   cli();
 826   
 827   /*
 828    * if type (family) changed, unlink from old type object (o_nat)
 829    * will call o_nat->alias_done_1()
 830    */
 831   
 832   if (o_nat != n_nat)
 833     nat_unbind(o_nat, alias);
 834 
 835   /*
 836    * if diff hash key, change alias position in hashed list
 837    */
 838   
 839   if (n_hash != alias->hash)
 840   {
 841     *aliasp = (*aliasp)->next;
 842     alias->hash = n_hash;
 843     aliasp = &alias_info->hash_tab[n_hash];
 844     alias->next = *aliasp;
 845     *aliasp = alias;
 846   }
 847   
 848   /*
 849    * if type (family) changed link to new type object (n_nat)
 850    * will call n_nat->alias_init_1()
 851    */
 852   
 853   if (o_nat != n_nat)
 854     nat_bind(n_nat, alias, sa);
 855   
 856   restore_flags(flags);
 857   return 0;
 858 }
 859 
 860 
 861 
 862 
 863 /*
 864  *  implements /proc/net/alias_types entry
 865  *  shows net_alias_type objects registered.
 866  */
 867 
 868 int net_alias_types_getinfo(char *buffer, char **start, off_t offset, int length, int dummy)
     /* [previous][next][first][last][top][bottom][index][help] */
 869 {
 870   off_t pos=0, begin=0;
 871   int len=0;
 872   struct net_alias_type *nat;
 873   unsigned idx;
 874   len=sprintf(buffer,"type    name            n_attach\n");
 875   for (idx=0 ; idx < 16 ; idx++)
 876     for (nat = nat_base[idx]; nat ; nat = nat->next)
 877     {
 878       len += sprintf(buffer+len, "%-7d %-15s %-7d\n",
 879                      nat->type, nat->name,nat->n_attach);
 880       pos=begin+len;
 881       if(pos<offset)
 882       {
 883         len=0;
 884         begin=pos;
 885       }
 886       if(pos>offset+length)
 887         break;
 888     }
 889   *start=buffer+(offset-begin);
 890   len-=(offset-begin);
 891   if(len>length)
 892     len=length; 
 893   return len;
 894 }
 895 
 896 
 897 /*
 898  *  implements /proc/net/aliases entry, shows alias devices.
 899  *   calls alias nat->alias_print_1 if not NULL and formats everything
 900  *   to a fixed rec. size without using local (stack) buffers
 901  *
 902  */
 903 
 904 #define NET_ALIASES_RECSIZ 64
 905 int net_alias_getinfo(char *buffer, char **start, off_t offset, int length, int dummy)
     /* [previous][next][first][last][top][bottom][index][help] */
 906 {
 907   off_t pos=0, begin=0;
 908   int len=0;
 909   int dlen;
 910   struct net_alias_type *nat;
 911   struct net_alias *alias;
 912   struct device *dev;
 913 
 914   len=sprintf(buffer,"%-*s\n",NET_ALIASES_RECSIZ-1,"device           family address");
 915   for (dev = dev_base; dev ; dev = dev->next)
 916     if (net_alias_is(dev))
 917     {
 918       alias = dev->my_alias;
 919       nat = alias->nat;
 920       dlen=sprintf(buffer+len, "%-16s %-6d ", alias->name, alias->dev.family);
 921       
 922       /*
 923        * call alias_type specific print function.
 924        */
 925       
 926       if (nat->alias_print_1)
 927         dlen += nat->alias_print_1(nat, alias, buffer+len+dlen, NET_ALIASES_RECSIZ - dlen);
 928       else
 929         dlen += sprintf(buffer+len+dlen, "-");
 930 
 931       /*
 932        * fill with spaces if needed 
 933        */
 934       
 935       if (dlen < NET_ALIASES_RECSIZ) memset(buffer+len+dlen, ' ', NET_ALIASES_RECSIZ - dlen);
 936       /*
 937        * truncate to NET_ALIASES_RECSIZ
 938        */
 939       
 940       len += NET_ALIASES_RECSIZ;
 941       buffer[len-1] = '\n';
 942       
 943       pos=begin+len;
 944       if(pos<offset)
 945       {
 946         len=0;
 947         begin=pos;
 948       }
 949       if(pos>offset+length)
 950         break;
 951     }
 952   *start=buffer+(offset-begin);
 953   len-=(offset-begin);
 954   if(len>length)
 955     len=length; 
 956   return len;
 957 }
 958 
 959 
 960 /*
 961  * notifier for devices events
 962  */
 963 
 964 int net_alias_device_event(struct notifier_block *this, unsigned long event, void *ptr)
     /* [previous][next][first][last][top][bottom][index][help] */
 965 {
 966   struct device *dev = ptr;
 967 
 968   if (event == NETDEV_DOWN)
 969   {
 970 #ifdef ALIAS_USER_LAND_DEBUG
 971     printk("net_alias: NETDEV_DOWN for %s received\n", dev->name);
 972 #endif
 973     if (net_alias_has(dev))
 974       net_alias_free(dev);
 975   }
 976 
 977   if (event == NETDEV_UP)
 978   {
 979 #ifdef ALIAS_USER_LAND_DEBUG
 980     printk("net_alias: NETDEV_UP for %s received\n", dev->name);
 981 #endif
 982     dev->alias_info = 0;
 983   }
 984 
 985   return NOTIFY_DONE;
 986 }
 987 
 988 
 989 /*
 990  * device aliases address comparison workhorse
 991  * no checks for nat and alias_info, must be !NULL
 992  */
 993 
 994 static __inline__ struct device *
 995 nat_addr_chk(struct net_alias_type *nat, struct net_alias_info *alias_info, struct sockaddr *sa, int flags_on, int flags_off)
     /* [previous][next][first][last][top][bottom][index][help] */
 996 {
 997   struct net_alias *alias;
 998   for(alias = alias_info->hash_tab[nat_hash_key(nat,sa)];
 999       alias; alias = alias->next)
1000   {
1001     if (alias->dev.family != sa->sa_family) continue;
1002 
1003     /*
1004      * nat_dev_addr_chk_1 will call type specific address cmp function.
1005      */
1006     
1007     if (alias->dev.flags & flags_on && !(alias->dev.flags & flags_off) &&
1008         nat_dev_addr_chk_1(nat,&alias->dev,sa))
1009       return &alias->dev;
1010   }
1011   return NULL;
1012 }
1013 
1014 /*
1015  * nat_addr_chk enough for protocols whose addr is (fully) stored at pa_addr.
1016  * note that nat pointer is ignored because of static comparison.
1017  */
1018 
1019 static __inline__ struct device *
1020 nat_addr_chk32(struct net_alias_type *nat, struct net_alias_info *alias_info, int family, __u32 addr32, int flags_on, int flags_off)
     /* [previous][next][first][last][top][bottom][index][help] */
1021 {
1022   struct net_alias *alias;
1023   for (alias=alias_info->hash_tab[HASH(addr32,family)];
1024        alias; alias=alias->next)
1025   {
1026     if (alias->dev.family != family) continue;
1027     
1028     /*
1029      * "hard" (static) comparison between addr32 and pa_addr.
1030      */
1031     
1032     if (alias->dev.flags & flags_on && !(alias->dev.flags & flags_off) &&
1033         addr32 == alias->dev.pa_addr)
1034       return &alias->dev;
1035   }
1036   return NULL;
1037 }
1038 
1039 /*
1040  * returns alias device with specified address AND flags_on AND flags_off,
1041  * else NULL.
1042  * intended for main devices.
1043  */
1044 
1045 struct device *
1046 net_alias_dev_chk(struct device *main_dev, struct sockaddr *sa,int flags_on, int flags_off)
     /* [previous][next][first][last][top][bottom][index][help] */
1047 {
1048   struct net_alias_info *alias_info = main_dev->alias_info;
1049   struct net_alias_type *nat;
1050   
1051   /*
1052    * only if main_dev has aliases
1053    */
1054 
1055   if (!alias_info) return NULL;
1056   
1057   /*
1058    * get alias_type object for sa->sa_family.
1059    */
1060   
1061   nat = nat_getbytype(sa->sa_family);
1062   if (!nat)
1063     return NULL;
1064 
1065   return nat_addr_chk(nat, alias_info, sa, flags_on, flags_off);
1066 }
1067 
1068 /*
1069  * net_alias_dev_chk enough for protocols whose addr is (fully) stored
1070  * at pa_addr.
1071  */
1072 
1073 struct device *
1074 net_alias_dev_chk32(struct device *main_dev, int family, __u32 addr32,
     /* [previous][next][first][last][top][bottom][index][help] */
1075                 int flags_on, int flags_off)
1076 {
1077   struct net_alias_info *alias_info = main_dev->alias_info;
1078   
1079   /*
1080    * only if main_dev has aliases
1081    */
1082 
1083   if (!alias_info) return NULL;
1084   
1085   return nat_addr_chk32(NULL, alias_info, family, addr32, flags_on, flags_off);
1086 }
1087 
1088 
1089 /*
1090  * select closest (main or alias) device to <src,dst> addresses given. if no
1091  * further info is available, return main_dev (for easier calling arrangment).
1092  *
1093  * Should be called early at xxx_rcv() time for device selection
1094  */
1095 
1096 struct device *
1097 net_alias_dev_rcv_sel(struct device *main_dev, struct sockaddr *sa_src, struct sockaddr *sa_dst)
     /* [previous][next][first][last][top][bottom][index][help] */
1098 {
1099   int family;
1100   struct net_alias_type *nat;
1101   struct net_alias_info *alias_info;
1102   struct device *dev;
1103   
1104   if (main_dev == NULL) return NULL;
1105 
1106   /*
1107    * if not aliased, dont bother any more
1108    */
1109 
1110   if ((alias_info = main_dev->alias_info) == NULL)
1111     return main_dev;
1112 
1113   /*
1114    * find out family
1115    */
1116 
1117   family = (sa_src)? sa_src->sa_family : ((sa_dst)? sa_dst->sa_family : AF_UNSPEC);
1118   if (family == AF_UNSPEC) return main_dev;
1119 
1120   /*
1121    * get net_alias_type object for this family
1122    */
1123 
1124   if ( (nat = nat_getbytype(family)) == NULL ) return main_dev;
1125   
1126   /*
1127    * first step: find out if dst addr is main_dev's or one of its aliases'
1128    */
1129 
1130   if (sa_dst)
1131   {
1132     if (nat_dev_addr_chk_1(nat, main_dev,sa_dst))
1133       return main_dev;
1134 
1135     dev = nat_addr_chk(nat, alias_info, sa_dst, IFF_UP, 0);
1136 
1137     if (dev != NULL) return dev;
1138   }
1139 
1140   /*
1141    * second step: find the rcv addr 'closest' alias through nat method call
1142    */
1143 
1144   if ( sa_src == NULL || nat->dev_select == NULL) return main_dev;
1145   dev = nat->dev_select(nat, main_dev, sa_src);
1146 
1147   if (dev == NULL || dev->family != family) return main_dev;
1148   
1149   /*
1150    * dev ok only if it is alias of main_dev
1151    */
1152   
1153   dev = net_alias_is(dev)?
1154     ( (dev->my_alias->main_dev == main_dev)? dev : NULL) : NULL;
1155 
1156   /*
1157    * do not return NULL.
1158    */
1159   
1160   return (dev)? dev : main_dev;
1161 
1162 }
1163 
1164 /*
1165  * dev_rcv_sel32: dev_rcv_sel for 'pa_addr' protocols.
1166  */
1167 
1168 struct device *
1169 net_alias_dev_rcv_sel32(struct device *main_dev, int family, __u32 src, __u32 dst)
     /* [previous][next][first][last][top][bottom][index][help] */
1170 {
1171   struct net_alias_type *nat;
1172   struct net_alias_info *alias_info;
1173   struct sockaddr_in sin_src;
1174   struct device *dev;
1175   
1176   if (main_dev == NULL) return NULL;
1177 
1178   /*
1179    * if not aliased, dont bother any more
1180    */
1181 
1182   if ((alias_info = main_dev->alias_info) == NULL)
1183     return main_dev;
1184 
1185   /*
1186    * early return if dst is main_dev's address
1187    */
1188   
1189   if (dst == main_dev->pa_addr)
1190     return main_dev;
1191   
1192   if (family == AF_UNSPEC) return main_dev;
1193 
1194   /*
1195    * get net_alias_type object for this family
1196    */
1197 
1198   if ( (nat = nat_getbytype(family)) == NULL ) return main_dev;
1199   
1200   /*
1201    * first step: find out if dst address one of main_dev aliases'
1202    */
1203   
1204   if (dst)
1205   {
1206     dev = nat_addr_chk32(nat, alias_info, family, dst, IFF_UP, 0);
1207     if (dev) return dev;
1208   }
1209   
1210   /*
1211    * second step: find the rcv addr 'closest' alias through nat method call
1212    */
1213 
1214   if ( src == 0 || nat->dev_select == NULL) return main_dev;
1215 
1216   sin_src.sin_family = family;
1217   sin_src.sin_addr.s_addr = src;
1218     
1219   dev = nat->dev_select(nat, main_dev, (struct sockaddr *)&sin_src);
1220 
1221   if (dev == NULL) return main_dev;
1222   
1223   /*
1224    * dev ok only if it is alias of main_dev
1225    */
1226   
1227   dev = net_alias_is(dev)?
1228     ( (dev->my_alias->main_dev == main_dev)? dev : NULL) : NULL;
1229 
1230   /*
1231    * do not return NULL.
1232    */
1233   
1234   return (dev)? dev : main_dev;
1235   
1236 }
1237 
1238 
1239 /*
1240  * device event hook
1241  */
1242 
1243 static struct notifier_block net_alias_dev_notifier = {
1244   net_alias_device_event,
1245   NULL,
1246   0
1247 };
1248 
1249 
1250 /*
1251  * net_alias initialisation
1252  * called from net_dev_init().
1253  */
1254 
1255 void net_alias_init(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1256 {
1257 
1258   /*
1259    * register dev events notifier
1260    */
1261   
1262   register_netdevice_notifier(&net_alias_dev_notifier);
1263 
1264   /*
1265    * register /proc/net entries
1266    */
1267   
1268 #ifndef ALIAS_USER_LAND_DEBUG
1269   proc_net_register(&(struct proc_dir_entry) {
1270     PROC_NET_ALIAS_TYPES, 11, "alias_types",
1271     S_IFREG | S_IRUGO, 1, 0, 0,
1272     0, &proc_net_inode_operations,
1273     net_alias_types_getinfo
1274   });
1275   proc_net_register(&(struct proc_dir_entry) {
1276     PROC_NET_ALIASES, 7, "aliases",
1277     S_IFREG | S_IRUGO, 1, 0, 0,
1278     0, &proc_net_inode_operations,
1279     net_alias_getinfo
1280   });
1281 #endif
1282   
1283 }
1284 
1285 /*
1286  * net_alias type object registering func.
1287  */
1288 int register_net_alias_type(struct net_alias_type *nat, int type)
     /* [previous][next][first][last][top][bottom][index][help] */
1289 {
1290   unsigned hash;
1291   unsigned long flags;
1292   if (!nat)
1293   {
1294     printk("register_net_alias_type(): NULL arg\n");
1295     return -EINVAL;
1296   }
1297   nat->type = type;
1298   nat->n_attach = 0;
1299   hash = nat->type & 0x0f;
1300   save_flags(flags);
1301   cli();
1302   nat->next = nat_base[hash];
1303   nat_base[hash] = nat;
1304   restore_flags(flags);
1305   return 0;
1306 }
1307 
1308 /*
1309  * net_alias type object unreg.
1310  */
1311 int unregister_net_alias_type(struct net_alias_type *nat)
     /* [previous][next][first][last][top][bottom][index][help] */
1312 {
1313   struct net_alias_type **natp;
1314   unsigned hash;
1315   unsigned long flags;
1316   
1317   if (!nat)
1318   {
1319     printk("unregister_net_alias_type(): NULL arg\n");
1320     return -EINVAL;
1321   }
1322 
1323   /*
1324    * only allow unregistration if it has no attachments
1325    */
1326   if (nat->n_attach)
1327   {
1328     printk("unregister_net_alias_type(): has %d attachments. failed\n",
1329            nat->n_attach);
1330     return -EINVAL;
1331   }
1332   hash = nat->type & 0x0f;
1333   save_flags(flags);
1334   cli();
1335   for (natp = &nat_base[hash]; *natp ; natp = &(*natp)->next)
1336   {
1337     if (nat==(*natp))
1338     {
1339       *natp = nat->next;
1340       restore_flags(flags);
1341       return 0;
1342     }
1343   }
1344   restore_flags(flags);
1345   printk("unregister_net_alias_type(type=%d): not found!\n", nat->type);
1346   return -EINVAL;
1347 }
1348 

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