root/net/core/skbuff.c

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

DEFINITIONS

This source file includes following definitions.
  1. show_net_buffers
  2. skb_check
  3. skb_queue_head_init
  4. skb_queue_head
  5. skb_queue_tail
  6. skb_dequeue
  7. skb_insert
  8. skb_append
  9. skb_unlink
  10. skb_put
  11. skb_push
  12. skb_pull
  13. skb_headroom
  14. skb_tailroom
  15. skb_reserve
  16. skb_trim
  17. kfree_skb
  18. alloc_skb
  19. kfree_skbmem
  20. skb_clone
  21. skb_device_lock
  22. skb_device_unlock
  23. dev_kfree_skb
  24. dev_alloc_skb
  25. skb_device_locked

   1 /*
   2  *      Routines having to do with the 'struct sk_buff' memory handlers.
   3  *
   4  *      Authors:        Alan Cox <iiitac@pyr.swan.ac.uk>
   5  *                      Florian La Roche <rzsfl@rz.uni-sb.de>
   6  *
   7  *      Fixes:  
   8  *              Alan Cox        :       Fixed the worst of the load balancer bugs.
   9  *              Dave Platt      :       Interrupt stacking fix.
  10  *      Richard Kooijman        :       Timestamp fixes.
  11  *              Alan Cox        :       Changed buffer format.
  12  *
  13  *      This program is free software; you can redistribute it and/or
  14  *      modify it under the terms of the GNU General Public License
  15  *      as published by the Free Software Foundation; either version
  16  *      2 of the License, or (at your option) any later version.
  17  */
  18 
  19 /*
  20  *      Note: There are a load of cli()/sti() pairs protecting the net_memory type
  21  *      variables. Without them for some reason the ++/-- operators do not come out
  22  *      atomic. Also with gcc 2.4.5 these counts can come out wrong anyway - use 2.5.8!!
  23  */
  24 
  25 #include <linux/config.h>
  26 #include <linux/types.h>
  27 #include <linux/kernel.h>
  28 #include <linux/sched.h>
  29 #include <asm/segment.h>
  30 #include <asm/system.h>
  31 #include <linux/mm.h>
  32 #include <linux/interrupt.h>
  33 #include <linux/in.h>
  34 #include <linux/inet.h>
  35 #include <linux/netdevice.h>
  36 #include <net/ip.h>
  37 #include <net/protocol.h>
  38 #include <linux/string.h>
  39 #include <net/route.h>
  40 #include <net/tcp.h>
  41 #include <net/udp.h>
  42 #include <linux/skbuff.h>
  43 #include <net/sock.h>
  44 
  45 
  46 /*
  47  *      Resource tracking variables
  48  */
  49 
  50 volatile unsigned long net_skbcount = 0;
  51 volatile unsigned long net_locked = 0;
  52 volatile unsigned long net_allocs = 0;
  53 volatile unsigned long net_fails  = 0;
  54 volatile unsigned long net_free_locked = 0;
  55 
  56 void show_net_buffers(void)
     /* [previous][next][first][last][top][bottom][index][help] */
  57 {
  58         printk("Networking buffers in use          : %lu\n",net_skbcount);
  59         printk("Network buffers locked by drivers  : %lu\n",net_locked);
  60         printk("Total network buffer allocations   : %lu\n",net_allocs);
  61         printk("Total failed network buffer allocs : %lu\n",net_fails);
  62         printk("Total free while locked events     : %lu\n",net_free_locked);
  63 }
  64 
  65 #if CONFIG_SKB_CHECK
  66 
  67 /*
  68  *      Debugging paranoia. Can go later when this crud stack works
  69  */
  70 
  71 int skb_check(struct sk_buff *skb, int head, int line, char *file)
     /* [previous][next][first][last][top][bottom][index][help] */
  72 {
  73         if (head) {
  74                 if (skb->magic_debug_cookie != SK_HEAD_SKB) {
  75                         printk("File: %s Line %d, found a bad skb-head\n",
  76                                 file,line);
  77                         return -1;
  78                 }
  79                 if (!skb->next || !skb->prev) {
  80                         printk("skb_check: head without next or prev\n");
  81                         return -1;
  82                 }
  83                 if (skb->next->magic_debug_cookie != SK_HEAD_SKB
  84                         && skb->next->magic_debug_cookie != SK_GOOD_SKB) {
  85                         printk("File: %s Line %d, bad next head-skb member\n",
  86                                 file,line);
  87                         return -1;
  88                 }
  89                 if (skb->prev->magic_debug_cookie != SK_HEAD_SKB
  90                         && skb->prev->magic_debug_cookie != SK_GOOD_SKB) {
  91                         printk("File: %s Line %d, bad prev head-skb member\n",
  92                                 file,line);
  93                         return -1;
  94                 }
  95 #if 0
  96                 {
  97                 struct sk_buff *skb2 = skb->next;
  98                 int i = 0;
  99                 while (skb2 != skb && i < 5) {
 100                         if (skb_check(skb2, 0, line, file) < 0) {
 101                                 printk("bad queue element in whole queue\n");
 102                                 return -1;
 103                         }
 104                         i++;
 105                         skb2 = skb2->next;
 106                 }
 107                 }
 108 #endif
 109                 return 0;
 110         }
 111         if (skb->next != NULL && skb->next->magic_debug_cookie != SK_HEAD_SKB
 112                 && skb->next->magic_debug_cookie != SK_GOOD_SKB) {
 113                 printk("File: %s Line %d, bad next skb member\n",
 114                         file,line);
 115                 return -1;
 116         }
 117         if (skb->prev != NULL && skb->prev->magic_debug_cookie != SK_HEAD_SKB
 118                 && skb->prev->magic_debug_cookie != SK_GOOD_SKB) {
 119                 printk("File: %s Line %d, bad prev skb member\n",
 120                         file,line);
 121                 return -1;
 122         }
 123 
 124 
 125         if(skb->magic_debug_cookie==SK_FREED_SKB)
 126         {
 127                 printk("File: %s Line %d, found a freed skb lurking in the undergrowth!\n",
 128                         file,line);
 129                 printk("skb=%p, real size=%d, free=%d\n",
 130                         skb,skb->truesize,skb->free);
 131                 return -1;
 132         }
 133         if(skb->magic_debug_cookie!=SK_GOOD_SKB)
 134         {
 135                 printk("File: %s Line %d, passed a non skb!\n", file,line);
 136                 printk("skb=%p, real size=%d, free=%d\n",
 137                         skb,skb->truesize,skb->free);
 138                 return -1;
 139         }
 140         if(skb->head>skb->data)
 141         {
 142                 printk("File: %s Line %d, head > data !\n", file,line);
 143                 printk("skb=%p, head=%p, data=%p\n",
 144                         skb,skb->head,skb->data);
 145                 return -1;
 146         }
 147         if(skb->tail>skb->end)
 148         {
 149                 printk("File: %s Line %d, tail > end!\n", file,line);
 150                 printk("skb=%p, tail=%p, end=%p\n",
 151                         skb,skb->tail,skb->end);
 152                 return -1;
 153         }
 154         if(skb->data>skb->tail)
 155         {
 156                 printk("File: %s Line %d, data > tail!\n", file,line);
 157                 printk("skb=%p, data=%p, tail=%p\n",
 158                         skb,skb->data,skb->tail);
 159                 return -1;
 160         }
 161         if(skb->tail-skb->data!=skb->len)
 162         {
 163                 printk("File: %s Line %d, wrong length\n", file,line);
 164                 printk("skb=%p, data=%p, end=%p len=%ld\n",
 165                         skb,skb->data,skb->end,skb->len);
 166                 return -1;
 167         }
 168         if((unsigned long) skb->end > (unsigned long) skb)
 169         {
 170                 printk("File: %s Line %d, control overrun\n", file,line);
 171                 printk("skb=%p, end=%p\n",
 172                         skb,skb->end);
 173                 return -1;
 174         }
 175 
 176         /* Guess it might be acceptable then */
 177         return 0;
 178 }
 179 #endif
 180 
 181 
 182 #if CONFIG_SKB_CHECK
 183 void skb_queue_head_init(struct sk_buff_head *list)
     /* [previous][next][first][last][top][bottom][index][help] */
 184 {
 185         list->prev = (struct sk_buff *)list;
 186         list->next = (struct sk_buff *)list;
 187         list->magic_debug_cookie = SK_HEAD_SKB;
 188 }
 189 
 190 
 191 /*
 192  *      Insert an sk_buff at the start of a list.
 193  */
 194 void skb_queue_head(struct sk_buff_head *list_,struct sk_buff *newsk)
     /* [previous][next][first][last][top][bottom][index][help] */
 195 {
 196         unsigned long flags;
 197         struct sk_buff *list = (struct sk_buff *)list_;
 198 
 199         save_flags(flags);
 200         cli();
 201 
 202         IS_SKB(newsk);
 203         IS_SKB_HEAD(list);
 204         if (newsk->next || newsk->prev)
 205                 printk("Suspicious queue head: sk_buff on list!\n");
 206 
 207         newsk->next = list->next;
 208         newsk->prev = list;
 209 
 210         newsk->next->prev = newsk;
 211         newsk->prev->next = newsk;
 212 
 213         restore_flags(flags);
 214 }
 215 
 216 /*
 217  *      Insert an sk_buff at the end of a list.
 218  */
 219 void skb_queue_tail(struct sk_buff_head *list_, struct sk_buff *newsk)
     /* [previous][next][first][last][top][bottom][index][help] */
 220 {
 221         unsigned long flags;
 222         struct sk_buff *list = (struct sk_buff *)list_;
 223 
 224         save_flags(flags);
 225         cli();
 226 
 227         if (newsk->next || newsk->prev)
 228                 printk("Suspicious queue tail: sk_buff on list!\n");
 229         IS_SKB(newsk);
 230         IS_SKB_HEAD(list);
 231 
 232         newsk->next = list;
 233         newsk->prev = list->prev;
 234 
 235         newsk->next->prev = newsk;
 236         newsk->prev->next = newsk;
 237 
 238         restore_flags(flags);
 239 }
 240 
 241 /*
 242  *      Remove an sk_buff from a list. This routine is also interrupt safe
 243  *      so you can grab read and free buffers as another process adds them.
 244  */
 245 
 246 struct sk_buff *skb_dequeue(struct sk_buff_head *list_)
     /* [previous][next][first][last][top][bottom][index][help] */
 247 {
 248         long flags;
 249         struct sk_buff *result;
 250         struct sk_buff *list = (struct sk_buff *)list_;
 251 
 252         save_flags(flags);
 253         cli();
 254 
 255         IS_SKB_HEAD(list);
 256 
 257         result = list->next;
 258         if (result == list) {
 259                 restore_flags(flags);
 260                 return NULL;
 261         }
 262 
 263         result->next->prev = list;
 264         list->next = result->next;
 265 
 266         result->next = NULL;
 267         result->prev = NULL;
 268 
 269         restore_flags(flags);
 270 
 271         IS_SKB(result);
 272         return result;
 273 }
 274 
 275 /*
 276  *      Insert a packet before another one in a list.
 277  */
 278 void skb_insert(struct sk_buff *old, struct sk_buff *newsk)
     /* [previous][next][first][last][top][bottom][index][help] */
 279 {
 280         unsigned long flags;
 281 
 282         IS_SKB(old);
 283         IS_SKB(newsk);
 284 
 285         if(!old->next || !old->prev)
 286                 printk("insert before unlisted item!\n");
 287         if(newsk->next || newsk->prev)
 288                 printk("inserted item is already on a list.\n");
 289 
 290         save_flags(flags);
 291         cli();
 292         newsk->next = old;
 293         newsk->prev = old->prev;
 294         old->prev = newsk;
 295         newsk->prev->next = newsk;
 296 
 297         restore_flags(flags);
 298 }
 299 
 300 /*
 301  *      Place a packet after a given packet in a list.
 302  */
 303 void skb_append(struct sk_buff *old, struct sk_buff *newsk)
     /* [previous][next][first][last][top][bottom][index][help] */
 304 {
 305         unsigned long flags;
 306 
 307         IS_SKB(old);
 308         IS_SKB(newsk);
 309 
 310         if(!old->next || !old->prev)
 311                 printk("append before unlisted item!\n");
 312         if(newsk->next || newsk->prev)
 313                 printk("append item is already on a list.\n");
 314 
 315         save_flags(flags);
 316         cli();
 317 
 318         newsk->prev = old;
 319         newsk->next = old->next;
 320         newsk->next->prev = newsk;
 321         old->next = newsk;
 322 
 323         restore_flags(flags);
 324 }
 325 
 326 /*
 327  *      Remove an sk_buff from its list. Works even without knowing the list it
 328  *      is sitting on, which can be handy at times. It also means that THE LIST
 329  *      MUST EXIST when you unlink. Thus a list must have its contents unlinked
 330  *      _FIRST_.
 331  */
 332 void skb_unlink(struct sk_buff *skb)
     /* [previous][next][first][last][top][bottom][index][help] */
 333 {
 334         unsigned long flags;
 335 
 336         save_flags(flags);
 337         cli();
 338 
 339         IS_SKB(skb);
 340 
 341         if(skb->prev && skb->next)
 342         {
 343                 skb->next->prev = skb->prev;
 344                 skb->prev->next = skb->next;
 345                 skb->next = NULL;
 346                 skb->prev = NULL;
 347         }
 348 #ifdef PARANOID_BUGHUNT_MODE    /* This is legal but we sometimes want to watch it */
 349         else
 350                 printk("skb_unlink: not a linked element\n");
 351 #endif
 352         restore_flags(flags);
 353 }
 354 
 355 /*
 356  *      Add data to an sk_buff
 357  */
 358  
 359 unsigned char *skb_put(struct sk_buff *skb, int len)
     /* [previous][next][first][last][top][bottom][index][help] */
 360 {
 361         unsigned char *tmp=skb->tail;
 362         IS_SKB(skb);
 363         skb->tail+=len;
 364         skb->len+=len;
 365         IS_SKB(skb);
 366         if(skb->tail>skb->end)
 367                 panic("skput:over: %p:%d", __builtin_return_address(0),len);
 368         return tmp;
 369 }
 370 
 371 unsigned char *skb_push(struct sk_buff *skb, int len)
     /* [previous][next][first][last][top][bottom][index][help] */
 372 {
 373         IS_SKB(skb);
 374         skb->data-=len;
 375         skb->len+=len;
 376         IS_SKB(skb);
 377         if(skb->data<skb->head)
 378                 panic("skpush:under: %p:%d", __builtin_return_address(0),len);
 379         return skb->data;
 380 }
 381 
 382 int skb_pull(struct sk_buff *skb, int len)
     /* [previous][next][first][last][top][bottom][index][help] */
 383 {
 384         IS_SKB(skb);
 385         if(len>skb->len)
 386                 len=skb->len;
 387         skb->data+=len;
 388         skb->len-=len;
 389         return len;
 390 }
 391 
 392 int skb_headroom(struct sk_buff *skb)
     /* [previous][next][first][last][top][bottom][index][help] */
 393 {
 394         IS_SKB(skb);
 395         return skb->data-skb->head;
 396 }
 397 
 398 int skb_tailroom(struct sk_buff *skb)
     /* [previous][next][first][last][top][bottom][index][help] */
 399 {
 400         IS_SKB(skb);
 401         return skb->end-skb->tail;
 402 }
 403 
 404 void skb_reserve(struct sk_buff *skb, int len)
     /* [previous][next][first][last][top][bottom][index][help] */
 405 {
 406         IS_SKB(skb);
 407         skb->data+=len;
 408         skb->tail+=len;
 409         if(skb->tail>skb->end)
 410                 panic("sk_res: over");
 411         if(skb->data<skb->head)
 412                 panic("sk_res: under");
 413         IS_SKB(skb);
 414 }
 415 
 416 void skb_trim(struct sk_buff *skb, int len)
     /* [previous][next][first][last][top][bottom][index][help] */
 417 {
 418         IS_SKB(skb);
 419         if(skb->len>len)
 420         {
 421                 skb->len=len;
 422                 skb->tail=skb->data+len;
 423         }
 424 }
 425 
 426 
 427 
 428 #endif
 429 
 430 /*
 431  *      Free an sk_buff. This still knows about things it should
 432  *      not need to like protocols and sockets.
 433  */
 434 
 435 void kfree_skb(struct sk_buff *skb, int rw)
     /* [previous][next][first][last][top][bottom][index][help] */
 436 {
 437         if (skb == NULL)
 438         {
 439                 printk("kfree_skb: skb = NULL (from %p)\n",
 440                         __builtin_return_address(0));
 441                 return;
 442         }
 443 #if CONFIG_SKB_CHECK
 444         IS_SKB(skb);
 445 #endif
 446         if (skb->lock)
 447         {
 448                 skb->free = 3;    /* Free when unlocked */
 449                 net_free_locked++;
 450                 return;
 451         }
 452         if (skb->free == 2)
 453                 printk("Warning: kfree_skb passed an skb that nobody set the free flag on! (from %p)\n",
 454                         __builtin_return_address(0));
 455         if (skb->next)
 456                 printk("Warning: kfree_skb passed an skb still on a list (from %p).\n",
 457                         __builtin_return_address(0));
 458         if (skb->sk)
 459         {
 460                 if(skb->sk->prot!=NULL)
 461                 {
 462                         if (rw)
 463                                 skb->sk->prot->rfree(skb->sk, skb);
 464                         else
 465                                 skb->sk->prot->wfree(skb->sk, skb);
 466 
 467                 }
 468                 else
 469                 {
 470                         unsigned long flags;
 471                         /* Non INET - default wmalloc/rmalloc handler */
 472                         save_flags(flags);
 473                         cli();
 474                         if (rw)
 475                                 skb->sk->rmem_alloc-=skb->truesize;
 476                         else
 477                                 skb->sk->wmem_alloc-=skb->truesize;
 478                         restore_flags(flags);
 479                         if(!skb->sk->dead)
 480                                 skb->sk->write_space(skb->sk);
 481                         kfree_skbmem(skb);
 482                 }
 483         }
 484         else
 485                 kfree_skbmem(skb);
 486 }
 487 
 488 /*
 489  *      Allocate a new skbuff. We do this ourselves so we can fill in a few 'private'
 490  *      fields and also do memory statistics to find all the [BEEP] leaks.
 491  */
 492 struct sk_buff *alloc_skb(unsigned int size,int priority)
     /* [previous][next][first][last][top][bottom][index][help] */
 493 {
 494         struct sk_buff *skb;
 495         unsigned long flags;
 496         int len=size;
 497         unsigned char *bptr;
 498 
 499         if (intr_count && priority!=GFP_ATOMIC) 
 500         {
 501                 static int count = 0;
 502                 if (++count < 5) {
 503                         printk("alloc_skb called nonatomically from interrupt %p\n",
 504                                 __builtin_return_address(0));
 505                         priority = GFP_ATOMIC;
 506                 }
 507         }
 508 
 509         size=(size+15)&~15;             /* Allow for alignments. Make a multiple of 16 bytes */
 510         size+=sizeof(struct sk_buff);   /* And stick the control itself on the end */
 511         
 512         /*
 513          *      Allocate some space
 514          */
 515          
 516         bptr=(unsigned char *)kmalloc(size,priority);
 517         if (bptr == NULL)
 518         {
 519                 net_fails++;
 520                 return NULL;
 521         }
 522 #ifdef PARANOID_BUGHUNT_MODE
 523         if(skb->magic_debug_cookie == SK_GOOD_SKB)
 524                 printk("Kernel kmalloc handed us an existing skb (%p)\n",skb);
 525 #endif
 526         /*
 527          *      Now we play a little game with the caches. Linux kmalloc is
 528          *      a bit cache dumb, in fact its just about maximally non 
 529          *      optimal for typical kernel buffers. We actually run faster
 530          *      by doing the following. Which is to deliberately put the
 531          *      skb at the _end_ not the start of the memory block.
 532          */
 533         net_allocs++;
 534         
 535         skb=(struct sk_buff *)(bptr+size)-1;
 536 
 537         skb->free = 2;  /* Invalid so we pick up forgetful users */
 538         skb->lock = 0;
 539         skb->pkt_type = PACKET_HOST;    /* Default type */
 540         skb->prev = skb->next = NULL;
 541         skb->link3 = NULL;
 542         skb->sk = NULL;
 543         skb->truesize=size;
 544         skb->localroute=0;
 545         skb->stamp.tv_sec=0;    /* No idea about time */
 546         skb->localroute = 0;
 547         skb->ip_summed = 0;
 548         save_flags(flags);
 549         cli();
 550         net_skbcount++;
 551         restore_flags(flags);
 552 #if CONFIG_SKB_CHECK
 553         skb->magic_debug_cookie = SK_GOOD_SKB;
 554 #endif
 555         skb->users = 0;
 556         /* Load the data pointers */
 557         skb->head=bptr;
 558         skb->data=bptr;
 559         skb->tail=bptr;
 560         skb->end=bptr+len;
 561         skb->len=0;
 562         return skb;
 563 }
 564 
 565 /*
 566  *      Free an skbuff by memory
 567  */
 568 
 569 void kfree_skbmem(struct sk_buff *skb)
     /* [previous][next][first][last][top][bottom][index][help] */
 570 {
 571         unsigned long flags;
 572         save_flags(flags);
 573         cli();
 574         kfree((void *)skb->head);
 575         net_skbcount--;
 576         restore_flags(flags);
 577 }
 578 
 579 /*
 580  *      Duplicate an sk_buff. The new one is not owned by a socket or locked
 581  *      and will be freed on deletion.
 582  */
 583 
 584 struct sk_buff *skb_clone(struct sk_buff *skb, int priority)
     /* [previous][next][first][last][top][bottom][index][help] */
 585 {
 586         struct sk_buff *n;
 587         unsigned long offset;
 588 
 589         /*
 590          *      Allocate the copy buffer
 591          */
 592          
 593         IS_SKB(skb);
 594         
 595         n=alloc_skb(skb->truesize-sizeof(struct sk_buff),priority);
 596         if(n==NULL)
 597                 return NULL;
 598 
 599         /*
 600          *      Shift between the two data areas in bytes
 601          */
 602          
 603         offset=n->head-skb->head;
 604 
 605         /* Set the data pointer */
 606         skb_reserve(n,skb->data-skb->head);
 607         /* Set the tail pointer and length */
 608         skb_put(n,skb->len);
 609         /* Copy the bytes */
 610         memcpy(n->head,skb->head,skb->end-skb->head);
 611         n->link3=NULL;
 612         n->sk=NULL;
 613         n->when=skb->when;
 614         n->dev=skb->dev;
 615         n->h.raw=skb->h.raw+offset;
 616         n->mac.raw=skb->mac.raw+offset;
 617         n->ip_hdr=(struct iphdr *)(((char *)skb->ip_hdr)+offset);
 618         n->saddr=skb->saddr;
 619         n->daddr=skb->daddr;
 620         n->raddr=skb->raddr;
 621         n->acked=skb->acked;
 622         n->used=skb->used;
 623         n->free=1;
 624         n->arp=skb->arp;
 625         n->tries=0;
 626         n->lock=0;
 627         n->users=0;
 628         n->pkt_type=skb->pkt_type;
 629         n->stamp=skb->stamp;
 630         
 631         IS_SKB(n);
 632         return n;
 633 }
 634 
 635 
 636 /*
 637  *     Skbuff device locking
 638  */
 639 
 640 void skb_device_lock(struct sk_buff *skb)
     /* [previous][next][first][last][top][bottom][index][help] */
 641 {
 642         if(skb->lock)
 643                 printk("double lock on device queue!\n");
 644         else
 645                 net_locked++;
 646         skb->lock++;
 647 }
 648 
 649 void skb_device_unlock(struct sk_buff *skb)
     /* [previous][next][first][last][top][bottom][index][help] */
 650 {
 651         if(skb->lock==0)
 652                 printk("double unlock on device queue!\n");
 653         skb->lock--;
 654         if(skb->lock==0)
 655                 net_locked--;
 656 }
 657 
 658 void dev_kfree_skb(struct sk_buff *skb, int mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 659 {
 660         unsigned long flags;
 661 
 662         save_flags(flags);
 663         cli();
 664         if(skb->lock==1)
 665                 net_locked--;
 666 
 667         if (!--skb->lock && (skb->free == 1 || skb->free == 3))
 668         {
 669                 restore_flags(flags);
 670                 kfree_skb(skb,mode);
 671         }
 672         else
 673                 restore_flags(flags);
 674 }
 675 
 676 struct sk_buff *dev_alloc_skb(unsigned int length)
     /* [previous][next][first][last][top][bottom][index][help] */
 677 {
 678         struct sk_buff *skb;
 679 
 680         skb = alloc_skb(length+16, GFP_ATOMIC);
 681         if (skb)
 682                 skb_reserve(skb,16);
 683         return skb;
 684 }
 685 
 686 int skb_device_locked(struct sk_buff *skb)
     /* [previous][next][first][last][top][bottom][index][help] */
 687 {
 688         return skb->lock? 1 : 0;
 689 }
 690 

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