Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 158964
b: refs/heads/master
c: d7ca4cc
h: refs/heads/master
v: v3
  • Loading branch information
Sridhar Samudrala authored and David S. Miller committed Jul 12, 2009
1 parent 84124be commit 0e0afb5
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 2 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 30ffee8480c13fbcf8ab6c28e31f79dfff683117
refs/heads/master: d7ca4cc01fd154f2da30ae6dae160fa5800af758
3 changes: 3 additions & 0 deletions trunk/include/net/udp.h
Original file line number Diff line number Diff line change
Expand Up @@ -207,4 +207,7 @@ extern void udp4_proc_exit(void);
#endif

extern void udp_init(void);

extern int udp4_ufo_send_check(struct sk_buff *skb);
extern struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb, int features);
#endif /* _UDP_H */
12 changes: 11 additions & 1 deletion trunk/net/ipv4/af_inet.c
Original file line number Diff line number Diff line change
Expand Up @@ -1187,6 +1187,7 @@ static struct sk_buff *inet_gso_segment(struct sk_buff *skb, int features)
int proto;
int ihl;
int id;
unsigned int offset = 0;

if (!(features & NETIF_F_V4_CSUM))
features &= ~NETIF_F_SG;
Expand Down Expand Up @@ -1229,7 +1230,14 @@ static struct sk_buff *inet_gso_segment(struct sk_buff *skb, int features)
skb = segs;
do {
iph = ip_hdr(skb);
iph->id = htons(id++);
if (proto == IPPROTO_UDP) {
iph->id = htons(id);
iph->frag_off = htons(offset >> 3);
if (skb->next != NULL)
iph->frag_off |= htons(IP_MF);
offset += (skb->len - skb->mac_len - iph->ihl * 4);
} else
iph->id = htons(id++);
iph->tot_len = htons(skb->len - skb->mac_len);
iph->check = 0;
iph->check = ip_fast_csum(skb_network_header(skb), iph->ihl);
Expand Down Expand Up @@ -1425,6 +1433,8 @@ static struct net_protocol tcp_protocol = {
static struct net_protocol udp_protocol = {
.handler = udp_rcv,
.err_handler = udp_err,
.gso_send_check = udp4_ufo_send_check,
.gso_segment = udp4_ufo_fragment,
.no_policy = 1,
.netns_ok = 1,
};
Expand Down
61 changes: 61 additions & 0 deletions trunk/net/ipv4/udp.c
Original file line number Diff line number Diff line change
Expand Up @@ -1816,6 +1816,67 @@ void __init udp_init(void)
sysctl_udp_wmem_min = SK_MEM_QUANTUM;
}

int udp4_ufo_send_check(struct sk_buff *skb)
{
const struct iphdr *iph;
struct udphdr *uh;

if (!pskb_may_pull(skb, sizeof(*uh)))
return -EINVAL;

iph = ip_hdr(skb);
uh = udp_hdr(skb);

uh->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr, skb->len,
IPPROTO_UDP, 0);
skb->csum_start = skb_transport_header(skb) - skb->head;
skb->csum_offset = offsetof(struct udphdr, check);
skb->ip_summed = CHECKSUM_PARTIAL;
return 0;
}

struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb, int features)
{
struct sk_buff *segs = ERR_PTR(-EINVAL);
unsigned int mss;
int offset;
__wsum csum;

mss = skb_shinfo(skb)->gso_size;
if (unlikely(skb->len <= mss))
goto out;

if (skb_gso_ok(skb, features | NETIF_F_GSO_ROBUST)) {
/* Packet is from an untrusted source, reset gso_segs. */
int type = skb_shinfo(skb)->gso_type;

if (unlikely(type & ~(SKB_GSO_UDP | SKB_GSO_DODGY) ||
!(type & (SKB_GSO_UDP))))
goto out;

skb_shinfo(skb)->gso_segs = DIV_ROUND_UP(skb->len, mss);

segs = NULL;
goto out;
}

/* Do software UFO. Complete and fill in the UDP checksum as HW cannot
* do checksum of UDP packets sent as multiple IP fragments.
*/
offset = skb->csum_start - skb_headroom(skb);
csum = skb_checksum(skb, offset, skb->len- offset, 0);
offset += skb->csum_offset;
*(__sum16 *)(skb->data + offset) = csum_fold(csum);
skb->ip_summed = CHECKSUM_NONE;

/* Fragment the skb. IP headers of the fragments are updated in
* inet_gso_segment()
*/
segs = skb_segment(skb, features);
out:
return segs;
}

EXPORT_SYMBOL(udp_disconnect);
EXPORT_SYMBOL(udp_ioctl);
EXPORT_SYMBOL(udp_prot);
Expand Down

0 comments on commit 0e0afb5

Please sign in to comment.