Skip to content

Commit bd6e40d

Browse files
committed
Expose FreeRTOS+TCP checksum APIs to the firewall.
Signed-off-by: Hugo Lefeuvre <[email protected]> (cherry picked from commit af215ef)
1 parent 14aa581 commit bd6e40d

File tree

2 files changed

+85
-0
lines changed

2 files changed

+85
-0
lines changed

lib/tcpip/checksum-internal.h

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// Copyright SCI Semiconductor and CHERIoT Contributors.
2+
// SPDX-License-Identifier: MIT
3+
4+
#pragma once
5+
#include <compartment-macros.h>
6+
#include <stddef.h>
7+
#include <stdint.h>
8+
/**
9+
* Internal APIs that the TCP/IP compartment exposes for the firewall to use.
10+
*
11+
* These should be called only from the firewall compartment (validated by
12+
* checking the compartment linkage report). These APIs trust the caller and
13+
* do *not* check arguments.
14+
*/
15+
16+
/**
17+
* Returns the IPv4 checksum for passed packet.
18+
*
19+
* This function is stateless and can be called at any point of the lifetime of
20+
* the TCP/IP stack.
21+
*
22+
* The IPv4 header (only) should be passed in `ipv4Header`, along with its
23+
* length in `headerLength`.
24+
*
25+
* The returned checksum is in network byte order and can be used as-is for
26+
* transmission in the IPv4 header.
27+
*/
28+
uint16_t __cheri_compartment("TCPIP")
29+
network_calculate_ipv4_checksum(const uint8_t *ipv4Header,
30+
size_t headerLength);
31+
32+
/**
33+
* Returns the TCP checksum for passed packet.
34+
*
35+
* This function is stateless and can be called at any point of the lifetime of
36+
* the TCP/IP stack.
37+
*
38+
* Unlike `network_calculate_ipv4_checksum`, this takes the entire Ethernet
39+
* frame into `frame`, along with its length in `frameLength`.
40+
*
41+
* The offset of the TCP checksum in the `frame` buffer must be passed in
42+
* `tcpChecksumOffset`.
43+
*
44+
* The returned checksum is in network byte order and can be used as-is for
45+
* transmission in the TCP header.
46+
*/
47+
uint16_t __cheri_compartment("TCPIP")
48+
network_calculate_tcp_checksum(const uint8_t *frame,
49+
size_t frameLength,
50+
size_t tcpChecksumOffset);

lib/tcpip/network_wrapper.cc

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <tcpip_error_handler.h>
88

99
#include "../firewall/firewall.hh"
10+
#include "checksum-internal.h"
1011
#include "network-internal.h"
1112
#include "tcpip-internal.h"
1213

@@ -472,6 +473,40 @@ namespace
472473
}
473474
} // namespace
474475

476+
uint16_t network_calculate_ipv4_checksum(const uint8_t *ipv4Header,
477+
size_t headerLength)
478+
{
479+
// Note: no restarting checks because stateless.
480+
481+
// `usGenerateChecksum` returns a checksum which is 1) not negated (we
482+
// must bitwise NOT it) and 2) in host byte order.
483+
return htons(~usGenerateChecksum(
484+
0 /* generate checksum for the full packet */, ipv4Header, headerLength));
485+
}
486+
487+
uint16_t network_calculate_tcp_checksum(const uint8_t *frame,
488+
size_t frameLength,
489+
size_t tcpChecksumOffset)
490+
{
491+
// Note: no restarting checks because stateless.
492+
493+
// `usGenerateProtocolChecksum` *writes* the checksum into the packet
494+
// buffer. It is not possible to have it return the checksum instead of
495+
// modifying the buffer. This is really annoying because we only have a
496+
// read-only capability to the frame, as we want to *return* the
497+
// checksum.
498+
//
499+
// To workaround this, make a local copy of the Ethernet frame and
500+
// extract the computed checksum from it using `tcpChecksumOffset`.
501+
// Putting this copy on the stack should be fine since this is only
502+
// used in RST packets which have no payload.
503+
uint8_t copy[frameLength];
504+
memcpy(copy, frame, frameLength);
505+
uint16_t *checksum = reinterpret_cast<uint16_t *>(&copy[tcpChecksumOffset]);
506+
usGenerateProtocolChecksum(copy, frameLength, true /* write checksum */);
507+
return *checksum;
508+
}
509+
475510
int network_host_resolve(const char *hostname,
476511
bool useIPv6,
477512
NetworkAddress *address)

0 commit comments

Comments
 (0)