root/net/inet/skbuff.c

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

DEFINITIONS

This source file includes following definitions.
  1. skb_check
  2. skb_queue_head
  3. skb_queue_tail
  4. skb_dequeue
  5. skb_insert
  6. skb_append
  7. skb_unlink
  8. skb_new_list_head
  9. skb_peek
  10. skb_peek_copy
  11. kfree_skb
  12. alloc_skb
  13. kfree_skbmem

   1 /*
   2  * INET         An implementation of the TCP/IP protocol suite for the LINUX
   3  *              operating system.  INET is implemented using the  BSD Socket
   4  *              interface as the means of communication with the user level.
   5  *
   6  *              A saner implementation of the skbuff stuff scattered everywhere
   7  *              in the old NET2D code.
   8  *
   9  *      Authors:        Alan Cox <iiitac@pyr.swan.ac.uk>
  10  *
  11  *      Fixes:
  12  *              Alan Cox        :       Tracks memory and number of buffers for kernel memory report
  13  *                                      and memory leak hunting.
  14  */
  15  
  16 #include <linux/config.h>
  17 #include <linux/types.h>
  18 #include <linux/kernel.h>
  19 #include <asm/segment.h>
  20 #include <asm/system.h>
  21 #include <linux/mm.h>
  22 #include <linux/interrupt.h>
  23 #include <linux/in.h>
  24 #include "inet.h"
  25 #include "dev.h"
  26 #include "ip.h"
  27 #include "protocol.h"
  28 #include "arp.h"
  29 #include "route.h"
  30 #include "tcp.h"
  31 #include "udp.h"
  32 #include "skbuff.h"
  33 #include "sock.h"
  34 
  35 
  36 /* Socket buffer operations. Ideally much of this list swap stuff ought to be using
  37    exch instructions on the 386, and CAS/CAS2 on a 68K. This is the boring generic
  38    slow C version. No doubt when Linus sees this comment he'll do horrible things
  39    to this code 8-)
  40 */
  41 
  42 /*
  43  *      Resource tracking variables
  44  */
  45  
  46 volatile unsigned long net_memory=0;
  47 volatile unsigned long net_skbcount=0;
  48 
  49 /*
  50  *      Debugging paranoia. Can go later when this crud stack works
  51  */ 
  52  
  53 
  54 
  55 void skb_check(struct sk_buff *skb, int line, char *file)
     /* [previous][next][first][last][top][bottom][index][help] */
  56 {
  57         if(skb->magic_debug_cookie==SK_FREED_SKB)
  58         {
  59                 printk("File: %s Line %d, found a freed skb lurking in the undergrowth!\n",
  60                         file,line);
  61                 printk("skb=%p, real size=%ld, claimed size=%ld, magic=%d, list=%p, free=%d\n",
  62                         skb,skb->truesize,skb->mem_len,skb->magic,skb->list,skb->free);
  63         }
  64         if(skb->magic_debug_cookie!=SK_GOOD_SKB)
  65         {
  66                 printk("File: %s Line %d, passed a non skb!\n", file,line);
  67                 printk("skb=%p, real size=%ld, claimed size=%ld, magic=%d, list=%p, free=%d\n",
  68                         skb,skb->truesize,skb->mem_len,skb->magic,skb->list,skb->free);
  69         }
  70         if(skb->mem_len!=skb->truesize)
  71         {
  72                 printk("File: %s Line %d, Dubious size setting!\n",file,line);
  73                 printk("skb=%p, real size=%ld, claimed size=%ld, magic=%d, list=%p\n",
  74                         skb,skb->truesize,skb->mem_len,skb->magic,skb->list);
  75         }
  76         /* Guess it might be acceptable then */
  77 }
  78 
  79 /*
  80  *      Insert an sk_buff at the start of a list.
  81  */
  82     
  83 void skb_queue_head(struct sk_buff *volatile* list,struct sk_buff *newsk)
     /* [previous][next][first][last][top][bottom][index][help] */
  84 {
  85         unsigned long flags;
  86         
  87         IS_SKB(newsk);  
  88         if(newsk->list)
  89                 printk("Suspicious queue head: sk_buff on list!\n");
  90         save_flags(flags);
  91         cli();
  92         newsk->list=list;
  93         
  94         newsk->next=*list;
  95         
  96         if(*list)
  97                 newsk->prev=(*list)->prev;
  98         else
  99                 newsk->prev=newsk;
 100         newsk->prev->next=newsk;
 101         newsk->next->prev=newsk;
 102         IS_SKB(newsk->prev);
 103         IS_SKB(newsk->next);
 104         *list=newsk;
 105         restore_flags(flags);
 106 }
 107 
 108 /*
 109  *      Insert an sk_buff at the end of a list.
 110  */
 111  
 112 void skb_queue_tail(struct sk_buff *volatile* list, struct sk_buff *newsk)
     /* [previous][next][first][last][top][bottom][index][help] */
 113 {
 114         unsigned long flags;
 115         
 116         if(newsk->list)
 117                 printk("Suspicious queue tail: sk_buff on list!\n");
 118         
 119         IS_SKB(newsk);
 120         save_flags(flags);
 121         cli();
 122 
 123         newsk->list=list;
 124         if(*list)
 125         {
 126                 (*list)->prev->next=newsk;
 127                 newsk->prev=(*list)->prev;
 128                 newsk->next=*list;
 129                 (*list)->prev=newsk;
 130         }
 131         else
 132         {
 133                 newsk->next=newsk;
 134                 newsk->prev=newsk;
 135                 *list=newsk;
 136         }
 137         IS_SKB(newsk->prev);
 138         IS_SKB(newsk->next);            
 139         restore_flags(flags);
 140 
 141 }
 142 
 143 /*
 144  *      Remove an sk_buff from a list. This routine is also interrupt safe
 145  *      so you can grab read and free buffers as another process adds them.
 146  */
 147  
 148 struct sk_buff *skb_dequeue(struct sk_buff *volatile* list)
     /* [previous][next][first][last][top][bottom][index][help] */
 149 {
 150         long flags;
 151         struct sk_buff *result;
 152         
 153         save_flags(flags);
 154         cli();
 155         
 156         if(*list==NULL)
 157         {
 158                 restore_flags(flags);
 159                 return(NULL);
 160         }
 161         
 162         result=*list;
 163         if(result->next==result)
 164                 *list=NULL;
 165         else
 166         {
 167                 result->next->prev=result->prev;
 168                 result->prev->next=result->next;
 169                 *list=result->next;
 170         }
 171 
 172         IS_SKB(result);
 173         restore_flags(flags);
 174         
 175         if(result->list!=list)
 176                 printk("Dequeued packet has invalid list pointer\n");
 177 
 178         result->list=0;
 179         result->next=0;
 180         result->prev=0;
 181         return(result);
 182 }
 183 
 184 /*
 185  *      Insert a packet before another one in a list.
 186  */
 187  
 188 void skb_insert(struct sk_buff *old, struct sk_buff *newsk)
     /* [previous][next][first][last][top][bottom][index][help] */
 189 {
 190         unsigned long flags;
 191 
 192         IS_SKB(old);
 193         IS_SKB(newsk);
 194                 
 195         if(!old->list)
 196                 printk("insert before unlisted item!\n");
 197         if(newsk->list)
 198                 printk("inserted item is already on a list.\n");
 199                 
 200         save_flags(flags);
 201         cli();
 202         newsk->list=old->list;
 203         newsk->next=old;
 204         newsk->prev=old->prev;
 205         newsk->next->prev=newsk;
 206         newsk->prev->next=newsk;
 207         
 208         restore_flags(flags);
 209 }
 210 
 211 /*
 212  *      Place a packet after a given packet in a list.
 213  */
 214  
 215 void skb_append(struct sk_buff *old, struct sk_buff *newsk)
     /* [previous][next][first][last][top][bottom][index][help] */
 216 {
 217         unsigned long flags;
 218         
 219         IS_SKB(old);
 220         IS_SKB(newsk);
 221 
 222         if(!old->list)
 223                 printk("append before unlisted item!\n");
 224         if(newsk->list)
 225                 printk("append item is already on a list.\n");
 226                 
 227         save_flags(flags);
 228         cli();
 229         newsk->list=old->list;
 230         newsk->prev=old;
 231         newsk->next=old->next;
 232         newsk->next->prev=newsk;
 233         newsk->prev->next=newsk;
 234         
 235         restore_flags(flags);
 236 }
 237 
 238 /*
 239  *      Remove an sk_buff from its list. Works even without knowing the list it
 240  *      is sitting on, which can be handy at times. It also means that THE LIST
 241  *      MUST EXIST when you unlink. Thus a list must have its contents unlinked
 242  *      _FIRST_.
 243  */
 244  
 245 void skb_unlink(struct sk_buff *skb)
     /* [previous][next][first][last][top][bottom][index][help] */
 246 {
 247         unsigned long flags;
 248         save_flags(flags);
 249         cli();
 250 
 251         IS_SKB(skb);
 252         
 253         if(skb->list)
 254         {
 255                 skb->next->prev=skb->prev;
 256                 skb->prev->next=skb->next;
 257                 if(*skb->list==skb)
 258                 {
 259                         if(skb->next==skb)
 260                                 *skb->list=NULL;
 261                         else
 262                                 *skb->list=skb->next;
 263                 }
 264                 skb->next=0;
 265                 skb->prev=0;
 266                 skb->list=0;
 267         }
 268         restore_flags(flags);
 269 }
 270 
 271 /*
 272  *      An skbuff list has had its head reassigned. Move all the list
 273  *      pointers. Must be called with ints off during the whole head
 274  *      shifting
 275  */
 276 
 277 void skb_new_list_head(struct sk_buff *volatile* list)
     /* [previous][next][first][last][top][bottom][index][help] */
 278 {
 279         struct sk_buff *skb=skb_peek(list);
 280         if(skb!=NULL)
 281         {
 282                 do
 283                 {
 284                         IS_SKB(skb);
 285                         skb->list=list;
 286                         skb=skb->next;
 287                 }
 288                 while(skb!=*list);
 289         }
 290 }
 291                         
 292 /*
 293  *      Peek an sk_buff. Unlike most other operations you _MUST_
 294  *      be careful with this one. A peek leaves the buffer on the
 295  *      list and someone else may run off with it. For an interrupt
 296  *      type system cli() peek the buffer copy the data and sti();
 297  */
 298 
 299 struct sk_buff *skb_peek(struct sk_buff *volatile* list)
     /* [previous][next][first][last][top][bottom][index][help] */
 300 {
 301         return *list;
 302 }
 303 
 304 /*
 305  *      Get a clone of an sk_buff. This is the safe way to peek at
 306  *      a socket queue without accidents. Its a bit long but most
 307  *      of it acutally ends up as tiny bits of inline assembler
 308  *      anyway. Only the memcpy of upto 4K with ints off is not
 309  *      as nice as I'd like.
 310  */
 311  
 312 struct sk_buff *skb_peek_copy(struct sk_buff *volatile* list)
     /* [previous][next][first][last][top][bottom][index][help] */
 313 {
 314         struct sk_buff *orig,*newsk;
 315         unsigned long flags;
 316         unsigned int len;
 317         /* Now for some games to avoid races */
 318         
 319         do
 320         {
 321                 save_flags(flags);
 322                 cli();
 323                 orig=skb_peek(list);
 324                 if(orig==NULL)
 325                 {
 326                         restore_flags(flags);
 327                         return NULL;
 328                 }
 329                 IS_SKB(orig);
 330                 len=orig->truesize;
 331                 restore_flags(flags);
 332 
 333                 newsk=alloc_skb(len,GFP_KERNEL);        /* May sleep */
 334 
 335                 if(newsk==NULL)         /* Oh dear... not to worry */
 336                         return NULL;
 337         
 338                 save_flags(flags);
 339                 cli();
 340                 if(skb_peek(list)!=orig)        /* List changed go around another time */
 341                 {
 342                         restore_flags(flags);
 343                         newsk->sk=NULL;
 344                         newsk->free=1;
 345                         newsk->mem_addr=newsk;
 346                         newsk->mem_len=len;
 347                         kfree_skb(newsk, FREE_WRITE);
 348                         continue;
 349                 }
 350                 
 351                 IS_SKB(orig);
 352                 IS_SKB(newsk);
 353                 memcpy(newsk,orig,len);
 354                 newsk->list=NULL;
 355                 newsk->magic=0;
 356                 newsk->next=NULL;
 357                 newsk->prev=NULL;
 358                 newsk->mem_addr=newsk;
 359                 newsk->h.raw+=((char *)newsk-(char *)orig);
 360                 newsk->link3=NULL;
 361                 newsk->sk=NULL;
 362                 newsk->free=1;
 363         }
 364         while(0);
 365         
 366         restore_flags(flags);
 367         return(newsk);
 368 }       
 369         
 370 /*
 371  *      Free an sk_buff. This still knows about things it should
 372  *      not need to like protocols and sockets.
 373  */
 374 
 375 void kfree_skb(struct sk_buff *skb, int rw)
     /* [previous][next][first][last][top][bottom][index][help] */
 376 {
 377   if (skb == NULL) {
 378         printk("kfree_skb: skb = NULL\n");
 379         return;
 380   }
 381   IS_SKB(skb);
 382   if(skb->free == 2)
 383         printk("Warning: kfree_skb passed an skb that nobody set the free flag on!\n");
 384   if(skb->list)
 385         printk("Warning: kfree_skb passed an skb still on a list.\n");
 386   skb->magic = 0;
 387   if (skb->sk) {
 388         if (rw) {
 389              skb->sk->prot->rfree(skb->sk, skb->mem_addr, skb->mem_len);
 390         } else {
 391              skb->sk->prot->wfree(skb->sk, skb->mem_addr, skb->mem_len);
 392         }
 393   } else {
 394         kfree_skbmem(skb->mem_addr, skb->mem_len);
 395   }
 396 }
 397 
 398 /*
 399  *      Allocate a new skbuff. We do this ourselves so we can fill in a few 'private'
 400  *      fields and also do memory statistics to find all the [BEEP] leaks.
 401  */
 402  
 403  struct sk_buff *alloc_skb(unsigned int size,int priority)
     /* [previous][next][first][last][top][bottom][index][help] */
 404  {
 405         struct sk_buff *skb=(struct sk_buff *)kmalloc(size,priority);
 406         if(skb==NULL)
 407                 return NULL;
 408         skb->free= 2;   /* Invalid so we pick up forgetful users */
 409         skb->list= 0;   /* Not on a list */
 410         skb->truesize=size;
 411         skb->mem_len=size;
 412         skb->mem_addr=skb;
 413         skb->fraglist=NULL;
 414         net_memory+=size;
 415         net_skbcount++;
 416         skb->magic_debug_cookie=SK_GOOD_SKB;
 417         skb->users=0;
 418         return skb;
 419  }
 420 
 421 /*
 422  *      Free an skbuff by memory
 423  */     
 424 
 425 void kfree_skbmem(void *mem,unsigned size)
     /* [previous][next][first][last][top][bottom][index][help] */
 426 {
 427         struct sk_buff *x=mem;
 428         IS_SKB(x);
 429         if(x->magic_debug_cookie==SK_GOOD_SKB)
 430         {
 431                 x->magic_debug_cookie=SK_FREED_SKB;
 432                 kfree_s(mem,size);
 433                 net_skbcount--;
 434                 net_memory-=size;
 435         }
 436 }
 437  

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