diff options
Diffstat (limited to 'net/ipv4/ip_sockglue.c')
| -rw-r--r-- | net/ipv4/ip_sockglue.c | 33 |
1 files changed, 23 insertions, 10 deletions
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 31d8c71986b4..5cd99271d3a6 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c | |||
| @@ -432,17 +432,32 @@ void ip_local_error(struct sock *sk, int err, __be32 daddr, __be16 port, u32 inf | |||
| 432 | kfree_skb(skb); | 432 | kfree_skb(skb); |
| 433 | } | 433 | } |
| 434 | 434 | ||
| 435 | static bool ipv4_pktinfo_prepare_errqueue(const struct sock *sk, | 435 | /* IPv4 supports cmsg on all imcp errors and some timestamps |
| 436 | const struct sk_buff *skb, | 436 | * |
| 437 | int ee_origin) | 437 | * Timestamp code paths do not initialize the fields expected by cmsg: |
| 438 | * the PKTINFO fields in skb->cb[]. Fill those in here. | ||
| 439 | */ | ||
| 440 | static bool ipv4_datagram_support_cmsg(const struct sock *sk, | ||
| 441 | struct sk_buff *skb, | ||
| 442 | int ee_origin) | ||
| 438 | { | 443 | { |
| 439 | struct in_pktinfo *info = PKTINFO_SKB_CB(skb); | 444 | struct in_pktinfo *info; |
| 445 | |||
| 446 | if (ee_origin == SO_EE_ORIGIN_ICMP) | ||
| 447 | return true; | ||
| 440 | 448 | ||
| 441 | if ((ee_origin != SO_EE_ORIGIN_TIMESTAMPING) || | 449 | if (ee_origin == SO_EE_ORIGIN_LOCAL) |
| 442 | (!(sk->sk_tsflags & SOF_TIMESTAMPING_OPT_CMSG)) || | 450 | return false; |
| 451 | |||
| 452 | /* Support IP_PKTINFO on tstamp packets if requested, to correlate | ||
| 453 | * timestamp with egress dev. Not possible for packets without dev | ||
| 454 | * or without payload (SOF_TIMESTAMPING_OPT_TSONLY). | ||
| 455 | */ | ||
| 456 | if ((!(sk->sk_tsflags & SOF_TIMESTAMPING_OPT_CMSG)) || | ||
| 443 | (!skb->dev)) | 457 | (!skb->dev)) |
| 444 | return false; | 458 | return false; |
| 445 | 459 | ||
| 460 | info = PKTINFO_SKB_CB(skb); | ||
| 446 | info->ipi_spec_dst.s_addr = ip_hdr(skb)->saddr; | 461 | info->ipi_spec_dst.s_addr = ip_hdr(skb)->saddr; |
| 447 | info->ipi_ifindex = skb->dev->ifindex; | 462 | info->ipi_ifindex = skb->dev->ifindex; |
| 448 | return true; | 463 | return true; |
| @@ -483,7 +498,7 @@ int ip_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len) | |||
| 483 | 498 | ||
| 484 | serr = SKB_EXT_ERR(skb); | 499 | serr = SKB_EXT_ERR(skb); |
| 485 | 500 | ||
| 486 | if (sin && skb->len) { | 501 | if (sin && serr->port) { |
| 487 | sin->sin_family = AF_INET; | 502 | sin->sin_family = AF_INET; |
| 488 | sin->sin_addr.s_addr = *(__be32 *)(skb_network_header(skb) + | 503 | sin->sin_addr.s_addr = *(__be32 *)(skb_network_header(skb) + |
| 489 | serr->addr_offset); | 504 | serr->addr_offset); |
| @@ -496,9 +511,7 @@ int ip_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len) | |||
| 496 | sin = &errhdr.offender; | 511 | sin = &errhdr.offender; |
| 497 | memset(sin, 0, sizeof(*sin)); | 512 | memset(sin, 0, sizeof(*sin)); |
| 498 | 513 | ||
| 499 | if (skb->len && | 514 | if (ipv4_datagram_support_cmsg(sk, skb, serr->ee.ee_origin)) { |
| 500 | (serr->ee.ee_origin == SO_EE_ORIGIN_ICMP || | ||
| 501 | ipv4_pktinfo_prepare_errqueue(sk, skb, serr->ee.ee_origin))) { | ||
| 502 | sin->sin_family = AF_INET; | 515 | sin->sin_family = AF_INET; |
| 503 | sin->sin_addr.s_addr = ip_hdr(skb)->saddr; | 516 | sin->sin_addr.s_addr = ip_hdr(skb)->saddr; |
| 504 | if (inet_sk(sk)->cmsg_flags) | 517 | if (inet_sk(sk)->cmsg_flags) |
