📄 icmp.c
字号:
msg.icmph.icmp6_cksum = 0; msg.icmph.icmp6_pointer = htonl(info); msg.skb = skb; msg.offset = skb->nh.raw - skb->data; msg.csum = 0; msg.daddr = &hdr->saddr; len = skb->len - msg.offset + sizeof(struct icmp6hdr); len = min_t(unsigned int, len, IPV6_MIN_MTU - sizeof(struct ipv6hdr)); if (len < 0) { if (net_ratelimit()) printk(KERN_DEBUG "icmp: len problem\n"); goto out; } msg.len = len; ip6_build_xmit(sk, icmpv6_getfrag, &msg, &fl, len, NULL, -1, MSG_DONTWAIT); if (type >= ICMPV6_DEST_UNREACH && type <= ICMPV6_PARAMPROB) (&(icmpv6_statistics[smp_processor_id()*2].Icmp6OutDestUnreachs))[type-1]++; ICMP6_INC_STATS_BH(Icmp6OutMsgs);out: icmpv6_xmit_unlock();}static void icmpv6_echo_reply(struct sk_buff *skb){ struct sock *sk = icmpv6_socket->sk; struct icmp6hdr *icmph = (struct icmp6hdr *) skb->h.raw; struct in6_addr *saddr; struct icmpv6_msg msg; struct flowi fl; saddr = &skb->nh.ipv6h->daddr; if (ipv6_addr_type(saddr) & IPV6_ADDR_MULTICAST) saddr = NULL; msg.icmph.icmp6_type = ICMPV6_ECHO_REPLY; msg.icmph.icmp6_code = 0; msg.icmph.icmp6_cksum = 0; msg.icmph.icmp6_identifier = icmph->icmp6_identifier; msg.icmph.icmp6_sequence = icmph->icmp6_sequence; msg.skb = skb; msg.offset = 0; msg.csum = 0; msg.len = skb->len + sizeof(struct icmp6hdr); msg.daddr = &skb->nh.ipv6h->saddr; fl.proto = IPPROTO_ICMPV6; fl.nl_u.ip6_u.daddr = msg.daddr; fl.nl_u.ip6_u.saddr = saddr; fl.oif = skb->dev->ifindex; fl.fl6_flowlabel = 0; fl.uli_u.icmpt.type = ICMPV6_ECHO_REPLY; fl.uli_u.icmpt.code = 0; if (icmpv6_xmit_lock_bh()) return; ip6_build_xmit(sk, icmpv6_getfrag, &msg, &fl, msg.len, NULL, -1, MSG_DONTWAIT); ICMP6_INC_STATS_BH(Icmp6OutEchoReplies); ICMP6_INC_STATS_BH(Icmp6OutMsgs); icmpv6_xmit_unlock_bh();}static void icmpv6_notify(struct sk_buff *skb, int type, int code, u32 info){ struct in6_addr *saddr, *daddr; struct inet6_protocol *ipprot; struct sock *sk; int inner_offset; int hash; u8 nexthdr; if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) return; nexthdr = ((struct ipv6hdr *)skb->data)->nexthdr; if (ipv6_ext_hdr(nexthdr)) { /* now skip over extension headers */ inner_offset = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &nexthdr, skb->len - sizeof(struct ipv6hdr)); if (inner_offset<0) return; } else { inner_offset = sizeof(struct ipv6hdr); } /* Checkin header including 8 bytes of inner protocol header. */ if (!pskb_may_pull(skb, inner_offset+8)) return; saddr = &skb->nh.ipv6h->saddr; daddr = &skb->nh.ipv6h->daddr; /* BUGGG_FUTURE: we should try to parse exthdrs in this packet. Without this we will not able f.e. to make source routed pmtu discovery. Corresponding argument (opt) to notifiers is already added. --ANK (980726) */ hash = nexthdr & (MAX_INET_PROTOS - 1); for (ipprot = (struct inet6_protocol *) inet6_protos[hash]; ipprot != NULL; ipprot=(struct inet6_protocol *)ipprot->next) { if (ipprot->protocol != nexthdr) continue; if (ipprot->err_handler) ipprot->err_handler(skb, NULL, type, code, inner_offset, info); } read_lock(&raw_v6_lock); if ((sk = raw_v6_htable[hash]) != NULL) { while((sk = __raw_v6_lookup(sk, nexthdr, daddr, saddr))) { rawv6_err(sk, skb, NULL, type, code, inner_offset, info); sk = sk->next; } } read_unlock(&raw_v6_lock);} /* * Handle icmp messages */int icmpv6_rcv(struct sk_buff *skb){ struct net_device *dev = skb->dev; struct in6_addr *saddr, *daddr; struct ipv6hdr *orig_hdr; struct icmp6hdr *hdr; int type; ICMP6_INC_STATS_BH(Icmp6InMsgs); saddr = &skb->nh.ipv6h->saddr; daddr = &skb->nh.ipv6h->daddr; /* Perform checksum. */ if (skb->ip_summed == CHECKSUM_HW) { skb->ip_summed = CHECKSUM_UNNECESSARY; if (csum_ipv6_magic(saddr, daddr, skb->len, IPPROTO_ICMPV6, skb->csum)) { if (net_ratelimit()) printk(KERN_DEBUG "ICMPv6 hw checksum failed\n"); skb->ip_summed = CHECKSUM_NONE; } } if (skb->ip_summed == CHECKSUM_NONE) { if (csum_ipv6_magic(saddr, daddr, skb->len, IPPROTO_ICMPV6, skb_checksum(skb, 0, skb->len, 0))) { if (net_ratelimit()) printk(KERN_DEBUG "ICMPv6 checksum failed [%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x > %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]\n", ntohs(saddr->in6_u.u6_addr16[0]), ntohs(saddr->in6_u.u6_addr16[1]), ntohs(saddr->in6_u.u6_addr16[2]), ntohs(saddr->in6_u.u6_addr16[3]), ntohs(saddr->in6_u.u6_addr16[4]), ntohs(saddr->in6_u.u6_addr16[5]), ntohs(saddr->in6_u.u6_addr16[6]), ntohs(saddr->in6_u.u6_addr16[7]), ntohs(daddr->in6_u.u6_addr16[0]), ntohs(daddr->in6_u.u6_addr16[1]), ntohs(daddr->in6_u.u6_addr16[2]), ntohs(daddr->in6_u.u6_addr16[3]), ntohs(daddr->in6_u.u6_addr16[4]), ntohs(daddr->in6_u.u6_addr16[5]), ntohs(daddr->in6_u.u6_addr16[6]), ntohs(daddr->in6_u.u6_addr16[7])); goto discard_it; } } if (!pskb_pull(skb, sizeof(struct icmp6hdr))) goto discard_it; hdr = (struct icmp6hdr *) skb->h.raw; type = hdr->icmp6_type; if (type >= ICMPV6_DEST_UNREACH && type <= ICMPV6_PARAMPROB) (&icmpv6_statistics[smp_processor_id()*2].Icmp6InDestUnreachs)[type-ICMPV6_DEST_UNREACH]++; else if (type >= ICMPV6_ECHO_REQUEST && type <= NDISC_REDIRECT) (&icmpv6_statistics[smp_processor_id()*2].Icmp6InEchos)[type-ICMPV6_ECHO_REQUEST]++; switch (type) { case ICMPV6_ECHO_REQUEST: icmpv6_echo_reply(skb); break; case ICMPV6_ECHO_REPLY: /* we coulnd't care less */ break; case ICMPV6_PKT_TOOBIG: /* BUGGG_FUTURE: if packet contains rthdr, we cannot update standard destination cache. Seems, only "advanced" destination cache will allow to solve this problem --ANK (980726) */ if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) goto discard_it; hdr = (struct icmp6hdr *) skb->h.raw; orig_hdr = (struct ipv6hdr *) (hdr + 1); rt6_pmtu_discovery(&orig_hdr->daddr, &orig_hdr->saddr, dev, ntohl(hdr->icmp6_mtu)); /* * Drop through to notify */ case ICMPV6_DEST_UNREACH: case ICMPV6_TIME_EXCEED: case ICMPV6_PARAMPROB: icmpv6_notify(skb, type, hdr->icmp6_code, hdr->icmp6_mtu); break; case NDISC_ROUTER_SOLICITATION: case NDISC_ROUTER_ADVERTISEMENT: case NDISC_NEIGHBOUR_SOLICITATION: case NDISC_NEIGHBOUR_ADVERTISEMENT: case NDISC_REDIRECT: if (skb_is_nonlinear(skb) && skb_linearize(skb, GFP_ATOMIC) != 0) { kfree_skb(skb); return 0; } ndisc_rcv(skb); break; case ICMPV6_MGM_QUERY: igmp6_event_query(skb); break; case ICMPV6_MGM_REPORT: igmp6_event_report(skb); break; case ICMPV6_MGM_REDUCTION: break; default: if (net_ratelimit()) printk(KERN_DEBUG "icmpv6: msg of unkown type\n"); /* informational */ if (type & 0x80) break; /* * error of unkown type. * must pass to upper level */ icmpv6_notify(skb, type, hdr->icmp6_code, hdr->icmp6_mtu); }; kfree_skb(skb); return 0;discard_it: ICMP6_INC_STATS_BH(Icmp6InErrors); kfree_skb(skb); return 0;}int __init icmpv6_init(struct net_proto_family *ops){ struct sock *sk; int err; icmpv6_socket = sock_alloc(); if (icmpv6_socket == NULL) { printk(KERN_ERR "Failed to create the ICMP6 control socket.\n"); return -1; } icmpv6_socket->inode->i_uid = 0; icmpv6_socket->inode->i_gid = 0; icmpv6_socket->type = SOCK_RAW; if ((err = ops->create(icmpv6_socket, IPPROTO_ICMPV6)) < 0) { printk(KERN_ERR "Failed to initialize the ICMP6 control socket (err %d).\n", err); sock_release(icmpv6_socket); icmpv6_socket = NULL; /* for safety */ return err; } sk = icmpv6_socket->sk; sk->allocation = GFP_ATOMIC; sk->sndbuf = SK_WMEM_MAX*2; sk->prot->unhash(sk); inet6_add_protocol(&icmpv6_protocol); return 0;}void icmpv6_cleanup(void){ sock_release(icmpv6_socket); icmpv6_socket = NULL; /* For safety. */ inet6_del_protocol(&icmpv6_protocol);}static struct icmp6_err { int err; int fatal;} tab_unreach[] = { { ENETUNREACH, 0}, /* NOROUTE */ { EACCES, 1}, /* ADM_PROHIBITED */ { EHOSTUNREACH, 0}, /* Was NOT_NEIGHBOUR, now reserved */ { EHOSTUNREACH, 0}, /* ADDR_UNREACH */ { ECONNREFUSED, 1}, /* PORT_UNREACH */};int icmpv6_err_convert(int type, int code, int *err){ int fatal = 0; *err = EPROTO; switch (type) { case ICMPV6_DEST_UNREACH: fatal = 1; if (code <= ICMPV6_PORT_UNREACH) { *err = tab_unreach[code].err; fatal = tab_unreach[code].fatal; } break; case ICMPV6_PKT_TOOBIG: *err = EMSGSIZE; break; case ICMPV6_PARAMPROB: *err = EPROTO; fatal = 1; break; case ICMPV6_TIME_EXCEED: *err = EHOSTUNREACH; break; }; return fatal;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -