转:http://blog.csdn.net/nerdx/article/details/12624407
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
1.1 int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*))
-
{
-
struct iphdr *iph;
-
int raw = 0;
-
int ptr;
-
struct net_device *dev;
-
struct sk_buff *skb2;
-
unsigned int mtu, hlen, left, len, ll_rs;
-
int offset;
-
int not_last_frag;
-
struct rtable *rt = (struct rtable*)skb->dst;
-
int err = 0;
-
-
dev = rt->u.dst.dev;
-
-
iph = skb->nh.iph;
-
-
-
if (unlikely((iph->frag_off & htons(IP_DF)) && !skb->local_df)) {
-
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
-
htonl(dst_pmtu(&rt->u.dst)));
-
kfree_skb(skb);
-
return -EMSGSIZE;
-
}
-
-
-
-
-
-
-
-
-
-
-
-
-
hlen = iph->ihl * 4;
-
mtu = dst_pmtu(&rt->u.dst) - hlen;
-
-
if (skb_shinfo(skb)->frag_list) {
-
struct sk_buff *frag;
-
int first_len = skb_pagelen(skb);
-
-
if (first_len - hlen > mtu ||
-
((first_len - hlen) & 7) ||
-
(iph->frag_off & htons(IP_MF|IP_OFFSET)) ||
-
skb_cloned(skb))
-
goto slow_path;
-
-
for (frag = skb_shinfo(skb)->frag_list; frag; frag = frag->next) {
-
-
if (frag->len > mtu ||
-
((frag->len & 7) && frag->next) ||
-
skb_headroom(frag) < hlen)
-
goto slow_path;
-
-
if (skb_shared(frag))
-
goto slow_path;
-
}
-
-
err = 0;
-
offset = 0;
-
frag = skb_shinfo(skb)->frag_list;
-
skb_shinfo(skb)->frag_list = NULL;
-
-
skb->data_len = first_len - skb_headlen(skb);
-
skb->len = first_len;
-
iph->tot_len = htons(first_len);
-
iph->frag_off |= htons(IP_MF);
-
ip_send_check(iph);
-
-
for (;;) {
-
if (frag) {
-
frag->ip_summed = CHECKSUM_NONE;
-
frag->h.raw = frag->data;
-
frag->nh.raw = __skb_push(frag, hlen);
-
memcpy(frag->nh.raw, iph, hlen);
-
iph = frag->nh.iph;
-
iph->tot_len = htons(frag->len);
-
ip_copy_metadata(frag, skb);
-
if (offset == 0)
-
ip_options_fragment(frag);
-
offset += skb->len - hlen;
-
iph->frag_off = htons(offset>>3);
-
if (frag->next != NULL)
-
iph->frag_off |= htons(IP_MF);
-
ip_send_check(iph);
-
}
-
-
err = output(skb);
-
-
if (err || !frag)
-
break;
-
-
skb = frag;
-
frag = skb->next;
-
skb->next = NULL;
-
}
-
-
if (err == 0) {
-
IP_INC_STATS(IPSTATS_MIB_FRAGOKS);
-
return 0;
-
}
-
-
while (frag) {
-
skb = frag->next;
-
kfree_skb(frag);
-
frag = skb;
-
}
-
IP_INC_STATS(IPSTATS_MIB_FRAGFAILS);
-
return err;
-
}
-
-
-
slow_path:
-
left = skb->len - hlen;
-
ptr = raw + hlen;
-
-
offset = (ntohs(iph->frag_off) & IP_OFFSET) << 3;
-
not_last_frag = iph->frag_off & htons(IP_MF);
-
-
-
while(left > 0) {
-
len = left;
-
if (len > mtu)
-
len = mtu;
-
-
if (len < left) {
-
len &= ~7;
-
}
-
-
if ((skb2 = alloc_skb(len+hlen+ll_rs, GFP_ATOMIC)) == NULL) {
-
NETDEBUG(printk(KERN_INFO "IP: frag: no memory for new fragment!\n"));
-
err = -ENOMEM;
-
goto fail;
-
}
-
-
ip_copy_metadata(skb2, skb);
-
skb_reserve(skb2, ll_rs);
-
skb_put(skb2, len + hlen);
-
skb2->nh.raw = skb2->data;
-
skb2->h.raw = skb2->data + hlen;
-
-
if (skb->sk)
-
skb_set_owner_w(skb2, skb->sk);
-
-
memcpy(skb2->nh.raw, skb->data, hlen);
-
-
-
if (skb_copy_bits(skb, ptr, skb2->h.raw, len))
-
BUG();
-
left -= len;
-
-
iph = skb2->nh.iph;
-
iph->frag_off = htons((offset >> 3));
-
-
-
-
-
if (offset == 0)
-
ip_options_fragment(skb);
-
-
if (left > 0 || not_last_frag)
-
iph->frag_off |= htons(IP_MF);
-
ptr += len;
-
offset += len;
-
-
IP_INC_STATS(IPSTATS_MIB_FRAGCREATES);
-
-
iph->tot_len = htons(len + hlen);
-
-
ip_send_check(iph);
-
-
err = output(skb2);
-
if (err)
-
goto fail;
-
}
-
kfree_skb(skb);
-
IP_INC_STATS(IPSTATS_MIB_FRAGOKS);
-
return err;
-
-
fail:
-
kfree_skb(skb);
-
IP_INC_STATS(IPSTATS_MIB_FRAGFAILS);
-
return err;
-
}
-
-
-
-
2.1 void ip_options_fragment(struct sk_buff * skb)
-
{
-
unsigned char * optptr = skb->nh.raw;
-
struct ip_options * opt = &(IPCB(skb)->opt);
-
int l = opt->optlen;
-
int optlen;
-
-
while (l > 0) {
-
switch (*optptr) {
-
case IPOPT_END:
-
return;
-
case IPOPT_NOOP:
-
l--;
-
optptr++;
-
continue;
-
}
-
optlen = optptr[1];
-
if (optlen<2 || optlen>l)
-
return;
-
if (!IPOPT_COPIED(*optptr))
-
memset(optptr, IPOPT_NOOP, optlen);
-
l -= optlen;
-
optptr += optlen;
-
}
-
opt->ts = 0;
-
opt->rr = 0;
-
opt->rr_needaddr = 0;
-
opt->ts_needaddr = 0;
-
opt->ts_needtime = 0;
-
return;
-
}
-
阅读(611) | 评论(0) | 转发(0) |