I have to do a very similar process in my MPLS for Linux implementation.
Here is a solution for 2.3.99-pre5. If anyone sees a better way to do this
(or errors in my implementation) please let me know.
This has been taken out of it's context so code has been added to help clarify.
The goal is to add a 4 byte shim to head of an SKB (take note that I cannot
take full credit/blame for this code :-)
int mpls_opcode_push(struct sk_buff **skb, more unrelated parameters) {
struct sk_buff *orig_skb = *skb;
struct sk_buff *new_skb = NULL;
/*
* you'll notice that I have added a field to the skb_buf to keep track of
* any space I create due to other MPLS related activities
*/
if(orig_skb->mpls_gap >= sizeof(u32)) {
/*
* if we have room between data and end of mac.raw
* just shift the data,n.raw,nh.raw pointers and use the room
* this would happen if we had a pop previous to this
*/
printk("%s: using gap\n",fn_name);
skb_push(orig_skb,sizeof(u32));
orig_skb->h.raw -= sizeof(u32);
orig_skb->nh.raw -= sizeof(u32);
orig_skb->mpls_gap -= sizeof(u32);
} else if((orig_skb->end - orig_skb->tail) > sizeof(u32)) {
/*
* if we have tailroom, just move tha data down enough room for
* the shim
*/
printk("%s: using tailroom\n",fn_name);
memmove(orig_skb->data+sizeof(u32),orig_skb->data,orig_skb->len);
orig_skb->len += sizeof(u32);
printk("%s: done using tailroom\n",fn_name);
} else {
/*
* we have no room in the inn, go ahead and create a new sk_buff
* with enough extra room for one shim
*/
printk("%s: creating larger packet\n",fn_name);
new_skb = alloc_skb(orig_skb->truesize + sizeof(u32),GFP_ATOMIC);
if(new_skb == NULL) return -ENOMEM;
/*
I hate hard-coding numbers like this: Maybe use mpls_gap
Revist --JHS
*/
skb_reserve(new_skb,16);
skb_put(new_skb,sizeof(u32)+orig_skb->len);
memmove(new_skb->data+sizeof(u32), orig_skb->data, orig_skb->len);
/*
* this is what skb_grow does
*/
copy_skb_header(new_skb,orig_skb);
kfree_skb(orig_skb);
orig_skb = *skb = new_skb;
}
I hope this helps.
Jim
On Wed, Apr 19, 2000 at 10:44:48AM -0400, Sumit Garg wrote:
> Hello,
> I am trying to modify the contents of a well formed sk_buff in a
> function called from
> dev_queue_xmit() with properly filled in sk_buff.
> I may need to add or delete or simply overwrite certain portions of the
> data in skbuff buffer.
> Now .. If I plainly overwrite a chunk of data in buffer , and update the
> checksums of TCP, IP headers.. things work fine.
> However if I try to ADD new data or DELETE... the same sk_buff keeps
> transmitting.. though it gets acks
>
> By the way, I am trying to modify sk_buffs generated by a specific
> telnet session. and once I do the modifications.. that telnet session
> hangs up. (though I can start new telnet connections)
>
> Any insight?
>
> The code: diff the the amount by which I need to change the size. I
> need to replace the data at
> (o_buf) of length (o_len) in sk_buff (skb) by new data in a buffer
> pointed to by n_buf of length n_len.
>
> o_offset=o_buf - (char*) skb->data;
> skb_len=skb->len;
>
> if (skb_tailroom(skb)>=diff) {
> if (diff>0) { // grow
> skb_put(skb,diff);
> memmove(o_buf + n_len, o_buf + o_len,
> skb_len - (o_offset + o_len) );
> memmove(o_buf, n_buf, n_len);
> } else { // shrink
> memmove(o_buf+n_len, o_buf+o_len, skb->len - (o_offset +
> o_len));
> skb_trim(skb,skb->len+diff);
> memmove(o_buf,n_buf,n_len);
> }
>
>
>
>
> Thanks
> Sumit
>
--
James R. Leu
|