aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/ip_output.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4/ip_output.c')
-rw-r--r--net/ipv4/ip_output.c83
1 files changed, 78 insertions, 5 deletions
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index 87e350069abb..17758234a3e3 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -275,7 +275,8 @@ int ip_output(struct sk_buff *skb)
275{ 275{
276 IP_INC_STATS(IPSTATS_MIB_OUTREQUESTS); 276 IP_INC_STATS(IPSTATS_MIB_OUTREQUESTS);
277 277
278 if (skb->len > dst_mtu(skb->dst) && !skb_shinfo(skb)->tso_size) 278 if (skb->len > dst_mtu(skb->dst) &&
279 !(skb_shinfo(skb)->ufo_size || skb_shinfo(skb)->tso_size))
279 return ip_fragment(skb, ip_finish_output); 280 return ip_fragment(skb, ip_finish_output);
280 else 281 else
281 return ip_finish_output(skb); 282 return ip_finish_output(skb);
@@ -688,6 +689,60 @@ csum_page(struct page *page, int offset, int copy)
688 return csum; 689 return csum;
689} 690}
690 691
692inline int ip_ufo_append_data(struct sock *sk,
693 int getfrag(void *from, char *to, int offset, int len,
694 int odd, struct sk_buff *skb),
695 void *from, int length, int hh_len, int fragheaderlen,
696 int transhdrlen, int mtu,unsigned int flags)
697{
698 struct sk_buff *skb;
699 int err;
700
701 /* There is support for UDP fragmentation offload by network
702 * device, so create one single skb packet containing complete
703 * udp datagram
704 */
705 if ((skb = skb_peek_tail(&sk->sk_write_queue)) == NULL) {
706 skb = sock_alloc_send_skb(sk,
707 hh_len + fragheaderlen + transhdrlen + 20,
708 (flags & MSG_DONTWAIT), &err);
709
710 if (skb == NULL)
711 return err;
712
713 /* reserve space for Hardware header */
714 skb_reserve(skb, hh_len);
715
716 /* create space for UDP/IP header */
717 skb_put(skb,fragheaderlen + transhdrlen);
718
719 /* initialize network header pointer */
720 skb->nh.raw = skb->data;
721
722 /* initialize protocol header pointer */
723 skb->h.raw = skb->data + fragheaderlen;
724
725 skb->ip_summed = CHECKSUM_HW;
726 skb->csum = 0;
727 sk->sk_sndmsg_off = 0;
728 }
729
730 err = skb_append_datato_frags(sk,skb, getfrag, from,
731 (length - transhdrlen));
732 if (!err) {
733 /* specify the length of each IP datagram fragment*/
734 skb_shinfo(skb)->ufo_size = (mtu - fragheaderlen);
735 __skb_queue_tail(&sk->sk_write_queue, skb);
736
737 return 0;
738 }
739 /* There is not enough support do UFO ,
740 * so follow normal path
741 */
742 kfree_skb(skb);
743 return err;
744}
745
691/* 746/*
692 * ip_append_data() and ip_append_page() can make one large IP datagram 747 * ip_append_data() and ip_append_page() can make one large IP datagram
693 * from many pieces of data. Each pieces will be holded on the socket 748 * from many pieces of data. Each pieces will be holded on the socket
@@ -777,6 +832,15 @@ int ip_append_data(struct sock *sk,
777 csummode = CHECKSUM_HW; 832 csummode = CHECKSUM_HW;
778 833
779 inet->cork.length += length; 834 inet->cork.length += length;
835 if (((length > mtu) && (sk->sk_protocol == IPPROTO_UDP)) &&
836 (rt->u.dst.dev->features & NETIF_F_UFO)) {
837
838 if(ip_ufo_append_data(sk, getfrag, from, length, hh_len,
839 fragheaderlen, transhdrlen, mtu, flags))
840 goto error;
841
842 return 0;
843 }
780 844
781 /* So, what's going on in the loop below? 845 /* So, what's going on in the loop below?
782 * 846 *
@@ -1008,14 +1072,23 @@ ssize_t ip_append_page(struct sock *sk, struct page *page,
1008 return -EINVAL; 1072 return -EINVAL;
1009 1073
1010 inet->cork.length += size; 1074 inet->cork.length += size;
1075 if ((sk->sk_protocol == IPPROTO_UDP) &&
1076 (rt->u.dst.dev->features & NETIF_F_UFO))
1077 skb_shinfo(skb)->ufo_size = (mtu - fragheaderlen);
1078
1011 1079
1012 while (size > 0) { 1080 while (size > 0) {
1013 int i; 1081 int i;
1014 1082
1015 /* Check if the remaining data fits into current packet. */ 1083 if (skb_shinfo(skb)->ufo_size)
1016 len = mtu - skb->len; 1084 len = size;
1017 if (len < size) 1085 else {
1018 len = maxfraglen - skb->len; 1086
1087 /* Check if the remaining data fits into current packet. */
1088 len = mtu - skb->len;
1089 if (len < size)
1090 len = maxfraglen - skb->len;
1091 }
1019 if (len <= 0) { 1092 if (len <= 0) {
1020 struct sk_buff *skb_prev; 1093 struct sk_buff *skb_prev;
1021 char *data; 1094 char *data;