Kernel version: 2.6.34
ICMP module is relatively simple, you should pay attention to the ICMP rate limiting policy, to the IP layer transfer data Ip_append_data () and Ip_push_pending_frames ().
In Net/ipv4/af_inet.c, the Inet_init () registers the ICMP protocol, and it can be seen from here that the ICMP module is bound to the IP module. Inet_add_protocol () adds Icmp_protocol to the global volume Inet_protos.
if (Inet_add_protocol (&icmp_protocol, ipproto_icmp) < 0)
PRINTK (kern_crit "Inet_init:cannot add ICMP Protocol\n ");
The ICMP_PROTOCOL definition is as follows:
static const struct Net_protocol Icmp_protocol = {
. Handler = ICMP_RCV,
. No_policy = 1,< C6/>.NETNS_OK = 1,
};
In addition to registering the ICMP protocol, initialize the ICMP module, which is completed by Icmp_init ().
if (Icmp_init () < 0)
panic ("Failed to create the ICMP control socket.\n");
The Icmp_init () function is simple, register_pernet_subsys (&icmp_sk_ops), while registering the ICMP network subsystem calls Icmp_sk_ops.init (that is, icmp_sk_ init function) To complete its initialization, see the Icmp_sk_init () function in the following detail.
First, the net is to match the number of CPUs (Nr_cpu_ids) a struct sock structure space, where the net is the global network name, is generally init_inet.
Net->ipv4.icmp_sk = Kzalloc (nr_cpu_ids * sizeof (struct sock *), Gfp_kernel);
Each CPU I, its sock structure is located in net icmp_sk[i]. On each CPU I, initialize the icmp_sk[i that has just been allocated:
-The first step, Inet_ctl_sock_create () creates SK and assigns it to icmp_sk[i in net->ipv4.icmp_sk[i] = sk.
-Step two: ICMP send buffer size sk_sndbuf set to 128K
FOR_EACH_POSSIBLE_CPU (i) {
struct sock *sk;
Err = Inet_ctl_sock_create (&sk, pf_inet,
sock_raw, ipproto_icmp, net);
if (Err < 0)
Goto fail;
Net->ipv4.icmp_sk[i] = SK;
Sk->sk_sndbuf =
(2 * (1024) + sizeof (struct sk_buff)));
Sock_set_flag (SK, sock_use_write_queue);
Inet_sk (SK)->pmtudisc = Ip_pmtudisc_dont;
}
Ignoring the ICMP echo message sent to the broadcast address, ignoring the wrong response message sent to the broadcast address;
net-
>ipv4.sysctl_icmp_echo_ignore_all = 0;
net->ipv4.sysctl_icmp_echo_ignore_broadcasts = 1;
net->ipv4.sysctl_icmp_ignore_bogus_error_responses = 1;
Set the ICMP processing rate, where the ratelimit and Ratemask parameters are used specifically for subsequent speed limit processing.
Net->ipv4.sysctl_icmp_ratelimit = 1 * HZ;
Net->ipv4.sysctl_icmp_ratemask = 0x1818;
net->ipv4.sysctl_icmp_errors_use_inbound_ifaddr = 0;
After the initialization is completed, or from the receiving of ICMP, ICMP_RCV completes the processing of ICMP packets.
Gets the ICMP header, at which point Skb->transport_header is set in the IP module Processing ip_local_deliver_finish () to point to the ICMP header location.
icmph = ICMP_HDR (SKB);
The type of ICMP is assigned to a different handler function.
Icmp_pointers[icmph->type].handler (SKB);
Icmp_pointers is the global amount defined in Icmp.c, in part as follows:
static const struct Icmp_control icmp_pointers[nr_icmp_types + 1] = {
[icmp_echoreply] = {
. Handler = Icmp_discard ,
},
[1] = {
. Handler = Icmp_discard,
. Error = 1,
}, ...
}
For example, for the received ICMP message type 0 or 1 (response or Destination unreachable), the protocol stack to do is discard it –icmp_discard (). Examples of ICMP echo and ICMP timestamp are described below.
Received ICMP echo message execution Icmp_echo ()
Icmp_param is a reply-time message that directly copies the Echo's ICMP header Icmp_hdr (SKB), only changing the header's type = Icmp_echo_reply, and then calling icmp_reply () processing the send.
struct ICMP_BXM icmp_param;
icmp_param.data.icmph = *ICMP_HDR (SKB);
Icmp_param.data.icmph.type = icmp_echoreply;
ICMP_PARAM.SKB = SKB;
Icmp_param.offset = 0;
Icmp_param.data_len = skb->len;
Icmp_param.head_len = sizeof (struct ICMPHDR);
Icmp_reply (&icmp_param, SKB);
Execute icmp_timestamp after receiving ICMP timestamp message ()