root/net/appletalk/aarp.c

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

DEFINITIONS

This source file includes following definitions.
  1. aarp_expire
  2. aarp_send_query
  3. aarp_send_reply
  4. aarp_send_probe
  5. aarp_expire_timer
  6. aarp_kick
  7. aarp_expire_device
  8. aarp_expire_timeout
  9. aarp_device_event
  10. aarp_alloc
  11. aarp_find_entry
  12. aarp_send_ddp
  13. aarp_resolved
  14. aarp_rcv
  15. aarp_proto_init

   1 /*
   2  *      AARP:           An implementation of the Appletalk aarp protocol for
   3  *                      ethernet 'ELAP'.
   4  *
   5  *              Alan Cox  <Alan.Cox@linux.org>
   6  *                        <iialan@www.linux.org.uk>
   7  *
   8  *      This doesn't fit cleanly with the IP arp. This isn't a problem as
   9  *      the IP arp wants extracting from the device layer in 1.3.x anyway.
  10  *      [see the pre-1.3 test code for details 8)]
  11  *
  12  *      FIXME:
  13  *              We ought to handle the retransmits with a single list and a 
  14  *      seperate fast timer for when it is needed.
  15  *
  16  *              This program is free software; you can redistribute it and/or
  17  *              modify it under the terms of the GNU General Public License
  18  *              as published by the Free Software Foundation; either version
  19  *              2 of the License, or (at your option) any later version.
  20  *
  21  *
  22  *      References:
  23  *              Inside Appletalk (2nd Ed).
  24  */
  25  
  26 #include <asm/segment.h>
  27 #include <asm/system.h>
  28 #include <asm/bitops.h>
  29 #include <linux/config.h>
  30 #include <linux/types.h>
  31 #include <linux/kernel.h>
  32 #include <linux/sched.h>
  33 #include <linux/string.h>
  34 #include <linux/mm.h>
  35 #include <linux/socket.h>
  36 #include <linux/sockios.h>
  37 #include <linux/in.h>
  38 #include <linux/errno.h>
  39 #include <linux/interrupt.h>
  40 #include <linux/if_ether.h>
  41 #include <linux/inet.h>
  42 #include <linux/notifier.h>
  43 #include <linux/netdevice.h>
  44 #include <linux/etherdevice.h>
  45 #include <linux/skbuff.h>
  46 #include <net/sock.h>
  47 #include <net/datalink.h>
  48 #include <net/psnap.h>
  49 #include <net/atalk.h>
  50 
  51 #ifdef CONFIG_ATALK
  52 /*
  53  *      Lists of aarp entries
  54  */
  55  
  56 struct aarp_entry
  57 {
  58         /* These first two are only used for unresolved entries */
  59         unsigned long last_sent;                /* Last time we xmitted the aarp request */
  60         struct sk_buff_head packet_queue;       /* Queue of frames wait for resolution */
  61         unsigned long expires_at;               /* Entry expiry time */
  62         struct at_addr target_addr;             /* DDP Address */
  63         struct device *dev;                     /* Device to use */
  64         char hwaddr[6];                         /* Physical i/f address of target/router */
  65         unsigned short xmit_count;              /* When this hits 10 we give up */
  66         struct aarp_entry *next;                /* Next entry in chain */
  67 };
  68 
  69 
  70 /*
  71  *      Hashed list of resolved and unresolved entries
  72  */
  73 
  74 static struct aarp_entry *resolved[AARP_HASH_SIZE], *unresolved[AARP_HASH_SIZE];
  75 static int unresolved_count=0;
  76 
  77 /*
  78  *      Used to walk the list and purge/kick entries.
  79  */
  80  
  81 static struct timer_list aarp_timer;
  82 
  83 /*
  84  *      Delete an aarp queue
  85  */
  86 
  87 static void aarp_expire(struct aarp_entry *a)
     /* [previous][next][first][last][top][bottom][index][help] */
  88 {
  89         struct sk_buff *skb;
  90         
  91         while((skb=skb_dequeue(&a->packet_queue))!=NULL)
  92                 kfree_skb(skb, FREE_WRITE);
  93         kfree_s(a,sizeof(*a));
  94 }
  95 
  96 /*
  97  *      Send an aarp queue entry request
  98  */
  99  
 100 static void aarp_send_query(struct aarp_entry *a)
     /* [previous][next][first][last][top][bottom][index][help] */
 101 {
 102         static char aarp_eth_multicast[ETH_ALEN]={ 0x09, 0x00, 0x07, 0xFF, 0xFF, 0xFF };
 103         struct device *dev=a->dev;
 104         int len=dev->hard_header_len+sizeof(struct elapaarp)+aarp_dl->header_length;
 105         struct sk_buff *skb=alloc_skb(len, GFP_ATOMIC);
 106         struct elapaarp *eah=(struct elapaarp *)(skb->data+dev->hard_header_len+aarp_dl->header_length);
 107         struct at_addr *sat=atalk_find_dev_addr(dev);
 108         
 109         if(skb==NULL || sat==NULL)
 110                 return;
 111         
 112         /*
 113          *      Set up the buffer.
 114          */             
 115          
 116         skb->arp        =       1;
 117         skb->free       =       1;
 118         skb->len        =       len;
 119         skb->dev        =       a->dev;
 120         
 121         /*
 122          *      Set up the ARP.
 123          */
 124          
 125         eah->hw_type    =       htons(AARP_HW_TYPE_ETHERNET);
 126         eah->pa_type    =       htons(ETH_P_ATALK);
 127         eah->hw_len     =       ETH_ALEN;       
 128         eah->pa_len     =       AARP_PA_ALEN;
 129         eah->function   =       htons(AARP_REQUEST);
 130         
 131         memcpy(eah->hw_src, dev->dev_addr, ETH_ALEN);
 132         
 133         eah->pa_src_zero=       0;
 134         eah->pa_src_net =       sat->s_net;
 135         eah->pa_src_node=       sat->s_node;
 136         
 137         memset(eah->hw_dst, '\0', ETH_ALEN);
 138         
 139         eah->pa_dst_zero=       0;
 140         eah->pa_dst_net =       a->target_addr.s_net;
 141         eah->pa_dst_node=       a->target_addr.s_node;
 142         
 143         /*
 144          *      Add ELAP headers and set target to the AARP multicast.
 145          */
 146          
 147         aarp_dl->datalink_header(aarp_dl, skb, aarp_eth_multicast);     
 148 
 149         /*
 150          *      Send it.
 151          */     
 152          
 153          
 154         dev_queue_xmit(skb, dev, SOPRI_NORMAL);
 155         
 156         /*
 157          *      Update the sending count
 158          */
 159          
 160         a->xmit_count++;
 161 }
 162 
 163 static void aarp_send_reply(struct device *dev, struct at_addr *us, struct at_addr *them, unsigned char *sha)
     /* [previous][next][first][last][top][bottom][index][help] */
 164 {
 165         int len=dev->hard_header_len+sizeof(struct elapaarp)+aarp_dl->header_length;
 166         struct sk_buff *skb=alloc_skb(len, GFP_ATOMIC);
 167         struct elapaarp *eah=(struct elapaarp *)(skb->data+dev->hard_header_len+aarp_dl->header_length);
 168         
 169         if(skb==NULL)
 170                 return;
 171         
 172         /*
 173          *      Set up the buffer.
 174          */             
 175          
 176         skb->arp        =       1;
 177         skb->free       =       1;
 178         skb->len        =       len;
 179         skb->dev        =       dev;
 180         
 181         /*
 182          *      Set up the ARP.
 183          */
 184          
 185         eah->hw_type    =       htons(AARP_HW_TYPE_ETHERNET);
 186         eah->pa_type    =       htons(ETH_P_ATALK);
 187         eah->hw_len     =       ETH_ALEN;       
 188         eah->pa_len     =       AARP_PA_ALEN;
 189         eah->function   =       htons(AARP_REPLY);
 190         
 191         memcpy(eah->hw_src, dev->dev_addr, ETH_ALEN);
 192         
 193         eah->pa_src_zero=       0;
 194         eah->pa_src_net =       us->s_net;
 195         eah->pa_src_node=       us->s_node;
 196         
 197         if(sha==NULL)
 198                 memset(eah->hw_dst, '\0', ETH_ALEN);
 199         else
 200                 memcpy(eah->hw_dst, sha, ETH_ALEN);
 201         
 202         eah->pa_dst_zero=       0;
 203         eah->pa_dst_net =       them->s_net;
 204         eah->pa_dst_node=       them->s_node;
 205         
 206         /*
 207          *      Add ELAP headers and set target to the AARP multicast.
 208          */
 209          
 210         aarp_dl->datalink_header(aarp_dl, skb, sha);    
 211 
 212         /*
 213          *      Send it.
 214          */     
 215          
 216         dev_queue_xmit(skb, dev, SOPRI_NORMAL);
 217         
 218 }
 219 
 220 /*
 221  *      Send probe frames. Called from atif_probe_device.
 222  */
 223  
 224 void aarp_send_probe(struct device *dev, struct at_addr *us)
     /* [previous][next][first][last][top][bottom][index][help] */
 225 {
 226         int len=dev->hard_header_len+sizeof(struct elapaarp)+aarp_dl->header_length;
 227         struct sk_buff *skb=alloc_skb(len, GFP_ATOMIC);
 228         struct elapaarp *eah=(struct elapaarp *)(skb->data+dev->hard_header_len+aarp_dl->header_length);
 229         static char aarp_eth_multicast[ETH_ALEN]={ 0x09, 0x00, 0x07, 0xFF, 0xFF, 0xFF };
 230         
 231         if(skb==NULL)
 232                 return;
 233         
 234         /*
 235          *      Set up the buffer.
 236          */             
 237          
 238         skb->arp        =       1;
 239         skb->free       =       1;
 240         skb->len        =       len;
 241         skb->dev        =       dev;
 242         
 243         /*
 244          *      Set up the ARP.
 245          */
 246          
 247         eah->hw_type    =       htons(AARP_HW_TYPE_ETHERNET);
 248         eah->pa_type    =       htons(ETH_P_ATALK);
 249         eah->hw_len     =       ETH_ALEN;       
 250         eah->pa_len     =       AARP_PA_ALEN;
 251         eah->function   =       htons(AARP_PROBE);
 252         
 253         memcpy(eah->hw_src, dev->dev_addr, ETH_ALEN);
 254         
 255         eah->pa_src_zero=       0;
 256         eah->pa_src_net =       us->s_net;
 257         eah->pa_src_node=       us->s_node;
 258         
 259         memset(eah->hw_dst, '\0', ETH_ALEN);
 260         
 261         eah->pa_dst_zero=       0;
 262         eah->pa_dst_net =       us->s_net;
 263         eah->pa_dst_node=       us->s_node;
 264         
 265         /*
 266          *      Add ELAP headers and set target to the AARP multicast.
 267          */
 268          
 269         aarp_dl->datalink_header(aarp_dl, skb, aarp_eth_multicast);     
 270 
 271         /*
 272          *      Send it.
 273          */     
 274          
 275         dev_queue_xmit(skb, dev, SOPRI_NORMAL);
 276         
 277 }
 278         
 279 /*
 280  *      Handle an aarp timer expire
 281  */
 282 
 283 static void aarp_expire_timer(struct aarp_entry **n)
     /* [previous][next][first][last][top][bottom][index][help] */
 284 {
 285         struct aarp_entry *t;
 286         while((*n)!=NULL)
 287         {
 288                 /* Expired ? */
 289                 if((*n)->expires_at < jiffies)
 290                 {
 291                         t= *n;
 292                         *n=(*n)->next;
 293                         aarp_expire(t);
 294                 }
 295                 else
 296                         n=&((*n)->next);
 297         }
 298 }
 299 
 300 /*
 301  *      Kick all pending requests 5 times a second.
 302  */
 303  
 304 static void aarp_kick(struct aarp_entry **n)
     /* [previous][next][first][last][top][bottom][index][help] */
 305 {
 306         struct aarp_entry *t;
 307         while((*n)!=NULL)
 308         {
 309                 /* Expired - if this will be the 11th transmit, we delete
 310                    instead */
 311                 if((*n)->xmit_count>=AARP_RETRANSMIT_LIMIT)
 312                 {
 313                         t= *n;
 314                         *n=(*n)->next;
 315                         aarp_expire(t);
 316                 }
 317                 else
 318                 {
 319                         aarp_send_query(*n);
 320                         n=&((*n)->next);
 321                 }
 322         }
 323 }
 324 
 325 /*
 326  *      A device has gone down. Take all entries referring to the device
 327  *      and remove them.
 328  */
 329  
 330 static void aarp_expire_device(struct aarp_entry **n, struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 331 {
 332         struct aarp_entry *t;
 333         while((*n)!=NULL)
 334         {
 335                 if((*n)->dev==dev)
 336                 {
 337                         t= *n;
 338                         *n=(*n)->next;
 339                         aarp_expire(t);
 340                 }
 341                 else
 342                         n=&((*n)->next);
 343         }
 344 }
 345                 
 346 /*
 347  *      Handle the timer event 
 348  */
 349  
 350 static void aarp_expire_timeout(unsigned long unused)
     /* [previous][next][first][last][top][bottom][index][help] */
 351 {
 352         int ct=0;
 353         for(ct=0;ct<AARP_HASH_SIZE;ct++)
 354         {
 355                 aarp_expire_timer(&resolved[ct]);
 356                 aarp_kick(&unresolved[ct]);
 357                 aarp_expire_timer(&unresolved[ct]);
 358         }
 359         del_timer(&aarp_timer);
 360         if(unresolved_count==0)
 361                 aarp_timer.expires=AARP_EXPIRY_TIME;
 362         else
 363                 aarp_timer.expires=AARP_TICK_TIME;
 364         add_timer(&aarp_timer);
 365 }
 366 
 367 /*
 368  *      Network device notifier chain handler.
 369  */
 370  
 371 static int aarp_device_event(unsigned long event, void *ptr)
     /* [previous][next][first][last][top][bottom][index][help] */
 372 {
 373         int ct=0;
 374         if(event==NETDEV_DOWN)
 375         {
 376                 for(ct=0;ct<AARP_HASH_SIZE;ct++)
 377                 {
 378                         aarp_expire_device(&resolved[ct],ptr);
 379                         aarp_expire_device(&unresolved[ct],ptr);
 380                 }
 381         }
 382         return NOTIFY_DONE;
 383 }
 384 
 385 /*
 386  *      Create a new aarp entry.
 387  */
 388  
 389 static struct aarp_entry *aarp_alloc(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 390 {
 391         struct aarp_entry *a=kmalloc(sizeof(struct aarp_entry), GFP_ATOMIC);
 392         if(a==NULL)
 393                 return NULL;
 394         skb_queue_head_init(&a->packet_queue);
 395         return a;
 396 }
 397 
 398 /*
 399  *      Find an entry. We might return an expired but not yet purged entry. We
 400  *      don't care as it will do no harm.
 401  */
 402  
 403 static struct aarp_entry *aarp_find_entry(struct aarp_entry *list, struct device *dev, struct at_addr *sat)
     /* [previous][next][first][last][top][bottom][index][help] */
 404 {
 405         unsigned long flags;
 406         save_flags(flags);
 407         cli();
 408         while(list)
 409         {
 410                 if(list->target_addr.s_net==sat->s_net &&
 411                    list->target_addr.s_node==sat->s_node && list->dev==dev)
 412                         break;
 413                 list=list->next;
 414         }
 415         restore_flags(flags);
 416         return list;
 417 }
 418 
 419 /*
 420  *      Send a DDP frame
 421  */
 422  
 423 int aarp_send_ddp(struct device *dev,struct sk_buff *skb, struct at_addr *sa, void *hwaddr)
     /* [previous][next][first][last][top][bottom][index][help] */
 424 {
 425         static char ddp_eth_multicast[ETH_ALEN]={ 0x09, 0x00, 0x07, 0xFF, 0xFF, 0xFF };
 426         int hash;
 427         struct aarp_entry *a;
 428         unsigned long flags;
 429         
 430         /*
 431          *      Non ELAP we cannot do.
 432          */
 433         if(dev->type!=ARPHRD_ETHER)
 434         {
 435                 return -1;
 436         }
 437 
 438         skb->dev = dev;
 439                         
 440         hash=sa->s_node%(AARP_HASH_SIZE-1);
 441         save_flags(flags);
 442         cli();
 443         
 444         /*
 445          *      Do we have a resolved entry ?
 446          */
 447          
 448         if(sa->s_node==ATADDR_BCAST)
 449         {
 450                 ddp_dl->datalink_header(ddp_dl, skb, ddp_eth_multicast);
 451                 if(skb->sk==NULL)
 452                         dev_queue_xmit(skb, skb->dev, SOPRI_NORMAL);
 453                 else
 454                         dev_queue_xmit(skb, skb->dev, skb->sk->priority);
 455                 restore_flags(flags);
 456                 return 1;
 457         }
 458         a=aarp_find_entry(resolved[hash],dev,sa);
 459         if(a!=NULL)
 460         {
 461                 /*
 462                  *      Return 1 and fill in the address
 463                  */
 464                 a->expires_at=jiffies+AARP_EXPIRY_TIME*10;
 465                 ddp_dl->datalink_header(ddp_dl, skb, a->hwaddr);
 466                 if(skb->sk==NULL)
 467                         dev_queue_xmit(skb, skb->dev, SOPRI_NORMAL);
 468                 else
 469                         dev_queue_xmit(skb, skb->dev, skb->sk->priority);
 470                 restore_flags(flags);
 471                 return 1;
 472         }
 473         /*
 474          *      Do we have an unresolved entry: This is the less common path
 475          */
 476         a=aarp_find_entry(unresolved[hash],dev,sa);
 477         if(a!=NULL)
 478         {
 479                 /*
 480                  *      Queue onto the unresolved queue
 481                  */
 482                 skb_queue_tail(&a->packet_queue, skb);
 483                 restore_flags(flags);
 484                 return 0;
 485         }
 486         /*
 487          *      Allocate a new entry
 488          */
 489         a=aarp_alloc();
 490         if(a==NULL)
 491         {
 492                 /*
 493                  *      Whoops slipped... good job it's an unreliable 
 494                  *      protocol 8)     
 495                  */
 496                 restore_flags(flags);
 497                 return -1;
 498         }
 499         /*
 500          *      Set up the queue
 501          */
 502         skb_queue_tail(&a->packet_queue, skb);
 503         a->expires_at=jiffies+AARP_RESOLVE_TIME;
 504         a->dev=dev;
 505         a->next=unresolved[hash];
 506         a->target_addr= *sa;
 507         a->xmit_count=0;
 508         unresolved[hash]=a;
 509         unresolved_count++;
 510         restore_flags(flags);
 511         /*
 512          *      Send an initial request for the address
 513          */
 514         aarp_send_query(a);
 515         /*
 516          *      Switch to fast timer if needed (That is if this is the
 517          *      first unresolved entry to get added)
 518          */
 519         if(unresolved_count==1)
 520         {
 521                 del_timer(&aarp_timer);
 522                 aarp_timer.expires=AARP_TICK_TIME;
 523                 add_timer(&aarp_timer);
 524         }
 525         /*
 526          *      Tell the ddp layer we have taken over for this frame.
 527          */
 528         return 0;
 529 }
 530 
 531 static void aarp_resolved(struct aarp_entry **list, struct aarp_entry *a, int hash)
     /* [previous][next][first][last][top][bottom][index][help] */
 532 {
 533         struct sk_buff *skb;
 534         while(*list!=NULL)
 535         {
 536                 if(*list==a)
 537                 {
 538                         unresolved_count--;
 539                         *list=a->next;
 540                         /* Move into the resolved list */
 541                         a->next=resolved[hash];
 542                         resolved[hash]=a;
 543                         /* Kick frames off */
 544                         while((skb=skb_dequeue(&a->packet_queue))!=NULL)
 545                         {
 546                                 a->expires_at=jiffies+AARP_EXPIRY_TIME*10;
 547                                 ddp_dl->datalink_header(ddp_dl,skb,a->hwaddr);
 548                                 if(skb->sk==NULL)
 549                                         dev_queue_xmit(skb, skb->dev, SOPRI_NORMAL);
 550                                 else
 551                                         dev_queue_xmit(skb, skb->dev, skb->sk->priority);
 552                         }
 553                 }
 554                 else
 555                         list=&((*list)->next);
 556         }
 557 }
 558 
 559 static int aarp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
     /* [previous][next][first][last][top][bottom][index][help] */
 560 {
 561         struct elapaarp *ea=(struct elapaarp *)skb->h.raw;
 562         struct aarp_entry *a;
 563         struct at_addr sa, *ma;
 564         unsigned long flags;
 565         int hash;
 566         struct atalk_iface *ifa;
 567         
 568         
 569         /*
 570          *      We only do ethernet SNAP AARP
 571          */
 572          
 573         if(dev->type!=ARPHRD_ETHER)
 574         {
 575                 kfree_skb(skb, FREE_READ);
 576                 return 0;
 577         }
 578         
 579         /*
 580          *      Frame size ok ?
 581          */
 582          
 583         if(skb->len<sizeof(*ea))
 584         {
 585                 kfree_skb(skb, FREE_READ);
 586                 return 0;
 587         }
 588 
 589         ea->function=ntohs(ea->function);
 590         
 591         /*
 592          *      Sanity check fields.
 593          */
 594          
 595         if(ea->function<AARP_REQUEST || ea->function > AARP_PROBE || ea->hw_len != ETH_ALEN || ea->pa_len != AARP_PA_ALEN ||
 596                 ea->pa_src_zero != 0 || ea->pa_dst_zero != 0)
 597         {
 598                 kfree_skb(skb, FREE_READ);
 599                 return 0;
 600         }
 601         
 602         /*
 603          *      Looks good
 604          */
 605         
 606         hash=ea->pa_src_node%(AARP_HASH_SIZE-1);
 607 
 608         /*
 609          *      Build an address
 610          */
 611          
 612         sa.s_node=ea->pa_src_node;
 613         sa.s_net=ea->pa_src_net;
 614         
 615         /*
 616          *      Process the packet
 617          */
 618          
 619         save_flags(flags);
 620 
 621         /*
 622          *      Check for replies of me
 623          */
 624                         
 625         ifa=atalk_find_dev(dev);
 626         if(ifa==NULL)
 627         {
 628                 restore_flags(flags);
 629                 kfree_skb(skb, FREE_READ);
 630                 return 1;               
 631         }
 632         if(ifa->status&ATIF_PROBE)
 633         {                       
 634                 if(ifa->address.s_node==ea->pa_dst_node && ifa->address.s_net==ea->pa_dst_net)
 635                 {
 636                         /*
 637                          *      Fail the probe (in use)
 638                          */
 639                         ifa->status|=ATIF_PROBE_FAIL;
 640                         restore_flags(flags);
 641                         kfree_skb(skb, FREE_READ);
 642                         return 1;               
 643                 }
 644         }                                
 645         
 646         switch(ea->function)
 647         {
 648                 case AARP_REPLY:        
 649                         if(unresolved_count==0) /* Speed up */
 650                                 break;
 651                         /*
 652                          *      Find the entry  
 653                          */
 654                          
 655                         cli();
 656                         if((a=aarp_find_entry(unresolved[hash],dev,&sa))==NULL || dev != a->dev)
 657                                 break;
 658                         /*
 659                          *      We can fill one in - this is good
 660                          */
 661                         memcpy(a->hwaddr,ea->hw_src,ETH_ALEN);
 662                         aarp_resolved(&unresolved[hash],a,hash);
 663                         if(unresolved_count==0)
 664                         {
 665                                 del_timer(&aarp_timer);
 666                                 aarp_timer.expires=AARP_EXPIRY_TIME;
 667                                 add_timer(&aarp_timer);
 668                         }
 669                         break;
 670                         
 671                 case AARP_REQUEST:
 672                 case AARP_PROBE:
 673                         /*
 674                          *      If it is my address set ma to my address and reply. We can treat probe and
 675                          *      request the same. Probe simply means we shouldn't cache the querying host, 
 676                          *      as in a probe they are proposing an address not using one.
 677                          */
 678                          
 679                         ma=&ifa->address;
 680                         sa.s_node=ea->pa_dst_node;
 681                         sa.s_net=ea->pa_dst_net;
 682                         
 683                         if(sa.s_node!=ma->s_node)
 684                                 break;
 685                         if(sa.s_net && ma->s_net && sa.s_net!=ma->s_net)
 686                                 break;
 687 
 688                         sa.s_node=ea->pa_src_node;
 689                         sa.s_net=ea->pa_src_net;
 690                         
 691                         /*
 692                          *      aarp_my_address has found the address to use for us.
 693                          */
 694                         aarp_send_reply(dev,ma,&sa,ea->hw_src);
 695                         break;
 696         }
 697         restore_flags(flags);
 698         kfree_skb(skb, FREE_READ);
 699         return 1;               
 700 }
 701 
 702 static struct notifier_block aarp_notifier={
 703         aarp_device_event,
 704         NULL,
 705         0
 706 };
 707 
 708 
 709 void aarp_proto_init(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 710 {
 711         static char aarp_snap_id[]={0x00,0x00,0x00,0x80,0xF3};
 712         if((aarp_dl=register_snap_client(aarp_snap_id, aarp_rcv))==NULL)
 713                 printk("Unable to register AARP with SNAP.\n");
 714         init_timer(&aarp_timer);
 715         aarp_timer.function=aarp_expire_timeout;
 716         aarp_timer.data=0;
 717         aarp_timer.expires=AARP_EXPIRY_TIME;
 718         add_timer(&aarp_timer);
 719         register_netdevice_notifier(&aarp_notifier);
 720 }
 721 #endif

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