diff options
author | Wei Yongjun <yjwei@cn.fujitsu.com> | 2008-11-02 11:11:01 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-11-03 02:52:45 -0500 |
commit | f26ba1751145edbf52b2c89a40e389f2fbdfc1af (patch) | |
tree | abb81ca460a07a99852f9c579d4c3324faacc801 /net | |
parent | 70d9d15833864e7120c3ffcfdbd6fa61f5f9726a (diff) |
udp: Fix the SNMP counter of UDP_MIB_INDATAGRAMS
If UDP echo is sent to xinetd/echo-dgram, the UDP reply will be received
at the sender. But the SNMP counter of UDP_MIB_INDATAGRAMS will be not
increased, UDP6_MIB_INDATAGRAMS will be increased instead.
Endpoint A Endpoint B
UDP Echo request ----------->
(IPv4, Dst port=7)
<---------- UDP Echo Reply
(IPv4, Src port=7)
This bug is come from this patch cb75994ec311b2cd50e5205efdcc0696abd6675d.
It do counter UDP[6]_MIB_INDATAGRAMS until udp[v6]_recvmsg. Because
xinetd used IPv6 socket to receive UDP messages, thus, when received
UDP packet, the UDP6_MIB_INDATAGRAMS will be increased in function
udpv6_recvmsg() even if the packet is a IPv4 UDP packet.
This patch fixed the problem.
Signed-off-by: Wei Yongjun <yjwei@cn.fujitsu.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv6/udp.c | 18 |
1 files changed, 13 insertions, 5 deletions
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 71e259e866a1..18696af106d6 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c | |||
@@ -138,6 +138,7 @@ int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk, | |||
138 | int peeked; | 138 | int peeked; |
139 | int err; | 139 | int err; |
140 | int is_udplite = IS_UDPLITE(sk); | 140 | int is_udplite = IS_UDPLITE(sk); |
141 | int is_udp4; | ||
141 | 142 | ||
142 | if (addr_len) | 143 | if (addr_len) |
143 | *addr_len=sizeof(struct sockaddr_in6); | 144 | *addr_len=sizeof(struct sockaddr_in6); |
@@ -158,6 +159,8 @@ try_again: | |||
158 | else if (copied < ulen) | 159 | else if (copied < ulen) |
159 | msg->msg_flags |= MSG_TRUNC; | 160 | msg->msg_flags |= MSG_TRUNC; |
160 | 161 | ||
162 | is_udp4 = (skb->protocol == htons(ETH_P_IP)); | ||
163 | |||
161 | /* | 164 | /* |
162 | * If checksum is needed at all, try to do it while copying the | 165 | * If checksum is needed at all, try to do it while copying the |
163 | * data. If the data is truncated, or if we only want a partial | 166 | * data. If the data is truncated, or if we only want a partial |
@@ -180,9 +183,14 @@ try_again: | |||
180 | if (err) | 183 | if (err) |
181 | goto out_free; | 184 | goto out_free; |
182 | 185 | ||
183 | if (!peeked) | 186 | if (!peeked) { |
184 | UDP6_INC_STATS_USER(sock_net(sk), | 187 | if (is_udp4) |
185 | UDP_MIB_INDATAGRAMS, is_udplite); | 188 | UDP_INC_STATS_USER(sock_net(sk), |
189 | UDP_MIB_INDATAGRAMS, is_udplite); | ||
190 | else | ||
191 | UDP6_INC_STATS_USER(sock_net(sk), | ||
192 | UDP_MIB_INDATAGRAMS, is_udplite); | ||
193 | } | ||
186 | 194 | ||
187 | sock_recv_timestamp(msg, sk, skb); | 195 | sock_recv_timestamp(msg, sk, skb); |
188 | 196 | ||
@@ -196,7 +204,7 @@ try_again: | |||
196 | sin6->sin6_flowinfo = 0; | 204 | sin6->sin6_flowinfo = 0; |
197 | sin6->sin6_scope_id = 0; | 205 | sin6->sin6_scope_id = 0; |
198 | 206 | ||
199 | if (skb->protocol == htons(ETH_P_IP)) | 207 | if (is_udp4) |
200 | ipv6_addr_set(&sin6->sin6_addr, 0, 0, | 208 | ipv6_addr_set(&sin6->sin6_addr, 0, 0, |
201 | htonl(0xffff), ip_hdr(skb)->saddr); | 209 | htonl(0xffff), ip_hdr(skb)->saddr); |
202 | else { | 210 | else { |
@@ -207,7 +215,7 @@ try_again: | |||
207 | } | 215 | } |
208 | 216 | ||
209 | } | 217 | } |
210 | if (skb->protocol == htons(ETH_P_IP)) { | 218 | if (is_udp4) { |
211 | if (inet->cmsg_flags) | 219 | if (inet->cmsg_flags) |
212 | ip_cmsg_recv(msg, skb); | 220 | ip_cmsg_recv(msg, skb); |
213 | } else { | 221 | } else { |