diff options
Diffstat (limited to 'net/packet/af_packet.c')
-rw-r--r-- | net/packet/af_packet.c | 57 |
1 files changed, 48 insertions, 9 deletions
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 6dc01bdeb76b..8973ea78831e 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c | |||
@@ -200,7 +200,8 @@ struct packet_sock { | |||
200 | #endif | 200 | #endif |
201 | struct packet_type prot_hook; | 201 | struct packet_type prot_hook; |
202 | spinlock_t bind_lock; | 202 | spinlock_t bind_lock; |
203 | char running; /* prot_hook is attached*/ | 203 | unsigned int running:1, /* prot_hook is attached*/ |
204 | auxdata:1; | ||
204 | int ifindex; /* bound device */ | 205 | int ifindex; /* bound device */ |
205 | __be16 num; | 206 | __be16 num; |
206 | #ifdef CONFIG_PACKET_MULTICAST | 207 | #ifdef CONFIG_PACKET_MULTICAST |
@@ -214,6 +215,8 @@ struct packet_sock { | |||
214 | #endif | 215 | #endif |
215 | }; | 216 | }; |
216 | 217 | ||
218 | #define PACKET_SKB_CB(__skb) ((struct tpacket_auxdata *)((__skb)->cb)) | ||
219 | |||
217 | #ifdef CONFIG_PACKET_MMAP | 220 | #ifdef CONFIG_PACKET_MMAP |
218 | 221 | ||
219 | static inline char *packet_lookup_frame(struct packet_sock *po, unsigned int position) | 222 | static inline char *packet_lookup_frame(struct packet_sock *po, unsigned int position) |
@@ -462,6 +465,7 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet | |||
462 | u8 * skb_head = skb->data; | 465 | u8 * skb_head = skb->data; |
463 | int skb_len = skb->len; | 466 | int skb_len = skb->len; |
464 | unsigned int snaplen, res; | 467 | unsigned int snaplen, res; |
468 | struct tpacket_auxdata *aux; | ||
465 | 469 | ||
466 | if (skb->pkt_type == PACKET_LOOPBACK) | 470 | if (skb->pkt_type == PACKET_LOOPBACK) |
467 | goto drop; | 471 | goto drop; |
@@ -523,6 +527,15 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet | |||
523 | if (dev->hard_header_parse) | 527 | if (dev->hard_header_parse) |
524 | sll->sll_halen = dev->hard_header_parse(skb, sll->sll_addr); | 528 | sll->sll_halen = dev->hard_header_parse(skb, sll->sll_addr); |
525 | 529 | ||
530 | aux = PACKET_SKB_CB(skb); | ||
531 | aux->tp_status = TP_STATUS_USER; | ||
532 | if (skb->ip_summed == CHECKSUM_PARTIAL) | ||
533 | aux->tp_status |= TP_STATUS_CSUMNOTREADY; | ||
534 | aux->tp_len = skb->len; | ||
535 | aux->tp_snaplen = snaplen; | ||
536 | aux->tp_mac = 0; | ||
537 | aux->tp_net = skb->nh.raw - skb->data; | ||
538 | |||
526 | if (pskb_trim(skb, snaplen)) | 539 | if (pskb_trim(skb, snaplen)) |
527 | goto drop_n_acct; | 540 | goto drop_n_acct; |
528 | 541 | ||
@@ -582,11 +595,12 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct packe | |||
582 | else if (skb->pkt_type == PACKET_OUTGOING) { | 595 | else if (skb->pkt_type == PACKET_OUTGOING) { |
583 | /* Special case: outgoing packets have ll header at head */ | 596 | /* Special case: outgoing packets have ll header at head */ |
584 | skb_pull(skb, skb->nh.raw - skb->data); | 597 | skb_pull(skb, skb->nh.raw - skb->data); |
585 | if (skb->ip_summed == CHECKSUM_PARTIAL) | ||
586 | status |= TP_STATUS_CSUMNOTREADY; | ||
587 | } | 598 | } |
588 | } | 599 | } |
589 | 600 | ||
601 | if (skb->ip_summed == CHECKSUM_PARTIAL) | ||
602 | status |= TP_STATUS_CSUMNOTREADY; | ||
603 | |||
590 | snaplen = skb->len; | 604 | snaplen = skb->len; |
591 | 605 | ||
592 | res = run_filter(skb, sk, snaplen); | 606 | res = run_filter(skb, sk, snaplen); |
@@ -1119,6 +1133,11 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
1119 | if (msg->msg_name) | 1133 | if (msg->msg_name) |
1120 | memcpy(msg->msg_name, skb->cb, msg->msg_namelen); | 1134 | memcpy(msg->msg_name, skb->cb, msg->msg_namelen); |
1121 | 1135 | ||
1136 | if (pkt_sk(sk)->auxdata) { | ||
1137 | struct tpacket_auxdata *aux = PACKET_SKB_CB(skb); | ||
1138 | put_cmsg(msg, SOL_PACKET, PACKET_AUXDATA, sizeof(*aux), aux); | ||
1139 | } | ||
1140 | |||
1122 | /* | 1141 | /* |
1123 | * Free or return the buffer as appropriate. Again this | 1142 | * Free or return the buffer as appropriate. Again this |
1124 | * hides all the races and re-entrancy issues from us. | 1143 | * hides all the races and re-entrancy issues from us. |
@@ -1317,6 +1336,7 @@ static int | |||
1317 | packet_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen) | 1336 | packet_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen) |
1318 | { | 1337 | { |
1319 | struct sock *sk = sock->sk; | 1338 | struct sock *sk = sock->sk; |
1339 | struct packet_sock *po = pkt_sk(sk); | ||
1320 | int ret; | 1340 | int ret; |
1321 | 1341 | ||
1322 | if (level != SOL_PACKET) | 1342 | if (level != SOL_PACKET) |
@@ -1369,6 +1389,18 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv | |||
1369 | return 0; | 1389 | return 0; |
1370 | } | 1390 | } |
1371 | #endif | 1391 | #endif |
1392 | case PACKET_AUXDATA: | ||
1393 | { | ||
1394 | int val; | ||
1395 | |||
1396 | if (optlen < sizeof(val)) | ||
1397 | return -EINVAL; | ||
1398 | if (copy_from_user(&val, optval, sizeof(val))) | ||
1399 | return -EFAULT; | ||
1400 | |||
1401 | po->auxdata = !!val; | ||
1402 | return 0; | ||
1403 | } | ||
1372 | default: | 1404 | default: |
1373 | return -ENOPROTOOPT; | 1405 | return -ENOPROTOOPT; |
1374 | } | 1406 | } |
@@ -1378,8 +1410,11 @@ static int packet_getsockopt(struct socket *sock, int level, int optname, | |||
1378 | char __user *optval, int __user *optlen) | 1410 | char __user *optval, int __user *optlen) |
1379 | { | 1411 | { |
1380 | int len; | 1412 | int len; |
1413 | int val; | ||
1381 | struct sock *sk = sock->sk; | 1414 | struct sock *sk = sock->sk; |
1382 | struct packet_sock *po = pkt_sk(sk); | 1415 | struct packet_sock *po = pkt_sk(sk); |
1416 | void *data; | ||
1417 | struct tpacket_stats st; | ||
1383 | 1418 | ||
1384 | if (level != SOL_PACKET) | 1419 | if (level != SOL_PACKET) |
1385 | return -ENOPROTOOPT; | 1420 | return -ENOPROTOOPT; |
@@ -1392,9 +1427,6 @@ static int packet_getsockopt(struct socket *sock, int level, int optname, | |||
1392 | 1427 | ||
1393 | switch(optname) { | 1428 | switch(optname) { |
1394 | case PACKET_STATISTICS: | 1429 | case PACKET_STATISTICS: |
1395 | { | ||
1396 | struct tpacket_stats st; | ||
1397 | |||
1398 | if (len > sizeof(struct tpacket_stats)) | 1430 | if (len > sizeof(struct tpacket_stats)) |
1399 | len = sizeof(struct tpacket_stats); | 1431 | len = sizeof(struct tpacket_stats); |
1400 | spin_lock_bh(&sk->sk_receive_queue.lock); | 1432 | spin_lock_bh(&sk->sk_receive_queue.lock); |
@@ -1403,16 +1435,23 @@ static int packet_getsockopt(struct socket *sock, int level, int optname, | |||
1403 | spin_unlock_bh(&sk->sk_receive_queue.lock); | 1435 | spin_unlock_bh(&sk->sk_receive_queue.lock); |
1404 | st.tp_packets += st.tp_drops; | 1436 | st.tp_packets += st.tp_drops; |
1405 | 1437 | ||
1406 | if (copy_to_user(optval, &st, len)) | 1438 | data = &st; |
1407 | return -EFAULT; | 1439 | break; |
1440 | case PACKET_AUXDATA: | ||
1441 | if (len > sizeof(int)) | ||
1442 | len = sizeof(int); | ||
1443 | val = po->auxdata; | ||
1444 | |||
1445 | data = &val; | ||
1408 | break; | 1446 | break; |
1409 | } | ||
1410 | default: | 1447 | default: |
1411 | return -ENOPROTOOPT; | 1448 | return -ENOPROTOOPT; |
1412 | } | 1449 | } |
1413 | 1450 | ||
1414 | if (put_user(len, optlen)) | 1451 | if (put_user(len, optlen)) |
1415 | return -EFAULT; | 1452 | return -EFAULT; |
1453 | if (copy_to_user(optval, data, len)) | ||
1454 | return -EFAULT; | ||
1416 | return 0; | 1455 | return 0; |
1417 | } | 1456 | } |
1418 | 1457 | ||