aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6')
-rw-r--r--net/ipv6/af_inet6.c20
-rw-r--r--net/ipv6/ip6_fib.c16
-rw-r--r--net/ipv6/ip6_input.c6
-rw-r--r--net/ipv6/ip6_output.c26
-rw-r--r--net/ipv6/ip6_tunnel.c4
-rw-r--r--net/ipv6/ip6mr.c2
-rw-r--r--net/ipv6/mcast.c1
-rw-r--r--net/ipv6/sit.c6
-rw-r--r--net/ipv6/udp.c141
-rw-r--r--net/ipv6/xfrm6_policy.c33
10 files changed, 212 insertions, 43 deletions
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index caa0278d30a9..bf85d5f97032 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -772,6 +772,11 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, int features)
772 struct sk_buff *segs = ERR_PTR(-EINVAL); 772 struct sk_buff *segs = ERR_PTR(-EINVAL);
773 struct ipv6hdr *ipv6h; 773 struct ipv6hdr *ipv6h;
774 struct inet6_protocol *ops; 774 struct inet6_protocol *ops;
775 int proto;
776 struct frag_hdr *fptr;
777 unsigned int unfrag_ip6hlen;
778 u8 *prevhdr;
779 int offset = 0;
775 780
776 if (!(features & NETIF_F_V6_CSUM)) 781 if (!(features & NETIF_F_V6_CSUM))
777 features &= ~NETIF_F_SG; 782 features &= ~NETIF_F_SG;
@@ -791,10 +796,9 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, int features)
791 __skb_pull(skb, sizeof(*ipv6h)); 796 __skb_pull(skb, sizeof(*ipv6h));
792 segs = ERR_PTR(-EPROTONOSUPPORT); 797 segs = ERR_PTR(-EPROTONOSUPPORT);
793 798
799 proto = ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr);
794 rcu_read_lock(); 800 rcu_read_lock();
795 ops = rcu_dereference(inet6_protos[ 801 ops = rcu_dereference(inet6_protos[proto]);
796 ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr)]);
797
798 if (likely(ops && ops->gso_segment)) { 802 if (likely(ops && ops->gso_segment)) {
799 skb_reset_transport_header(skb); 803 skb_reset_transport_header(skb);
800 segs = ops->gso_segment(skb, features); 804 segs = ops->gso_segment(skb, features);
@@ -808,6 +812,16 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, int features)
808 ipv6h = ipv6_hdr(skb); 812 ipv6h = ipv6_hdr(skb);
809 ipv6h->payload_len = htons(skb->len - skb->mac_len - 813 ipv6h->payload_len = htons(skb->len - skb->mac_len -
810 sizeof(*ipv6h)); 814 sizeof(*ipv6h));
815 if (proto == IPPROTO_UDP) {
816 unfrag_ip6hlen = ip6_find_1stfragopt(skb, &prevhdr);
817 fptr = (struct frag_hdr *)(skb_network_header(skb) +
818 unfrag_ip6hlen);
819 fptr->frag_off = htons(offset);
820 if (skb->next != NULL)
821 fptr->frag_off |= htons(IP6_MF);
822 offset += (ntohs(ipv6h->payload_len) -
823 sizeof(struct frag_hdr));
824 }
811 } 825 }
812 826
813out: 827out:
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
index 52ee1dced2ff..0e93ca56eb69 100644
--- a/net/ipv6/ip6_fib.c
+++ b/net/ipv6/ip6_fib.c
@@ -164,12 +164,6 @@ static __inline__ void rt6_release(struct rt6_info *rt)
164 dst_free(&rt->u.dst); 164 dst_free(&rt->u.dst);
165} 165}
166 166
167#ifdef CONFIG_IPV6_MULTIPLE_TABLES
168#define FIB_TABLE_HASHSZ 256
169#else
170#define FIB_TABLE_HASHSZ 1
171#endif
172
173static void fib6_link_table(struct net *net, struct fib6_table *tb) 167static void fib6_link_table(struct net *net, struct fib6_table *tb)
174{ 168{
175 unsigned int h; 169 unsigned int h;
@@ -180,7 +174,7 @@ static void fib6_link_table(struct net *net, struct fib6_table *tb)
180 */ 174 */
181 rwlock_init(&tb->tb6_lock); 175 rwlock_init(&tb->tb6_lock);
182 176
183 h = tb->tb6_id & (FIB_TABLE_HASHSZ - 1); 177 h = tb->tb6_id & (FIB6_TABLE_HASHSZ - 1);
184 178
185 /* 179 /*
186 * No protection necessary, this is the only list mutatation 180 * No protection necessary, this is the only list mutatation
@@ -231,7 +225,7 @@ struct fib6_table *fib6_get_table(struct net *net, u32 id)
231 225
232 if (id == 0) 226 if (id == 0)
233 id = RT6_TABLE_MAIN; 227 id = RT6_TABLE_MAIN;
234 h = id & (FIB_TABLE_HASHSZ - 1); 228 h = id & (FIB6_TABLE_HASHSZ - 1);
235 rcu_read_lock(); 229 rcu_read_lock();
236 head = &net->ipv6.fib_table_hash[h]; 230 head = &net->ipv6.fib_table_hash[h];
237 hlist_for_each_entry_rcu(tb, node, head, tb6_hlist) { 231 hlist_for_each_entry_rcu(tb, node, head, tb6_hlist) {
@@ -382,7 +376,7 @@ static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
382 arg.net = net; 376 arg.net = net;
383 w->args = &arg; 377 w->args = &arg;
384 378
385 for (h = s_h; h < FIB_TABLE_HASHSZ; h++, s_e = 0) { 379 for (h = s_h; h < FIB6_TABLE_HASHSZ; h++, s_e = 0) {
386 e = 0; 380 e = 0;
387 head = &net->ipv6.fib_table_hash[h]; 381 head = &net->ipv6.fib_table_hash[h];
388 hlist_for_each_entry(tb, node, head, tb6_hlist) { 382 hlist_for_each_entry(tb, node, head, tb6_hlist) {
@@ -1368,7 +1362,7 @@ void fib6_clean_all(struct net *net, int (*func)(struct rt6_info *, void *arg),
1368 unsigned int h; 1362 unsigned int h;
1369 1363
1370 rcu_read_lock(); 1364 rcu_read_lock();
1371 for (h = 0; h < FIB_TABLE_HASHSZ; h++) { 1365 for (h = 0; h < FIB6_TABLE_HASHSZ; h++) {
1372 head = &net->ipv6.fib_table_hash[h]; 1366 head = &net->ipv6.fib_table_hash[h];
1373 hlist_for_each_entry_rcu(table, node, head, tb6_hlist) { 1367 hlist_for_each_entry_rcu(table, node, head, tb6_hlist) {
1374 write_lock_bh(&table->tb6_lock); 1368 write_lock_bh(&table->tb6_lock);
@@ -1483,7 +1477,7 @@ static int fib6_net_init(struct net *net)
1483 if (!net->ipv6.rt6_stats) 1477 if (!net->ipv6.rt6_stats)
1484 goto out_timer; 1478 goto out_timer;
1485 1479
1486 net->ipv6.fib_table_hash = kcalloc(FIB_TABLE_HASHSZ, 1480 net->ipv6.fib_table_hash = kcalloc(FIB6_TABLE_HASHSZ,
1487 sizeof(*net->ipv6.fib_table_hash), 1481 sizeof(*net->ipv6.fib_table_hash),
1488 GFP_KERNEL); 1482 GFP_KERNEL);
1489 if (!net->ipv6.fib_table_hash) 1483 if (!net->ipv6.fib_table_hash)
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c
index 6d6a4277c677..2d9cbaa67edb 100644
--- a/net/ipv6/ip6_input.c
+++ b/net/ipv6/ip6_input.c
@@ -63,7 +63,7 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt
63 63
64 if (skb->pkt_type == PACKET_OTHERHOST) { 64 if (skb->pkt_type == PACKET_OTHERHOST) {
65 kfree_skb(skb); 65 kfree_skb(skb);
66 return 0; 66 return NET_RX_DROP;
67 } 67 }
68 68
69 rcu_read_lock(); 69 rcu_read_lock();
@@ -133,7 +133,7 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt
133 if (ipv6_parse_hopopts(skb) < 0) { 133 if (ipv6_parse_hopopts(skb) < 0) {
134 IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_INHDRERRORS); 134 IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_INHDRERRORS);
135 rcu_read_unlock(); 135 rcu_read_unlock();
136 return 0; 136 return NET_RX_DROP;
137 } 137 }
138 } 138 }
139 139
@@ -149,7 +149,7 @@ err:
149drop: 149drop:
150 rcu_read_unlock(); 150 rcu_read_unlock();
151 kfree_skb(skb); 151 kfree_skb(skb);
152 return 0; 152 return NET_RX_DROP;
153} 153}
154 154
155/* 155/*
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 87f8419a68fd..93beee944657 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -57,18 +57,6 @@
57 57
58static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)); 58static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *));
59 59
60static __inline__ void ipv6_select_ident(struct sk_buff *skb, struct frag_hdr *fhdr)
61{
62 static u32 ipv6_fragmentation_id = 1;
63 static DEFINE_SPINLOCK(ip6_id_lock);
64
65 spin_lock_bh(&ip6_id_lock);
66 fhdr->identification = htonl(ipv6_fragmentation_id);
67 if (++ipv6_fragmentation_id == 0)
68 ipv6_fragmentation_id = 1;
69 spin_unlock_bh(&ip6_id_lock);
70}
71
72int __ip6_local_out(struct sk_buff *skb) 60int __ip6_local_out(struct sk_buff *skb)
73{ 61{
74 int len; 62 int len;
@@ -706,7 +694,7 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
706 skb_reset_network_header(skb); 694 skb_reset_network_header(skb);
707 memcpy(skb_network_header(skb), tmp_hdr, hlen); 695 memcpy(skb_network_header(skb), tmp_hdr, hlen);
708 696
709 ipv6_select_ident(skb, fh); 697 ipv6_select_ident(fh);
710 fh->nexthdr = nexthdr; 698 fh->nexthdr = nexthdr;
711 fh->reserved = 0; 699 fh->reserved = 0;
712 fh->frag_off = htons(IP6_MF); 700 fh->frag_off = htons(IP6_MF);
@@ -844,7 +832,7 @@ slow_path:
844 fh->nexthdr = nexthdr; 832 fh->nexthdr = nexthdr;
845 fh->reserved = 0; 833 fh->reserved = 0;
846 if (!frag_id) { 834 if (!frag_id) {
847 ipv6_select_ident(skb, fh); 835 ipv6_select_ident(fh);
848 frag_id = fh->identification; 836 frag_id = fh->identification;
849 } else 837 } else
850 fh->identification = frag_id; 838 fh->identification = frag_id;
@@ -1087,11 +1075,13 @@ static inline int ip6_ufo_append_data(struct sock *sk,
1087 if (!err) { 1075 if (!err) {
1088 struct frag_hdr fhdr; 1076 struct frag_hdr fhdr;
1089 1077
1090 /* specify the length of each IP datagram fragment*/ 1078 /* Specify the length of each IPv6 datagram fragment.
1091 skb_shinfo(skb)->gso_size = mtu - fragheaderlen - 1079 * It has to be a multiple of 8.
1092 sizeof(struct frag_hdr); 1080 */
1081 skb_shinfo(skb)->gso_size = (mtu - fragheaderlen -
1082 sizeof(struct frag_hdr)) & ~7;
1093 skb_shinfo(skb)->gso_type = SKB_GSO_UDP; 1083 skb_shinfo(skb)->gso_type = SKB_GSO_UDP;
1094 ipv6_select_ident(skb, &fhdr); 1084 ipv6_select_ident(&fhdr);
1095 skb_shinfo(skb)->ip6_frag_id = fhdr.identification; 1085 skb_shinfo(skb)->ip6_frag_id = fhdr.identification;
1096 __skb_queue_tail(&sk->sk_write_queue, skb); 1086 __skb_queue_tail(&sk->sk_write_queue, skb);
1097 1087
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index 51f410e7775a..a1d6045c4694 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -1063,14 +1063,14 @@ ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
1063 goto tx_err; 1063 goto tx_err;
1064 1064
1065 t->recursion--; 1065 t->recursion--;
1066 return 0; 1066 return NETDEV_TX_OK;
1067 1067
1068tx_err: 1068tx_err:
1069 stats->tx_errors++; 1069 stats->tx_errors++;
1070 stats->tx_dropped++; 1070 stats->tx_dropped++;
1071 kfree_skb(skb); 1071 kfree_skb(skb);
1072 t->recursion--; 1072 t->recursion--;
1073 return 0; 1073 return NETDEV_TX_OK;
1074} 1074}
1075 1075
1076static void ip6_tnl_set_cap(struct ip6_tnl *t) 1076static void ip6_tnl_set_cap(struct ip6_tnl *t)
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c
index c769f155c698..07ded5075b33 100644
--- a/net/ipv6/ip6mr.c
+++ b/net/ipv6/ip6mr.c
@@ -427,7 +427,7 @@ static int reg_vif_xmit(struct sk_buff *skb, struct net_device *dev)
427 MRT6MSG_WHOLEPKT); 427 MRT6MSG_WHOLEPKT);
428 read_unlock(&mrt_lock); 428 read_unlock(&mrt_lock);
429 kfree_skb(skb); 429 kfree_skb(skb);
430 return 0; 430 return NETDEV_TX_OK;
431} 431}
432 432
433static const struct net_device_ops reg_vif_netdev_ops = { 433static const struct net_device_ops reg_vif_netdev_ops = {
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
index 4b264ed40a8c..71c3dacec1ed 100644
--- a/net/ipv6/mcast.c
+++ b/net/ipv6/mcast.c
@@ -2107,7 +2107,6 @@ static int ip6_mc_add_src(struct inet6_dev *idev, struct in6_addr *pmca,
2107 for (j=0; j<i; j++) 2107 for (j=0; j<i; j++)
2108 (void) ip6_mc_del1_src(pmc, sfmode, &psfsrc[i]); 2108 (void) ip6_mc_del1_src(pmc, sfmode, &psfsrc[i]);
2109 } else if (isexclude != (pmc->mca_sfcount[MCAST_EXCLUDE] != 0)) { 2109 } else if (isexclude != (pmc->mca_sfcount[MCAST_EXCLUDE] != 0)) {
2110 struct inet6_dev *idev = pmc->idev;
2111 struct ip6_sf_list *psf; 2110 struct ip6_sf_list *psf;
2112 2111
2113 /* filter mode change */ 2112 /* filter mode change */
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index 98b7327d0949..d335a306a4db 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -753,7 +753,7 @@ static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
753 stats->tx_dropped++; 753 stats->tx_dropped++;
754 dev_kfree_skb(skb); 754 dev_kfree_skb(skb);
755 tunnel->recursion--; 755 tunnel->recursion--;
756 return 0; 756 return NETDEV_TX_OK;
757 } 757 }
758 if (skb->sk) 758 if (skb->sk)
759 skb_set_owner_w(new_skb, skb->sk); 759 skb_set_owner_w(new_skb, skb->sk);
@@ -794,7 +794,7 @@ static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
794 794
795 IPTUNNEL_XMIT(); 795 IPTUNNEL_XMIT();
796 tunnel->recursion--; 796 tunnel->recursion--;
797 return 0; 797 return NETDEV_TX_OK;
798 798
799tx_error_icmp: 799tx_error_icmp:
800 dst_link_failure(skb); 800 dst_link_failure(skb);
@@ -802,7 +802,7 @@ tx_error:
802 stats->tx_errors++; 802 stats->tx_errors++;
803 dev_kfree_skb(skb); 803 dev_kfree_skb(skb);
804 tunnel->recursion--; 804 tunnel->recursion--;
805 return 0; 805 return NETDEV_TX_OK;
806} 806}
807 807
808static void ipip6_tunnel_bind_dev(struct net_device *dev) 808static void ipip6_tunnel_bind_dev(struct net_device *dev)
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 33b59bd92c4d..d79fa6724451 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -638,6 +638,47 @@ static void udp_v6_flush_pending_frames(struct sock *sk)
638 } 638 }
639} 639}
640 640
641/**
642 * udp6_hwcsum_outgoing - handle outgoing HW checksumming
643 * @sk: socket we are sending on
644 * @skb: sk_buff containing the filled-in UDP header
645 * (checksum field must be zeroed out)
646 */
647static void udp6_hwcsum_outgoing(struct sock *sk, struct sk_buff *skb,
648 const struct in6_addr *saddr,
649 const struct in6_addr *daddr, int len)
650{
651 unsigned int offset;
652 struct udphdr *uh = udp_hdr(skb);
653 __wsum csum = 0;
654
655 if (skb_queue_len(&sk->sk_write_queue) == 1) {
656 /* Only one fragment on the socket. */
657 skb->csum_start = skb_transport_header(skb) - skb->head;
658 skb->csum_offset = offsetof(struct udphdr, check);
659 uh->check = ~csum_ipv6_magic(saddr, daddr, len, IPPROTO_UDP, 0);
660 } else {
661 /*
662 * HW-checksum won't work as there are two or more
663 * fragments on the socket so that all csums of sk_buffs
664 * should be together
665 */
666 offset = skb_transport_offset(skb);
667 skb->csum = skb_checksum(skb, offset, skb->len - offset, 0);
668
669 skb->ip_summed = CHECKSUM_NONE;
670
671 skb_queue_walk(&sk->sk_write_queue, skb) {
672 csum = csum_add(csum, skb->csum);
673 }
674
675 uh->check = csum_ipv6_magic(saddr, daddr, len, IPPROTO_UDP,
676 csum);
677 if (uh->check == 0)
678 uh->check = CSUM_MANGLED_0;
679 }
680}
681
641/* 682/*
642 * Sending 683 * Sending
643 */ 684 */
@@ -668,7 +709,11 @@ static int udp_v6_push_pending_frames(struct sock *sk)
668 709
669 if (is_udplite) 710 if (is_udplite)
670 csum = udplite_csum_outgoing(sk, skb); 711 csum = udplite_csum_outgoing(sk, skb);
671 else 712 else if (skb->ip_summed == CHECKSUM_PARTIAL) { /* UDP hardware csum */
713 udp6_hwcsum_outgoing(sk, skb, &fl->fl6_src, &fl->fl6_dst,
714 up->len);
715 goto send;
716 } else
672 csum = udp_csum_outgoing(sk, skb); 717 csum = udp_csum_outgoing(sk, skb);
673 718
674 /* add protocol-dependent pseudo-header */ 719 /* add protocol-dependent pseudo-header */
@@ -677,6 +722,7 @@ static int udp_v6_push_pending_frames(struct sock *sk)
677 if (uh->check == 0) 722 if (uh->check == 0)
678 uh->check = CSUM_MANGLED_0; 723 uh->check = CSUM_MANGLED_0;
679 724
725send:
680 err = ip6_push_pending_frames(sk); 726 err = ip6_push_pending_frames(sk);
681out: 727out:
682 up->len = 0; 728 up->len = 0;
@@ -1032,9 +1078,102 @@ int compat_udpv6_getsockopt(struct sock *sk, int level, int optname,
1032} 1078}
1033#endif 1079#endif
1034 1080
1081static int udp6_ufo_send_check(struct sk_buff *skb)
1082{
1083 struct ipv6hdr *ipv6h;
1084 struct udphdr *uh;
1085
1086 if (!pskb_may_pull(skb, sizeof(*uh)))
1087 return -EINVAL;
1088
1089 ipv6h = ipv6_hdr(skb);
1090 uh = udp_hdr(skb);
1091
1092 uh->check = ~csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr, skb->len,
1093 IPPROTO_UDP, 0);
1094 skb->csum_start = skb_transport_header(skb) - skb->head;
1095 skb->csum_offset = offsetof(struct udphdr, check);
1096 skb->ip_summed = CHECKSUM_PARTIAL;
1097 return 0;
1098}
1099
1100static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb, int features)
1101{
1102 struct sk_buff *segs = ERR_PTR(-EINVAL);
1103 unsigned int mss;
1104 unsigned int unfrag_ip6hlen, unfrag_len;
1105 struct frag_hdr *fptr;
1106 u8 *mac_start, *prevhdr;
1107 u8 nexthdr;
1108 u8 frag_hdr_sz = sizeof(struct frag_hdr);
1109 int offset;
1110 __wsum csum;
1111
1112 mss = skb_shinfo(skb)->gso_size;
1113 if (unlikely(skb->len <= mss))
1114 goto out;
1115
1116 if (skb_gso_ok(skb, features | NETIF_F_GSO_ROBUST)) {
1117 /* Packet is from an untrusted source, reset gso_segs. */
1118 int type = skb_shinfo(skb)->gso_type;
1119
1120 if (unlikely(type & ~(SKB_GSO_UDP | SKB_GSO_DODGY) ||
1121 !(type & (SKB_GSO_UDP))))
1122 goto out;
1123
1124 skb_shinfo(skb)->gso_segs = DIV_ROUND_UP(skb->len, mss);
1125
1126 segs = NULL;
1127 goto out;
1128 }
1129
1130 /* Do software UFO. Complete and fill in the UDP checksum as HW cannot
1131 * do checksum of UDP packets sent as multiple IP fragments.
1132 */
1133 offset = skb->csum_start - skb_headroom(skb);
1134 csum = skb_checksum(skb, offset, skb->len- offset, 0);
1135 offset += skb->csum_offset;
1136 *(__sum16 *)(skb->data + offset) = csum_fold(csum);
1137 skb->ip_summed = CHECKSUM_NONE;
1138
1139 /* Check if there is enough headroom to insert fragment header. */
1140 if ((skb_headroom(skb) < frag_hdr_sz) &&
1141 pskb_expand_head(skb, frag_hdr_sz, 0, GFP_ATOMIC))
1142 goto out;
1143
1144 /* Find the unfragmentable header and shift it left by frag_hdr_sz
1145 * bytes to insert fragment header.
1146 */
1147 unfrag_ip6hlen = ip6_find_1stfragopt(skb, &prevhdr);
1148 nexthdr = *prevhdr;
1149 *prevhdr = NEXTHDR_FRAGMENT;
1150 unfrag_len = skb_network_header(skb) - skb_mac_header(skb) +
1151 unfrag_ip6hlen;
1152 mac_start = skb_mac_header(skb);
1153 memmove(mac_start-frag_hdr_sz, mac_start, unfrag_len);
1154
1155 skb->mac_header -= frag_hdr_sz;
1156 skb->network_header -= frag_hdr_sz;
1157
1158 fptr = (struct frag_hdr *)(skb_network_header(skb) + unfrag_ip6hlen);
1159 fptr->nexthdr = nexthdr;
1160 fptr->reserved = 0;
1161 ipv6_select_ident(fptr);
1162
1163 /* Fragment the skb. ipv6 header and the remaining fields of the
1164 * fragment header are updated in ipv6_gso_segment()
1165 */
1166 segs = skb_segment(skb, features);
1167
1168out:
1169 return segs;
1170}
1171
1035static struct inet6_protocol udpv6_protocol = { 1172static struct inet6_protocol udpv6_protocol = {
1036 .handler = udpv6_rcv, 1173 .handler = udpv6_rcv,
1037 .err_handler = udpv6_err, 1174 .err_handler = udpv6_err,
1175 .gso_send_check = udp6_ufo_send_check,
1176 .gso_segment = udp6_ufo_fragment,
1038 .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, 1177 .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
1039}; 1178};
1040 1179
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c
index 3a3c677bc0f2..611cffcf554f 100644
--- a/net/ipv6/xfrm6_policy.c
+++ b/net/ipv6/xfrm6_policy.c
@@ -306,9 +306,24 @@ static void xfrm6_policy_fini(void)
306 xfrm_policy_unregister_afinfo(&xfrm6_policy_afinfo); 306 xfrm_policy_unregister_afinfo(&xfrm6_policy_afinfo);
307} 307}
308 308
309static struct ctl_table xfrm6_policy_table[] = {
310 {
311 .ctl_name = CTL_UNNUMBERED,
312 .procname = "xfrm6_gc_thresh",
313 .data = &xfrm6_dst_ops.gc_thresh,
314 .maxlen = sizeof(int),
315 .mode = 0644,
316 .proc_handler = proc_dointvec,
317 },
318 { }
319};
320
321static struct ctl_table_header *sysctl_hdr;
322
309int __init xfrm6_init(void) 323int __init xfrm6_init(void)
310{ 324{
311 int ret; 325 int ret;
326 unsigned int gc_thresh;
312 327
313 ret = xfrm6_policy_init(); 328 ret = xfrm6_policy_init();
314 if (ret) 329 if (ret)
@@ -317,6 +332,22 @@ int __init xfrm6_init(void)
317 ret = xfrm6_state_init(); 332 ret = xfrm6_state_init();
318 if (ret) 333 if (ret)
319 goto out_policy; 334 goto out_policy;
335 /*
336 * We need a good default value for the xfrm6 gc threshold.
337 * In ipv4 we set it to the route hash table size * 8, which
338 * is half the size of the maximaum route cache for ipv4. It
339 * would be good to do the same thing for v6, except the table is
340 * constructed differently here. Here each table for a net namespace
341 * can have FIB_TABLE_HASHSZ entries, so lets go with the same
342 * computation that we used for ipv4 here. Also, lets keep the initial
343 * gc_thresh to a minimum of 1024, since, the ipv6 route cache defaults
344 * to that as a minimum as well
345 */
346 gc_thresh = FIB6_TABLE_HASHSZ * 8;
347 xfrm6_dst_ops.gc_thresh = (gc_thresh < 1024) ? 1024 : gc_thresh;
348
349 sysctl_hdr = register_net_sysctl_table(&init_net, net_ipv6_ctl_path,
350 xfrm6_policy_table);
320out: 351out:
321 return ret; 352 return ret;
322out_policy: 353out_policy:
@@ -326,6 +357,8 @@ out_policy:
326 357
327void xfrm6_fini(void) 358void xfrm6_fini(void)
328{ 359{
360 if (sysctl_hdr)
361 unregister_net_sysctl_table(sysctl_hdr);
329 //xfrm6_input_fini(); 362 //xfrm6_input_fini();
330 xfrm6_policy_fini(); 363 xfrm6_policy_fini();
331 xfrm6_state_fini(); 364 xfrm6_state_fini();