diff options
Diffstat (limited to 'net/packet/af_packet.c')
-rw-r--r-- | net/packet/af_packet.c | 79 |
1 files changed, 66 insertions, 13 deletions
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 6dc01bdeb76b..a6fa48788e8f 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c | |||
@@ -60,6 +60,7 @@ | |||
60 | #include <linux/netdevice.h> | 60 | #include <linux/netdevice.h> |
61 | #include <linux/if_packet.h> | 61 | #include <linux/if_packet.h> |
62 | #include <linux/wireless.h> | 62 | #include <linux/wireless.h> |
63 | #include <linux/kernel.h> | ||
63 | #include <linux/kmod.h> | 64 | #include <linux/kmod.h> |
64 | #include <net/ip.h> | 65 | #include <net/ip.h> |
65 | #include <net/protocol.h> | 66 | #include <net/protocol.h> |
@@ -200,7 +201,8 @@ struct packet_sock { | |||
200 | #endif | 201 | #endif |
201 | struct packet_type prot_hook; | 202 | struct packet_type prot_hook; |
202 | spinlock_t bind_lock; | 203 | spinlock_t bind_lock; |
203 | char running; /* prot_hook is attached*/ | 204 | unsigned int running:1, /* prot_hook is attached*/ |
205 | auxdata:1; | ||
204 | int ifindex; /* bound device */ | 206 | int ifindex; /* bound device */ |
205 | __be16 num; | 207 | __be16 num; |
206 | #ifdef CONFIG_PACKET_MULTICAST | 208 | #ifdef CONFIG_PACKET_MULTICAST |
@@ -214,6 +216,16 @@ struct packet_sock { | |||
214 | #endif | 216 | #endif |
215 | }; | 217 | }; |
216 | 218 | ||
219 | struct packet_skb_cb { | ||
220 | unsigned int origlen; | ||
221 | union { | ||
222 | struct sockaddr_pkt pkt; | ||
223 | struct sockaddr_ll ll; | ||
224 | } sa; | ||
225 | }; | ||
226 | |||
227 | #define PACKET_SKB_CB(__skb) ((struct packet_skb_cb *)((__skb)->cb)) | ||
228 | |||
217 | #ifdef CONFIG_PACKET_MMAP | 229 | #ifdef CONFIG_PACKET_MMAP |
218 | 230 | ||
219 | static inline char *packet_lookup_frame(struct packet_sock *po, unsigned int position) | 231 | static inline char *packet_lookup_frame(struct packet_sock *po, unsigned int position) |
@@ -293,7 +305,7 @@ static int packet_rcv_spkt(struct sk_buff *skb, struct net_device *dev, struct | |||
293 | /* drop conntrack reference */ | 305 | /* drop conntrack reference */ |
294 | nf_reset(skb); | 306 | nf_reset(skb); |
295 | 307 | ||
296 | spkt = (struct sockaddr_pkt*)skb->cb; | 308 | spkt = &PACKET_SKB_CB(skb)->sa.pkt; |
297 | 309 | ||
298 | skb_push(skb, skb->data-skb->mac.raw); | 310 | skb_push(skb, skb->data-skb->mac.raw); |
299 | 311 | ||
@@ -512,7 +524,10 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet | |||
512 | skb = nskb; | 524 | skb = nskb; |
513 | } | 525 | } |
514 | 526 | ||
515 | sll = (struct sockaddr_ll*)skb->cb; | 527 | BUILD_BUG_ON(sizeof(*PACKET_SKB_CB(skb)) + MAX_ADDR_LEN - 8 > |
528 | sizeof(skb->cb)); | ||
529 | |||
530 | sll = &PACKET_SKB_CB(skb)->sa.ll; | ||
516 | sll->sll_family = AF_PACKET; | 531 | sll->sll_family = AF_PACKET; |
517 | sll->sll_hatype = dev->type; | 532 | sll->sll_hatype = dev->type; |
518 | sll->sll_protocol = skb->protocol; | 533 | sll->sll_protocol = skb->protocol; |
@@ -523,6 +538,8 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet | |||
523 | if (dev->hard_header_parse) | 538 | if (dev->hard_header_parse) |
524 | sll->sll_halen = dev->hard_header_parse(skb, sll->sll_addr); | 539 | sll->sll_halen = dev->hard_header_parse(skb, sll->sll_addr); |
525 | 540 | ||
541 | PACKET_SKB_CB(skb)->origlen = skb->len; | ||
542 | |||
526 | if (pskb_trim(skb, snaplen)) | 543 | if (pskb_trim(skb, snaplen)) |
527 | goto drop_n_acct; | 544 | goto drop_n_acct; |
528 | 545 | ||
@@ -582,11 +599,12 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct packe | |||
582 | else if (skb->pkt_type == PACKET_OUTGOING) { | 599 | else if (skb->pkt_type == PACKET_OUTGOING) { |
583 | /* Special case: outgoing packets have ll header at head */ | 600 | /* Special case: outgoing packets have ll header at head */ |
584 | skb_pull(skb, skb->nh.raw - skb->data); | 601 | skb_pull(skb, skb->nh.raw - skb->data); |
585 | if (skb->ip_summed == CHECKSUM_PARTIAL) | ||
586 | status |= TP_STATUS_CSUMNOTREADY; | ||
587 | } | 602 | } |
588 | } | 603 | } |
589 | 604 | ||
605 | if (skb->ip_summed == CHECKSUM_PARTIAL) | ||
606 | status |= TP_STATUS_CSUMNOTREADY; | ||
607 | |||
590 | snaplen = skb->len; | 608 | snaplen = skb->len; |
591 | 609 | ||
592 | res = run_filter(skb, sk, snaplen); | 610 | res = run_filter(skb, sk, snaplen); |
@@ -1092,7 +1110,7 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
1092 | * it in now. | 1110 | * it in now. |
1093 | */ | 1111 | */ |
1094 | 1112 | ||
1095 | sll = (struct sockaddr_ll*)skb->cb; | 1113 | sll = &PACKET_SKB_CB(skb)->sa.ll; |
1096 | if (sock->type == SOCK_PACKET) | 1114 | if (sock->type == SOCK_PACKET) |
1097 | msg->msg_namelen = sizeof(struct sockaddr_pkt); | 1115 | msg->msg_namelen = sizeof(struct sockaddr_pkt); |
1098 | else | 1116 | else |
@@ -1117,7 +1135,22 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
1117 | sock_recv_timestamp(msg, sk, skb); | 1135 | sock_recv_timestamp(msg, sk, skb); |
1118 | 1136 | ||
1119 | if (msg->msg_name) | 1137 | if (msg->msg_name) |
1120 | memcpy(msg->msg_name, skb->cb, msg->msg_namelen); | 1138 | memcpy(msg->msg_name, &PACKET_SKB_CB(skb)->sa, |
1139 | msg->msg_namelen); | ||
1140 | |||
1141 | if (pkt_sk(sk)->auxdata) { | ||
1142 | struct tpacket_auxdata aux; | ||
1143 | |||
1144 | aux.tp_status = TP_STATUS_USER; | ||
1145 | if (skb->ip_summed == CHECKSUM_PARTIAL) | ||
1146 | aux.tp_status |= TP_STATUS_CSUMNOTREADY; | ||
1147 | aux.tp_len = PACKET_SKB_CB(skb)->origlen; | ||
1148 | aux.tp_snaplen = skb->len; | ||
1149 | aux.tp_mac = 0; | ||
1150 | aux.tp_net = skb->nh.raw - skb->data; | ||
1151 | |||
1152 | put_cmsg(msg, SOL_PACKET, PACKET_AUXDATA, sizeof(aux), &aux); | ||
1153 | } | ||
1121 | 1154 | ||
1122 | /* | 1155 | /* |
1123 | * Free or return the buffer as appropriate. Again this | 1156 | * Free or return the buffer as appropriate. Again this |
@@ -1317,6 +1350,7 @@ static int | |||
1317 | packet_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen) | 1350 | packet_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen) |
1318 | { | 1351 | { |
1319 | struct sock *sk = sock->sk; | 1352 | struct sock *sk = sock->sk; |
1353 | struct packet_sock *po = pkt_sk(sk); | ||
1320 | int ret; | 1354 | int ret; |
1321 | 1355 | ||
1322 | if (level != SOL_PACKET) | 1356 | if (level != SOL_PACKET) |
@@ -1369,6 +1403,18 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv | |||
1369 | return 0; | 1403 | return 0; |
1370 | } | 1404 | } |
1371 | #endif | 1405 | #endif |
1406 | case PACKET_AUXDATA: | ||
1407 | { | ||
1408 | int val; | ||
1409 | |||
1410 | if (optlen < sizeof(val)) | ||
1411 | return -EINVAL; | ||
1412 | if (copy_from_user(&val, optval, sizeof(val))) | ||
1413 | return -EFAULT; | ||
1414 | |||
1415 | po->auxdata = !!val; | ||
1416 | return 0; | ||
1417 | } | ||
1372 | default: | 1418 | default: |
1373 | return -ENOPROTOOPT; | 1419 | return -ENOPROTOOPT; |
1374 | } | 1420 | } |
@@ -1378,8 +1424,11 @@ static int packet_getsockopt(struct socket *sock, int level, int optname, | |||
1378 | char __user *optval, int __user *optlen) | 1424 | char __user *optval, int __user *optlen) |
1379 | { | 1425 | { |
1380 | int len; | 1426 | int len; |
1427 | int val; | ||
1381 | struct sock *sk = sock->sk; | 1428 | struct sock *sk = sock->sk; |
1382 | struct packet_sock *po = pkt_sk(sk); | 1429 | struct packet_sock *po = pkt_sk(sk); |
1430 | void *data; | ||
1431 | struct tpacket_stats st; | ||
1383 | 1432 | ||
1384 | if (level != SOL_PACKET) | 1433 | if (level != SOL_PACKET) |
1385 | return -ENOPROTOOPT; | 1434 | return -ENOPROTOOPT; |
@@ -1392,9 +1441,6 @@ static int packet_getsockopt(struct socket *sock, int level, int optname, | |||
1392 | 1441 | ||
1393 | switch(optname) { | 1442 | switch(optname) { |
1394 | case PACKET_STATISTICS: | 1443 | case PACKET_STATISTICS: |
1395 | { | ||
1396 | struct tpacket_stats st; | ||
1397 | |||
1398 | if (len > sizeof(struct tpacket_stats)) | 1444 | if (len > sizeof(struct tpacket_stats)) |
1399 | len = sizeof(struct tpacket_stats); | 1445 | len = sizeof(struct tpacket_stats); |
1400 | spin_lock_bh(&sk->sk_receive_queue.lock); | 1446 | spin_lock_bh(&sk->sk_receive_queue.lock); |
@@ -1403,16 +1449,23 @@ static int packet_getsockopt(struct socket *sock, int level, int optname, | |||
1403 | spin_unlock_bh(&sk->sk_receive_queue.lock); | 1449 | spin_unlock_bh(&sk->sk_receive_queue.lock); |
1404 | st.tp_packets += st.tp_drops; | 1450 | st.tp_packets += st.tp_drops; |
1405 | 1451 | ||
1406 | if (copy_to_user(optval, &st, len)) | 1452 | data = &st; |
1407 | return -EFAULT; | 1453 | break; |
1454 | case PACKET_AUXDATA: | ||
1455 | if (len > sizeof(int)) | ||
1456 | len = sizeof(int); | ||
1457 | val = po->auxdata; | ||
1458 | |||
1459 | data = &val; | ||
1408 | break; | 1460 | break; |
1409 | } | ||
1410 | default: | 1461 | default: |
1411 | return -ENOPROTOOPT; | 1462 | return -ENOPROTOOPT; |
1412 | } | 1463 | } |
1413 | 1464 | ||
1414 | if (put_user(len, optlen)) | 1465 | if (put_user(len, optlen)) |
1415 | return -EFAULT; | 1466 | return -EFAULT; |
1467 | if (copy_to_user(optval, data, len)) | ||
1468 | return -EFAULT; | ||
1416 | return 0; | 1469 | return 0; |
1417 | } | 1470 | } |
1418 | 1471 | ||