diff options
Diffstat (limited to 'net/packet/af_packet.c')
-rw-r--r-- | net/packet/af_packet.c | 94 |
1 files changed, 62 insertions, 32 deletions
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 28d47e8f2873..02e401cd683f 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c | |||
@@ -114,22 +114,22 @@ On receive: | |||
114 | ----------- | 114 | ----------- |
115 | 115 | ||
116 | Incoming, dev->hard_header!=NULL | 116 | Incoming, dev->hard_header!=NULL |
117 | mac.raw -> ll header | 117 | mac_header -> ll header |
118 | data -> data | 118 | data -> data |
119 | 119 | ||
120 | Outgoing, dev->hard_header!=NULL | 120 | Outgoing, dev->hard_header!=NULL |
121 | mac.raw -> ll header | 121 | mac_header -> ll header |
122 | data -> ll header | 122 | data -> ll header |
123 | 123 | ||
124 | Incoming, dev->hard_header==NULL | 124 | Incoming, dev->hard_header==NULL |
125 | mac.raw -> UNKNOWN position. It is very likely, that it points to ll header. | 125 | mac_header -> UNKNOWN position. It is very likely, that it points to ll |
126 | PPP makes it, that is wrong, because introduce assymetry | 126 | header. PPP makes it, that is wrong, because introduce |
127 | between rx and tx paths. | 127 | assymetry between rx and tx paths. |
128 | data -> data | 128 | data -> data |
129 | 129 | ||
130 | Outgoing, dev->hard_header==NULL | 130 | Outgoing, dev->hard_header==NULL |
131 | mac.raw -> data. ll header is still not built! | 131 | mac_header -> data. ll header is still not built! |
132 | data -> data | 132 | data -> data |
133 | 133 | ||
134 | Resume | 134 | Resume |
135 | If dev->hard_header==NULL we are unlikely to restore sensible ll header. | 135 | If dev->hard_header==NULL we are unlikely to restore sensible ll header. |
@@ -139,12 +139,12 @@ On transmit: | |||
139 | ------------ | 139 | ------------ |
140 | 140 | ||
141 | dev->hard_header != NULL | 141 | dev->hard_header != NULL |
142 | mac.raw -> ll header | 142 | mac_header -> ll header |
143 | data -> ll header | 143 | data -> ll header |
144 | 144 | ||
145 | dev->hard_header == NULL (ll header is added by device, we cannot control it) | 145 | dev->hard_header == NULL (ll header is added by device, we cannot control it) |
146 | mac.raw -> data | 146 | mac_header -> data |
147 | data -> data | 147 | data -> data |
148 | 148 | ||
149 | We should set nh.raw on output to correct posistion, | 149 | We should set nh.raw on output to correct posistion, |
150 | packet classifier depends on it. | 150 | packet classifier depends on it. |
@@ -201,7 +201,8 @@ struct packet_sock { | |||
201 | struct packet_type prot_hook; | 201 | struct packet_type prot_hook; |
202 | spinlock_t bind_lock; | 202 | spinlock_t bind_lock; |
203 | unsigned int running:1, /* prot_hook is attached*/ | 203 | unsigned int running:1, /* prot_hook is attached*/ |
204 | auxdata:1; | 204 | auxdata:1, |
205 | origdev:1; | ||
205 | int ifindex; /* bound device */ | 206 | int ifindex; /* bound device */ |
206 | __be16 num; | 207 | __be16 num; |
207 | #ifdef CONFIG_PACKET_MULTICAST | 208 | #ifdef CONFIG_PACKET_MULTICAST |
@@ -284,7 +285,7 @@ static int packet_rcv_spkt(struct sk_buff *skb, struct net_device *dev, struct | |||
284 | * Incoming packets have ll header pulled, | 285 | * Incoming packets have ll header pulled, |
285 | * push it back. | 286 | * push it back. |
286 | * | 287 | * |
287 | * For outgoing ones skb->data == skb->mac.raw | 288 | * For outgoing ones skb->data == skb_mac_header(skb) |
288 | * so that this procedure is noop. | 289 | * so that this procedure is noop. |
289 | */ | 290 | */ |
290 | 291 | ||
@@ -303,7 +304,7 @@ static int packet_rcv_spkt(struct sk_buff *skb, struct net_device *dev, struct | |||
303 | 304 | ||
304 | spkt = &PACKET_SKB_CB(skb)->sa.pkt; | 305 | spkt = &PACKET_SKB_CB(skb)->sa.pkt; |
305 | 306 | ||
306 | skb_push(skb, skb->data-skb->mac.raw); | 307 | skb_push(skb, skb->data - skb_mac_header(skb)); |
307 | 308 | ||
308 | /* | 309 | /* |
309 | * The SOCK_PACKET socket receives _all_ frames. | 310 | * The SOCK_PACKET socket receives _all_ frames. |
@@ -401,14 +402,14 @@ static int packet_sendmsg_spkt(struct kiocb *iocb, struct socket *sock, | |||
401 | * notable one here. This should really be fixed at the driver level. | 402 | * notable one here. This should really be fixed at the driver level. |
402 | */ | 403 | */ |
403 | skb_reserve(skb, LL_RESERVED_SPACE(dev)); | 404 | skb_reserve(skb, LL_RESERVED_SPACE(dev)); |
404 | skb->nh.raw = skb->data; | 405 | skb_reset_network_header(skb); |
405 | 406 | ||
406 | /* Try to align data part correctly */ | 407 | /* Try to align data part correctly */ |
407 | if (dev->hard_header) { | 408 | if (dev->hard_header) { |
408 | skb->data -= dev->hard_header_len; | 409 | skb->data -= dev->hard_header_len; |
409 | skb->tail -= dev->hard_header_len; | 410 | skb->tail -= dev->hard_header_len; |
410 | if (len < dev->hard_header_len) | 411 | if (len < dev->hard_header_len) |
411 | skb->nh.raw = skb->data; | 412 | skb_reset_network_header(skb); |
412 | } | 413 | } |
413 | 414 | ||
414 | /* Returns -EFAULT on error */ | 415 | /* Returns -EFAULT on error */ |
@@ -488,10 +489,10 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet | |||
488 | never delivered to user. | 489 | never delivered to user. |
489 | */ | 490 | */ |
490 | if (sk->sk_type != SOCK_DGRAM) | 491 | if (sk->sk_type != SOCK_DGRAM) |
491 | skb_push(skb, skb->data - skb->mac.raw); | 492 | skb_push(skb, skb->data - skb_mac_header(skb)); |
492 | else if (skb->pkt_type == PACKET_OUTGOING) { | 493 | else if (skb->pkt_type == PACKET_OUTGOING) { |
493 | /* Special case: outgoing packets have ll header at head */ | 494 | /* Special case: outgoing packets have ll header at head */ |
494 | skb_pull(skb, skb->nh.raw - skb->data); | 495 | skb_pull(skb, skb_network_offset(skb)); |
495 | } | 496 | } |
496 | } | 497 | } |
497 | 498 | ||
@@ -528,7 +529,10 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet | |||
528 | sll->sll_hatype = dev->type; | 529 | sll->sll_hatype = dev->type; |
529 | sll->sll_protocol = skb->protocol; | 530 | sll->sll_protocol = skb->protocol; |
530 | sll->sll_pkttype = skb->pkt_type; | 531 | sll->sll_pkttype = skb->pkt_type; |
531 | sll->sll_ifindex = dev->ifindex; | 532 | if (unlikely(po->origdev) && skb->pkt_type == PACKET_HOST) |
533 | sll->sll_ifindex = orig_dev->ifindex; | ||
534 | else | ||
535 | sll->sll_ifindex = dev->ifindex; | ||
532 | sll->sll_halen = 0; | 536 | sll->sll_halen = 0; |
533 | 537 | ||
534 | if (dev->hard_header_parse) | 538 | if (dev->hard_header_parse) |
@@ -582,6 +586,7 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct packe | |||
582 | unsigned long status = TP_STATUS_LOSING|TP_STATUS_USER; | 586 | unsigned long status = TP_STATUS_LOSING|TP_STATUS_USER; |
583 | unsigned short macoff, netoff; | 587 | unsigned short macoff, netoff; |
584 | struct sk_buff *copy_skb = NULL; | 588 | struct sk_buff *copy_skb = NULL; |
589 | struct timeval tv; | ||
585 | 590 | ||
586 | if (skb->pkt_type == PACKET_LOOPBACK) | 591 | if (skb->pkt_type == PACKET_LOOPBACK) |
587 | goto drop; | 592 | goto drop; |
@@ -591,10 +596,10 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct packe | |||
591 | 596 | ||
592 | if (dev->hard_header) { | 597 | if (dev->hard_header) { |
593 | if (sk->sk_type != SOCK_DGRAM) | 598 | if (sk->sk_type != SOCK_DGRAM) |
594 | skb_push(skb, skb->data - skb->mac.raw); | 599 | skb_push(skb, skb->data - skb_mac_header(skb)); |
595 | else if (skb->pkt_type == PACKET_OUTGOING) { | 600 | else if (skb->pkt_type == PACKET_OUTGOING) { |
596 | /* Special case: outgoing packets have ll header at head */ | 601 | /* Special case: outgoing packets have ll header at head */ |
597 | skb_pull(skb, skb->nh.raw - skb->data); | 602 | skb_pull(skb, skb_network_offset(skb)); |
598 | } | 603 | } |
599 | } | 604 | } |
600 | 605 | ||
@@ -612,7 +617,7 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct packe | |||
612 | if (sk->sk_type == SOCK_DGRAM) { | 617 | if (sk->sk_type == SOCK_DGRAM) { |
613 | macoff = netoff = TPACKET_ALIGN(TPACKET_HDRLEN) + 16; | 618 | macoff = netoff = TPACKET_ALIGN(TPACKET_HDRLEN) + 16; |
614 | } else { | 619 | } else { |
615 | unsigned maclen = skb->nh.raw - skb->data; | 620 | unsigned maclen = skb_network_offset(skb); |
616 | netoff = TPACKET_ALIGN(TPACKET_HDRLEN + (maclen < 16 ? 16 : maclen)); | 621 | netoff = TPACKET_ALIGN(TPACKET_HDRLEN + (maclen < 16 ? 16 : maclen)); |
617 | macoff = netoff - maclen; | 622 | macoff = netoff - maclen; |
618 | } | 623 | } |
@@ -656,12 +661,13 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct packe | |||
656 | h->tp_snaplen = snaplen; | 661 | h->tp_snaplen = snaplen; |
657 | h->tp_mac = macoff; | 662 | h->tp_mac = macoff; |
658 | h->tp_net = netoff; | 663 | h->tp_net = netoff; |
659 | if (skb->tstamp.off_sec == 0) { | 664 | if (skb->tstamp.tv64 == 0) { |
660 | __net_timestamp(skb); | 665 | __net_timestamp(skb); |
661 | sock_enable_timestamp(sk); | 666 | sock_enable_timestamp(sk); |
662 | } | 667 | } |
663 | h->tp_sec = skb->tstamp.off_sec; | 668 | tv = ktime_to_timeval(skb->tstamp); |
664 | h->tp_usec = skb->tstamp.off_usec; | 669 | h->tp_sec = tv.tv_sec; |
670 | h->tp_usec = tv.tv_usec; | ||
665 | 671 | ||
666 | sll = (struct sockaddr_ll*)((u8*)h + TPACKET_ALIGN(sizeof(*h))); | 672 | sll = (struct sockaddr_ll*)((u8*)h + TPACKET_ALIGN(sizeof(*h))); |
667 | sll->sll_halen = 0; | 673 | sll->sll_halen = 0; |
@@ -671,7 +677,10 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct packe | |||
671 | sll->sll_hatype = dev->type; | 677 | sll->sll_hatype = dev->type; |
672 | sll->sll_protocol = skb->protocol; | 678 | sll->sll_protocol = skb->protocol; |
673 | sll->sll_pkttype = skb->pkt_type; | 679 | sll->sll_pkttype = skb->pkt_type; |
674 | sll->sll_ifindex = dev->ifindex; | 680 | if (unlikely(po->origdev) && skb->pkt_type == PACKET_HOST) |
681 | sll->sll_ifindex = orig_dev->ifindex; | ||
682 | else | ||
683 | sll->sll_ifindex = dev->ifindex; | ||
675 | 684 | ||
676 | h->tp_status = status; | 685 | h->tp_status = status; |
677 | smp_mb(); | 686 | smp_mb(); |
@@ -766,14 +775,14 @@ static int packet_sendmsg(struct kiocb *iocb, struct socket *sock, | |||
766 | goto out_unlock; | 775 | goto out_unlock; |
767 | 776 | ||
768 | skb_reserve(skb, LL_RESERVED_SPACE(dev)); | 777 | skb_reserve(skb, LL_RESERVED_SPACE(dev)); |
769 | skb->nh.raw = skb->data; | 778 | skb_reset_network_header(skb); |
770 | 779 | ||
771 | if (dev->hard_header) { | 780 | if (dev->hard_header) { |
772 | int res; | 781 | int res; |
773 | err = -EINVAL; | 782 | err = -EINVAL; |
774 | res = dev->hard_header(skb, dev, ntohs(proto), addr, NULL, len); | 783 | res = dev->hard_header(skb, dev, ntohs(proto), addr, NULL, len); |
775 | if (sock->type != SOCK_DGRAM) { | 784 | if (sock->type != SOCK_DGRAM) { |
776 | skb->tail = skb->data; | 785 | skb_reset_tail_pointer(skb); |
777 | skb->len = 0; | 786 | skb->len = 0; |
778 | } else if (res < 0) | 787 | } else if (res < 0) |
779 | goto out_free; | 788 | goto out_free; |
@@ -1143,7 +1152,7 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
1143 | aux.tp_len = PACKET_SKB_CB(skb)->origlen; | 1152 | aux.tp_len = PACKET_SKB_CB(skb)->origlen; |
1144 | aux.tp_snaplen = skb->len; | 1153 | aux.tp_snaplen = skb->len; |
1145 | aux.tp_mac = 0; | 1154 | aux.tp_mac = 0; |
1146 | aux.tp_net = skb->nh.raw - skb->data; | 1155 | aux.tp_net = skb_network_offset(skb); |
1147 | 1156 | ||
1148 | put_cmsg(msg, SOL_PACKET, PACKET_AUXDATA, sizeof(aux), &aux); | 1157 | put_cmsg(msg, SOL_PACKET, PACKET_AUXDATA, sizeof(aux), &aux); |
1149 | } | 1158 | } |
@@ -1411,6 +1420,18 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv | |||
1411 | po->auxdata = !!val; | 1420 | po->auxdata = !!val; |
1412 | return 0; | 1421 | return 0; |
1413 | } | 1422 | } |
1423 | case PACKET_ORIGDEV: | ||
1424 | { | ||
1425 | int val; | ||
1426 | |||
1427 | if (optlen < sizeof(val)) | ||
1428 | return -EINVAL; | ||
1429 | if (copy_from_user(&val, optval, sizeof(val))) | ||
1430 | return -EFAULT; | ||
1431 | |||
1432 | po->origdev = !!val; | ||
1433 | return 0; | ||
1434 | } | ||
1414 | default: | 1435 | default: |
1415 | return -ENOPROTOOPT; | 1436 | return -ENOPROTOOPT; |
1416 | } | 1437 | } |
@@ -1454,6 +1475,13 @@ static int packet_getsockopt(struct socket *sock, int level, int optname, | |||
1454 | 1475 | ||
1455 | data = &val; | 1476 | data = &val; |
1456 | break; | 1477 | break; |
1478 | case PACKET_ORIGDEV: | ||
1479 | if (len > sizeof(int)) | ||
1480 | len = sizeof(int); | ||
1481 | val = po->origdev; | ||
1482 | |||
1483 | data = &val; | ||
1484 | break; | ||
1457 | default: | 1485 | default: |
1458 | return -ENOPROTOOPT; | 1486 | return -ENOPROTOOPT; |
1459 | } | 1487 | } |
@@ -1543,6 +1571,8 @@ static int packet_ioctl(struct socket *sock, unsigned int cmd, | |||
1543 | } | 1571 | } |
1544 | case SIOCGSTAMP: | 1572 | case SIOCGSTAMP: |
1545 | return sock_get_timestamp(sk, (struct timeval __user *)arg); | 1573 | return sock_get_timestamp(sk, (struct timeval __user *)arg); |
1574 | case SIOCGSTAMPNS: | ||
1575 | return sock_get_timestampns(sk, (struct timespec __user *)arg); | ||
1546 | 1576 | ||
1547 | #ifdef CONFIG_INET | 1577 | #ifdef CONFIG_INET |
1548 | case SIOCADDRT: | 1578 | case SIOCADDRT: |