diff options
Diffstat (limited to 'net/core')
-rw-r--r-- | net/core/dev.c | 39 | ||||
-rw-r--r-- | net/core/rtnetlink.c | 2 | ||||
-rw-r--r-- | net/core/skbuff.c | 7 | ||||
-rw-r--r-- | net/core/sock.c | 11 |
4 files changed, 42 insertions, 17 deletions
diff --git a/net/core/dev.c b/net/core/dev.c index f1c52cbd6ef7..08976b08df5b 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1190,11 +1190,14 @@ out: /** * skb_gso_segment - Perform segmentation on skb. * @skb: buffer to segment - * @sg: whether scatter-gather is supported on the target. + * @features: features for the output path (see dev->features) * * This function segments the given skb and returns a list of segments. + * + * It may return NULL if the skb requires no segmentation. This is + * only possible when GSO is used for verifying header integrity. */ -struct sk_buff *skb_gso_segment(struct sk_buff *skb, int sg) +struct sk_buff *skb_gso_segment(struct sk_buff *skb, int features) { struct sk_buff *segs = ERR_PTR(-EPROTONOSUPPORT); struct packet_type *ptype; @@ -1210,12 +1213,14 @@ struct sk_buff *skb_gso_segment(struct sk_buff *skb, int sg) rcu_read_lock(); list_for_each_entry_rcu(ptype, &ptype_base[ntohs(type) & 15], list) { if (ptype->type == type && !ptype->dev && ptype->gso_segment) { - segs = ptype->gso_segment(skb, sg); + segs = ptype->gso_segment(skb, features); break; } } rcu_read_unlock(); + __skb_push(skb, skb->data - skb->mac.raw); + return segs; } @@ -1234,7 +1239,6 @@ void netdev_rx_csum_fault(struct net_device *dev) EXPORT_SYMBOL(netdev_rx_csum_fault); #endif -#ifdef CONFIG_HIGHMEM /* Actually, we should eliminate this check as soon as we know, that: * 1. IOMMU is present and allows to map all the memory. * 2. No high memory really exists on this machine. @@ -1242,6 +1246,7 @@ EXPORT_SYMBOL(netdev_rx_csum_fault); static inline int illegal_highdma(struct net_device *dev, struct sk_buff *skb) { +#ifdef CONFIG_HIGHMEM int i; if (dev->features & NETIF_F_HIGHDMA) @@ -1251,11 +1256,9 @@ static inline int illegal_highdma(struct net_device *dev, struct sk_buff *skb) if (PageHighMem(skb_shinfo(skb)->frags[i].page)) return 1; +#endif return 0; } -#else -#define illegal_highdma(dev, skb) (0) -#endif struct dev_gso_cb { void (*destructor)(struct sk_buff *skb); @@ -1291,9 +1294,15 @@ static int dev_gso_segment(struct sk_buff *skb) { struct net_device *dev = skb->dev; struct sk_buff *segs; + int features = dev->features & ~(illegal_highdma(dev, skb) ? + NETIF_F_SG : 0); + + segs = skb_gso_segment(skb, features); + + /* Verifying header integrity only. */ + if (!segs) + return 0; - segs = skb_gso_segment(skb, dev->features & NETIF_F_SG && - !illegal_highdma(dev, skb)); if (unlikely(IS_ERR(segs))) return PTR_ERR(segs); @@ -1310,13 +1319,17 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) if (netdev_nit) dev_queue_xmit_nit(skb, dev); - if (!netif_needs_gso(dev, skb)) - return dev->hard_start_xmit(skb, dev); + if (netif_needs_gso(dev, skb)) { + if (unlikely(dev_gso_segment(skb))) + goto out_kfree_skb; + if (skb->next) + goto gso; + } - if (unlikely(dev_gso_segment(skb))) - goto out_kfree_skb; + return dev->hard_start_xmit(skb, dev); } +gso: do { struct sk_buff *nskb = skb->next; int rc; diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 3fcfa9c59e1f..f25aac17497a 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -663,7 +663,7 @@ rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *errp) sz_idx = type>>2; kind = type&3; - if (kind != 2 && security_netlink_recv(skb)) { + if (kind != 2 && security_netlink_recv(skb, CAP_NET_ADMIN)) { *errp = -EPERM; return -1; } diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 6edbb90cbcec..a1c9ecf4f1e0 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -272,7 +272,7 @@ static void skb_clone_fraglist(struct sk_buff *skb) skb_get(list); } -void skb_release_data(struct sk_buff *skb) +static void skb_release_data(struct sk_buff *skb) { if (!skb->cloned || !atomic_sub_return(skb->nohdr ? (1 << SKB_DATAREF_SHIFT) + 1 : 1, @@ -1848,13 +1848,13 @@ EXPORT_SYMBOL_GPL(skb_pull_rcsum); /** * skb_segment - Perform protocol segmentation on skb. * @skb: buffer to segment - * @sg: whether scatter-gather can be used for generated segments + * @features: features for the output path (see dev->features) * * This function performs segmentation on the given skb. It returns * the segment at the given position. It returns NULL if there are * no more segments to generate, or when an error is encountered. */ -struct sk_buff *skb_segment(struct sk_buff *skb, int sg) +struct sk_buff *skb_segment(struct sk_buff *skb, int features) { struct sk_buff *segs = NULL; struct sk_buff *tail = NULL; @@ -1863,6 +1863,7 @@ struct sk_buff *skb_segment(struct sk_buff *skb, int sg) unsigned int offset = doffset; unsigned int headroom; unsigned int len; + int sg = features & NETIF_F_SG; int nfrags = skb_shinfo(skb)->nr_frags; int err = -ENOMEM; int i = 0; diff --git a/net/core/sock.c b/net/core/sock.c index 5d820c376653..204a8dec65cc 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -565,6 +565,13 @@ set_rcvbuf: ret = -ENONET; break; + case SO_PASSSEC: + if (valbool) + set_bit(SOCK_PASSSEC, &sock->flags); + else + clear_bit(SOCK_PASSSEC, &sock->flags); + break; + /* We implement the SO_SNDLOWAT etc to not be settable (1003.1g 5.3) */ default: @@ -723,6 +730,10 @@ int sock_getsockopt(struct socket *sock, int level, int optname, v.val = sk->sk_state == TCP_LISTEN; break; + case SO_PASSSEC: + v.val = test_bit(SOCK_PASSSEC, &sock->flags) ? 1 : 0; + break; + case SO_PEERSEC: return security_socket_getpeersec_stream(sock, optval, optlen, len); |