icmp.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:16k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * Internet Control Message Protocol (ICMPv6)
  3.  * Linux INET6 implementation
  4.  *
  5.  * Authors:
  6.  * Pedro Roque <roque@di.fc.ul.pt>
  7.  *
  8.  * $Id: icmp.c,v 1.37 2001/09/18 22:29:10 davem Exp $
  9.  *
  10.  * Based on net/ipv4/icmp.c
  11.  *
  12.  * RFC 1885
  13.  *
  14.  * This program is free software; you can redistribute it and/or
  15.  *      modify it under the terms of the GNU General Public License
  16.  *      as published by the Free Software Foundation; either version
  17.  *      2 of the License, or (at your option) any later version.
  18.  */
  19. /*
  20.  * Changes:
  21.  *
  22.  * Andi Kleen : exception handling
  23.  * Andi Kleen add rate limits. never reply to a icmp.
  24.  * add more length checks and other fixes.
  25.  * yoshfuji : ensure to sent parameter problem for
  26.  * fragments.
  27.  */
  28. #define __NO_VERSION__
  29. #include <linux/module.h>
  30. #include <linux/errno.h>
  31. #include <linux/types.h>
  32. #include <linux/socket.h>
  33. #include <linux/in.h>
  34. #include <linux/kernel.h>
  35. #include <linux/sched.h>
  36. #include <linux/sockios.h>
  37. #include <linux/net.h>
  38. #include <linux/skbuff.h>
  39. #include <linux/init.h>
  40. #include <linux/inet.h>
  41. #include <linux/netdevice.h>
  42. #include <linux/icmpv6.h>
  43. #include <net/ip.h>
  44. #include <net/sock.h>
  45. #include <net/ipv6.h>
  46. #include <net/checksum.h>
  47. #include <net/protocol.h>
  48. #include <net/raw.h>
  49. #include <net/rawv6.h>
  50. #include <net/transp_v6.h>
  51. #include <net/ip6_route.h>
  52. #include <net/addrconf.h>
  53. #include <net/icmp.h>
  54. #include <asm/uaccess.h>
  55. #include <asm/system.h>
  56. struct icmpv6_mib icmpv6_statistics[NR_CPUS*2];
  57. /*
  58.  * ICMP socket for flow control.
  59.  */
  60. struct socket *icmpv6_socket;
  61. int icmpv6_rcv(struct sk_buff *skb);
  62. static struct inet6_protocol icmpv6_protocol = 
  63. {
  64. icmpv6_rcv, /* handler */
  65. NULL, /* error control */
  66. NULL, /* next */
  67. IPPROTO_ICMPV6, /* protocol ID */
  68. 0, /* copy */
  69. NULL, /* data */
  70. "ICMPv6"         /* name */
  71. };
  72. struct icmpv6_msg {
  73. struct icmp6hdr icmph;
  74. struct sk_buff *skb;
  75. int offset;
  76. struct in6_addr *daddr;
  77. int len;
  78. __u32 csum;
  79. };
  80. static int icmpv6_xmit_holder = -1;
  81. static int icmpv6_xmit_lock_bh(void)
  82. {
  83. if (!spin_trylock(&icmpv6_socket->sk->lock.slock)) {
  84. if (icmpv6_xmit_holder == smp_processor_id())
  85. return -EAGAIN;
  86. spin_lock(&icmpv6_socket->sk->lock.slock);
  87. }
  88. icmpv6_xmit_holder = smp_processor_id();
  89. return 0;
  90. }
  91. static __inline__ int icmpv6_xmit_lock(void)
  92. {
  93. int ret;
  94. local_bh_disable();
  95. ret = icmpv6_xmit_lock_bh();
  96. if (ret)
  97. local_bh_enable();
  98. return ret;
  99. }
  100. static void icmpv6_xmit_unlock_bh(void)
  101. {
  102. icmpv6_xmit_holder = -1;
  103. spin_unlock(&icmpv6_socket->sk->lock.slock);
  104. }
  105. static __inline__ void icmpv6_xmit_unlock(void)
  106. {
  107. icmpv6_xmit_unlock_bh();
  108. local_bh_enable();
  109. }
  110. /*
  111.  * getfrag callback
  112.  */
  113. static int icmpv6_getfrag(const void *data, struct in6_addr *saddr, 
  114.    char *buff, unsigned int offset, unsigned int len)
  115. {
  116. struct icmpv6_msg *msg = (struct icmpv6_msg *) data;
  117. struct icmp6hdr *icmph;
  118. __u32 csum;
  119. if (offset) {
  120. csum = skb_copy_and_csum_bits(msg->skb, msg->offset +
  121.       (offset - sizeof(struct icmp6hdr)),
  122.       buff, len, msg->csum);
  123. msg->csum = csum;
  124. return 0;
  125. }
  126. csum = csum_partial_copy_nocheck((void *) &msg->icmph, buff,
  127.  sizeof(struct icmp6hdr), msg->csum);
  128. csum = skb_copy_and_csum_bits(msg->skb, msg->offset,
  129.       buff + sizeof(struct icmp6hdr),
  130.       len - sizeof(struct icmp6hdr), csum);
  131. icmph = (struct icmp6hdr *) buff;
  132. icmph->icmp6_cksum = csum_ipv6_magic(saddr, msg->daddr, msg->len,
  133.      IPPROTO_ICMPV6, csum);
  134. return 0; 
  135. }
  136. /* 
  137.  * Slightly more convenient version of icmpv6_send.
  138.  */
  139. void icmpv6_param_prob(struct sk_buff *skb, int code, int pos)
  140. {
  141. icmpv6_send(skb, ICMPV6_PARAMPROB, code, pos, skb->dev);
  142. kfree_skb(skb);
  143. }
  144. /*
  145.  * Figure out, may we reply to this packet with icmp error.
  146.  *
  147.  * We do not reply, if:
  148.  * - it was icmp error message.
  149.  * - it is truncated, so that it is known, that protocol is ICMPV6
  150.  *   (i.e. in the middle of some exthdr)
  151.  *
  152.  * --ANK (980726)
  153.  */
  154. static int is_ineligible(struct sk_buff *skb)
  155. {
  156. int ptr = (u8*)(skb->nh.ipv6h+1) - skb->data;
  157. int len = skb->len - ptr;
  158. __u8 nexthdr = skb->nh.ipv6h->nexthdr;
  159. if (len < 0)
  160. return 1;
  161. ptr = ipv6_skip_exthdr(skb, ptr, &nexthdr, len);
  162. if (ptr < 0)
  163. return 0;
  164. if (nexthdr == IPPROTO_ICMPV6) {
  165. u8 type;
  166. if (skb_copy_bits(skb, ptr+offsetof(struct icmp6hdr, icmp6_type),
  167.   &type, 1)
  168.     || !(type & ICMPV6_INFOMSG_MASK))
  169. return 1;
  170. }
  171. return 0;
  172. }
  173. int sysctl_icmpv6_time = 1*HZ; 
  174. /* 
  175.  * Check the ICMP output rate limit 
  176.  */
  177. static inline int icmpv6_xrlim_allow(struct sock *sk, int type,
  178.      struct flowi *fl)
  179. {
  180. struct dst_entry *dst;
  181. int res = 0;
  182. /* Informational messages are not limited. */
  183. if (type & ICMPV6_INFOMSG_MASK)
  184. return 1;
  185. /* Do not limit pmtu discovery, it would break it. */
  186. if (type == ICMPV6_PKT_TOOBIG)
  187. return 1;
  188. /* 
  189.  * Look up the output route.
  190.  * XXX: perhaps the expire for routing entries cloned by
  191.  * this lookup should be more aggressive (not longer than timeout).
  192.  */
  193. dst = ip6_route_output(sk, fl);
  194. if (dst->error) {
  195. IP6_INC_STATS(Ip6OutNoRoutes);
  196. } else if (dst->dev && (dst->dev->flags&IFF_LOOPBACK)) {
  197. res = 1;
  198. } else {
  199. struct rt6_info *rt = (struct rt6_info *)dst;
  200. int tmo = sysctl_icmpv6_time;
  201. /* Give more bandwidth to wider prefixes. */
  202. if (rt->rt6i_dst.plen < 128)
  203. tmo >>= ((128 - rt->rt6i_dst.plen)>>5);
  204. res = xrlim_allow(dst, tmo);
  205. }
  206. dst_release(dst);
  207. return res;
  208. }
  209. /*
  210.  * an inline helper for the "simple" if statement below
  211.  * checks if parameter problem report is caused by an
  212.  * unrecognized IPv6 option that has the Option Type 
  213.  * highest-order two bits set to 10
  214.  */
  215. static __inline__ int opt_unrec(struct sk_buff *skb, __u32 offset)
  216. {
  217. u8 optval;
  218. offset += skb->nh.raw - skb->data;
  219. if (skb_copy_bits(skb, offset, &optval, 1))
  220. return 1;
  221. return (optval&0xC0) == 0x80;
  222. }
  223. /*
  224.  * Send an ICMP message in response to a packet in error
  225.  */
  226. void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info, 
  227.  struct net_device *dev)
  228. {
  229. struct ipv6hdr *hdr = skb->nh.ipv6h;
  230. struct sock *sk = icmpv6_socket->sk;
  231. struct in6_addr *saddr = NULL;
  232. int iif = 0;
  233. struct icmpv6_msg msg;
  234. struct flowi fl;
  235. int addr_type = 0;
  236. int len;
  237. if ((u8*)hdr < skb->head || (u8*)(hdr+1) > skb->tail)
  238. return;
  239. /*
  240.  * Make sure we respect the rules 
  241.  * i.e. RFC 1885 2.4(e)
  242.  * Rule (e.1) is enforced by not using icmpv6_send
  243.  * in any code that processes icmp errors.
  244.  */
  245. addr_type = ipv6_addr_type(&hdr->daddr);
  246. if (ipv6_chk_addr(&hdr->daddr, skb->dev))
  247. saddr = &hdr->daddr;
  248. /*
  249.  * Dest addr check
  250.  */
  251. if ((addr_type & IPV6_ADDR_MULTICAST || skb->pkt_type != PACKET_HOST)) {
  252. if (type != ICMPV6_PKT_TOOBIG &&
  253.     !(type == ICMPV6_PARAMPROB && 
  254.       code == ICMPV6_UNK_OPTION && 
  255.       (opt_unrec(skb, info))))
  256. return;
  257. saddr = NULL;
  258. }
  259. addr_type = ipv6_addr_type(&hdr->saddr);
  260. /*
  261.  * Source addr check
  262.  */
  263. if (addr_type & IPV6_ADDR_LINKLOCAL)
  264. iif = skb->dev->ifindex;
  265. /*
  266.  * Must not send if we know that source is Anycast also.
  267.  * for now we don't know that.
  268.  */
  269. if ((addr_type == IPV6_ADDR_ANY) || (addr_type & IPV6_ADDR_MULTICAST)) {
  270. if (net_ratelimit())
  271. printk(KERN_DEBUG "icmpv6_send: addr_any/mcast sourcen");
  272. return;
  273. }
  274. /* 
  275.  * Never answer to a ICMP packet.
  276.  */
  277. if (is_ineligible(skb)) {
  278. if (net_ratelimit())
  279. printk(KERN_DEBUG "icmpv6_send: no reply to icmp errorn"); 
  280. return;
  281. }
  282. fl.proto = IPPROTO_ICMPV6;
  283. fl.nl_u.ip6_u.daddr = &hdr->saddr;
  284. fl.nl_u.ip6_u.saddr = saddr;
  285. fl.oif = iif;
  286. fl.fl6_flowlabel = 0;
  287. fl.uli_u.icmpt.type = type;
  288. fl.uli_u.icmpt.code = code;
  289. if (icmpv6_xmit_lock())
  290. return;
  291. if (!icmpv6_xrlim_allow(sk, type, &fl))
  292. goto out;
  293. /*
  294.  * ok. kick it. checksum will be provided by the 
  295.  * getfrag_t callback.
  296.  */
  297. msg.icmph.icmp6_type = type;
  298. msg.icmph.icmp6_code = code;
  299. msg.icmph.icmp6_cksum = 0;
  300. msg.icmph.icmp6_pointer = htonl(info);
  301. msg.skb = skb;
  302. msg.offset = skb->nh.raw - skb->data;
  303. msg.csum = 0;
  304. msg.daddr = &hdr->saddr;
  305. len = skb->len - msg.offset + sizeof(struct icmp6hdr);
  306. len = min_t(unsigned int, len, IPV6_MIN_MTU - sizeof(struct ipv6hdr));
  307. if (len < 0) {
  308. if (net_ratelimit())
  309. printk(KERN_DEBUG "icmp: len problemn");
  310. goto out;
  311. }
  312. msg.len = len;
  313. ip6_build_xmit(sk, icmpv6_getfrag, &msg, &fl, len, NULL, -1,
  314.        MSG_DONTWAIT);
  315. if (type >= ICMPV6_DEST_UNREACH && type <= ICMPV6_PARAMPROB)
  316. (&(icmpv6_statistics[smp_processor_id()*2].Icmp6OutDestUnreachs))[type-1]++;
  317. ICMP6_INC_STATS_BH(Icmp6OutMsgs);
  318. out:
  319. icmpv6_xmit_unlock();
  320. }
  321. static void icmpv6_echo_reply(struct sk_buff *skb)
  322. {
  323. struct sock *sk = icmpv6_socket->sk;
  324. struct icmp6hdr *icmph = (struct icmp6hdr *) skb->h.raw;
  325. struct in6_addr *saddr;
  326. struct icmpv6_msg msg;
  327. struct flowi fl;
  328. saddr = &skb->nh.ipv6h->daddr;
  329. if (ipv6_addr_type(saddr) & IPV6_ADDR_MULTICAST)
  330. saddr = NULL;
  331. msg.icmph.icmp6_type = ICMPV6_ECHO_REPLY;
  332. msg.icmph.icmp6_code = 0;
  333. msg.icmph.icmp6_cksum = 0;
  334. msg.icmph.icmp6_identifier = icmph->icmp6_identifier;
  335. msg.icmph.icmp6_sequence = icmph->icmp6_sequence;
  336. msg.skb = skb;
  337. msg.offset = 0;
  338. msg.csum = 0;
  339. msg.len = skb->len + sizeof(struct icmp6hdr);
  340. msg.daddr =  &skb->nh.ipv6h->saddr;
  341. fl.proto = IPPROTO_ICMPV6;
  342. fl.nl_u.ip6_u.daddr = msg.daddr;
  343. fl.nl_u.ip6_u.saddr = saddr;
  344. fl.oif = skb->dev->ifindex;
  345. fl.fl6_flowlabel = 0;
  346. fl.uli_u.icmpt.type = ICMPV6_ECHO_REPLY;
  347. fl.uli_u.icmpt.code = 0;
  348. if (icmpv6_xmit_lock_bh())
  349. return;
  350. ip6_build_xmit(sk, icmpv6_getfrag, &msg, &fl, msg.len, NULL, -1,
  351.        MSG_DONTWAIT);
  352. ICMP6_INC_STATS_BH(Icmp6OutEchoReplies);
  353. ICMP6_INC_STATS_BH(Icmp6OutMsgs);
  354. icmpv6_xmit_unlock_bh();
  355. }
  356. static void icmpv6_notify(struct sk_buff *skb, int type, int code, u32 info)
  357. {
  358. struct in6_addr *saddr, *daddr;
  359. struct inet6_protocol *ipprot;
  360. struct sock *sk;
  361. int inner_offset;
  362. int hash;
  363. u8 nexthdr;
  364. if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
  365. return;
  366. nexthdr = ((struct ipv6hdr *)skb->data)->nexthdr;
  367. if (ipv6_ext_hdr(nexthdr)) {
  368. /* now skip over extension headers */
  369. inner_offset = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &nexthdr, skb->len - sizeof(struct ipv6hdr));
  370. if (inner_offset<0)
  371. return;
  372. } else {
  373. inner_offset = sizeof(struct ipv6hdr);
  374. }
  375. /* Checkin header including 8 bytes of inner protocol header. */
  376. if (!pskb_may_pull(skb, inner_offset+8))
  377. return;
  378. saddr = &skb->nh.ipv6h->saddr;
  379. daddr = &skb->nh.ipv6h->daddr;
  380. /* BUGGG_FUTURE: we should try to parse exthdrs in this packet.
  381.    Without this we will not able f.e. to make source routed
  382.    pmtu discovery.
  383.    Corresponding argument (opt) to notifiers is already added.
  384.    --ANK (980726)
  385.  */
  386. hash = nexthdr & (MAX_INET_PROTOS - 1);
  387. for (ipprot = (struct inet6_protocol *) inet6_protos[hash]; 
  388.      ipprot != NULL; 
  389.      ipprot=(struct inet6_protocol *)ipprot->next) {
  390. if (ipprot->protocol != nexthdr)
  391. continue;
  392. if (ipprot->err_handler)
  393. ipprot->err_handler(skb, NULL, type, code, inner_offset, info);
  394. }
  395. read_lock(&raw_v6_lock);
  396. if ((sk = raw_v6_htable[hash]) != NULL) {
  397. while((sk = __raw_v6_lookup(sk, nexthdr, daddr, saddr))) {
  398. rawv6_err(sk, skb, NULL, type, code, inner_offset, info);
  399. sk = sk->next;
  400. }
  401. }
  402. read_unlock(&raw_v6_lock);
  403. }
  404.   
  405. /*
  406.  * Handle icmp messages
  407.  */
  408. int icmpv6_rcv(struct sk_buff *skb)
  409. {
  410. struct net_device *dev = skb->dev;
  411. struct in6_addr *saddr, *daddr;
  412. struct ipv6hdr *orig_hdr;
  413. struct icmp6hdr *hdr;
  414. int type;
  415. ICMP6_INC_STATS_BH(Icmp6InMsgs);
  416. saddr = &skb->nh.ipv6h->saddr;
  417. daddr = &skb->nh.ipv6h->daddr;
  418. /* Perform checksum. */
  419. if (skb->ip_summed == CHECKSUM_HW) {
  420. skb->ip_summed = CHECKSUM_UNNECESSARY;
  421. if (csum_ipv6_magic(saddr, daddr, skb->len, IPPROTO_ICMPV6,
  422.     skb->csum)) {
  423. if (net_ratelimit())
  424. printk(KERN_DEBUG "ICMPv6 hw checksum failedn");
  425. skb->ip_summed = CHECKSUM_NONE;
  426. }
  427. }
  428. if (skb->ip_summed == CHECKSUM_NONE) {
  429. if (csum_ipv6_magic(saddr, daddr, skb->len, IPPROTO_ICMPV6,
  430.     skb_checksum(skb, 0, skb->len, 0))) {
  431. if (net_ratelimit())
  432. printk(KERN_DEBUG "ICMPv6 checksum failed [%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x > %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]n",
  433.        ntohs(saddr->s6_addr16[0]),
  434.        ntohs(saddr->s6_addr16[1]),
  435.        ntohs(saddr->s6_addr16[2]),
  436.        ntohs(saddr->s6_addr16[3]),
  437.        ntohs(saddr->s6_addr16[4]),
  438.        ntohs(saddr->s6_addr16[5]),
  439.        ntohs(saddr->s6_addr16[6]),
  440.        ntohs(saddr->s6_addr16[7]),
  441.        ntohs(daddr->s6_addr16[0]),
  442.        ntohs(daddr->s6_addr16[1]),
  443.        ntohs(daddr->s6_addr16[2]),
  444.        ntohs(daddr->s6_addr16[3]),
  445.        ntohs(daddr->s6_addr16[4]),
  446.        ntohs(daddr->s6_addr16[5]),
  447.        ntohs(daddr->s6_addr16[6]),
  448.        ntohs(daddr->s6_addr16[7]));
  449. goto discard_it;
  450. }
  451. }
  452. if (!pskb_pull(skb, sizeof(struct icmp6hdr)))
  453. goto discard_it;
  454. hdr = (struct icmp6hdr *) skb->h.raw;
  455. type = hdr->icmp6_type;
  456. if (type >= ICMPV6_DEST_UNREACH && type <= ICMPV6_PARAMPROB)
  457. (&icmpv6_statistics[smp_processor_id()*2].Icmp6InDestUnreachs)[type-ICMPV6_DEST_UNREACH]++;
  458. else if (type >= ICMPV6_ECHO_REQUEST && type <= NDISC_REDIRECT)
  459. (&icmpv6_statistics[smp_processor_id()*2].Icmp6InEchos)[type-ICMPV6_ECHO_REQUEST]++;
  460. switch (type) {
  461. case ICMPV6_ECHO_REQUEST:
  462. icmpv6_echo_reply(skb);
  463. break;
  464. case ICMPV6_ECHO_REPLY:
  465. /* we coulnd't care less */
  466. break;
  467. case ICMPV6_PKT_TOOBIG:
  468. /* BUGGG_FUTURE: if packet contains rthdr, we cannot update
  469.    standard destination cache. Seems, only "advanced"
  470.    destination cache will allow to solve this problem
  471.    --ANK (980726)
  472.  */
  473. if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
  474. goto discard_it;
  475. hdr = (struct icmp6hdr *) skb->h.raw;
  476. orig_hdr = (struct ipv6hdr *) (hdr + 1);
  477. rt6_pmtu_discovery(&orig_hdr->daddr, &orig_hdr->saddr, dev,
  478.    ntohl(hdr->icmp6_mtu));
  479. /*
  480.  * Drop through to notify
  481.  */
  482. case ICMPV6_DEST_UNREACH:
  483. case ICMPV6_TIME_EXCEED:
  484. case ICMPV6_PARAMPROB:
  485. icmpv6_notify(skb, type, hdr->icmp6_code, hdr->icmp6_mtu);
  486. break;
  487. case NDISC_ROUTER_SOLICITATION:
  488. case NDISC_ROUTER_ADVERTISEMENT:
  489. case NDISC_NEIGHBOUR_SOLICITATION:
  490. case NDISC_NEIGHBOUR_ADVERTISEMENT:
  491. case NDISC_REDIRECT:
  492. if (skb_is_nonlinear(skb) &&
  493.     skb_linearize(skb, GFP_ATOMIC) != 0) {
  494. kfree_skb(skb);
  495. return 0;
  496. }
  497. ndisc_rcv(skb);
  498. break;
  499. case ICMPV6_MGM_QUERY:
  500. igmp6_event_query(skb);
  501. break;
  502. case ICMPV6_MGM_REPORT:
  503. igmp6_event_report(skb);
  504. break;
  505. case ICMPV6_MGM_REDUCTION:
  506. break;
  507. default:
  508. if (net_ratelimit())
  509. printk(KERN_DEBUG "icmpv6: msg of unkown typen");
  510. /* informational */
  511. if (type & ICMPV6_INFOMSG_MASK)
  512. break;
  513. /* 
  514.  * error of unkown type. 
  515.  * must pass to upper level 
  516.  */
  517. icmpv6_notify(skb, type, hdr->icmp6_code, hdr->icmp6_mtu);
  518. };
  519. kfree_skb(skb);
  520. return 0;
  521. discard_it:
  522. ICMP6_INC_STATS_BH(Icmp6InErrors);
  523. kfree_skb(skb);
  524. return 0;
  525. }
  526. int __init icmpv6_init(struct net_proto_family *ops)
  527. {
  528. struct sock *sk;
  529. int err;
  530. icmpv6_socket = sock_alloc();
  531. if (icmpv6_socket == NULL) {
  532. printk(KERN_ERR
  533.        "Failed to create the ICMP6 control socket.n");
  534. return -1;
  535. }
  536. icmpv6_socket->inode->i_uid = 0;
  537. icmpv6_socket->inode->i_gid = 0;
  538. icmpv6_socket->type = SOCK_RAW;
  539. if ((err = ops->create(icmpv6_socket, IPPROTO_ICMPV6)) < 0) {
  540. printk(KERN_ERR
  541.        "Failed to initialize the ICMP6 control socket (err %d).n",
  542.        err);
  543. sock_release(icmpv6_socket);
  544. icmpv6_socket = NULL; /* for safety */
  545. return err;
  546. }
  547. sk = icmpv6_socket->sk;
  548. sk->allocation = GFP_ATOMIC;
  549. sk->sndbuf = SK_WMEM_MAX*2;
  550. sk->prot->unhash(sk);
  551. inet6_add_protocol(&icmpv6_protocol);
  552. return 0;
  553. }
  554. void icmpv6_cleanup(void)
  555. {
  556. sock_release(icmpv6_socket);
  557. icmpv6_socket = NULL; /* For safety. */
  558. inet6_del_protocol(&icmpv6_protocol);
  559. }
  560. static struct icmp6_err {
  561. int err;
  562. int fatal;
  563. } tab_unreach[] = {
  564. { ENETUNREACH, 0}, /* NOROUTE */
  565. { EACCES, 1}, /* ADM_PROHIBITED */
  566. { EHOSTUNREACH, 0}, /* Was NOT_NEIGHBOUR, now reserved */
  567. { EHOSTUNREACH, 0}, /* ADDR_UNREACH */
  568. { ECONNREFUSED, 1}, /* PORT_UNREACH */
  569. };
  570. int icmpv6_err_convert(int type, int code, int *err)
  571. {
  572. int fatal = 0;
  573. *err = EPROTO;
  574. switch (type) {
  575. case ICMPV6_DEST_UNREACH:
  576. fatal = 1;
  577. if (code <= ICMPV6_PORT_UNREACH) {
  578. *err  = tab_unreach[code].err;
  579. fatal = tab_unreach[code].fatal;
  580. }
  581. break;
  582. case ICMPV6_PKT_TOOBIG:
  583. *err = EMSGSIZE;
  584. break;
  585. case ICMPV6_PARAMPROB:
  586. *err = EPROTO;
  587. fatal = 1;
  588. break;
  589. case ICMPV6_TIME_EXCEED:
  590. *err = EHOSTUNREACH;
  591. break;
  592. };
  593. return fatal;
  594. }