aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/ip6_output.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2010-05-21 00:04:44 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2010-05-21 00:04:44 -0400
commitf8965467f366fd18f01feafb5db10512d7b4422c (patch)
tree3706a9cd779859271ca61b85c63a1bc3f82d626e /net/ipv6/ip6_output.c
parenta26272e5200765691e67d6780e52b32498fdb659 (diff)
parent2ec8c6bb5d8f3a62a79f463525054bae1e3d4487 (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6: (1674 commits) qlcnic: adding co maintainer ixgbe: add support for active DA cables ixgbe: dcb, do not tag tc_prio_control frames ixgbe: fix ixgbe_tx_is_paused logic ixgbe: always enable vlan strip/insert when DCB is enabled ixgbe: remove some redundant code in setting FCoE FIP filter ixgbe: fix wrong offset to fc_frame_header in ixgbe_fcoe_ddp ixgbe: fix header len when unsplit packet overflows to data buffer ipv6: Never schedule DAD timer on dead address ipv6: Use POSTDAD state ipv6: Use state_lock to protect ifa state ipv6: Replace inet6_ifaddr->dead with state cxgb4: notify upper drivers if the device is already up when they load cxgb4: keep interrupts available when the ports are brought down cxgb4: fix initial addition of MAC address cnic: Return SPQ credit to bnx2x after ring setup and shutdown. cnic: Convert cnic_local_flags to atomic ops. can: Fix SJA1000 command register writes on SMP systems bridge: fix build for CONFIG_SYSFS disabled ARCNET: Limit com20020 PCI ID matches for SOHARD cards ... Fix up various conflicts with pcmcia tree drivers/net/ {pcmcia/3c589_cs.c, wireless/orinoco/orinoco_cs.c and wireless/orinoco/spectrum_cs.c} and feature removal (Documentation/feature-removal-schedule.txt). Also fix a non-content conflict due to pm_qos_requirement getting renamed in the PM tree (now pm_qos_request) in net/mac80211/scan.c
Diffstat (limited to 'net/ipv6/ip6_output.c')
-rw-r--r--net/ipv6/ip6_output.c103
1 files changed, 52 insertions, 51 deletions
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 75d5ef830097..cd963f64e27c 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -67,8 +67,8 @@ int __ip6_local_out(struct sk_buff *skb)
67 len = 0; 67 len = 0;
68 ipv6_hdr(skb)->payload_len = htons(len); 68 ipv6_hdr(skb)->payload_len = htons(len);
69 69
70 return nf_hook(PF_INET6, NF_INET_LOCAL_OUT, skb, NULL, skb_dst(skb)->dev, 70 return nf_hook(NFPROTO_IPV6, NF_INET_LOCAL_OUT, skb, NULL,
71 dst_output); 71 skb_dst(skb)->dev, dst_output);
72} 72}
73 73
74int ip6_local_out(struct sk_buff *skb) 74int ip6_local_out(struct sk_buff *skb)
@@ -83,22 +83,6 @@ int ip6_local_out(struct sk_buff *skb)
83} 83}
84EXPORT_SYMBOL_GPL(ip6_local_out); 84EXPORT_SYMBOL_GPL(ip6_local_out);
85 85
86static int ip6_output_finish(struct sk_buff *skb)
87{
88 struct dst_entry *dst = skb_dst(skb);
89
90 if (dst->hh)
91 return neigh_hh_output(dst->hh, skb);
92 else if (dst->neighbour)
93 return dst->neighbour->output(skb);
94
95 IP6_INC_STATS_BH(dev_net(dst->dev),
96 ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES);
97 kfree_skb(skb);
98 return -EINVAL;
99
100}
101
102/* dev_loopback_xmit for use with netfilter. */ 86/* dev_loopback_xmit for use with netfilter. */
103static int ip6_dev_loopback_xmit(struct sk_buff *newskb) 87static int ip6_dev_loopback_xmit(struct sk_buff *newskb)
104{ 88{
@@ -112,8 +96,7 @@ static int ip6_dev_loopback_xmit(struct sk_buff *newskb)
112 return 0; 96 return 0;
113} 97}
114 98
115 99static int ip6_finish_output2(struct sk_buff *skb)
116static int ip6_output2(struct sk_buff *skb)
117{ 100{
118 struct dst_entry *dst = skb_dst(skb); 101 struct dst_entry *dst = skb_dst(skb);
119 struct net_device *dev = dst->dev; 102 struct net_device *dev = dst->dev;
@@ -125,7 +108,7 @@ static int ip6_output2(struct sk_buff *skb)
125 struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb)); 108 struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb));
126 109
127 if (!(dev->flags & IFF_LOOPBACK) && sk_mc_loop(skb->sk) && 110 if (!(dev->flags & IFF_LOOPBACK) && sk_mc_loop(skb->sk) &&
128 ((mroute6_socket(dev_net(dev)) && 111 ((mroute6_socket(dev_net(dev), skb) &&
129 !(IP6CB(skb)->flags & IP6SKB_FORWARDED)) || 112 !(IP6CB(skb)->flags & IP6SKB_FORWARDED)) ||
130 ipv6_chk_mcast_addr(dev, &ipv6_hdr(skb)->daddr, 113 ipv6_chk_mcast_addr(dev, &ipv6_hdr(skb)->daddr,
131 &ipv6_hdr(skb)->saddr))) { 114 &ipv6_hdr(skb)->saddr))) {
@@ -135,8 +118,8 @@ static int ip6_output2(struct sk_buff *skb)
135 is not supported in any case. 118 is not supported in any case.
136 */ 119 */
137 if (newskb) 120 if (newskb)
138 NF_HOOK(PF_INET6, NF_INET_POST_ROUTING, newskb, 121 NF_HOOK(NFPROTO_IPV6, NF_INET_POST_ROUTING,
139 NULL, newskb->dev, 122 newskb, NULL, newskb->dev,
140 ip6_dev_loopback_xmit); 123 ip6_dev_loopback_xmit);
141 124
142 if (ipv6_hdr(skb)->hop_limit == 0) { 125 if (ipv6_hdr(skb)->hop_limit == 0) {
@@ -151,8 +134,15 @@ static int ip6_output2(struct sk_buff *skb)
151 skb->len); 134 skb->len);
152 } 135 }
153 136
154 return NF_HOOK(PF_INET6, NF_INET_POST_ROUTING, skb, NULL, skb->dev, 137 if (dst->hh)
155 ip6_output_finish); 138 return neigh_hh_output(dst->hh, skb);
139 else if (dst->neighbour)
140 return dst->neighbour->output(skb);
141
142 IP6_INC_STATS_BH(dev_net(dst->dev),
143 ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES);
144 kfree_skb(skb);
145 return -EINVAL;
156} 146}
157 147
158static inline int ip6_skb_dst_mtu(struct sk_buff *skb) 148static inline int ip6_skb_dst_mtu(struct sk_buff *skb)
@@ -163,29 +153,37 @@ static inline int ip6_skb_dst_mtu(struct sk_buff *skb)
163 skb_dst(skb)->dev->mtu : dst_mtu(skb_dst(skb)); 153 skb_dst(skb)->dev->mtu : dst_mtu(skb_dst(skb));
164} 154}
165 155
156static int ip6_finish_output(struct sk_buff *skb)
157{
158 if ((skb->len > ip6_skb_dst_mtu(skb) && !skb_is_gso(skb)) ||
159 dst_allfrag(skb_dst(skb)))
160 return ip6_fragment(skb, ip6_finish_output2);
161 else
162 return ip6_finish_output2(skb);
163}
164
166int ip6_output(struct sk_buff *skb) 165int ip6_output(struct sk_buff *skb)
167{ 166{
167 struct net_device *dev = skb_dst(skb)->dev;
168 struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb)); 168 struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb));
169 if (unlikely(idev->cnf.disable_ipv6)) { 169 if (unlikely(idev->cnf.disable_ipv6)) {
170 IP6_INC_STATS(dev_net(skb_dst(skb)->dev), idev, 170 IP6_INC_STATS(dev_net(dev), idev,
171 IPSTATS_MIB_OUTDISCARDS); 171 IPSTATS_MIB_OUTDISCARDS);
172 kfree_skb(skb); 172 kfree_skb(skb);
173 return 0; 173 return 0;
174 } 174 }
175 175
176 if ((skb->len > ip6_skb_dst_mtu(skb) && !skb_is_gso(skb)) || 176 return NF_HOOK_COND(NFPROTO_IPV6, NF_INET_POST_ROUTING, skb, NULL, dev,
177 dst_allfrag(skb_dst(skb))) 177 ip6_finish_output,
178 return ip6_fragment(skb, ip6_output2); 178 !(IP6CB(skb)->flags & IP6SKB_REROUTED));
179 else
180 return ip6_output2(skb);
181} 179}
182 180
183/* 181/*
184 * xmit an sk_buff (used by TCP) 182 * xmit an sk_buff (used by TCP, SCTP and DCCP)
185 */ 183 */
186 184
187int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl, 185int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl,
188 struct ipv6_txoptions *opt, int ipfragok) 186 struct ipv6_txoptions *opt)
189{ 187{
190 struct net *net = sock_net(sk); 188 struct net *net = sock_net(sk);
191 struct ipv6_pinfo *np = inet6_sk(sk); 189 struct ipv6_pinfo *np = inet6_sk(sk);
@@ -218,8 +216,7 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl,
218 } 216 }
219 kfree_skb(skb); 217 kfree_skb(skb);
220 skb = skb2; 218 skb = skb2;
221 if (sk) 219 skb_set_owner_w(skb, sk);
222 skb_set_owner_w(skb, sk);
223 } 220 }
224 if (opt->opt_flen) 221 if (opt->opt_flen)
225 ipv6_push_frag_opts(skb, opt, &proto); 222 ipv6_push_frag_opts(skb, opt, &proto);
@@ -231,10 +228,6 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl,
231 skb_reset_network_header(skb); 228 skb_reset_network_header(skb);
232 hdr = ipv6_hdr(skb); 229 hdr = ipv6_hdr(skb);
233 230
234 /* Allow local fragmentation. */
235 if (ipfragok)
236 skb->local_df = 1;
237
238 /* 231 /*
239 * Fill in the IPv6 header 232 * Fill in the IPv6 header
240 */ 233 */
@@ -261,8 +254,8 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl,
261 if ((skb->len <= mtu) || skb->local_df || skb_is_gso(skb)) { 254 if ((skb->len <= mtu) || skb->local_df || skb_is_gso(skb)) {
262 IP6_UPD_PO_STATS(net, ip6_dst_idev(skb_dst(skb)), 255 IP6_UPD_PO_STATS(net, ip6_dst_idev(skb_dst(skb)),
263 IPSTATS_MIB_OUT, skb->len); 256 IPSTATS_MIB_OUT, skb->len);
264 return NF_HOOK(PF_INET6, NF_INET_LOCAL_OUT, skb, NULL, dst->dev, 257 return NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, skb, NULL,
265 dst_output); 258 dst->dev, dst_output);
266 } 259 }
267 260
268 if (net_ratelimit()) 261 if (net_ratelimit())
@@ -538,7 +531,7 @@ int ip6_forward(struct sk_buff *skb)
538 hdr->hop_limit--; 531 hdr->hop_limit--;
539 532
540 IP6_INC_STATS_BH(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTFORWDATAGRAMS); 533 IP6_INC_STATS_BH(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTFORWDATAGRAMS);
541 return NF_HOOK(PF_INET6, NF_INET_FORWARD, skb, skb->dev, dst->dev, 534 return NF_HOOK(NFPROTO_IPV6, NF_INET_FORWARD, skb, skb->dev, dst->dev,
542 ip6_forward_finish); 535 ip6_forward_finish);
543 536
544error: 537error:
@@ -1109,7 +1102,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
1109 int offset, int len, int odd, struct sk_buff *skb), 1102 int offset, int len, int odd, struct sk_buff *skb),
1110 void *from, int length, int transhdrlen, 1103 void *from, int length, int transhdrlen,
1111 int hlimit, int tclass, struct ipv6_txoptions *opt, struct flowi *fl, 1104 int hlimit, int tclass, struct ipv6_txoptions *opt, struct flowi *fl,
1112 struct rt6_info *rt, unsigned int flags) 1105 struct rt6_info *rt, unsigned int flags, int dontfrag)
1113{ 1106{
1114 struct inet_sock *inet = inet_sk(sk); 1107 struct inet_sock *inet = inet_sk(sk);
1115 struct ipv6_pinfo *np = inet6_sk(sk); 1108 struct ipv6_pinfo *np = inet6_sk(sk);
@@ -1223,15 +1216,23 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
1223 */ 1216 */
1224 1217
1225 inet->cork.length += length; 1218 inet->cork.length += length;
1226 if (((length > mtu) && (sk->sk_protocol == IPPROTO_UDP)) && 1219 if (length > mtu) {
1227 (rt->u.dst.dev->features & NETIF_F_UFO)) { 1220 int proto = sk->sk_protocol;
1221 if (dontfrag && (proto == IPPROTO_UDP || proto == IPPROTO_RAW)){
1222 ipv6_local_rxpmtu(sk, fl, mtu-exthdrlen);
1223 return -EMSGSIZE;
1224 }
1228 1225
1229 err = ip6_ufo_append_data(sk, getfrag, from, length, hh_len, 1226 if (proto == IPPROTO_UDP &&
1230 fragheaderlen, transhdrlen, mtu, 1227 (rt->u.dst.dev->features & NETIF_F_UFO)) {
1231 flags); 1228
1232 if (err) 1229 err = ip6_ufo_append_data(sk, getfrag, from, length,
1233 goto error; 1230 hh_len, fragheaderlen,
1234 return 0; 1231 transhdrlen, mtu, flags);
1232 if (err)
1233 goto error;
1234 return 0;
1235 }
1235 } 1236 }
1236 1237
1237 if ((skb = skb_peek_tail(&sk->sk_write_queue)) == NULL) 1238 if ((skb = skb_peek_tail(&sk->sk_write_queue)) == NULL)