diff --git a/src/EtherSia.cpp b/src/EtherSia.cpp index a29ccc6..b3b8139 100644 --- a/src/EtherSia.cpp +++ b/src/EtherSia.cpp @@ -113,6 +113,24 @@ uint16_t EtherSia::receivePacket() if (len) { IPv6Packet& packet = (IPv6Packet&)_ptr; + + if (packet.protocol() == IP6_PROTO_HBH) { + // Packet with Hop-by-Hop Extension + IPv6HopByHopPacket& packet = (IPv6HopByHopPacket&)_ptr; + if (!packet.isValid() || !checkEthernetAddresses(packet)) { + _bufferContainsReceived = false; + } else { + if(packet.nextHeader() == IP6_PROTO_ICMP6) { + ICMPv6Packet& packet = (ICMPv6Packet&)_ptr; + if(packet.type == ICMP6_TYPE_MLQ && (packet.mld.target.isZero() || packet.mld.target == _globalAddress)) { + // Multiast Listener Query, answer with listener Report for Solicited Node address + icmp6SendMLR(); + } + } + } + return 0; + } + if (!packet.isValid() || !checkEthernetAddresses(packet)) { _bufferContainsReceived = false; return 0; @@ -127,6 +145,7 @@ uint16_t EtherSia::receivePacket() return 0; } } + } else { // We didn't receive anything _bufferContainsReceived = false; diff --git a/src/EtherSia.h b/src/EtherSia.h index 0bc4f5d..ce355a0 100644 --- a/src/EtherSia.h +++ b/src/EtherSia.h @@ -14,6 +14,7 @@ #include "MACAddress.h" #include "IPv6Address.h" #include "IPv6Packet.h" +#include "IPv6HopByHopPacket.h" #include "Socket.h" #include "UDPSocket.h" @@ -369,6 +370,11 @@ class EtherSia { */ virtual uint16_t readFrame(uint8_t *buffer, uint16_t bufsize) = 0; + /** + * Send a Multicast Listener Report for the Solicited Node address + */ + void icmp6SendMLR(); + protected: IPv6Address _linkLocalAddress; /**< The IPv6 Link-local address of the Ethernet Interface */ IPv6Address _globalAddress; /**< The IPv6 Global address of the Ethernet Interface */ @@ -468,6 +474,13 @@ class EtherSia { * Ensures the protocol and checksum are set before sending. */ void icmp6PacketSend(); + + /** + * Send an ICMPv6 packet stored in the EtherSia packet buffer + * Ensures the protocol and checksum are set before sending. + * @param hbh true if the packet to send contains a Hop-by-Hop option + */ + void icmp6PacketSend(bool hbh); }; #include "PingClient.h" diff --git a/src/ICMPv6Packet.h b/src/ICMPv6Packet.h index e768088..f219678 100644 --- a/src/ICMPv6Packet.h +++ b/src/ICMPv6Packet.h @@ -10,6 +10,8 @@ #define ICMP6_TYPE_PARAM_PROB 4 #define ICMP6_TYPE_ECHO 128 #define ICMP6_TYPE_ECHO_REPLY 129 +#define ICMP6_TYPE_MLQ 130 +#define ICMP6_TYPE_MLR 131 #define ICMP6_TYPE_RS 133 #define ICMP6_TYPE_RA 134 #define ICMP6_TYPE_NS 135 @@ -168,13 +170,28 @@ struct icmp6_na_header { /* Verify that compiler gets the structure size correct */ static_assert(sizeof(struct icmp6_na_header) == ICMP6_NA_HEADER_LEN, "Size is not correct"); +/** + * Structure for accessing the fields of a ICMP6 Multicast Listener Discovery packet + * @private + */ +struct icmp6_mld_header { + uint16_t max_response_delay; + uint8_t reserved[2]; + IPv6Address target; +} __attribute__((__packed__)); +#define ICMP6_MLD_HEADER_LEN (20) +#define ICMP6_MLD_HEADER_OFFSET (ICMP6_HEADER_OFFSET + ICMP6_HEADER_LEN) + +/* Verify that compiler gets the structure size correct */ +static_assert(sizeof(struct icmp6_mld_header) == ICMP6_MLD_HEADER_LEN, "Size is not correct"); + /** * Class for accessing the fields of a ICMP6 packet * @private */ -class ICMPv6Packet : public IPv6Packet { +template class ICMPv6Packet : public T { public: uint8_t type; @@ -188,6 +205,7 @@ class ICMPv6Packet : public IPv6Packet { struct icmp6_rs_header rs; struct icmp6_na_header na; struct icmp6_ns_header ns; + struct icmp6_mld_header mld; } __attribute__((__packed__)); } __attribute__((__packed__)); diff --git a/src/IPv6HopByHopPacket.cpp b/src/IPv6HopByHopPacket.cpp new file mode 100644 index 0000000..4a1b7d3 --- /dev/null +++ b/src/IPv6HopByHopPacket.cpp @@ -0,0 +1,77 @@ +#include + +#include "EtherSia.h" +#include "IPv6HopByHopPacket.h" + +IPv6HopByHopPacket::IPv6HopByHopPacket() +{ + memset(this, 0, sizeof(IPv6HopByHopPacket)); + init(); +} + +void IPv6HopByHopPacket::setNextHeader(uint8_t header) { + _next_header = header; +} + +uint8_t IPv6HopByHopPacket::nextHeader() { + return _next_header; +} + +void IPv6HopByHopPacket::setHopByHopLength(uint8_t length) { + _hbh_length = length; +} + +uint8_t IPv6HopByHopPacket::hopByHopLength() { + return _hbh_length; +} + +uint8_t IPv6HopByHopPacket::optionType() { + return hbh_option[0]; +} + +void IPv6HopByHopPacket::setMLDRouterAlert() { + _router_alert.option_type = 5; + _router_alert.length = 2; + _router_alert.alert_type = 0; + _router_alert.padding = 0; +} + +uint8_t* IPv6HopByHopPacket::payload() +{ + return (uint8_t *)(this) + sizeof(IPv6HopByHopPacket); +} + +uint16_t IPv6HopByHopPacket::calculateChecksum() +{ + /* First sum pseudoheader. */ + /* IP protocol and length fields. This addition cannot carry. */ + volatile uint16_t newsum = (payloadLength() - 8) + nextHeader(); + + /* Sum IP source and destination addresses. */ + newsum = chksum(newsum, (uint8_t *)(source()), 16); + newsum = chksum(newsum, (uint8_t *)(destination()), 16); + + /* Sum the payload header and data */ + newsum = chksum(newsum, payload(), (payloadLength() - 8)); + + return ~newsum; +} + +boolean IPv6HopByHopPacket::isValid() +{ + if (this->_etherType != ntohs(ETHER_TYPE_IPV6)) { + return false; + } + + // Check the version header + if (this->version() != 6) { + return false; + } + + // Verify the packet checksum (it should add up to 0) + if (calculateChecksum() != 0) { + return false; + } + + return true; +} diff --git a/src/IPv6HopByHopPacket.h b/src/IPv6HopByHopPacket.h new file mode 100644 index 0000000..0e715fc --- /dev/null +++ b/src/IPv6HopByHopPacket.h @@ -0,0 +1,104 @@ +/** + * Header file for the ICMPv6Packet class + * @file IPv6HopByHopPacket.h + */ +#include "util.h" + +#ifndef IPV6_HOP_BY_HOP_PACKET_H +#define IPV6_HOP_BY_HOP_PACKET_H + +/** Field-Type Value of a Router Alert option */ +#define IPV6_HBH_OPTION_ROUTER_ALERT 5 + +/** Length of a Multicast Listener Discovery Hop-by-Hop option **/ +#define IPV6_HBH_MLD_OPTION_LENGTH 8 + +/** + * Structure representing a Router Alert option + * @private + */ +struct router_alert { + uint8_t option_type; + uint8_t length; + uint16_t alert_type; + uint16_t padding; +} __attribute__((__packed__)); + +/** + * Class for getting and setting the fields of an IPv6 Hop-by-Hop Packet + * with Hop-by-Hop extension and its Ethernet header + */ +class IPv6HopByHopPacket : public IPv6Packet { + public: + /** + * Constructor for new empty IPv6 Hop-by-Hop packet + */ + IPv6HopByHopPacket(); + + /** + * Set the type of the Hop by Hop packet payload + * @param header typecode of the payload type + */ + void setNextHeader(uint8_t header); + + /** + * Return the type of the Hop by Hop packet payload + * @return typecode of the payload type + */ + uint8_t nextHeader(); + + /** + * Set the Hop by Hop option length + * @param length hop by hop option length + */ + void setHopByHopLength(uint8_t length); + + /** + * Return the Hop by Hop option length + * @return hop by hop option length + */ + uint8_t hopByHopLength(); + + /** + * Return the Hop by Hop option type + * @return hop by hop option type + */ + uint8_t optionType(); + + /** + * Set Hop-by-Hop option to Routar Alert with + * MLD alert-type + */ + void setMLDRouterAlert(); + + /** + * Calculate the 16-bit checksum for the IPv6 packet + * @return the checksum of the packet + */ + uint16_t calculateChecksum(); + + /** + * Get a pointer to the start of the IPv6 Hop-by-Hop packet payload + * May be used to get or change the contents of the packet + * @return a pointer to the memory containing the packet payload + */ + uint8_t* payload(); + + /** + * Check if the Ethernet and IPv6 headers are valid + * Also verifies the checksum of the packet + * + * @return true if the packets fields are valid + */ + boolean isValid(); + + protected: + uint8_t _next_header; ///< The Type of the packet payload + uint8_t _hbh_length; ///< The hop-by-hop option length + union { + uint8_t hbh_option[6]; ///< Raw hop-by-hop option content + struct router_alert _router_alert; ///< RouterAlert hop-by-hop option + }; +} __attribute__((__packed__)); + +#endif \ No newline at end of file diff --git a/src/IPv6Packet.h b/src/IPv6Packet.h index 592284f..eab7f6d 100644 --- a/src/IPv6Packet.h +++ b/src/IPv6Packet.h @@ -20,6 +20,7 @@ enum ether_types { /** Enumeration of IP protocol numbers */ enum ip_protocol { + IP6_PROTO_HBH = 0, ///< IP protocol number for TCP IP6_PROTO_TCP = 6, ///< IP protocol number for TCP IP6_PROTO_UDP = 17, ///< IP protocol number for UDP IP6_PROTO_ICMP6 = 58 ///< IP protocol number for ICMP6 diff --git a/src/PingClient.cpp b/src/PingClient.cpp index 9acde2f..ddff9b1 100644 --- a/src/PingClient.cpp +++ b/src/PingClient.cpp @@ -18,7 +18,7 @@ boolean PingClient::setRemoteAddress(const char *remoteAddress) boolean PingClient::havePacket() { - ICMPv6Packet& packet = (ICMPv6Packet&)_ether.packet(); + ICMPv6Packet& packet = (ICMPv6Packet&)_ether.packet(); if (!_ether.bufferContainsReceived()) { return false; @@ -75,7 +75,7 @@ void PingClient::send() void PingClient::sendInternal(uint16_t length, boolean /*isReply*/) { - ICMPv6Packet& packet = (ICMPv6Packet&)_ether.packet(); + ICMPv6Packet& packet = (ICMPv6Packet&)_ether.packet(); uint16_t totalLen = ICMP6_HEADER_LEN + ICMP6_ECHO_HEADER_LEN + length; packet.setProtocol(IP6_PROTO_ICMP6); @@ -100,13 +100,13 @@ void PingClient::sendInternal(uint16_t length, boolean /*isReply*/) uint8_t* PingClient::payload() { - ICMPv6Packet& packet = (ICMPv6Packet&)_ether.packet(); + ICMPv6Packet& packet = (ICMPv6Packet&)_ether.packet(); return (uint8_t*)(packet.payload()) + ICMP6_HEADER_LEN + ICMP6_ECHO_HEADER_LEN; } uint16_t PingClient::payloadLength() { - ICMPv6Packet& packet = (ICMPv6Packet&)_ether.packet(); + ICMPv6Packet& packet = (ICMPv6Packet&)_ether.packet(); return packet.payloadLength() - ICMP6_HEADER_LEN - ICMP6_ECHO_HEADER_LEN; } diff --git a/src/icmp6.cpp b/src/icmp6.cpp index 7dd046a..c39b7bb 100644 --- a/src/icmp6.cpp +++ b/src/icmp6.cpp @@ -6,7 +6,7 @@ void EtherSia::icmp6ErrorReply(uint8_t type, uint8_t code) { - ICMPv6Packet& packet = (ICMPv6Packet&)_ptr; + ICMPv6Packet& packet = (ICMPv6Packet&)_ptr; uint16_t payloadLen = IP6_HEADER_LEN + packet.payloadLength(); const uint16_t payloadMax = ETHERSIA_MAX_PACKET_SIZE - ICMP6_ERROR_HEADER_OFFSET - ICMP6_ERROR_HEADER_LEN; @@ -40,7 +40,7 @@ void EtherSia::icmp6ErrorReply(uint8_t type, uint8_t code) void EtherSia::icmp6NSReply() { - ICMPv6Packet& packet = (ICMPv6Packet&)_ptr; + ICMPv6Packet& packet = (ICMPv6Packet&)_ptr; // Does the Neighbour Solicitation target belong to us? uint8_t type = isOurAddress(packet.ns.target); @@ -68,7 +68,7 @@ void EtherSia::icmp6NSReply() void EtherSia::icmp6EchoReply() { - ICMPv6Packet& packet = (ICMPv6Packet&)_ptr; + ICMPv6Packet& packet = (ICMPv6Packet&)_ptr; prepareReply(); packet.type = ICMP6_TYPE_ECHO_REPLY; @@ -79,7 +79,7 @@ void EtherSia::icmp6EchoReply() void EtherSia::icmp6SendNS(IPv6Address &targetAddress, IPv6Address &sourceAddress) { - ICMPv6Packet& packet = (ICMPv6Packet&)_ptr; + ICMPv6Packet& packet = (ICMPv6Packet&)_ptr; packet.destination().setSolicitedNodeMulticastAddress(targetAddress); packet.etherDestination().setIPv6Multicast(packet.destination()); @@ -108,7 +108,7 @@ void EtherSia::icmp6SendNS(IPv6Address &targetAddress, IPv6Address &sourceAddres void EtherSia::icmp6SendRS() { - ICMPv6Packet& packet = (ICMPv6Packet&)_ptr; + ICMPv6Packet& packet = (ICMPv6Packet&)_ptr; prepareSend(); packet.setPayloadLength(ICMP6_HEADER_LEN + ICMP6_RS_HEADER_LEN); @@ -128,14 +128,48 @@ void EtherSia::icmp6SendRS() icmp6PacketSend(); } -void EtherSia::icmp6PacketSend() +void EtherSia::icmp6SendMLR() { - ICMPv6Packet& packet = (ICMPv6Packet&)_ptr; + ICMPv6Packet& packet = (ICMPv6Packet&)_ptr; + + prepareSend(); + packet.setPayloadLength(IPV6_HBH_MLD_OPTION_LENGTH + ICMP6_HEADER_LEN + ICMP6_MLD_HEADER_LEN); + packet.setHopLimit(1); + packet.setSource(_linkLocalAddress); + packet.destination().setSolicitedNodeMulticastAddress(_globalAddress); + packet.etherDestination().setIPv6Multicast(packet.destination()); + + packet.type = ICMP6_TYPE_MLR; + packet.code = 0; + + packet.setNextHeader(IP6_PROTO_ICMP6); + packet.setHopByHopLength(0); + packet.setMLDRouterAlert(); - packet.setProtocol(IP6_PROTO_ICMP6); - packet.checksum = 0; - packet.checksum = htons(packet.calculateChecksum()); + memset(packet.mld.reserved, 0, sizeof(packet.rs.reserved)); + packet.mld.max_response_delay = 0; + packet.mld.target.setSolicitedNodeMulticastAddress(_globalAddress); + icmp6PacketSend(true); +} + +void EtherSia::icmp6PacketSend() +{ + icmp6PacketSend(false); +} +void EtherSia::icmp6PacketSend(bool hbh) +{ + if(hbh){ + ICMPv6Packet& packet = (ICMPv6Packet&)_ptr; + packet.setProtocol(IP6_PROTO_HBH); + packet.checksum = 0; + packet.checksum = htons(packet.calculateChecksum()) /*0xe979*/; + } else { + ICMPv6Packet& packet = (ICMPv6Packet&)_ptr; + packet.setProtocol(IP6_PROTO_ICMP6); + packet.checksum = 0; + packet.checksum = htons(packet.calculateChecksum()); + } send(); } @@ -164,7 +198,7 @@ void EtherSia::icmp6ProcessPrefix(struct icmp6_prefix_information *pi) void EtherSia::icmp6ProcessRA() { - ICMPv6Packet& packet = (ICMPv6Packet&)_ptr; + ICMPv6Packet& packet = (ICMPv6Packet&)_ptr; int16_t remaining = packet.payloadLength() - ICMP6_HEADER_LEN - ICMP6_RA_HEADER_LEN; uint8_t *ptr = _buffer + ICMP6_RA_HEADER_OFFSET + ICMP6_RA_HEADER_LEN; @@ -201,7 +235,7 @@ void EtherSia::icmp6ProcessRA() MACAddress* EtherSia::icmp6ProcessNA(IPv6Address &expected) { - ICMPv6Packet& packet = (ICMPv6Packet&)_ptr; + ICMPv6Packet& packet = (ICMPv6Packet&)_ptr; if (packet.na.target != expected) { return NULL; } @@ -216,7 +250,7 @@ MACAddress* EtherSia::icmp6ProcessNA(IPv6Address &expected) boolean EtherSia::icmp6ProcessPacket() { - ICMPv6Packet& packet = (ICMPv6Packet&)_ptr; + ICMPv6Packet& packet = (ICMPv6Packet&)_ptr; if (isOurAddress(packet.destination()) == 0) { // Packet isn't addressed to us @@ -272,7 +306,7 @@ MACAddress* EtherSia::discoverNeighbour(const char* addrstr) MACAddress* EtherSia::discoverNeighbour(IPv6Address& address, uint8_t attempts) { - ICMPv6Packet& packet = (ICMPv6Packet&)_ptr; + ICMPv6Packet& packet = (ICMPv6Packet&)_ptr; IPv6Address *sourceAddress = NULL; unsigned long nextNeighbourSolicitation = millis(); uint8_t count = 0; diff --git a/tests/45_check_ipv6_hop_by_hop_packet.tc b/tests/45_check_ipv6_hop_by_hop_packet.tc new file mode 100644 index 0000000..ce7117d --- /dev/null +++ b/tests/45_check_ipv6_hop_by_hop_packet.tc @@ -0,0 +1,186 @@ +#include "Arduino.h" +#include "hext.hh" +#include "EtherSia.h" + +#include "IPv6Packet.h" +#suite IPv6HopByHopPacket + + +#test new_packet +IPv6HopByHopPacket packet; +uint8_t zeroMac[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; +uint8_t zeroAddress[16] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; +ck_assert_mem_eq(packet.etherSource(), zeroMac, 6); +ck_assert_mem_eq(packet.etherDestination(), zeroMac, 6); +ck_assert_int_eq(packet.version(), 6); +ck_assert_int_eq(packet.hopLimit(), IP6_DEFAULT_HOP_LIMIT); +ck_assert_mem_eq(packet.source(), zeroAddress, 16); +ck_assert_mem_eq(packet.destination(), zeroAddress, 16); + + +#test isValid_null_packet +uint8_t buffer[sizeof(IPv6HopByHopPacket)]; +memset(buffer, 0, sizeof(buffer)); +IPv6HopByHopPacket *packet = (IPv6HopByHopPacket *)buffer; +ck_assert(packet->isValid() == false); + + +#test icmp6MulticastListenerQueryIsValid +HextFile rs("packets/icmp6_multicast_listener_query.hext"); +IPv6HopByHopPacket *packet = (IPv6HopByHopPacket *)rs.buffer; +ck_assert(packet-> calculateChecksum() == 0); + + +#test icmp6MulticastListenerReportIsValid +HextFile rs("packets/icmp6_multicast_listener_report.hext"); +IPv6HopByHopPacket *packet = (IPv6HopByHopPacket *)rs.buffer; +ck_assert(packet-> calculateChecksum() == 0); + + +#test isValid_wrong_version +HextFile rs("packets/icmp6_multicast_listener_report.hext"); +rs.buffer[14] = 0x40; +IPv6HopByHopPacket *packet = (IPv6HopByHopPacket *)rs.buffer; +ck_assert(packet->isValid() == false); + +#test isValid_wrong_checksum +HextFile rs("packets/icmp6_multicast_listener_report.hext"); +// Tamper with the source address +rs.buffer[0x40] = 0x00; +rs.buffer[0x41] = 0xFF; +IPv6HopByHopPacket *packet = (IPv6HopByHopPacket *)rs.buffer; +ck_assert(packet->isValid() == false); + +#test invalidate +HextFile rs("packets/icmp6_multicast_listener_report.hext"); +IPv6HopByHopPacket *packet = (IPv6HopByHopPacket *)rs.buffer; +ck_assert(packet->isValid() == true); +packet->invalidate(); +ck_assert(packet->isValid() == false); + +#test etherType +HextFile rs("packets/icmp6_multicast_listener_report.hext"); +IPv6HopByHopPacket *packet = (IPv6HopByHopPacket *)rs.buffer; +ck_assert_int_eq(packet->etherType(), 0x86dd); + +#test version +HextFile rs("packets/icmp6_multicast_listener_report.hext"); +IPv6HopByHopPacket *packet = (IPv6HopByHopPacket *)rs.buffer; +ck_assert_int_eq(packet->version(), 6); + +#test length +HextFile rs("packets/icmp6_multicast_listener_report.hext"); +IPv6HopByHopPacket *packet = (IPv6HopByHopPacket *)rs.buffer; +ck_assert_int_eq(packet->length(), 86); + +#test payloadLength +HextFile rs("packets/icmp6_multicast_listener_report.hext"); +IPv6HopByHopPacket *packet = (IPv6HopByHopPacket *)rs.buffer; +ck_assert_int_eq(packet->payloadLength(), 32); + +#test setPayloadLength +IPv6HopByHopPacket packet; +packet.setPayloadLength(256); +ck_assert_int_eq(packet.payloadLength(), 256); + +#test protocol +HextFile rs("packets/icmp6_multicast_listener_report.hext"); +IPv6HopByHopPacket *packet = (IPv6HopByHopPacket *)rs.buffer; +ck_assert_int_eq(packet->protocol(), IP6_PROTO_HBH); + +#test setProtocol +IPv6HopByHopPacket packet; +packet.setProtocol(IP6_PROTO_TCP); +ck_assert_int_eq(packet.protocol(), IP6_PROTO_TCP); + +#test hopLimit +HextFile rs("packets/icmp6_multicast_listener_report.hext"); +IPv6HopByHopPacket *packet = (IPv6HopByHopPacket *)rs.buffer; +ck_assert_int_eq(packet->hopLimit(), 1); + +#test setHopLimit +IPv6HopByHopPacket packet; +packet.setHopLimit(10); +ck_assert_int_eq(packet.hopLimit(), 10); + +#test etherSource +HextFile rs("packets/icmp6_multicast_listener_report.hext"); +MACAddress expect("c8:5b:76:f4:21:34"); +IPv6HopByHopPacket *packet = (IPv6HopByHopPacket *)rs.buffer; +ck_assert_mem_eq(packet->etherSource(), expect, 6); + +#test setEtherSource +MACAddress addr("01:23:45:67:89:10"); +IPv6HopByHopPacket packet; +packet.setEtherSource(addr); +ck_assert_mem_eq(packet.etherSource(), addr, 6); + +#test etherDestination +HextFile rs("packets/icmp6_multicast_listener_report.hext"); +MACAddress expect("33:33:ff:36:14:b9"); +IPv6HopByHopPacket *packet = (IPv6HopByHopPacket *)rs.buffer; +ck_assert_mem_eq(packet->etherDestination(), expect, 6); + +#test setEtherDestination +MACAddress addr("01:23:45:67:89:10"); +IPv6HopByHopPacket packet; +packet.setEtherDestination(addr); +ck_assert_mem_eq(packet.etherDestination(), addr, 6); + +#test source +HextFile rs("packets/icmp6_multicast_listener_report.hext"); +IPv6Address expect("fe80::f697:307e:e636:14b9"); +IPv6HopByHopPacket *packet = (IPv6HopByHopPacket *)rs.buffer; +ck_assert_mem_eq(packet->source(), expect, 16); + +#test setSource +IPv6Address addr("fe80::c58e:e533:e358:7006"); +IPv6HopByHopPacket packet; +packet.setSource(addr); +ck_assert_mem_eq(packet.source(), addr, 16); + +#test destination +HextFile rs("packets/icmp6_multicast_listener_report.hext"); +IPv6Address expect("ff02::0001:ff36:14b9"); +IPv6HopByHopPacket *packet = (IPv6HopByHopPacket *)rs.buffer; +ck_assert_mem_eq(packet->destination(), expect, 16); + +#test setDestination +IPv6Address addr("2001:4860:4860::8888"); +IPv6HopByHopPacket packet; +packet.setDestination(addr); +ck_assert_mem_eq(packet.destination(), addr, 16); + +#test calculateChecksum +HextFile rs("packets/icmp6_multicast_listener_report.hext"); +IPv6HopByHopPacket *packet = (IPv6HopByHopPacket *)rs.buffer; +// Calculation comes out as 0 because of the checksum field in the ICMP6 header +ck_assert_int_eq(packet->calculateChecksum(), 0x0000); + +#test constructPacket +IPv6HopByHopPacket packet; +packet.etherSource().fromString("a6:69:c0:80:da:3b"); +packet.etherDestination().fromString("36:b4:40:75:3b:a6"); +packet.setProtocol(0); +packet.setPayloadLength(8); +packet.source().fromString("fe80::a469:c0ff:fe80:da3b"); +packet.destination().fromString("fe80::34b4:40ff:fe75:3ba6"); +packet.setNextHeader(254); +packet.setHopLimit(1); + +HextFile expect("packets/ipv6hbh_empty.hext"); +ck_assert_int_eq(sizeof(IPv6HopByHopPacket), expect.length); +ck_assert_mem_eq(&packet, expect.buffer, expect.length); + + +#test castReference +HextFile rs("packets/icmp6_multicast_listener_report.hext"); + +IPv6HopByHopPacket *packetRef = (IPv6HopByHopPacket *)rs.buffer; +ck_assert(packetRef->isValid()); + +IPv6HopByHopPacket& packet = (IPv6HopByHopPacket &)rs.buffer; +ck_assert(packet.isValid()); diff --git a/tests/packets/icmp6_multicast_listener_query.hext b/tests/packets/icmp6_multicast_listener_query.hext new file mode 100644 index 0000000..8edf418 --- /dev/null +++ b/tests/packets/icmp6_multicast_listener_query.hext @@ -0,0 +1,25 @@ +33:33:00:00:00:01 # Ethernet Destination +60:e3:27:4f:f0:6b # Ethernet Source +86dd # EtherType (IPv6) + +60 00 00 00 # IPv6 header +0020 # Length (32 bytes) +00 # IPv6HbH Protocol +01 # Hop Limit + + +fe80:0000:0000:0000:62e3:27ff:fe4f:f06b # IPv6 Source Address +ff02:0000:0000:0000:0000:0000:0000:0001 # IPv6 Destination Address + +3a # Next Header (ICMPv6) +00 # Length +05 02 00 00 # Router Alert +00 00 # Padding + +82 # ICMPv6 multicast listener query (130) +00 # ICMPv6 Code +f301 # Checksum +1388 # Maximum response delay (5000ms) +0000 # Reserved + +0000:0000:0000:0000:0000:0000:0000:0000 # Multicast Address \ No newline at end of file diff --git a/tests/packets/icmp6_multicast_listener_report.hext b/tests/packets/icmp6_multicast_listener_report.hext new file mode 100644 index 0000000..8cb8fe9 --- /dev/null +++ b/tests/packets/icmp6_multicast_listener_report.hext @@ -0,0 +1,24 @@ +33:33:ff:36:14:b9 # Ethernet Destination +c8:5b:76:f4:21:34 # Ethernet Source +86dd # EtherType (IPv6) + +60 00 00 00 # IPv6 header +0020 # Length (32 bytes) +00 # IPv6HbH Protocol +01 # Hop Limit + +fe80:0000:0000:0000:f697:307e:e636:14b9 # IPv6 Source Address +ff02:0000:0000:0000:0000:0001:ff36:14b9 # IPv6 Destination Address + +3a # Next Header (ICMPv6) +00 # Length +05 02 00 00 # Router Alert +01 00 # Padding + +83 # ICMPv6 multicast listener report (131) +00 # ICMPv6 Code +363e # Checksum +0000 # Maximum response delay (5000ms) +0000 # Reserved + +ff02:0000:0000:0000:0000:0001:ff36:14b9 # Multicast Address \ No newline at end of file diff --git a/tests/packets/ipv6hbh_empty.hext b/tests/packets/ipv6hbh_empty.hext new file mode 100644 index 0000000..701e0c8 --- /dev/null +++ b/tests/packets/ipv6hbh_empty.hext @@ -0,0 +1,15 @@ +36:b4:40:75:3b:a6 # Ethernet Destination +a6:69:c0:80:da:3b # Ethernet Source +86dd # EtherType (IPv6) + +60 00 00 00 # IPv6 header +0008 # Length (0 bytes) +00 # Protocol (0xfe = Use for experimentation and testing) +01 # Hop Limit + +fe80:0000:0000:0000:a469:c0ff:fe80:da3b # IPv6 Source Address +fe80:0000:0000:0000:34b4:40ff:fe75:3ba6 # IPv6 Destination Address + +fe # Next header +00 # Length +00 00 00 00 00 00 # Padding \ No newline at end of file