Hi, thanks for your reply. skb_pull() was fine for splitting the large frame into small chunks for passing down to our card. I didn't need skb_push() as I didn't want the segments added to the front of the skb, skb_put was indeed what I needed. It all seems to work OK. We can now send and receive 32K frames (a limit of the hdlc controller on our card), passed to the card in small chunks. Thanks Kevin -----Original Message----- From: nospamnospam@vip.cybercity.dk [mailto:nospamnospam@vip.cybercity.dk] Sent: 14 May 2003 17:34 To: kevin.curtis@farsite.co.uk Cc: linux-net@vger.kernel.org Subject: Re: skb_pull() > It looks to me as though the skb-pull() function is what I want. I can pull > each 1K chunk off at a time. Is it really that simple? However, an element > of doubt has been put in my mind by the description of the function in the > Linux Device Drivers book ("Removes data from the head of the packet. The > driver won't need to use this function, but is included for completeness.") > Hopefully, it is complete. I think "completeness" refers to the book, not to the functionality of skb_pull(). I think it is most unsual to use skb_pull() in a network device driver. > Will I be able to use skb_push() > function to assemble a 4K frame in a similar manner on the receive side? Normally, you'd use skb_put(). This assumes that the first chunk is received first: skb = dev_alloc_skb (4K + alignment); skb_reserve (skb, alignment); insl (ioaddr + x, skb_put (skb, 1K), 1K); /* 1st chunk. */ ... insl (ioaddr + x, skb_put (skb, 1K), 1K); /* 2nd chunk. */ ... insl (ioaddr + x, skb_put (skb, 1K), 1K); /* 3rd chunk. */ ... insl (ioaddr + x, skb_put (skb, 1K), 1K); /* 4th chunk. */ If you get the first chunk last, then use skb_push(): skb = dev_alloc_skb (4K + alignment); skb_reserve (skb, 4K + alignment); insl (ioaddr + x, skb_push (skb, 1K), 1K); /* 4th chunk. */ ... insl (ioaddr + x, skb_push (skb, 1K), 1K); /* 3rd chunk. */ ... insl (ioaddr + x, skb_push (skb, 1K), 1K); /* 2nd chunk. */ ... insl (ioaddr + x, skb_push (skb, 1K), 1K); /* 1st chunk. */ (I don't know what skb_push() returns, I'm assuming it returns a pointer to the new 1K chunk in skb_put() style. If not, modify accordingly.) This should work fine with 2.2 kernels too. All of the above assumed that you use PIO transfers. With a DMA device, you'll need to manage the pointers yourself on the receive side when dealing with the chunks. Something like: skb = dev_alloc_skb (4K + alignment); skb_reserve (skb, alignment); dma_pointer = pci_map_single (pdev, skb->head, 4K, PCI_DMA_FROMDEVICE); /* await completion of DMA */ skb_put (skb, length_of_whole_packet); pci_unmap_single (pdev, dma_pointer, skb->head, 4K, PCI_DMA_FROMDEVICE); (Please the the order of the arguments.) Regards, Rask Ingemann Lambertsen - : send the line "unsubscribe linux-net" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html