aboutsummaryrefslogtreecommitdiffstats
path: root/net/packet
diff options
context:
space:
mode:
authorPaul Chavent <Paul.Chavent@onera.fr>2012-11-06 18:10:47 -0500
committerDavid S. Miller <davem@davemloft.net>2012-11-07 18:54:30 -0500
commit5920cd3a41f1aefc30e9ce86384fc2fe9f5fe0c0 (patch)
treececc965a19e1ffe6957d8dcf2e55566562f93e0c /net/packet
parent7da716aee2532399e213a14f656d304098f67a11 (diff)
packet: tx_ring: allow the user to choose tx data offset
The tx data offset of packet mmap tx ring used to be : (TPACKET2_HDRLEN - sizeof(struct sockaddr_ll)) The problem is that, with SOCK_RAW socket, the payload (14 bytes after the beginning of the user data) is misaligned. This patch allows to let the user gives an offset for it's tx data if he desires. Set sock option PACKET_TX_HAS_OFF to 1, then specify in each frame of your tx ring tp_net for SOCK_DGRAM, or tp_mac for SOCK_RAW. Signed-off-by: Paul Chavent <paul.chavent@onera.fr> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/packet')
-rw-r--r--net/packet/af_packet.c46
-rw-r--r--net/packet/internal.h1
2 files changed, 46 insertions, 1 deletions
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 9034f52659b5..f262dbfc7f06 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) {
@@ -3109,6 +3137,19 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
3109 3137
3110 return fanout_add(sk, val & 0xffff, val >> 16); 3138 return fanout_add(sk, val & 0xffff, val >> 16);
3111 } 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 }
3112 default: 3153 default:
3113 return -ENOPROTOOPT; 3154 return -ENOPROTOOPT;
3114 } 3155 }
@@ -3200,6 +3241,9 @@ static int packet_getsockopt(struct socket *sock, int level, int optname,
3200 ((u32)po->fanout->type << 16)) : 3241 ((u32)po->fanout->type << 16)) :
3201 0); 3242 0);
3202 break; 3243 break;
3244 case PACKET_TX_HAS_OFF:
3245 val = po->tp_tx_has_off;
3246 break;
3203 default: 3247 default:
3204 return -ENOPROTOOPT; 3248 return -ENOPROTOOPT;
3205 } 3249 }
diff --git a/net/packet/internal.h b/net/packet/internal.h
index 44945f6b7252..e84cab8cb7a9 100644
--- a/net/packet/internal.h
+++ b/net/packet/internal.h
@@ -109,6 +109,7 @@ struct packet_sock {
109 unsigned int tp_hdrlen; 109 unsigned int tp_hdrlen;
110 unsigned int tp_reserve; 110 unsigned int tp_reserve;
111 unsigned int tp_loss:1; 111 unsigned int tp_loss:1;
112 unsigned int tp_tx_has_off:1;
112 unsigned int tp_tstamp; 113 unsigned int tp_tstamp;
113 struct packet_type prot_hook ____cacheline_aligned_in_smp; 114 struct packet_type prot_hook ____cacheline_aligned_in_smp;
114}; 115};