root/net/inet/rarp.c

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

DEFINITIONS

This source file includes following definitions.
  1. rarp_init
  2. rarp_release_entry
  3. rarp_destroy
  4. rarp_rcv
  5. rarp_req_set
  6. rarp_req_get
  7. rarp_ioctl
  8. rarp_get_info

   1 /* linux/net/inet/rarp.c
   2  *
   3  * Copyright (C) 1994 by Ross Martin
   4  * Based on linux/net/inet/arp.c, Copyright (C) 1994 by Florian La Roche
   5  *
   6  * This module implements the Reverse Address Resolution Protocol 
   7  * (RARP, RFC 903), which is used to convert low level addresses such
   8  * as ethernet addresses into high level addresses such as IP addresses.
   9  * The most common use of RARP is as a means for a diskless workstation 
  10  * to discover its IP address during a network boot.
  11  *
  12  **
  13  ***    WARNING:::::::::::::::::::::::::::::::::WARNING
  14  ****
  15  *****  SUN machines seem determined to boot solely from the person who
  16  ****   answered their RARP query. NEVER add a SUN to your RARP table
  17  ***    unless you have all the rest to boot the box from it. 
  18  **
  19  * 
  20  * Currently, only ethernet address -> IP address is likely to work.
  21  * (Is RARP ever used for anything else?)
  22  *
  23  * This code is free software; you can redistribute it and/or
  24  * modify it under the terms of the GNU General Public License
  25  * as published by the Free Software Foundation; either version
  26  * 2 of the License, or (at your option) any later version.
  27  *
  28  */
  29 
  30 #include <linux/types.h>
  31 #include <linux/string.h>
  32 #include <linux/kernel.h>
  33 #include <linux/sched.h>
  34 #include <linux/config.h>
  35 #include <linux/socket.h>
  36 #include <linux/sockios.h>
  37 #include <linux/errno.h>
  38 #include <linux/if_arp.h>
  39 #include <linux/in.h>
  40 #include <asm/system.h>
  41 #include <asm/segment.h>
  42 #include <stdarg.h>
  43 #include <linux/inet.h>
  44 #include <linux/netdevice.h>
  45 #include <linux/etherdevice.h>
  46 #include "ip.h"
  47 #include "route.h"
  48 #include "protocol.h"
  49 #include "tcp.h"
  50 #include <linux/skbuff.h>
  51 #include "sock.h"
  52 #include "arp.h"
  53 #include "rarp.h"
  54 #ifdef CONFIG_AX25
  55 #include "ax25.h"
  56 #endif
  57 
  58 #ifdef CONFIG_INET_RARP
  59 
  60 /*
  61  *      This structure defines the RARP mapping cache. As long as we make 
  62  *      changes in this structure, we keep interrupts off.
  63  */
  64 
  65 struct rarp_table
  66 {
  67         struct rarp_table  *next;             /* Linked entry list           */
  68         unsigned long      ip;                /* ip address of entry         */
  69         unsigned char      ha[MAX_ADDR_LEN];  /* Hardware address            */
  70         unsigned char      hlen;              /* Length of hardware address  */
  71         unsigned char      htype;             /* Type of hardware in use     */
  72         struct device      *dev;              /* Device the entry is tied to */
  73 };
  74 
  75 struct rarp_table *rarp_tables = NULL;
  76 
  77 
  78 static struct packet_type rarp_packet_type =
  79 {
  80         0,  /* Should be: __constant_htons(ETH_P_RARP) - but this _doesn't_ come out constant! */
  81         0,                /* copy */
  82         rarp_rcv,
  83         NULL,
  84         NULL
  85 };
  86 
  87 static initflag = 1;
  88 
  89 /*
  90  *      Called once when data first added to rarp cache with ioctl.
  91  */
  92 
  93 static void rarp_init (void)
     /* [previous][next][first][last][top][bottom][index][help] */
  94 {
  95         /* Register the packet type */
  96         rarp_packet_type.type=htons(ETH_P_RARP);
  97         dev_add_pack(&rarp_packet_type);
  98 }
  99 
 100 /*
 101  *      Release the memory for this entry.
 102  */
 103 
 104 static inline void rarp_release_entry(struct rarp_table *entry)
     /* [previous][next][first][last][top][bottom][index][help] */
 105 {
 106         kfree_s(entry, sizeof(struct rarp_table));
 107         return;
 108 }
 109 
 110 /*
 111  *      Delete a RARP mapping entry in the cache.
 112  */
 113 
 114 static void rarp_destroy(unsigned long ip_addr)
     /* [previous][next][first][last][top][bottom][index][help] */
 115 {
 116         struct rarp_table *entry;
 117         struct rarp_table **pentry;
 118   
 119         cli();
 120         pentry = &rarp_tables;
 121         while ((entry = *pentry) != NULL)
 122         {
 123                 if (entry->ip == ip_addr)
 124                 {
 125                         *pentry = entry->next;
 126                         sti();
 127                         rarp_release_entry(entry);
 128                         return;
 129                 }
 130                 pentry = &entry->next;
 131         }
 132         sti();
 133 }
 134 
 135 
 136 /*
 137  *      Receive an arp request by the device layer.  Maybe it should be 
 138  *      rewritten to use the incoming packet for the reply. The current 
 139  *      "overhead" time isn't that high...
 140  */
 141 
 142 int rarp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
     /* [previous][next][first][last][top][bottom][index][help] */
 143 {
 144 /*
 145  *      We shouldn't use this type conversion. Check later.
 146  */
 147         struct arphdr *rarp = (struct arphdr *)skb->h.raw;
 148         unsigned char *rarp_ptr = (unsigned char *)(rarp+1);
 149         struct rarp_table *entry;
 150         long sip,tip;
 151         unsigned char *sha,*tha;            /* s for "source", t for "target" */
 152   
 153 /*
 154  *      If this test doesn't pass, its not IP, or we should ignore it anyway
 155  */
 156 
 157         if (rarp->ar_hln != dev->addr_len || dev->type != ntohs(rarp->ar_hrd) 
 158                 || dev->flags&IFF_NOARP)
 159         {
 160                 kfree_skb(skb, FREE_READ);
 161                 return 0;
 162         }
 163 
 164 /*
 165  *      If it's not a RARP request, delete it.
 166  */
 167         if (rarp->ar_op != htons(ARPOP_RREQUEST))
 168         {
 169                 kfree_skb(skb, FREE_READ);
 170                 return 0;
 171         }
 172 
 173 /*
 174  *      For now we will only deal with IP addresses.
 175  */
 176 
 177         if (
 178 #ifdef CONFIG_AX25
 179                 (rarp->ar_pro != htons(AX25_P_IP) && dev->type == ARPHRD_AX25) ||
 180 #endif
 181                 (rarp->ar_pro != htons(ETH_P_IP) && dev->type != ARPHRD_AX25)
 182                 || rarp->ar_pln != 4)
 183         {
 184         /*
 185          *      This packet is not for us. Remove it. 
 186          */
 187         kfree_skb(skb, FREE_READ);
 188         return 0;
 189 }
 190   
 191 /*
 192  *      Extract variable width fields
 193  */
 194 
 195         sha=rarp_ptr;
 196         rarp_ptr+=dev->addr_len;
 197         memcpy(&sip,rarp_ptr,4);
 198         rarp_ptr+=4;
 199         tha=rarp_ptr;
 200         rarp_ptr+=dev->addr_len;
 201         memcpy(&tip,rarp_ptr,4);
 202 
 203 /*
 204  *      Process entry
 205  */
 206   
 207         cli();
 208         for (entry = rarp_tables; entry != NULL; entry = entry->next)
 209         if (!memcmp(entry->ha, sha, rarp->ar_hln))
 210                 break;
 211   
 212         if (entry != NULL)
 213         {
 214                 sip=entry->ip;
 215                 sti();
 216 
 217                 arp_send(ARPOP_RREPLY, ETH_P_RARP, sip, dev, dev->pa_addr, sha, 
 218                         dev->dev_addr);
 219         }
 220         else
 221                 sti();
 222 
 223         kfree_skb(skb, FREE_READ);
 224         return 0;
 225 }
 226 
 227 
 228 /*
 229  *      Set (create) a RARP cache entry.
 230  */
 231 
 232 static int rarp_req_set(struct arpreq *req)
     /* [previous][next][first][last][top][bottom][index][help] */
 233 {
 234         struct arpreq r;
 235         struct rarp_table *entry;
 236         struct sockaddr_in *si;
 237         int htype, hlen;
 238         unsigned long ip;
 239         struct rtable *rt;
 240   
 241         memcpy_fromfs(&r, req, sizeof(r));
 242   
 243         /*
 244          *      We only understand about IP addresses... 
 245          */
 246 
 247         if (r.arp_pa.sa_family != AF_INET)
 248                 return -EPFNOSUPPORT;
 249   
 250         switch (r.arp_ha.sa_family) 
 251         {
 252                 case ARPHRD_ETHER:
 253                         htype = ARPHRD_ETHER;
 254                         hlen = ETH_ALEN;
 255                         break;
 256 #ifdef CONFIG_AX25
 257                 case ARPHRD_AX25:
 258                         htype = ARPHRD_AX25;
 259                         hlen = 7;
 260                 break;
 261 #endif
 262                 default:
 263                         return -EPFNOSUPPORT;
 264         }
 265 
 266         si = (struct sockaddr_in *) &r.arp_pa;
 267         ip = si->sin_addr.s_addr;
 268         if (ip == 0)
 269         {
 270                 printk("RARP: SETRARP: requested PA is 0.0.0.0 !\n");
 271                 return -EINVAL;
 272         }
 273   
 274 /*
 275  *      Is it reachable directly ?
 276  */
 277   
 278         rt = ip_rt_route(ip, NULL, NULL);
 279         if (rt == NULL)
 280                 return -ENETUNREACH;
 281 
 282 /*
 283  *      Is there an existing entry for this address?  Find out...
 284  */
 285   
 286         cli();
 287         for (entry = rarp_tables; entry != NULL; entry = entry->next)
 288                 if (entry->ip == ip)
 289                         break;
 290   
 291 /*
 292  *      If no entry was found, create a new one.
 293  */
 294 
 295         if (entry == NULL)
 296         {
 297                 entry = (struct rarp_table *) kmalloc(sizeof(struct rarp_table),
 298                                     GFP_ATOMIC);
 299                 if (entry == NULL)
 300                 {
 301                         sti();
 302                         return -ENOMEM;
 303                 }
 304                 if(initflag)
 305                 {
 306                         rarp_init();
 307                         initflag=0;
 308                 }
 309 
 310                 entry->next = rarp_tables;
 311                 rarp_tables = entry;
 312         }
 313 
 314         entry->ip = ip;
 315         entry->hlen = hlen;
 316         entry->htype = htype;
 317         memcpy(&entry->ha, &r.arp_ha.sa_data, hlen);
 318         entry->dev = rt->rt_dev;
 319 
 320         sti();  
 321 
 322         return 0;
 323 }
 324 
 325 
 326 /*
 327  *        Get a RARP cache entry.
 328  */
 329 
 330 static int rarp_req_get(struct arpreq *req)
     /* [previous][next][first][last][top][bottom][index][help] */
 331 {
 332         struct arpreq r;
 333         struct rarp_table *entry;
 334         struct sockaddr_in *si;
 335         unsigned long ip;
 336 
 337 /*
 338  *      We only understand about IP addresses...
 339  */
 340         
 341         memcpy_fromfs(&r, req, sizeof(r));
 342   
 343         if (r.arp_pa.sa_family != AF_INET)
 344                 return -EPFNOSUPPORT;
 345   
 346 /*
 347  *        Is there an existing entry for this address?
 348  */
 349 
 350         si = (struct sockaddr_in *) &r.arp_pa;
 351         ip = si->sin_addr.s_addr;
 352 
 353         cli();
 354         for (entry = rarp_tables; entry != NULL; entry = entry->next)
 355                 if (entry->ip == ip)
 356                         break;
 357 
 358         if (entry == NULL)
 359         {
 360                 sti();
 361                 return -ENXIO;
 362         }
 363 
 364 /*
 365  *        We found it; copy into structure.
 366  */
 367         
 368         memcpy(r.arp_ha.sa_data, &entry->ha, entry->hlen);
 369         r.arp_ha.sa_family = entry->htype;
 370         sti();
 371   
 372 /*
 373  *        Copy the information back
 374  */
 375   
 376         memcpy_tofs(req, &r, sizeof(r));
 377         return 0;
 378 }
 379 
 380 
 381 /*
 382  *      Handle a RARP layer I/O control request.
 383  */
 384 
 385 int rarp_ioctl(unsigned int cmd, void *arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 386 {
 387         struct arpreq r;
 388         struct sockaddr_in *si;
 389         int err;
 390 
 391         switch(cmd)
 392         {
 393                 case SIOCDRARP:
 394                         if (!suser())
 395                                 return -EPERM;
 396                         err = verify_area(VERIFY_READ, arg, sizeof(struct arpreq));
 397                         if(err)
 398                                 return err;
 399                         memcpy_fromfs(&r, arg, sizeof(r));
 400                         if (r.arp_pa.sa_family != AF_INET)
 401                                 return -EPFNOSUPPORT;
 402                         si = (struct sockaddr_in *) &r.arp_pa;
 403                         rarp_destroy(si->sin_addr.s_addr);
 404                         return 0;
 405 
 406                 case SIOCGRARP:
 407                         err = verify_area(VERIFY_WRITE, arg, sizeof(struct arpreq));
 408                         if(err)
 409                                 return err;
 410                         return rarp_req_get((struct arpreq *)arg);
 411                 case SIOCSRARP:
 412                         if (!suser())
 413                                 return -EPERM;
 414                         err = verify_area(VERIFY_READ, arg, sizeof(struct arpreq));
 415                         if(err)
 416                                 return err;
 417                         return rarp_req_set((struct arpreq *)arg);
 418                 default:
 419                         return -EINVAL;
 420         }
 421 
 422         /*NOTREACHED*/
 423         return 0;
 424 }
 425 
 426 int rarp_get_info(char *buffer, char **start, off_t offset, int length)
     /* [previous][next][first][last][top][bottom][index][help] */
 427 {
 428         int len=0;
 429         off_t begin=0;
 430         off_t pos=0;
 431         int size;
 432         struct rarp_table *entry;
 433         char ipbuffer[20];
 434         unsigned long netip;
 435         if(initflag)
 436         {
 437                 size = sprintf(buffer,"RARP disabled until entries added to cache.\n");
 438                 pos+=size;
 439                 len+=size;
 440         }   
 441         else
 442         {
 443                 size = sprintf(buffer,
 444                         "IP address       HW type             HW address\n");
 445                 pos+=size;
 446                 len+=size;
 447       
 448                 cli();
 449                 for(entry=rarp_tables; entry!=NULL; entry=entry->next)
 450                 {
 451                         netip=htonl(entry->ip);          /* switch to network order */
 452                         sprintf(ipbuffer,"%d.%d.%d.%d",
 453                                 (unsigned int)(netip>>24)&255,
 454                                 (unsigned int)(netip>>16)&255,
 455                                 (unsigned int)(netip>>8)&255,
 456                                 (unsigned int)(netip)&255);
 457 
 458                         size = sprintf(buffer+len,
 459                                 "%-17s%-20s%02x:%02x:%02x:%02x:%02x:%02x\n",
 460                                 ipbuffer,
 461                                 "10Mbps Ethernet",
 462                                 (unsigned int)entry->ha[0],
 463                                 (unsigned int)entry->ha[1],
 464                                 (unsigned int)entry->ha[2],
 465                                 (unsigned int)entry->ha[3],
 466                                 (unsigned int)entry->ha[4],
 467                                 (unsigned int)entry->ha[5]);
 468           
 469                         len+=size;
 470                         pos=begin+len;
 471           
 472                         if(pos<offset)
 473                         {
 474                                 len=0;
 475                                 begin=pos;
 476                         }
 477                         if(pos>offset+length)
 478                                 break;
 479                 }
 480                 sti();
 481         }      
 482 
 483         *start=buffer+(offset-begin);   /* Start of wanted data */
 484         len-=(offset-begin);            /* Start slop */
 485         if(len>length)
 486                 len=length;                     /* Ending slop */
 487         return len;
 488 }
 489 
 490 #endif

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