diff options
Diffstat (limited to 'net/packet/af_packet.c')
-rw-r--r-- | net/packet/af_packet.c | 50 |
1 files changed, 46 insertions, 4 deletions
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 94060edbbd70..e639645e8fec 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c | |||
@@ -1881,7 +1881,35 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb, | |||
1881 | skb_reserve(skb, hlen); | 1881 | skb_reserve(skb, hlen); |
1882 | skb_reset_network_header(skb); | 1882 | skb_reset_network_header(skb); |
1883 | 1883 | ||
1884 | data = ph.raw + po->tp_hdrlen - sizeof(struct sockaddr_ll); | 1884 | if (po->tp_tx_has_off) { |
1885 | int off_min, off_max, off; | ||
1886 | off_min = po->tp_hdrlen - sizeof(struct sockaddr_ll); | ||
1887 | off_max = po->tx_ring.frame_size - tp_len; | ||
1888 | if (sock->type == SOCK_DGRAM) { | ||
1889 | switch (po->tp_version) { | ||
1890 | case TPACKET_V2: | ||
1891 | off = ph.h2->tp_net; | ||
1892 | break; | ||
1893 | default: | ||
1894 | off = ph.h1->tp_net; | ||
1895 | break; | ||
1896 | } | ||
1897 | } else { | ||
1898 | switch (po->tp_version) { | ||
1899 | case TPACKET_V2: | ||
1900 | off = ph.h2->tp_mac; | ||
1901 | break; | ||
1902 | default: | ||
1903 | off = ph.h1->tp_mac; | ||
1904 | break; | ||
1905 | } | ||
1906 | } | ||
1907 | if (unlikely((off < off_min) || (off_max < off))) | ||
1908 | return -EINVAL; | ||
1909 | data = ph.raw + off; | ||
1910 | } else { | ||
1911 | data = ph.raw + po->tp_hdrlen - sizeof(struct sockaddr_ll); | ||
1912 | } | ||
1885 | to_write = tp_len; | 1913 | to_write = tp_len; |
1886 | 1914 | ||
1887 | if (sock->type == SOCK_DGRAM) { | 1915 | if (sock->type == SOCK_DGRAM) { |
@@ -1907,7 +1935,6 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb, | |||
1907 | to_write -= dev->hard_header_len; | 1935 | to_write -= dev->hard_header_len; |
1908 | } | 1936 | } |
1909 | 1937 | ||
1910 | err = -EFAULT; | ||
1911 | offset = offset_in_page(data); | 1938 | offset = offset_in_page(data); |
1912 | len_max = PAGE_SIZE - offset; | 1939 | len_max = PAGE_SIZE - offset; |
1913 | len = ((to_write > len_max) ? len_max : to_write); | 1940 | len = ((to_write > len_max) ? len_max : to_write); |
@@ -1957,7 +1984,6 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) | |||
1957 | 1984 | ||
1958 | mutex_lock(&po->pg_vec_lock); | 1985 | mutex_lock(&po->pg_vec_lock); |
1959 | 1986 | ||
1960 | err = -EBUSY; | ||
1961 | if (saddr == NULL) { | 1987 | if (saddr == NULL) { |
1962 | dev = po->prot_hook.dev; | 1988 | dev = po->prot_hook.dev; |
1963 | proto = po->num; | 1989 | proto = po->num; |
@@ -2478,7 +2504,7 @@ static int packet_create(struct net *net, struct socket *sock, int protocol, | |||
2478 | __be16 proto = (__force __be16)protocol; /* weird, but documented */ | 2504 | __be16 proto = (__force __be16)protocol; /* weird, but documented */ |
2479 | int err; | 2505 | int err; |
2480 | 2506 | ||
2481 | if (!capable(CAP_NET_RAW)) | 2507 | if (!ns_capable(net->user_ns, CAP_NET_RAW)) |
2482 | return -EPERM; | 2508 | return -EPERM; |
2483 | if (sock->type != SOCK_DGRAM && sock->type != SOCK_RAW && | 2509 | if (sock->type != SOCK_DGRAM && sock->type != SOCK_RAW && |
2484 | sock->type != SOCK_PACKET) | 2510 | sock->type != SOCK_PACKET) |
@@ -3111,6 +3137,19 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv | |||
3111 | 3137 | ||
3112 | return fanout_add(sk, val & 0xffff, val >> 16); | 3138 | return fanout_add(sk, val & 0xffff, val >> 16); |
3113 | } | 3139 | } |
3140 | case PACKET_TX_HAS_OFF: | ||
3141 | { | ||
3142 | unsigned int val; | ||
3143 | |||
3144 | if (optlen != sizeof(val)) | ||
3145 | return -EINVAL; | ||
3146 | if (po->rx_ring.pg_vec || po->tx_ring.pg_vec) | ||
3147 | return -EBUSY; | ||
3148 | if (copy_from_user(&val, optval, sizeof(val))) | ||
3149 | return -EFAULT; | ||
3150 | po->tp_tx_has_off = !!val; | ||
3151 | return 0; | ||
3152 | } | ||
3114 | default: | 3153 | default: |
3115 | return -ENOPROTOOPT; | 3154 | return -ENOPROTOOPT; |
3116 | } | 3155 | } |
@@ -3202,6 +3241,9 @@ static int packet_getsockopt(struct socket *sock, int level, int optname, | |||
3202 | ((u32)po->fanout->type << 16)) : | 3241 | ((u32)po->fanout->type << 16)) : |
3203 | 0); | 3242 | 0); |
3204 | break; | 3243 | break; |
3244 | case PACKET_TX_HAS_OFF: | ||
3245 | val = po->tp_tx_has_off; | ||
3246 | break; | ||
3205 | default: | 3247 | default: |
3206 | return -ENOPROTOOPT; | 3248 | return -ENOPROTOOPT; |
3207 | } | 3249 | } |