icmp.c 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. /*
  2. * GRUB -- GRand Unified Bootloader
  3. * Copyright (C) 2010,2011 Free Software Foundation, Inc.
  4. *
  5. * GRUB is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * GRUB is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include <grub/net.h>
  19. #include <grub/net/ip.h>
  20. #include <grub/net/netbuff.h>
  21. struct icmp_header
  22. {
  23. grub_uint8_t type;
  24. grub_uint8_t code;
  25. grub_uint16_t checksum;
  26. } GRUB_PACKED;
  27. struct ping_header
  28. {
  29. grub_uint16_t id;
  30. grub_uint16_t seq;
  31. } GRUB_PACKED;
  32. enum
  33. {
  34. ICMP_ECHO_REPLY = 0,
  35. ICMP_ECHO = 8,
  36. };
  37. grub_err_t
  38. grub_net_recv_icmp_packet (struct grub_net_buff *nb,
  39. struct grub_net_network_level_interface *inf,
  40. const grub_net_link_level_address_t *ll_src,
  41. const grub_net_network_level_address_t *src)
  42. {
  43. struct icmp_header *icmph;
  44. grub_err_t err;
  45. grub_uint16_t checksum;
  46. /* Ignore broadcast. */
  47. if (!inf)
  48. {
  49. grub_netbuff_free (nb);
  50. return GRUB_ERR_NONE;
  51. }
  52. icmph = (struct icmp_header *) nb->data;
  53. if (nb->tail - nb->data < (grub_ssize_t) sizeof (*icmph))
  54. {
  55. grub_netbuff_free (nb);
  56. return GRUB_ERR_NONE;
  57. }
  58. checksum = icmph->checksum;
  59. icmph->checksum = 0;
  60. if (checksum != grub_net_ip_chksum (nb->data, nb->tail - nb->data))
  61. {
  62. icmph->checksum = checksum;
  63. return GRUB_ERR_NONE;
  64. }
  65. icmph->checksum = checksum;
  66. err = grub_netbuff_pull (nb, sizeof (*icmph));
  67. if (err)
  68. return err;
  69. switch (icmph->type)
  70. {
  71. case ICMP_ECHO:
  72. {
  73. struct grub_net_buff *nb_reply;
  74. struct icmp_header *icmphr;
  75. if (icmph->code)
  76. break;
  77. nb_reply = grub_netbuff_make_pkt (nb->tail - nb->data + sizeof (*icmphr));
  78. if (!nb_reply)
  79. {
  80. grub_netbuff_free (nb);
  81. return grub_errno;
  82. }
  83. grub_memcpy (nb_reply->data + sizeof (*icmphr), nb->data, nb->tail - nb->data);
  84. icmphr = (struct icmp_header *) nb_reply->data;
  85. icmphr->type = ICMP_ECHO_REPLY;
  86. icmphr->code = 0;
  87. icmphr->checksum = 0;
  88. icmphr->checksum = grub_net_ip_chksum ((void *) nb_reply->data,
  89. nb_reply->tail - nb_reply->data);
  90. err = grub_net_send_ip_packet (inf, src, ll_src,
  91. nb_reply, GRUB_NET_IP_ICMP);
  92. grub_netbuff_free (nb);
  93. grub_netbuff_free (nb_reply);
  94. return err;
  95. }
  96. };
  97. grub_netbuff_free (nb);
  98. return GRUB_ERR_NONE;
  99. }