summaryrefslogtreecommitdiff
path: root/src/user
diff options
context:
space:
mode:
authordzwdz2022-08-21 15:16:46 +0200
committerdzwdz2022-08-21 15:16:46 +0200
commit2c3df5122edc3aaee5f8d3776a7d296310a5021e (patch)
treebb07299a18a7ffa46c036b1bb65f53db9ea0dfb3 /src/user
parent85b853189e59cb58cdd35a7e9e9ec23997fc42db (diff)
user/ethdump: fragment sent packets
Diffstat (limited to 'src/user')
-rw-r--r--src/user/app/ethdump/ipv4.c36
1 files changed, 22 insertions, 14 deletions
diff --git a/src/user/app/ethdump/ipv4.c b/src/user/app/ethdump/ipv4.c
index fda0c0c..3243d3c 100644
--- a/src/user/app/ethdump/ipv4.c
+++ b/src/user/app/ethdump/ipv4.c
@@ -183,25 +183,33 @@ void ipv4_parse(const uint8_t *buf, size_t len, struct ethernet ether) {
}
}
+static uint16_t next_id = 0;
void ipv4_send(const void *payload, size_t len, struct ipv4 ip) {
- size_t hdrlen = 20;
+ const size_t mtu = 1500;
+ const size_t hdrlen = 20;
ip.e.type = ET_IPv4;
if (!ip.src) ip.src = state.ip;
if (!ip.e.dst && ip.dst == 0xFFFFFFFF)
ip.e.dst = &MAC_BROADCAST;
- // TODO output fragmentation
-
- uint8_t *pkt = ether_start(hdrlen + len, ip.e);
- pkt[Version] = 0x40;
- pkt[HdrLen] |= hdrlen / 4;
- nput16(pkt + TotalLen, len + hdrlen);
- pkt[TTL] = 0xFF;
- pkt[Proto] = ip.proto;
- nput32(pkt + SrcIP, ip.src);
- nput32(pkt + DstIP, ip.dst);
- nput16(pkt + Checksum, ip_checksum(pkt, hdrlen));
- memcpy(pkt + hdrlen, payload, len);
- ether_finish(pkt);
+ uint16_t id = next_id++;
+ for (size_t off = 0, fraglen = mtu - hdrlen; off < len; off += fraglen) {
+ if (fraglen > len - off)
+ fraglen = len - off;
+ bool last = off + fraglen >= len;
+ uint8_t *pkt = ether_start(hdrlen + fraglen, ip.e);
+ pkt[Version] = 0x40;
+ pkt[HdrLen] |= hdrlen / 4;
+ nput16(pkt + TotalLen, hdrlen + fraglen);
+ nput16(pkt + Id, id);
+ nput16(pkt + FragInfo, (off >> 3) | (last ? 0 : MoreFrags));
+ pkt[TTL] = 0xFF;
+ pkt[Proto] = ip.proto;
+ nput32(pkt + SrcIP, ip.src);
+ nput32(pkt + DstIP, ip.dst);
+ nput16(pkt + Checksum, ip_checksum(pkt, hdrlen));
+ memcpy(pkt + hdrlen, payload + off, fraglen);
+ ether_finish(pkt);
+ }
}