Browse Source

[2902] Moved protocol utility functions to a separate file.

Marcin Siodelski 12 years ago
parent
commit
edd0b06234
4 changed files with 184 additions and 83 deletions
  1. 1 0
      src/lib/dhcp/Makefile.am
  2. 24 83
      src/lib/dhcp/pkt_filter_lpf.cc
  3. 94 0
      src/lib/dhcp/protocol_util.cc
  4. 65 0
      src/lib/dhcp/protocol_util.h

+ 1 - 0
src/lib/dhcp/Makefile.am

@@ -33,6 +33,7 @@ libb10_dhcp___la_SOURCES += option_custom.cc option_custom.h
 libb10_dhcp___la_SOURCES += option_data_types.cc option_data_types.h
 libb10_dhcp___la_SOURCES += option_definition.cc option_definition.h
 libb10_dhcp___la_SOURCES += option_space.cc option_space.h
+libb10_dhcp___la_SOURCES += protocol_util.cc protocol_util.h
 libb10_dhcp___la_SOURCES += pkt6.cc pkt6.h
 libb10_dhcp___la_SOURCES += pkt4.cc pkt4.h
 libb10_dhcp___la_SOURCES += pkt_filter.h

+ 24 - 83
src/lib/dhcp/pkt_filter_lpf.cc

@@ -16,94 +16,17 @@
 #include <dhcp/iface_mgr.h>
 #include <dhcp/pkt4.h>
 #include <dhcp/pkt_filter_lpf.h>
+#include <dhcp/protocol_util.h>
 #include <exceptions/exceptions.h>
 
 #include <linux/if_ether.h>
 #include <linux/if_packet.h>
-#include <netinet/ip.h>
-#include <netinet/udp.h>
 
 using namespace isc::util;
 
 namespace isc {
 namespace dhcp {
 
-void
-PktFilterLPF::assembleEthernetHeader(const Iface& iface,
-                                     const Pkt4Ptr& pkt,
-                                     util::OutputBuffer& out_buf) {
-
-    std::vector<uint8_t> dest_addr = pkt->getHWAddr()->hwaddr_;
-    if (dest_addr.empty()) {
-        dest_addr.resize(HWAddr::ETHERNET_HWADDR_LEN);
-    }
-    out_buf.writeData(&dest_addr[0], dest_addr.size());
-    out_buf.writeData(iface.getMac(), iface.getMacLen());
-
-    out_buf.writeUint16(0x0800);
-}
-
-void
-PktFilterLPF::assembleIpUdpHeader(const Pkt4Ptr& pkt,
-                                  util::OutputBuffer& out_buf) {
-
-    struct ip ip_hdr;
-    memset(&ip_hdr, 0, sizeof(ip_hdr));
-    ip_hdr.ip_hl = (ip_hdr.ip_hl | 5) & 0xF;
-    ip_hdr.ip_v = (ip_hdr.ip_v | 4) & 0xF;
-    ip_hdr.ip_tos = IPTOS_LOWDELAY;
-    ip_hdr.ip_len = htons(sizeof(ip) + sizeof(udphdr) +
-                          pkt->getBuffer().getLength());
-    ip_hdr.ip_id = 0;
-    ip_hdr.ip_off = 0;
-    ip_hdr.ip_ttl = 128;
-    ip_hdr.ip_p = IPPROTO_UDP;
-    ip_hdr.ip_src.s_addr = htonl(pkt->getLocalAddr());
-    ip_hdr.ip_dst.s_addr = htonl(pkt->getRemoteAddr());
-    ip_hdr.ip_sum = checksumFinish(checksum(reinterpret_cast<const char*>(&ip_hdr),
-                                            sizeof(ip_hdr)));
-
-    out_buf.writeData(static_cast<void*>(&ip_hdr), sizeof(ip_hdr));
-
-    struct udphdr udp_hdr;
-    memset(&udp_hdr, 0, sizeof(udp_hdr));
-    udp_hdr.source = htons(pkt->getLocalPort());
-    udp_hdr.dest = htons(pkt->getRemotePort());
-    udp_hdr.len = htons(sizeof(udp_hdr) + pkt->getBuffer().getLength());
-    udp_hdr.check = 0;
-
-    out_buf.writeData(static_cast<void*>(&udp_hdr), sizeof(udp_hdr));
-
-}
-
-uint16_t
-PktFilterLPF::checksum(const char* buf, const uint32_t buf_size,
-                       uint32_t sum) {
-
-    uint32_t i;
-    for (i = 0; i < (buf_size & ~1U); i += 2) {
-        uint16_t chunk = buf[i] << 8 | buf[i+1];
-        sum += chunk;
-        if (sum > 0xFFFF) {
-            sum -= 0xFFFF;
-        }
-    }
-
-    if (i < buf_size) {
-        sum += buf[i] << 8;
-        if (sum > 0xFFFF) {
-            sum -= 0xFFFF;
-        }
-    }
-
-    return (sum);
-}
-
-uint16_t
-PktFilterLPF::checksumFinish(uint16_t sum) {
-    return (htons(~sum));
-}
-
 int
 PktFilterLPF::openSocket(const Iface& iface, const isc::asiolink::IOAddress&,
                          const uint16_t, const bool,
@@ -131,9 +54,19 @@ PktFilterLPF::openSocket(const Iface& iface, const isc::asiolink::IOAddress&,
 }
 
 Pkt4Ptr
-PktFilterLPF::receive(const Iface&, const SocketInfo&) {
-    isc_throw(isc::NotImplemented,
-              "Linux Packet Filtering is not implemented yet");
+PktFilterLPF::receive(const Iface&, const SocketInfo& socket_info) {
+    // @todo: implement this function
+    unsigned char buf[1536];
+    int data_len = read(socket_info.sockfd_, buf, sizeof(buf));
+    if (data_len <= 0) {
+        return Pkt4Ptr();
+    }
+
+    // Length of the Ethernet, IP and UDP.
+    int data_offset = 42;
+    Pkt4Ptr pkt = Pkt4Ptr(new Pkt4(buf + data_offset,
+                                   data_len - data_offset));
+    return (pkt);
 }
 
 int
@@ -141,9 +74,17 @@ PktFilterLPF::send(const Iface& iface, uint16_t sockfd, const Pkt4Ptr& pkt) {
 
     OutputBuffer buf(14);
 
-    assembleEthernetHeader(iface, pkt, buf);
-    assembleIpUdpHeader(pkt, buf);
+    // Ethernet frame header
+    std::vector<uint8_t> dest_addr = pkt->getHWAddr()->hwaddr_;
+    if (dest_addr.empty()) {
+        dest_addr.resize(HWAddr::ETHERNET_HWADDR_LEN);
+    }
+    writeEthernetHeader(iface.getMac(), &dest_addr[0], buf);
+
+    // IP and UDP header
+    writeIpUdpHeader(pkt, buf);
 
+    // DHCPv4 message
     buf.writeData(pkt->getBuffer().getData(), pkt->getBuffer().getLength());
 
     sockaddr_ll sa;

+ 94 - 0
src/lib/dhcp/protocol_util.cc

@@ -0,0 +1,94 @@
+// Copyright (C) 2013  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <protocol_util.h>
+
+#include <netinet/ip.h>
+#include <netinet/udp.h>
+
+namespace isc {
+namespace dhcp {
+
+void
+writeEthernetHeader(const uint8_t* src_hw_addr, const uint8_t* dest_hw_addr,
+                         util::OutputBuffer& out_buf) {
+    // Write destination and source address.
+    out_buf.writeData(dest_hw_addr, HWAddr::ETHERNET_HWADDR_LEN);
+    out_buf.writeData(src_hw_addr, HWAddr::ETHERNET_HWADDR_LEN);
+    // Type IP.
+    out_buf.writeUint16(0x0800);
+}
+
+void
+writeIpUdpHeader(const Pkt4Ptr& pkt, util::OutputBuffer& out_buf) {
+
+    struct ip ip_hdr;
+    memset(&ip_hdr, 0, sizeof(ip_hdr));
+    ip_hdr.ip_hl = (ip_hdr.ip_hl | 5) & 0xF;
+    ip_hdr.ip_v = (ip_hdr.ip_v | 4) & 0xF;
+    ip_hdr.ip_tos = IPTOS_LOWDELAY;
+    ip_hdr.ip_len = htons(sizeof(ip) + sizeof(udphdr) +
+                          pkt->getBuffer().getLength());
+    ip_hdr.ip_id = 0;
+    ip_hdr.ip_off = 0;
+    ip_hdr.ip_ttl = 128;
+    ip_hdr.ip_p = IPPROTO_UDP;
+    ip_hdr.ip_src.s_addr = htonl(pkt->getLocalAddr());
+    ip_hdr.ip_dst.s_addr = htonl(pkt->getRemoteAddr());
+    ip_hdr.ip_sum =
+        wrapChecksum(calculateChecksum(reinterpret_cast<const char*>(&ip_hdr),
+                                       sizeof(ip_hdr)));
+
+    out_buf.writeData(static_cast<void*>(&ip_hdr), sizeof(ip_hdr));
+
+    struct udphdr udp_hdr;
+    memset(&udp_hdr, 0, sizeof(udp_hdr));
+    udp_hdr.source = htons(pkt->getLocalPort());
+    udp_hdr.dest = htons(pkt->getRemotePort());
+    udp_hdr.len = htons(sizeof(udp_hdr) + pkt->getBuffer().getLength());
+    udp_hdr.check = 0;
+
+    out_buf.writeData(static_cast<void*>(&udp_hdr), sizeof(udp_hdr));
+
+}
+
+uint16_t
+calculateChecksum(const char* buf, const uint32_t buf_size, uint32_t sum) {
+    uint32_t i;
+    for (i = 0; i < (buf_size & ~1U); i += 2) {
+        uint16_t chunk = buf[i] << 8 | buf[i+1];
+        sum += chunk;
+        if (sum > 0xFFFF) {
+            sum -= 0xFFFF;
+        }
+    }
+
+    if (i < buf_size) {
+        sum += buf[i] << 8;
+        if (sum > 0xFFFF) {
+            sum -= 0xFFFF;
+        }
+    }
+
+    return (sum);
+
+}
+
+uint16_t
+wrapChecksum(uint16_t sum) {
+    return (htons(~sum));
+}
+
+}
+}

+ 65 - 0
src/lib/dhcp/protocol_util.h

@@ -0,0 +1,65 @@
+// Copyright (C) 2013  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef PROTOCOL_UTIL_H
+#define PROTOCOL_UTIL_H
+
+#include <dhcp/pkt4.h>
+#include <util/buffer.h>
+
+#include <stdint.h>
+
+namespace isc {
+namespace dhcp {
+
+/// @brief Writes ethernet frame header into a buffer.
+///
+/// @param src_hw_addr source HW address.
+/// @param dst_hw_addr destination HW address.
+/// @param [out] out_buf buffer where a header is written.
+void writeEthernetHeader(const uint8_t* src_hw_addr,
+                         const uint8_t* dest_hw_addr,
+                         util::OutputBuffer& out_buf);
+
+/// @brief Writes both IP and UDP header into output buffer
+///
+/// This utility function assembles IP and UDP packet headers for the
+/// provided DHCPv4 message. The source and destination addreses and
+/// ports stored in the Pkt4 object are copied as source and destination
+/// addresses and ports into IP/UDP headers.
+///
+/// @param pkt DHCPv4 packet to be sent in IP packet
+/// @param [out] out_buf buffer where an IP header is written
+void writeIpUdpHeader(const Pkt4Ptr& pkt, util::OutputBuffer& out_buf);
+
+/// @brief Calculates checksum for provided buffer
+///
+/// @param buf buffer for which the checksum is calculated.
+/// @param buf_size size of the buffer for which checksum is calculated.
+/// @param sum initial checksum value.
+///
+/// @return calculated checksum.
+uint16_t calculateChecksum(const char* buf, const uint32_t buf_size,
+                           uint32_t sum = 0);
+
+/// @brief Wraps the calculated checksum and stores it in network byte order.
+///
+/// @param sum calculated checksum
+///
+/// @return wrapped checksum value.
+uint16_t wrapChecksum(uint16_t sum);
+
+}
+}
+#endif // PROTOCOL_UTIL_H