/* Segmentation offload features */
 #define NETIF_F_GSO_SHIFT      16
+#define NETIF_F_GSO_MASK       0xffff0000
 #define NETIF_F_TSO            (SKB_GSO_TCPV4 << NETIF_F_GSO_SHIFT)
 #define NETIF_F_UFO            (SKB_GSO_UDPV4 << NETIF_F_GSO_SHIFT)
 #define NETIF_F_GSO_ROBUST     (SKB_GSO_DODGY << NETIF_F_GSO_SHIFT)
 
 extern void linkwatch_run_queue(void);
 
-static inline int skb_gso_ok(struct sk_buff *skb, int features)
+static inline int net_gso_ok(int features, int gso_type)
 {
-       int feature = skb_shinfo(skb)->gso_size ?
-                     skb_shinfo(skb)->gso_type << NETIF_F_GSO_SHIFT : 0;
+       int feature = gso_type << NETIF_F_GSO_SHIFT;
        return (features & feature) == feature;
 }
 
+static inline int skb_gso_ok(struct sk_buff *skb, int features)
+{
+       return net_gso_ok(features, skb_shinfo(skb)->gso_size ?
+                                   skb_shinfo(skb)->gso_type : 0);
+}
+
 static inline int netif_needs_gso(struct net_device *dev, struct sk_buff *skb)
 {
        return !skb_gso_ok(skb, dev->features);
 
   *    @sk_flags: %SO_LINGER (l_onoff), %SO_BROADCAST, %SO_KEEPALIVE, %SO_OOBINLINE settings
   *    @sk_no_check: %SO_NO_CHECK setting, wether or not checkup packets
   *    @sk_route_caps: route capabilities (e.g. %NETIF_F_TSO)
+  *    @sk_gso_type: GSO type (e.g. %SKB_GSO_TCPV4)
   *    @sk_lingertime: %SO_LINGER l_linger setting
   *    @sk_backlog: always used with the per-socket spinlock held
   *    @sk_callback_lock: used with the callbacks in the end of this struct
        gfp_t                   sk_allocation;
        int                     sk_sndbuf;
        int                     sk_route_caps;
+       int                     sk_gso_type;
        int                     sk_rcvlowat;
        unsigned long           sk_flags;
        unsigned long           sk_lingertime;
 
 extern struct dst_entry *sk_dst_check(struct sock *sk, u32 cookie);
 
+static inline int sk_can_gso(const struct sock *sk)
+{
+       return net_gso_ok(sk->sk_route_caps, sk->sk_gso_type);
+}
+
 static inline void sk_setup_caps(struct sock *sk, struct dst_entry *dst)
 {
        __sk_dst_set(sk, dst);
        sk->sk_route_caps = dst->dev->features;
        if (sk->sk_route_caps & NETIF_F_GSO)
-               sk->sk_route_caps |= NETIF_F_TSO;
-       if (sk->sk_route_caps & NETIF_F_TSO) {
+               sk->sk_route_caps |= NETIF_F_GSO_MASK;
+       if (sk_can_gso(sk)) {
                if (dst->header_len)
-                       sk->sk_route_caps &= ~NETIF_F_TSO;
+                       sk->sk_route_caps &= ~NETIF_F_GSO_MASK;
                else 
                        sk->sk_route_caps |= NETIF_F_SG | NETIF_F_HW_CSUM;
        }
 
        if (in_flight >= tp->snd_cwnd)
                return 1;
 
-       if (!(sk->sk_route_caps & NETIF_F_TSO))
+       if (!sk_can_gso(sk))
                return 0;
 
        left = tp->snd_cwnd - in_flight;
 
        int tmp = tp->mss_cache;
 
        if (sk->sk_route_caps & NETIF_F_SG) {
-               if (sk->sk_route_caps & NETIF_F_TSO)
+               if (sk_can_gso(sk))
                        tmp = 0;
                else {
                        int pgbreak = SKB_MAX_HEAD(MAX_TCP_HEADER);
 
                goto failure;
 
        /* OK, now commit destination to socket.  */
+       sk->sk_gso_type = SKB_GSO_TCPV4;
        sk_setup_caps(sk, &rt->u.dst);
 
        if (!tp->write_seq)
        if (!newsk)
                goto exit;
 
+       newsk->sk_gso_type = SKB_GSO_TCPV4;
        sk_setup_caps(newsk, dst);
 
        newtp                 = tcp_sk(newsk);
 
 
 static void tcp_set_skb_tso_segs(struct sock *sk, struct sk_buff *skb, unsigned int mss_now)
 {
-       if (skb->len <= mss_now ||
-           !(sk->sk_route_caps & NETIF_F_TSO)) {
+       if (skb->len <= mss_now || !sk_can_gso(sk)) {
                /* Avoid the costly divide in the normal
                 * non-TSO case.
                 */
                factor /= mss_now;
                skb_shinfo(skb)->gso_segs = factor;
                skb_shinfo(skb)->gso_size = mss_now;
-               skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
+               skb_shinfo(skb)->gso_type = sk->sk_gso_type;
        }
 }
 
 
        mss_now = tp->mss_cache;
 
-       if (large_allowed &&
-           (sk->sk_route_caps & NETIF_F_TSO) &&
-           !tp->urg_mode)
+       if (large_allowed && sk_can_gso(sk) && !tp->urg_mode)
                doing_tso = 1;
 
        if (dst) {