@@ -268,35 +268,36 @@ bool ip6_autoflowlabel(struct net *net, const struct sock *sk)
268268int ip6_xmit (const struct sock * sk , struct sk_buff * skb , struct flowi6 * fl6 ,
269269 __u32 mark , struct ipv6_txoptions * opt , int tclass , u32 priority )
270270{
271- struct net * net = sock_net (sk );
272271 const struct ipv6_pinfo * np = inet6_sk (sk );
273272 struct in6_addr * first_hop = & fl6 -> daddr ;
274273 struct dst_entry * dst = skb_dst (skb );
275- struct net_device * dev = dst_dev (dst );
276274 struct inet6_dev * idev = ip6_dst_idev (dst );
277275 struct hop_jumbo_hdr * hop_jumbo ;
278276 int hoplen = sizeof (* hop_jumbo );
277+ struct net * net = sock_net (sk );
279278 unsigned int head_room ;
279+ struct net_device * dev ;
280280 struct ipv6hdr * hdr ;
281281 u8 proto = fl6 -> flowi6_proto ;
282282 int seg_len = skb -> len ;
283- int hlimit = -1 ;
283+ int ret , hlimit = -1 ;
284284 u32 mtu ;
285285
286+ rcu_read_lock ();
287+
288+ dev = dst_dev_rcu (dst );
286289 head_room = sizeof (struct ipv6hdr ) + hoplen + LL_RESERVED_SPACE (dev );
287290 if (opt )
288291 head_room += opt -> opt_nflen + opt -> opt_flen ;
289292
290293 if (unlikely (head_room > skb_headroom (skb ))) {
291- /* Make sure idev stays alive */
292- rcu_read_lock ();
294+ /* idev stays alive while we hold rcu_read_lock(). */
293295 skb = skb_expand_head (skb , head_room );
294296 if (!skb ) {
295297 IP6_INC_STATS (net , idev , IPSTATS_MIB_OUTDISCARDS );
296- rcu_read_unlock () ;
297- return - ENOBUFS ;
298+ ret = - ENOBUFS ;
299+ goto unlock ;
298300 }
299- rcu_read_unlock ();
300301 }
301302
302303 if (opt ) {
@@ -358,17 +359,21 @@ int ip6_xmit(const struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6,
358359 * skb to its handler for processing
359360 */
360361 skb = l3mdev_ip6_out ((struct sock * )sk , skb );
361- if (unlikely (!skb ))
362- return 0 ;
362+ if (unlikely (!skb )) {
363+ ret = 0 ;
364+ goto unlock ;
365+ }
363366
364367 /* hooks should never assume socket lock is held.
365368 * we promote our socket to non const
366369 */
367- return NF_HOOK (NFPROTO_IPV6 , NF_INET_LOCAL_OUT ,
368- net , (struct sock * )sk , skb , NULL , dev ,
369- dst_output );
370+ ret = NF_HOOK (NFPROTO_IPV6 , NF_INET_LOCAL_OUT ,
371+ net , (struct sock * )sk , skb , NULL , dev ,
372+ dst_output );
373+ goto unlock ;
370374 }
371375
376+ ret = - EMSGSIZE ;
372377 skb -> dev = dev ;
373378 /* ipv6_local_error() does not require socket lock,
374379 * we promote our socket to non const
@@ -377,7 +382,9 @@ int ip6_xmit(const struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6,
377382
378383 IP6_INC_STATS (net , idev , IPSTATS_MIB_FRAGFAILS );
379384 kfree_skb (skb );
380- return - EMSGSIZE ;
385+ unlock :
386+ rcu_read_unlock ();
387+ return ret ;
381388}
382389EXPORT_SYMBOL (ip6_xmit );
383390
0 commit comments