diff options
Diffstat (limited to 'net/packet/af_packet.c')
-rw-r--r-- | net/packet/af_packet.c | 222 |
1 files changed, 182 insertions, 40 deletions
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 2cee87da4441..d56cae112dc8 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c | |||
@@ -5,8 +5,6 @@ | |||
5 | * | 5 | * |
6 | * PACKET - implements raw packet sockets. | 6 | * PACKET - implements raw packet sockets. |
7 | * | 7 | * |
8 | * Version: $Id: af_packet.c,v 1.61 2002/02/08 03:57:19 davem Exp $ | ||
9 | * | ||
10 | * Authors: Ross Biro | 8 | * Authors: Ross Biro |
11 | * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> | 9 | * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> |
12 | * Alan Cox, <gw4pts@gw4pts.ampr.org> | 10 | * Alan Cox, <gw4pts@gw4pts.ampr.org> |
@@ -188,6 +186,9 @@ struct packet_sock { | |||
188 | unsigned int pg_vec_order; | 186 | unsigned int pg_vec_order; |
189 | unsigned int pg_vec_pages; | 187 | unsigned int pg_vec_pages; |
190 | unsigned int pg_vec_len; | 188 | unsigned int pg_vec_len; |
189 | enum tpacket_versions tp_version; | ||
190 | unsigned int tp_hdrlen; | ||
191 | unsigned int tp_reserve; | ||
191 | #endif | 192 | #endif |
192 | }; | 193 | }; |
193 | 194 | ||
@@ -203,14 +204,52 @@ struct packet_skb_cb { | |||
203 | 204 | ||
204 | #ifdef CONFIG_PACKET_MMAP | 205 | #ifdef CONFIG_PACKET_MMAP |
205 | 206 | ||
206 | static inline struct tpacket_hdr *packet_lookup_frame(struct packet_sock *po, unsigned int position) | 207 | static void *packet_lookup_frame(struct packet_sock *po, unsigned int position, |
208 | int status) | ||
207 | { | 209 | { |
208 | unsigned int pg_vec_pos, frame_offset; | 210 | unsigned int pg_vec_pos, frame_offset; |
211 | union { | ||
212 | struct tpacket_hdr *h1; | ||
213 | struct tpacket2_hdr *h2; | ||
214 | void *raw; | ||
215 | } h; | ||
209 | 216 | ||
210 | pg_vec_pos = position / po->frames_per_block; | 217 | pg_vec_pos = position / po->frames_per_block; |
211 | frame_offset = position % po->frames_per_block; | 218 | frame_offset = position % po->frames_per_block; |
212 | 219 | ||
213 | return (struct tpacket_hdr *)(po->pg_vec[pg_vec_pos] + (frame_offset * po->frame_size)); | 220 | h.raw = po->pg_vec[pg_vec_pos] + (frame_offset * po->frame_size); |
221 | switch (po->tp_version) { | ||
222 | case TPACKET_V1: | ||
223 | if (status != h.h1->tp_status ? TP_STATUS_USER : | ||
224 | TP_STATUS_KERNEL) | ||
225 | return NULL; | ||
226 | break; | ||
227 | case TPACKET_V2: | ||
228 | if (status != h.h2->tp_status ? TP_STATUS_USER : | ||
229 | TP_STATUS_KERNEL) | ||
230 | return NULL; | ||
231 | break; | ||
232 | } | ||
233 | return h.raw; | ||
234 | } | ||
235 | |||
236 | static void __packet_set_status(struct packet_sock *po, void *frame, int status) | ||
237 | { | ||
238 | union { | ||
239 | struct tpacket_hdr *h1; | ||
240 | struct tpacket2_hdr *h2; | ||
241 | void *raw; | ||
242 | } h; | ||
243 | |||
244 | h.raw = frame; | ||
245 | switch (po->tp_version) { | ||
246 | case TPACKET_V1: | ||
247 | h.h1->tp_status = status; | ||
248 | break; | ||
249 | case TPACKET_V2: | ||
250 | h.h2->tp_status = status; | ||
251 | break; | ||
252 | } | ||
214 | } | 253 | } |
215 | #endif | 254 | #endif |
216 | 255 | ||
@@ -553,14 +592,19 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct packe | |||
553 | struct sock *sk; | 592 | struct sock *sk; |
554 | struct packet_sock *po; | 593 | struct packet_sock *po; |
555 | struct sockaddr_ll *sll; | 594 | struct sockaddr_ll *sll; |
556 | struct tpacket_hdr *h; | 595 | union { |
596 | struct tpacket_hdr *h1; | ||
597 | struct tpacket2_hdr *h2; | ||
598 | void *raw; | ||
599 | } h; | ||
557 | u8 * skb_head = skb->data; | 600 | u8 * skb_head = skb->data; |
558 | int skb_len = skb->len; | 601 | int skb_len = skb->len; |
559 | unsigned int snaplen, res; | 602 | unsigned int snaplen, res; |
560 | unsigned long status = TP_STATUS_LOSING|TP_STATUS_USER; | 603 | unsigned long status = TP_STATUS_LOSING|TP_STATUS_USER; |
561 | unsigned short macoff, netoff; | 604 | unsigned short macoff, netoff, hdrlen; |
562 | struct sk_buff *copy_skb = NULL; | 605 | struct sk_buff *copy_skb = NULL; |
563 | struct timeval tv; | 606 | struct timeval tv; |
607 | struct timespec ts; | ||
564 | 608 | ||
565 | if (skb->pkt_type == PACKET_LOOPBACK) | 609 | if (skb->pkt_type == PACKET_LOOPBACK) |
566 | goto drop; | 610 | goto drop; |
@@ -592,10 +636,13 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct packe | |||
592 | snaplen = res; | 636 | snaplen = res; |
593 | 637 | ||
594 | if (sk->sk_type == SOCK_DGRAM) { | 638 | if (sk->sk_type == SOCK_DGRAM) { |
595 | macoff = netoff = TPACKET_ALIGN(TPACKET_HDRLEN) + 16; | 639 | macoff = netoff = TPACKET_ALIGN(po->tp_hdrlen) + 16 + |
640 | po->tp_reserve; | ||
596 | } else { | 641 | } else { |
597 | unsigned maclen = skb_network_offset(skb); | 642 | unsigned maclen = skb_network_offset(skb); |
598 | netoff = TPACKET_ALIGN(TPACKET_HDRLEN + (maclen < 16 ? 16 : maclen)); | 643 | netoff = TPACKET_ALIGN(po->tp_hdrlen + |
644 | (maclen < 16 ? 16 : maclen)) + | ||
645 | po->tp_reserve; | ||
599 | macoff = netoff - maclen; | 646 | macoff = netoff - maclen; |
600 | } | 647 | } |
601 | 648 | ||
@@ -618,9 +665,8 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct packe | |||
618 | } | 665 | } |
619 | 666 | ||
620 | spin_lock(&sk->sk_receive_queue.lock); | 667 | spin_lock(&sk->sk_receive_queue.lock); |
621 | h = packet_lookup_frame(po, po->head); | 668 | h.raw = packet_lookup_frame(po, po->head, TP_STATUS_KERNEL); |
622 | 669 | if (!h.raw) | |
623 | if (h->tp_status) | ||
624 | goto ring_is_full; | 670 | goto ring_is_full; |
625 | po->head = po->head != po->frame_max ? po->head+1 : 0; | 671 | po->head = po->head != po->frame_max ? po->head+1 : 0; |
626 | po->stats.tp_packets++; | 672 | po->stats.tp_packets++; |
@@ -632,20 +678,41 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct packe | |||
632 | status &= ~TP_STATUS_LOSING; | 678 | status &= ~TP_STATUS_LOSING; |
633 | spin_unlock(&sk->sk_receive_queue.lock); | 679 | spin_unlock(&sk->sk_receive_queue.lock); |
634 | 680 | ||
635 | skb_copy_bits(skb, 0, (u8*)h + macoff, snaplen); | 681 | skb_copy_bits(skb, 0, h.raw + macoff, snaplen); |
636 | 682 | ||
637 | h->tp_len = skb->len; | 683 | switch (po->tp_version) { |
638 | h->tp_snaplen = snaplen; | 684 | case TPACKET_V1: |
639 | h->tp_mac = macoff; | 685 | h.h1->tp_len = skb->len; |
640 | h->tp_net = netoff; | 686 | h.h1->tp_snaplen = snaplen; |
641 | if (skb->tstamp.tv64) | 687 | h.h1->tp_mac = macoff; |
642 | tv = ktime_to_timeval(skb->tstamp); | 688 | h.h1->tp_net = netoff; |
643 | else | 689 | if (skb->tstamp.tv64) |
644 | do_gettimeofday(&tv); | 690 | tv = ktime_to_timeval(skb->tstamp); |
645 | h->tp_sec = tv.tv_sec; | 691 | else |
646 | h->tp_usec = tv.tv_usec; | 692 | do_gettimeofday(&tv); |
693 | h.h1->tp_sec = tv.tv_sec; | ||
694 | h.h1->tp_usec = tv.tv_usec; | ||
695 | hdrlen = sizeof(*h.h1); | ||
696 | break; | ||
697 | case TPACKET_V2: | ||
698 | h.h2->tp_len = skb->len; | ||
699 | h.h2->tp_snaplen = snaplen; | ||
700 | h.h2->tp_mac = macoff; | ||
701 | h.h2->tp_net = netoff; | ||
702 | if (skb->tstamp.tv64) | ||
703 | ts = ktime_to_timespec(skb->tstamp); | ||
704 | else | ||
705 | getnstimeofday(&ts); | ||
706 | h.h2->tp_sec = ts.tv_sec; | ||
707 | h.h2->tp_nsec = ts.tv_nsec; | ||
708 | h.h2->tp_vlan_tci = skb->vlan_tci; | ||
709 | hdrlen = sizeof(*h.h2); | ||
710 | break; | ||
711 | default: | ||
712 | BUG(); | ||
713 | } | ||
647 | 714 | ||
648 | sll = (struct sockaddr_ll*)((u8*)h + TPACKET_ALIGN(sizeof(*h))); | 715 | sll = h.raw + TPACKET_ALIGN(hdrlen); |
649 | sll->sll_halen = dev_parse_header(skb, sll->sll_addr); | 716 | sll->sll_halen = dev_parse_header(skb, sll->sll_addr); |
650 | sll->sll_family = AF_PACKET; | 717 | sll->sll_family = AF_PACKET; |
651 | sll->sll_hatype = dev->type; | 718 | sll->sll_hatype = dev->type; |
@@ -656,14 +723,14 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct packe | |||
656 | else | 723 | else |
657 | sll->sll_ifindex = dev->ifindex; | 724 | sll->sll_ifindex = dev->ifindex; |
658 | 725 | ||
659 | h->tp_status = status; | 726 | __packet_set_status(po, h.raw, status); |
660 | smp_mb(); | 727 | smp_mb(); |
661 | 728 | ||
662 | { | 729 | { |
663 | struct page *p_start, *p_end; | 730 | struct page *p_start, *p_end; |
664 | u8 *h_end = (u8 *)h + macoff + snaplen - 1; | 731 | u8 *h_end = h.raw + macoff + snaplen - 1; |
665 | 732 | ||
666 | p_start = virt_to_page(h); | 733 | p_start = virt_to_page(h.raw); |
667 | p_end = virt_to_page(h_end); | 734 | p_end = virt_to_page(h_end); |
668 | while (p_start <= p_end) { | 735 | while (p_start <= p_end) { |
669 | flush_dcache_page(p_start); | 736 | flush_dcache_page(p_start); |
@@ -1109,6 +1176,7 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
1109 | aux.tp_snaplen = skb->len; | 1176 | aux.tp_snaplen = skb->len; |
1110 | aux.tp_mac = 0; | 1177 | aux.tp_mac = 0; |
1111 | aux.tp_net = skb_network_offset(skb); | 1178 | aux.tp_net = skb_network_offset(skb); |
1179 | aux.tp_vlan_tci = skb->vlan_tci; | ||
1112 | 1180 | ||
1113 | put_cmsg(msg, SOL_PACKET, PACKET_AUXDATA, sizeof(aux), &aux); | 1181 | put_cmsg(msg, SOL_PACKET, PACKET_AUXDATA, sizeof(aux), &aux); |
1114 | } | 1182 | } |
@@ -1175,7 +1243,8 @@ static int packet_getname(struct socket *sock, struct sockaddr *uaddr, | |||
1175 | return 0; | 1243 | return 0; |
1176 | } | 1244 | } |
1177 | 1245 | ||
1178 | static void packet_dev_mc(struct net_device *dev, struct packet_mclist *i, int what) | 1246 | static int packet_dev_mc(struct net_device *dev, struct packet_mclist *i, |
1247 | int what) | ||
1179 | { | 1248 | { |
1180 | switch (i->type) { | 1249 | switch (i->type) { |
1181 | case PACKET_MR_MULTICAST: | 1250 | case PACKET_MR_MULTICAST: |
@@ -1185,13 +1254,14 @@ static void packet_dev_mc(struct net_device *dev, struct packet_mclist *i, int w | |||
1185 | dev_mc_delete(dev, i->addr, i->alen, 0); | 1254 | dev_mc_delete(dev, i->addr, i->alen, 0); |
1186 | break; | 1255 | break; |
1187 | case PACKET_MR_PROMISC: | 1256 | case PACKET_MR_PROMISC: |
1188 | dev_set_promiscuity(dev, what); | 1257 | return dev_set_promiscuity(dev, what); |
1189 | break; | 1258 | break; |
1190 | case PACKET_MR_ALLMULTI: | 1259 | case PACKET_MR_ALLMULTI: |
1191 | dev_set_allmulti(dev, what); | 1260 | return dev_set_allmulti(dev, what); |
1192 | break; | 1261 | break; |
1193 | default:; | 1262 | default:; |
1194 | } | 1263 | } |
1264 | return 0; | ||
1195 | } | 1265 | } |
1196 | 1266 | ||
1197 | static void packet_dev_mclist(struct net_device *dev, struct packet_mclist *i, int what) | 1267 | static void packet_dev_mclist(struct net_device *dev, struct packet_mclist *i, int what) |
@@ -1245,7 +1315,11 @@ static int packet_mc_add(struct sock *sk, struct packet_mreq_max *mreq) | |||
1245 | i->count = 1; | 1315 | i->count = 1; |
1246 | i->next = po->mclist; | 1316 | i->next = po->mclist; |
1247 | po->mclist = i; | 1317 | po->mclist = i; |
1248 | packet_dev_mc(dev, i, +1); | 1318 | err = packet_dev_mc(dev, i, 1); |
1319 | if (err) { | ||
1320 | po->mclist = i->next; | ||
1321 | kfree(i); | ||
1322 | } | ||
1249 | 1323 | ||
1250 | done: | 1324 | done: |
1251 | rtnl_unlock(); | 1325 | rtnl_unlock(); |
@@ -1358,6 +1432,38 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv | |||
1358 | pkt_sk(sk)->copy_thresh = val; | 1432 | pkt_sk(sk)->copy_thresh = val; |
1359 | return 0; | 1433 | return 0; |
1360 | } | 1434 | } |
1435 | case PACKET_VERSION: | ||
1436 | { | ||
1437 | int val; | ||
1438 | |||
1439 | if (optlen != sizeof(val)) | ||
1440 | return -EINVAL; | ||
1441 | if (po->pg_vec) | ||
1442 | return -EBUSY; | ||
1443 | if (copy_from_user(&val, optval, sizeof(val))) | ||
1444 | return -EFAULT; | ||
1445 | switch (val) { | ||
1446 | case TPACKET_V1: | ||
1447 | case TPACKET_V2: | ||
1448 | po->tp_version = val; | ||
1449 | return 0; | ||
1450 | default: | ||
1451 | return -EINVAL; | ||
1452 | } | ||
1453 | } | ||
1454 | case PACKET_RESERVE: | ||
1455 | { | ||
1456 | unsigned int val; | ||
1457 | |||
1458 | if (optlen != sizeof(val)) | ||
1459 | return -EINVAL; | ||
1460 | if (po->pg_vec) | ||
1461 | return -EBUSY; | ||
1462 | if (copy_from_user(&val, optval, sizeof(val))) | ||
1463 | return -EFAULT; | ||
1464 | po->tp_reserve = val; | ||
1465 | return 0; | ||
1466 | } | ||
1361 | #endif | 1467 | #endif |
1362 | case PACKET_AUXDATA: | 1468 | case PACKET_AUXDATA: |
1363 | { | 1469 | { |
@@ -1433,6 +1539,37 @@ static int packet_getsockopt(struct socket *sock, int level, int optname, | |||
1433 | 1539 | ||
1434 | data = &val; | 1540 | data = &val; |
1435 | break; | 1541 | break; |
1542 | #ifdef CONFIG_PACKET_MMAP | ||
1543 | case PACKET_VERSION: | ||
1544 | if (len > sizeof(int)) | ||
1545 | len = sizeof(int); | ||
1546 | val = po->tp_version; | ||
1547 | data = &val; | ||
1548 | break; | ||
1549 | case PACKET_HDRLEN: | ||
1550 | if (len > sizeof(int)) | ||
1551 | len = sizeof(int); | ||
1552 | if (copy_from_user(&val, optval, len)) | ||
1553 | return -EFAULT; | ||
1554 | switch (val) { | ||
1555 | case TPACKET_V1: | ||
1556 | val = sizeof(struct tpacket_hdr); | ||
1557 | break; | ||
1558 | case TPACKET_V2: | ||
1559 | val = sizeof(struct tpacket2_hdr); | ||
1560 | break; | ||
1561 | default: | ||
1562 | return -EINVAL; | ||
1563 | } | ||
1564 | data = &val; | ||
1565 | break; | ||
1566 | case PACKET_RESERVE: | ||
1567 | if (len > sizeof(unsigned int)) | ||
1568 | len = sizeof(unsigned int); | ||
1569 | val = po->tp_reserve; | ||
1570 | data = &val; | ||
1571 | break; | ||
1572 | #endif | ||
1436 | default: | 1573 | default: |
1437 | return -ENOPROTOOPT; | 1574 | return -ENOPROTOOPT; |
1438 | } | 1575 | } |
@@ -1540,7 +1677,7 @@ static int packet_ioctl(struct socket *sock, unsigned int cmd, | |||
1540 | case SIOCGIFDSTADDR: | 1677 | case SIOCGIFDSTADDR: |
1541 | case SIOCSIFDSTADDR: | 1678 | case SIOCSIFDSTADDR: |
1542 | case SIOCSIFFLAGS: | 1679 | case SIOCSIFFLAGS: |
1543 | if (sock_net(sk) != &init_net) | 1680 | if (!net_eq(sock_net(sk), &init_net)) |
1544 | return -ENOIOCTLCMD; | 1681 | return -ENOIOCTLCMD; |
1545 | return inet_dgram_ops.ioctl(sock, cmd, arg); | 1682 | return inet_dgram_ops.ioctl(sock, cmd, arg); |
1546 | #endif | 1683 | #endif |
@@ -1566,11 +1703,8 @@ static unsigned int packet_poll(struct file * file, struct socket *sock, | |||
1566 | spin_lock_bh(&sk->sk_receive_queue.lock); | 1703 | spin_lock_bh(&sk->sk_receive_queue.lock); |
1567 | if (po->pg_vec) { | 1704 | if (po->pg_vec) { |
1568 | unsigned last = po->head ? po->head-1 : po->frame_max; | 1705 | unsigned last = po->head ? po->head-1 : po->frame_max; |
1569 | struct tpacket_hdr *h; | ||
1570 | |||
1571 | h = packet_lookup_frame(po, last); | ||
1572 | 1706 | ||
1573 | if (h->tp_status) | 1707 | if (packet_lookup_frame(po, last, TP_STATUS_USER)) |
1574 | mask |= POLLIN | POLLRDNORM; | 1708 | mask |= POLLIN | POLLRDNORM; |
1575 | } | 1709 | } |
1576 | spin_unlock_bh(&sk->sk_receive_queue.lock); | 1710 | spin_unlock_bh(&sk->sk_receive_queue.lock); |
@@ -1665,11 +1799,21 @@ static int packet_set_ring(struct sock *sk, struct tpacket_req *req, int closing | |||
1665 | if (unlikely(po->pg_vec)) | 1799 | if (unlikely(po->pg_vec)) |
1666 | return -EBUSY; | 1800 | return -EBUSY; |
1667 | 1801 | ||
1802 | switch (po->tp_version) { | ||
1803 | case TPACKET_V1: | ||
1804 | po->tp_hdrlen = TPACKET_HDRLEN; | ||
1805 | break; | ||
1806 | case TPACKET_V2: | ||
1807 | po->tp_hdrlen = TPACKET2_HDRLEN; | ||
1808 | break; | ||
1809 | } | ||
1810 | |||
1668 | if (unlikely((int)req->tp_block_size <= 0)) | 1811 | if (unlikely((int)req->tp_block_size <= 0)) |
1669 | return -EINVAL; | 1812 | return -EINVAL; |
1670 | if (unlikely(req->tp_block_size & (PAGE_SIZE - 1))) | 1813 | if (unlikely(req->tp_block_size & (PAGE_SIZE - 1))) |
1671 | return -EINVAL; | 1814 | return -EINVAL; |
1672 | if (unlikely(req->tp_frame_size < TPACKET_HDRLEN)) | 1815 | if (unlikely(req->tp_frame_size < po->tp_hdrlen + |
1816 | po->tp_reserve)) | ||
1673 | return -EINVAL; | 1817 | return -EINVAL; |
1674 | if (unlikely(req->tp_frame_size & (TPACKET_ALIGNMENT - 1))) | 1818 | if (unlikely(req->tp_frame_size & (TPACKET_ALIGNMENT - 1))) |
1675 | return -EINVAL; | 1819 | return -EINVAL; |
@@ -1688,13 +1832,11 @@ static int packet_set_ring(struct sock *sk, struct tpacket_req *req, int closing | |||
1688 | goto out; | 1832 | goto out; |
1689 | 1833 | ||
1690 | for (i = 0; i < req->tp_block_nr; i++) { | 1834 | for (i = 0; i < req->tp_block_nr; i++) { |
1691 | char *ptr = pg_vec[i]; | 1835 | void *ptr = pg_vec[i]; |
1692 | struct tpacket_hdr *header; | ||
1693 | int k; | 1836 | int k; |
1694 | 1837 | ||
1695 | for (k = 0; k < po->frames_per_block; k++) { | 1838 | for (k = 0; k < po->frames_per_block; k++) { |
1696 | header = (struct tpacket_hdr *) ptr; | 1839 | __packet_set_status(po, ptr, TP_STATUS_KERNEL); |
1697 | header->tp_status = TP_STATUS_KERNEL; | ||
1698 | ptr += req->tp_frame_size; | 1840 | ptr += req->tp_frame_size; |
1699 | } | 1841 | } |
1700 | } | 1842 | } |