diff --git a/sys/include/net/inet_csum.h b/sys/include/net/inet_csum.h
index 53134053f6267618f919ad8b5190353544ee9558..6356e96998154526467cf64df9e7ee5cc94276e9 100644
--- a/sys/include/net/inet_csum.h
+++ b/sys/include/net/inet_csum.h
@@ -21,13 +21,15 @@
 #define INET_CSUM_H_
 
 #include <inttypes.h>
+#include <stddef.h>
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
 /**
- * @brief   Calculates the unnormalized Internet Checksum of @p buf.
+ * @brief   Calculates the unnormalized Internet Checksum of @p buf, where the
+ *          buffer provides a slice of the full checksum domain, calculated in order.
  *
  * @see <a href="https://tools.ietf.org/html/rfc1071">
  *          RFC 1071
@@ -35,14 +37,41 @@ extern "C" {
  *
  * @details The Internet Checksum is not normalized (i. e. its 1's complement
  *          was not taken of the result) to use it for further calculation.
+ *          This function handles padding an odd number of bytes across the full domain.
  *
- * @param[in] sum   An initial value for the checksum.
- * @param[in] buf   A buffer.
- * @param[in] len   Length of @p buf in byte.
+ * @param[in] sum       An initial value for the checksum.
+ * @param[in] buf       A buffer.
+ * @param[in] len       Length of @p buf in byte.
+ * @param[in] accum_len Accumulated length of checksum domain that has already
+ *                      been checksummed.
  *
  * @return  The unnormalized Internet Checksum of @p buf.
  */
-uint16_t inet_csum(uint16_t sum, const uint8_t *buf, uint16_t len);
+uint16_t inet_csum_slice(uint16_t sum, const uint8_t *buf, uint16_t len, size_t accum_len);
+
+/**
+ * @brief   Calculates the unnormalized Internet Checksum of @p buf, where the
+ *          buffer provides a standalone domain for the checksum.
+ *
+ * @see <a href="https://tools.ietf.org/html/rfc1071">
+ *          RFC 1071
+ *      </a>
+ *
+ * @details The Internet Checksum is not normalized (i. e. its 1's complement
+ *          was not taken of the result) to use it for further calculation.
+ *          This function, rather than inet_csum_slice(), has been used historically
+ *          when we are not concerned with padding for an odd number of bytes.
+ *
+ *
+ * @param[in] sum       An initial value for the checksum.
+ * @param[in] buf       A buffer.
+ * @param[in] len       Length of @p buf in byte.
+ *
+ * @return  The unnormalized Internet Checksum of @p buf.
+ */
+static inline uint16_t inet_csum(uint16_t sum, const uint8_t *buf, uint16_t len) {
+    return inet_csum_slice(sum, buf, len, 0);
+}
 
 #ifdef __cplusplus
 }
diff --git a/sys/net/crosslayer/inet_csum/inet_csum.c b/sys/net/crosslayer/inet_csum/inet_csum.c
index c53c025d6021d5782e5893db0069e74cf58da2ee..4a125fab7f5668cdef64d604fd16a4f3da04bfd3 100644
--- a/sys/net/crosslayer/inet_csum/inet_csum.c
+++ b/sys/net/crosslayer/inet_csum/inet_csum.c
@@ -20,7 +20,7 @@
 #define ENABLE_DEBUG    (0)
 #include "debug.h"
 
-uint16_t inet_csum(uint16_t sum, const uint8_t *buf, uint16_t len)
+uint16_t inet_csum_slice(uint16_t sum, const uint8_t *buf, uint16_t len, size_t accum_len)
 {
     uint32_t csum = sum;
 
@@ -34,14 +34,23 @@ uint16_t inet_csum(uint16_t sum, const uint8_t *buf, uint16_t len)
 #endif
 #endif
 
+    if (len == 0)
+        return csum;
+
+    if (accum_len & 1) {      /* if accumulated length is odd */
+        csum += *buf;         /* add first byte as bottom half of 16-byte word */
+        buf++;
+        len--;
+        accum_len++;
+    }
+
     for (int i = 0; i < (len >> 1); buf += 2, i++) {
         csum += (*buf << 8) + *(buf + 1);   /* group bytes by 16-byte words
                                              * and add them*/
     }
 
-    if (len & 1) {                      /* if len is odd */
-        csum += (*buf << 8);            /* add last byte as top half of 16-byte word */
-    }
+    if ((accum_len + len) & 1)      /* if accumulated length is odd */
+        csum += (*buf << 8);        /* add last byte as top half of 16-byte word */
 
     while (csum >> 16) {
         uint16_t carry = csum >> 16;
diff --git a/sys/net/gnrc/network_layer/icmpv6/gnrc_icmpv6.c b/sys/net/gnrc/network_layer/icmpv6/gnrc_icmpv6.c
index b85e7166db24b90576dba3d1574385b6db3a4286..c2d70fc0219a52caf25f66dd0677b8ca8857b028 100644
--- a/sys/net/gnrc/network_layer/icmpv6/gnrc_icmpv6.c
+++ b/sys/net/gnrc/network_layer/icmpv6/gnrc_icmpv6.c
@@ -42,7 +42,7 @@ static inline uint16_t _calc_csum(gnrc_pktsnip_t *hdr,
     uint16_t len = (uint16_t)hdr->size;
 
     while (payload && (payload != hdr)) {
-        csum = inet_csum(csum, payload->data, payload->size);
+        csum = inet_csum_slice(csum, payload->data, payload->size, len);
         len += (uint16_t)payload->size;
         payload = payload->next;
     }
diff --git a/sys/net/gnrc/transport_layer/udp/gnrc_udp.c b/sys/net/gnrc/transport_layer/udp/gnrc_udp.c
index e630d3d088a0e4393345e05bc462241f63341701..28034a53802a918ba2a3bbb4692d2cb694d5deb0 100644
--- a/sys/net/gnrc/transport_layer/udp/gnrc_udp.c
+++ b/sys/net/gnrc/transport_layer/udp/gnrc_udp.c
@@ -69,7 +69,7 @@ static uint16_t _calc_csum(gnrc_pktsnip_t *hdr, gnrc_pktsnip_t *pseudo_hdr,
 
     /* process the payload */
     while (payload && payload != hdr) {
-        csum = inet_csum(csum, (uint8_t *)(payload->data), payload->size);
+        csum = inet_csum_slice(csum, (uint8_t *)(payload->data), payload->size, len);
         len += (uint16_t)payload->size;
         payload = payload->next;
     }
diff --git a/tests/unittests/tests-inet_csum/tests-inet_csum.c b/tests/unittests/tests-inet_csum/tests-inet_csum.c
index 1af7299ca02df0f4551183038c65e4c60946c57c..ebb40e6e04c8118d04f0bcedb82dc1de763e8525 100644
--- a/tests/unittests/tests-inet_csum/tests-inet_csum.c
+++ b/tests/unittests/tests-inet_csum/tests-inet_csum.c
@@ -121,6 +121,50 @@ static void test_inet_csum__odd_len(void)
     TEST_ASSERT_EQUAL_INT(0xffff, inet_csum(17 + 39, data, sizeof(data)));
 }
 
+static void test_inet_csum__two_app_snips(void)
+{
+    /* CoAP header with Uri-Path and Content-Format options; odd length */
+    uint8_t data_hdr[] = {
+        0x50, 0x02, 0x00, 0x01, 0xb4, 0x74, 0x65, 0x73,
+        0x74, 0x10, 0xff,
+    };
+    /* Single character payload, 'a' */
+    uint8_t data_pyld[] = {
+        0x61,
+    };
+    uint16_t hdr_sum, pyld_sum, hdr_expected = 0xdcfc;
+
+    /* result unnormalized:
+     * initial sum (0) is arbitrary, and incoming length (0) must be even;
+     * we expect last byte is shifted left for this odd-sized header  */
+    hdr_sum = inet_csum_slice(0, data_hdr, sizeof(data_hdr), 0);
+    TEST_ASSERT_EQUAL_INT(hdr_expected, hdr_sum);
+
+    /* Since header was odd length, we expect the single byte in the payload
+     * snip is not shifted left */
+    pyld_sum = inet_csum_slice(hdr_expected, data_pyld, sizeof(data_pyld), sizeof(data_hdr));
+    TEST_ASSERT_EQUAL_INT(hdr_expected + 0x61, pyld_sum);
+}
+
+static void test_inet_csum__empty_app_buffer(void)
+{
+    /* CoAP header with Uri-Path and Content-Format options; odd length */
+    uint8_t data_hdr[] = {
+        0x50, 0x02, 0x00, 0x01, 0xb4, 0x74, 0x65, 0x73,
+        0x74, 0x10, 0xff,
+    };
+    uint16_t hdr_sum, pyld_sum, hdr_expected = 0xdcfc;
+
+    /* result unnormalized:
+     * explictly using an odd-sized header for the first slice, to setup corner case  */
+    hdr_sum = inet_csum_slice(0, data_hdr, sizeof(data_hdr), 0);
+    TEST_ASSERT_EQUAL_INT(hdr_expected, hdr_sum);
+
+    /* expect an empty buffer simply to reflect the incoming checksum */
+    pyld_sum = inet_csum_slice(hdr_expected, NULL, 0, sizeof(data_hdr));
+    TEST_ASSERT_EQUAL_INT(hdr_expected, pyld_sum);
+}
+
 Test *tests_inet_csum_tests(void)
 {
     EMB_UNIT_TESTFIXTURES(fixtures) {
@@ -130,6 +174,8 @@ Test *tests_inet_csum_tests(void)
         new_TestFixture(test_inet_csum__wraps_more_than_once),
         new_TestFixture(test_inet_csum__calculate_csum),
         new_TestFixture(test_inet_csum__odd_len),
+        new_TestFixture(test_inet_csum__two_app_snips),
+        new_TestFixture(test_inet_csum__empty_app_buffer),
     };
 
     EMB_UNIT_TESTCALLER(inet_csum_tests, NULL, NULL, fixtures);