mirror of
https://github.com/cesanta/mongoose.git
synced 2026-11-12 16:50:21 +00:00
Make mip-pcap work on Mac
This commit is contained in:
1 parent
9dea02e578
commit
b2624f6055
5 files changed
+220
-148
No files matched your search
@@ -0,0 +1,47 @@
|
|||||||
|
#MIP TCP / IP stack over pcap
|
||||||
|
|
||||||
|
This example allows to use Mongoose's MIP built-in TCP/IP stack on systems
|
||||||
|
that support pcap API, i.e. have libpcap library installed. The application
|
||||||
|
opens an interface and uses `pcap_next_ex()` for reading packets from the
|
||||||
|
interface, and `pcap_inject()` to write packets to the interface.
|
||||||
|
|
||||||
|
NOTE: depending on the libcap implementation, the injected packets may
|
||||||
|
or may not be looped back to the interface's TCP/IP stack. If they are
|
||||||
|
not looped back, then it is necessary to create a separate interface that
|
||||||
|
is bridged to the target interface - see MacOS example below.
|
||||||
|
|
||||||
|
## MacOS setup
|
||||||
|
|
||||||
|
MacOS has support for `feth` (fake ethernet) interfaces. One can create a pair
|
||||||
|
of `feth` interfaces and interlink them. Once a `feth` interface is assigned
|
||||||
|
a peer and an IP address, anything that gets injected to it, appears on a
|
||||||
|
peer interface and vice versa.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ sudo ifconfig feth0 create
|
||||||
|
$ sudo ifconfig feth1 create
|
||||||
|
$ sudo ifconfig feth1 peer feth 0 # Link two fake ethernet ifaces together
|
||||||
|
$ sudo ifconfig feth1 10.10 # Assign 10.0.0.10 to feth1
|
||||||
|
$ sudo ifconfig feth0 up
|
||||||
|
$ sudo ifconfig feth1 up
|
||||||
|
```
|
||||||
|
|
||||||
|
Now we have two Ethernet interfaces, `feth0` and `feth1`, interlinked and active.
|
||||||
|
On your Mac, go to "System Preferences" / Sharing, enable "Internet Sharing"
|
||||||
|
and choose "Thunderbolt bridge". This enables DHCP on the `bridge0` interface.
|
||||||
|
On my system it gets `192.168.2.1` IP address, and serves `192.168.2/24` net.
|
||||||
|
which is bridge for all Thunderbolt devices, and adds necessary routes to the
|
||||||
|
WiFi interface. We should add one of our fake interfaces to this bridge:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ sudo ifconfig bridge0 addm feth1
|
||||||
|
```
|
||||||
|
|
||||||
|
We cat start an example using the `feth0`:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ make -C examples/mip-pcap/ clean all ARGS="-i feth0"
|
||||||
|
...
|
||||||
|
2386718 3 mip.c:279:arp_cache_add ARP cache: added 0xc0a80201 @ 36:77:4d:be:e0:80
|
||||||
|
2386718 2 mip.c:300:onstatechange READY, IP: 192.168.2.17
|
||||||
|
```
|
||||||
+51
-40
@@ -6,45 +6,22 @@
|
|||||||
#include <pcap.h>
|
#include <pcap.h>
|
||||||
#include "mongoose.h"
|
#include "mongoose.h"
|
||||||
|
|
||||||
static struct mg_connection *s_sntp_conn = NULL;
|
#define MQTT_URL "mqtt://broker.hivemq.com:1883" // MQTT broker to connect to
|
||||||
|
#define MQTT_TOPIC "t/123" // Topic to subscribe to
|
||||||
|
|
||||||
static int s_signo;
|
static int s_signo;
|
||||||
void signal_handler(int signo) {
|
void signal_handler(int signo) {
|
||||||
s_signo = signo;
|
s_signo = signo;
|
||||||
}
|
}
|
||||||
|
|
||||||
// SNTP client callback
|
static size_t pcap_tx(const void *buf, size_t len, void *userdata) {
|
||||||
static void sfn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
int res = pcap_inject((pcap_t *) userdata, buf, len);
|
||||||
if (ev == MG_EV_SNTP_TIME) {
|
|
||||||
int64_t t = *(int64_t *) ev_data;
|
|
||||||
MG_INFO(("Got SNTP time: %lld ms from epoch", t));
|
|
||||||
} else if (ev == MG_EV_CLOSE) {
|
|
||||||
s_sntp_conn = NULL;
|
|
||||||
}
|
|
||||||
(void) fn_data, (void) c;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Called every 5 seconds. Increase that for production case.
|
|
||||||
static void timer_fn(void *arg) {
|
|
||||||
struct mg_mgr *mgr = (struct mg_mgr *) arg;
|
|
||||||
if (s_sntp_conn == NULL) s_sntp_conn = mg_sntp_connect(mgr, NULL, sfn, NULL);
|
|
||||||
if (s_sntp_conn != NULL) mg_sntp_request(s_sntp_conn);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int fail(const char *fmt, ...) {
|
|
||||||
va_list ap;
|
|
||||||
va_start(ap, fmt);
|
|
||||||
vfprintf(stderr, fmt, ap);
|
|
||||||
va_end(ap);
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t pcap_tx(const void *data, size_t len, void *userdata) {
|
|
||||||
int res = pcap_inject((pcap_t *) userdata, data, len);
|
|
||||||
if (res == PCAP_ERROR) {
|
if (res == PCAP_ERROR) {
|
||||||
MG_ERROR(("pcap_inject: %d", res));
|
MG_ERROR(("pcap_inject: %d", res));
|
||||||
}
|
}
|
||||||
return len;
|
MG_INFO(("TX %lu", len));
|
||||||
|
// mg_hexdump(buf, len);
|
||||||
|
return res == PCAP_ERROR ? 0 : len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool pcap_up(void *userdata) {
|
static bool pcap_up(void *userdata) {
|
||||||
@@ -58,21 +35,43 @@ static size_t pcap_rx(void *buf, size_t len, void *userdata) {
|
|||||||
if (pcap_next_ex((pcap_t *) userdata, &hdr, &pkt) == 1) {
|
if (pcap_next_ex((pcap_t *) userdata, &hdr, &pkt) == 1) {
|
||||||
received = hdr->len < len ? hdr->len : len;
|
received = hdr->len < len ? hdr->len : len;
|
||||||
memcpy(buf, pkt, received);
|
memcpy(buf, pkt, received);
|
||||||
|
MG_INFO(("RX %lu", received));
|
||||||
|
// mg_hexdump(buf, received);
|
||||||
}
|
}
|
||||||
return received;
|
return received;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||||
|
if (ev == MG_EV_HTTP_MSG) mg_http_reply(c, 200, NULL, "hi\n");
|
||||||
|
(void) fn_data, (void) ev_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
// MQTT event handler function
|
||||||
|
static void mfn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||||
|
if (ev == MG_EV_CONNECT && mg_url_is_ssl(MQTT_URL)) {
|
||||||
|
struct mg_tls_opts opts = {.ca = "ca.pem",
|
||||||
|
.srvname = mg_url_host(MQTT_URL)};
|
||||||
|
mg_tls_init(c, &opts);
|
||||||
|
} else if (ev == MG_EV_MQTT_OPEN) {
|
||||||
|
c->is_hexdumping = 1;
|
||||||
|
mg_mqtt_sub(c, mg_str(MQTT_TOPIC), 2);
|
||||||
|
} else if (ev == MG_EV_MQTT_MSG) {
|
||||||
|
struct mg_mqtt_message *mm = ev_data;
|
||||||
|
MG_INFO(("%.*s", (int) mm->data.len, mm->data.ptr));
|
||||||
|
} else if (ev == MG_EV_MQTT_CMD) {
|
||||||
|
struct mg_mqtt_message *mm = (struct mg_mqtt_message *) ev_data;
|
||||||
|
MG_DEBUG(("cmd %d qos %d", mm->cmd, mm->qos));
|
||||||
|
} else if (ev == MG_EV_CLOSE) {
|
||||||
|
}
|
||||||
|
(void) fn_data;
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
const char *iface = "lo0"; // Network iface
|
const char *iface = "lo0"; // Network iface
|
||||||
const char *mac = "aa:bb:cc:01:02:03"; // MAC address
|
const char *mac = "00:00:01:02:03:77"; // MAC address
|
||||||
const char *bpf = NULL; // "host x.x.x.x or ether host ff:ff:ff:ff:ff:ff";
|
const char *bpf = NULL; // "host x.x.x.x or ether host ff:ff:ff:ff:ff:ff";
|
||||||
char errbuf[PCAP_ERRBUF_SIZE] = "";
|
char errbuf[PCAP_ERRBUF_SIZE] = "";
|
||||||
|
|
||||||
struct mg_mgr mgr; // Event manager
|
|
||||||
mg_mgr_init(&mgr); // Initialise event manager
|
|
||||||
mg_log_set(MG_LL_DEBUG); // Set debug log level
|
|
||||||
mg_timer_add(&mgr, 3000, MG_TIMER_REPEAT | MG_TIMER_RUN_NOW, timer_fn, &mgr);
|
|
||||||
|
|
||||||
// Parse options
|
// Parse options
|
||||||
for (int i = 1; i < argc; i++) {
|
for (int i = 1; i < argc; i++) {
|
||||||
if (strcmp(argv[i], "-i") == 0 && i + 1 < argc) {
|
if (strcmp(argv[i], "-i") == 0 && i + 1 < argc) {
|
||||||
@@ -82,7 +81,8 @@ int main(int argc, char *argv[]) {
|
|||||||
} else if (strcmp(argv[i], "-bpf") == 0 && i + 1 < argc) {
|
} else if (strcmp(argv[i], "-bpf") == 0 && i + 1 < argc) {
|
||||||
bpf = argv[++i];
|
bpf = argv[++i];
|
||||||
} else {
|
} else {
|
||||||
return fail("unknown option %s", argv[i]);
|
MG_ERROR(("unknown option %s", argv[i]));
|
||||||
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,21 +97,27 @@ int main(int argc, char *argv[]) {
|
|||||||
}
|
}
|
||||||
pcap_freealldevs(devs);
|
pcap_freealldevs(devs);
|
||||||
}
|
}
|
||||||
fail("pcap_open_live: %s\n", errbuf);
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
pcap_setnonblock(ph, 1, errbuf);
|
pcap_setnonblock(ph, 1, errbuf);
|
||||||
|
pcap_setdirection(ph, PCAP_D_IN);
|
||||||
|
|
||||||
// Apply BPF to reduce noise. Let in only broadcasts and our own traffic
|
// Apply BPF to reduce noise. Let in only broadcasts and our own traffic
|
||||||
if (bpf != NULL) {
|
if (bpf != NULL) {
|
||||||
struct bpf_program bpfp;
|
struct bpf_program bpfp;
|
||||||
if (pcap_compile(ph, &bpfp, bpf, 1, 0)) fail("compile \n");
|
if (pcap_compile(ph, &bpfp, bpf, 1, 0)) MG_ERROR(("BPF compile failed\n"));
|
||||||
pcap_setfilter(ph, &bpfp);
|
pcap_setfilter(ph, &bpfp);
|
||||||
pcap_freecode(&bpfp);
|
pcap_freecode(&bpfp);
|
||||||
}
|
}
|
||||||
MG_INFO(("Opened interface %s\n", iface));
|
|
||||||
|
|
||||||
|
MG_INFO(("Opened interface %s", iface));
|
||||||
signal(SIGINT, signal_handler);
|
signal(SIGINT, signal_handler);
|
||||||
signal(SIGTERM, signal_handler);
|
signal(SIGTERM, signal_handler);
|
||||||
|
|
||||||
|
struct mg_mgr mgr; // Event manager
|
||||||
|
mg_mgr_init(&mgr); // Initialise event manager
|
||||||
|
mg_log_set(MG_LL_DEBUG); // Set debug log level
|
||||||
|
|
||||||
struct mip_cfg c = {.ip = 0, .mask = 0, .gw = 0};
|
struct mip_cfg c = {.ip = 0, .mask = 0, .gw = 0};
|
||||||
sscanf(mac, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &c.mac[0], &c.mac[1], &c.mac[2],
|
sscanf(mac, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &c.mac[0], &c.mac[1], &c.mac[2],
|
||||||
&c.mac[3], &c.mac[4], &c.mac[5]);
|
&c.mac[3], &c.mac[4], &c.mac[5]);
|
||||||
@@ -120,6 +126,11 @@ int main(int argc, char *argv[]) {
|
|||||||
mip_init(&mgr, &c, &driver, ph);
|
mip_init(&mgr, &c, &driver, ph);
|
||||||
MG_INFO(("Init done, starting main loop"));
|
MG_INFO(("Init done, starting main loop"));
|
||||||
|
|
||||||
|
mg_http_listen(&mgr, "http://0.0.0.0:8000", fn, NULL);
|
||||||
|
|
||||||
|
struct mg_mqtt_opts opts = {0};
|
||||||
|
// mg_mqtt_connect(&mgr, MQTT_URL, &opts, mfn, NULL);
|
||||||
|
|
||||||
while (s_signo == 0) mg_mgr_poll(&mgr, 1); // Infinite event loop
|
while (s_signo == 0) mg_mgr_poll(&mgr, 1); // Infinite event loop
|
||||||
|
|
||||||
mg_mgr_free(&mgr);
|
mg_mgr_free(&mgr);
|
||||||
|
|||||||
@@ -17,6 +17,12 @@
|
|||||||
#endif
|
#endif
|
||||||
#define MIP_ARP_CS (2 + 12 * MIP_ARP_ENTRIES) // ARP cache size
|
#define MIP_ARP_CS (2 + 12 * MIP_ARP_ENTRIES) // ARP cache size
|
||||||
|
|
||||||
|
struct connstate {
|
||||||
|
uint32_t seq, ack; // TCP seq/ack counters
|
||||||
|
uint64_t timer; // Used to send ACKs
|
||||||
|
uint8_t mac[6]; // Peer MAC address
|
||||||
|
};
|
||||||
|
|
||||||
struct str {
|
struct str {
|
||||||
uint8_t *buf;
|
uint8_t *buf;
|
||||||
size_t len;
|
size_t len;
|
||||||
@@ -238,14 +244,22 @@ static void arp_cache_init(uint8_t *p, int n, int size) {
|
|||||||
p[1] = p[3 + (n - 1) * size] = 2;
|
p[1] = p[3 + (n - 1) * size] = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void arp_cache_dump(const uint8_t *p) {
|
||||||
|
MG_INFO(("ARP cache:"));
|
||||||
|
for (uint8_t i = 0, j = p[1]; i < MIP_ARP_ENTRIES; i++, j = p[j + 1]) {
|
||||||
|
MG_INFO((" %d.%d.%d.%d -> %x:%x:%x:%x:%x:%x", p[j + 2], p[j + 3], p[j + 4],
|
||||||
|
p[j + 5], p[j + 6], p[j + 7], p[j + 8], p[j + 9], p[j + 10],
|
||||||
|
p[j + 11]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static uint8_t *arp_cache_find(struct mip_if *ifp, uint32_t ip) {
|
static uint8_t *arp_cache_find(struct mip_if *ifp, uint32_t ip) {
|
||||||
uint8_t *p = ifp->arp_cache;
|
uint8_t *p = ifp->arp_cache;
|
||||||
if (ip == 0) return NULL;
|
if (ip == 0 || ip == 0xffffffffU) return NULL;
|
||||||
if (p[0] == 0 || p[1] == 0) arp_cache_init(p, MIP_ARP_ENTRIES, 12);
|
|
||||||
for (uint8_t i = 0, j = p[1]; i < MIP_ARP_ENTRIES; i++, j = p[j + 1]) {
|
for (uint8_t i = 0, j = p[1]; i < MIP_ARP_ENTRIES; i++, j = p[j + 1]) {
|
||||||
if (memcmp(p + j + 2, &ip, sizeof(ip)) == 0) {
|
if (memcmp(p + j + 2, &ip, sizeof(ip)) == 0) {
|
||||||
p[1] = j, p[0] = p[j]; // Found entry! Point list head to us
|
p[1] = j, p[0] = p[j]; // Found entry! Point list head to us
|
||||||
// MG_DEBUG(("ARP find: %#lx @ %x:%x:%x:%x:%x:%x\n", (long) ip, p[j + 6],
|
// MG_DEBUG(("ARP find: %#lx @ %x:%x:%x:%x:%x:%x", (long) ip, p[j + 6],
|
||||||
// p[j + 7], p[j + 8], p[j + 9], p[j + 10], p[j + 11]));
|
// p[j + 7], p[j + 8], p[j + 9], p[j + 10], p[j + 11]));
|
||||||
return p + j + 6; // And return MAC address
|
return p + j + 6; // And return MAC address
|
||||||
}
|
}
|
||||||
@@ -285,9 +299,9 @@ static void onstatechange(struct mip_if *ifp) {
|
|||||||
MG_INFO(("READY, IP: %s", mg_ntoa(&addr, buf, sizeof(buf))));
|
MG_INFO(("READY, IP: %s", mg_ntoa(&addr, buf, sizeof(buf))));
|
||||||
arp_ask(ifp, ifp->gw);
|
arp_ask(ifp, ifp->gw);
|
||||||
} else if (ifp->state == MIP_STATE_UP) {
|
} else if (ifp->state == MIP_STATE_UP) {
|
||||||
MG_ERROR(("Network up"));
|
MG_ERROR(("Link up"));
|
||||||
} else if (ifp->state == MIP_STATE_DOWN) {
|
} else if (ifp->state == MIP_STATE_DOWN) {
|
||||||
MG_ERROR(("Network down"));
|
MG_ERROR(("Link down"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -330,7 +344,7 @@ static void tx_udp(struct mip_if *ifp, uint32_t ip_src, uint16_t sport,
|
|||||||
cs += (uint32_t) (ip->proto + sizeof(*udp) + len);
|
cs += (uint32_t) (ip->proto + sizeof(*udp) + len);
|
||||||
udp->csum = csumfin(cs);
|
udp->csum = csumfin(cs);
|
||||||
memmove(udp + 1, buf, len);
|
memmove(udp + 1, buf, len);
|
||||||
// MG_DEBUG(("UDP LEN %d %d\n", (int) len, (int) ifp->frame_len));
|
// MG_DEBUG(("UDP LEN %d %d", (int) len, (int) ifp->frame_len));
|
||||||
ifp->driver->tx(ifp->tx.buf,
|
ifp->driver->tx(ifp->tx.buf,
|
||||||
sizeof(struct eth) + sizeof(*ip) + sizeof(*udp) + len,
|
sizeof(struct eth) + sizeof(*ip) + sizeof(*udp) + len,
|
||||||
ifp->driver_data);
|
ifp->driver_data);
|
||||||
@@ -361,6 +375,7 @@ static void tx_dhcp_request(struct mip_if *ifp, uint32_t src, uint32_t dst) {
|
|||||||
memcpy(opts + 14, &dst, sizeof(dst));
|
memcpy(opts + 14, &dst, sizeof(dst));
|
||||||
memcpy(opts + 20, &src, sizeof(src));
|
memcpy(opts + 20, &src, sizeof(src));
|
||||||
tx_dhcp(ifp, src, dst, opts, sizeof(opts));
|
tx_dhcp(ifp, src, dst, opts, sizeof(opts));
|
||||||
|
MG_DEBUG(("DHCP request sent"));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tx_dhcp_discover(struct mip_if *ifp) {
|
static void tx_dhcp_discover(struct mip_if *ifp) {
|
||||||
@@ -370,6 +385,7 @@ static void tx_dhcp_discover(struct mip_if *ifp) {
|
|||||||
255 // End of options
|
255 // End of options
|
||||||
};
|
};
|
||||||
tx_dhcp(ifp, 0, 0xffffffff, opts, sizeof(opts));
|
tx_dhcp(ifp, 0, 0xffffffff, opts, sizeof(opts));
|
||||||
|
MG_DEBUG(("DHCP discover sent"));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rx_arp(struct mip_if *ifp, struct pkt *pkt) {
|
static void rx_arp(struct mip_if *ifp, struct pkt *pkt) {
|
||||||
@@ -397,7 +413,7 @@ static void rx_arp(struct mip_if *ifp, struct pkt *pkt) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void rx_icmp(struct mip_if *ifp, struct pkt *pkt) {
|
static void rx_icmp(struct mip_if *ifp, struct pkt *pkt) {
|
||||||
// MG_DEBUG(("ICMP %d\n", (int) len));
|
// MG_DEBUG(("ICMP %d", (int) len));
|
||||||
if (pkt->icmp->type == 8 && pkt->ip->dst == ifp->ip) {
|
if (pkt->icmp->type == 8 && pkt->ip->dst == ifp->ip) {
|
||||||
struct ip *ip = tx_ip(ifp, 1, ifp->ip, pkt->ip->src,
|
struct ip *ip = tx_ip(ifp, 1, ifp->ip, pkt->ip->src,
|
||||||
sizeof(struct icmp) + pkt->pay.len);
|
sizeof(struct icmp) + pkt->pay.len);
|
||||||
@@ -414,21 +430,21 @@ static void rx_dhcp(struct mip_if *ifp, struct pkt *pkt) {
|
|||||||
uint32_t ip = 0, gw = 0, mask = 0;
|
uint32_t ip = 0, gw = 0, mask = 0;
|
||||||
uint8_t *p = pkt->dhcp->options, *end = &pkt->raw.buf[pkt->raw.len];
|
uint8_t *p = pkt->dhcp->options, *end = &pkt->raw.buf[pkt->raw.len];
|
||||||
if (end < (uint8_t *) (pkt->dhcp + 1)) return;
|
if (end < (uint8_t *) (pkt->dhcp + 1)) return;
|
||||||
// MG_DEBUG(("DHCP %u\n", (unsigned) pkt->raw.len));
|
MG_DEBUG(("DHCP %u", (unsigned) pkt->raw.len));
|
||||||
while (p < end && p[0] != 255) {
|
while (p < end && p[0] != 255) {
|
||||||
if (p[0] == 1 && p[1] == sizeof(ifp->mask)) {
|
if (p[0] == 1 && p[1] == sizeof(ifp->mask)) {
|
||||||
memcpy(&mask, p + 2, sizeof(mask));
|
memcpy(&mask, p + 2, sizeof(mask));
|
||||||
// MG_DEBUG(("MASK %x\n", mask));
|
// MG_DEBUG(("MASK %x", mask));
|
||||||
} else if (p[0] == 3 && p[1] == sizeof(ifp->gw)) {
|
} else if (p[0] == 3 && p[1] == sizeof(ifp->gw)) {
|
||||||
memcpy(&gw, p + 2, sizeof(gw));
|
memcpy(&gw, p + 2, sizeof(gw));
|
||||||
ip = pkt->dhcp->yiaddr;
|
ip = pkt->dhcp->yiaddr;
|
||||||
// MG_DEBUG(("IP %x GW %x\n", ip, gw));
|
// MG_DEBUG(("IP %x GW %x", ip, gw));
|
||||||
}
|
}
|
||||||
p += p[1] + 2;
|
p += p[1] + 2;
|
||||||
}
|
}
|
||||||
if (ip && mask && gw && ifp->ip == 0) {
|
if (ip && mask && gw && ifp->ip == 0) {
|
||||||
// MG_DEBUG(("DHCP offer ip %#08lx mask %#08lx gw %#08lx\n",
|
// MG_DEBUG(("DHCP offer ip %#08lx mask %#08lx gw %#08lx", (long) ip,
|
||||||
// (long) ip, (long) mask, (long) gw));
|
// (long) mask, (long) gw));
|
||||||
arp_cache_add(ifp, pkt->dhcp->siaddr, ((struct eth *) pkt->raw.buf)->src);
|
arp_cache_add(ifp, pkt->dhcp->siaddr, ((struct eth *) pkt->raw.buf)->src);
|
||||||
ifp->ip = ip, ifp->gw = gw, ifp->mask = mask;
|
ifp->ip = ip, ifp->gw = gw, ifp->mask = mask;
|
||||||
ifp->state = MIP_STATE_READY;
|
ifp->state = MIP_STATE_READY;
|
||||||
@@ -470,11 +486,6 @@ static void rx_udp(struct mip_if *ifp, struct pkt *pkt) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct tcpstate {
|
|
||||||
uint32_t seq, ack;
|
|
||||||
time_t expire;
|
|
||||||
};
|
|
||||||
|
|
||||||
static size_t tx_tcp(struct mip_if *ifp, uint32_t dst_ip, uint8_t flags,
|
static size_t tx_tcp(struct mip_if *ifp, uint32_t dst_ip, uint8_t flags,
|
||||||
uint16_t sport, uint16_t dport, uint32_t seq, uint32_t ack,
|
uint16_t sport, uint16_t dport, uint32_t seq, uint32_t ack,
|
||||||
const void *buf, size_t len) {
|
const void *buf, size_t len) {
|
||||||
@@ -511,7 +522,7 @@ static size_t tx_tcp_pkt(struct mip_if *ifp, struct pkt *pkt, uint8_t flags,
|
|||||||
static struct mg_connection *accept_conn(struct mg_connection *lsn,
|
static struct mg_connection *accept_conn(struct mg_connection *lsn,
|
||||||
struct pkt *pkt) {
|
struct pkt *pkt) {
|
||||||
struct mg_connection *c = mg_alloc_conn(lsn->mgr);
|
struct mg_connection *c = mg_alloc_conn(lsn->mgr);
|
||||||
struct tcpstate *s = (struct tcpstate *) (c + 1);
|
struct connstate *s = (struct connstate *) (c + 1);
|
||||||
s->seq = mg_ntohl(pkt->tcp->ack), s->ack = mg_ntohl(pkt->tcp->seq);
|
s->seq = mg_ntohl(pkt->tcp->ack), s->ack = mg_ntohl(pkt->tcp->seq);
|
||||||
c->rem.ip = pkt->ip->src;
|
c->rem.ip = pkt->ip->src;
|
||||||
c->rem.port = pkt->tcp->sport;
|
c->rem.port = pkt->tcp->sport;
|
||||||
@@ -530,8 +541,8 @@ static struct mg_connection *accept_conn(struct mg_connection *lsn,
|
|||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool read_conn(struct mg_connection *c, struct pkt *pkt) {
|
static void read_conn(struct mg_connection *c, struct pkt *pkt) {
|
||||||
struct tcpstate *s = (struct tcpstate *) (c + 1);
|
struct connstate *s = (struct connstate *) (c + 1);
|
||||||
if (pkt->tcp->flags & TH_FIN) {
|
if (pkt->tcp->flags & TH_FIN) {
|
||||||
s->ack = mg_htonl(pkt->tcp->seq) + 1, s->seq = mg_htonl(pkt->tcp->ack);
|
s->ack = mg_htonl(pkt->tcp->seq) + 1, s->seq = mg_htonl(pkt->tcp->ack);
|
||||||
c->is_closing = 1;
|
c->is_closing = 1;
|
||||||
@@ -547,9 +558,7 @@ static bool read_conn(struct mg_connection *c, struct pkt *pkt) {
|
|||||||
c->recv.len += pkt->pay.len;
|
c->recv.len += pkt->pay.len;
|
||||||
struct mg_str evd = mg_str_n((char *) pkt->pay.buf, pkt->pay.len);
|
struct mg_str evd = mg_str_n((char *) pkt->pay.buf, pkt->pay.len);
|
||||||
mg_call(c, MG_EV_READ, &evd);
|
mg_call(c, MG_EV_READ, &evd);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rx_tcp(struct mip_if *ifp, struct pkt *pkt) {
|
static void rx_tcp(struct mip_if *ifp, struct pkt *pkt) {
|
||||||
@@ -558,7 +567,7 @@ static void rx_tcp(struct mip_if *ifp, struct pkt *pkt) {
|
|||||||
MG_INFO(("%lu %hhu %d", c ? c->id : 0, pkt->tcp->flags, (int) pkt->pay.len));
|
MG_INFO(("%lu %hhu %d", c ? c->id : 0, pkt->tcp->flags, (int) pkt->pay.len));
|
||||||
#endif
|
#endif
|
||||||
if (c != NULL && c->is_connecting && pkt->tcp->flags & (TH_SYN | TH_ACK)) {
|
if (c != NULL && c->is_connecting && pkt->tcp->flags & (TH_SYN | TH_ACK)) {
|
||||||
struct tcpstate *s = (struct tcpstate *) (c + 1);
|
struct connstate *s = (struct connstate *) (c + 1);
|
||||||
s->seq = mg_ntohl(pkt->tcp->ack), s->ack = mg_ntohl(pkt->tcp->seq) + 1;
|
s->seq = mg_ntohl(pkt->tcp->ack), s->ack = mg_ntohl(pkt->tcp->seq) + 1;
|
||||||
tx_tcp_pkt(ifp, pkt, TH_ACK, pkt->tcp->ack, NULL, 0);
|
tx_tcp_pkt(ifp, pkt, TH_ACK, pkt->tcp->ack, NULL, 0);
|
||||||
c->is_connecting = 0; // Client connected
|
c->is_connecting = 0; // Client connected
|
||||||
@@ -571,14 +580,7 @@ static void rx_tcp(struct mip_if *ifp, struct pkt *pkt) {
|
|||||||
mg_ntohl(pkt->ip->dst), mg_ntohs(pkt->tcp->dport)));
|
mg_ntohl(pkt->ip->dst), mg_ntohs(pkt->tcp->dport)));
|
||||||
mg_hexdump(pkt->pay.buf, pkt->pay.len);
|
mg_hexdump(pkt->pay.buf, pkt->pay.len);
|
||||||
#endif
|
#endif
|
||||||
if (read_conn(c, pkt)) {
|
read_conn(c, pkt);
|
||||||
// Send ACK immediately, no piggyback yet
|
|
||||||
// TODO() Set a timer and send ACK if timer expires and no segment was
|
|
||||||
// sent ? (clear timer on segment sent)
|
|
||||||
struct tcpstate *s = (struct tcpstate *) (c + 1);
|
|
||||||
tx_tcp(ifp, c->rem.ip, TH_ACK, c->loc.port, c->rem.port, mg_htonl(s->seq),
|
|
||||||
mg_htonl(s->ack), NULL, 0);
|
|
||||||
}
|
|
||||||
} else if ((c = getpeer(ifp->mgr, pkt, true)) == NULL) {
|
} else if ((c = getpeer(ifp->mgr, pkt, true)) == NULL) {
|
||||||
tx_tcp_pkt(ifp, pkt, TH_RST | TH_ACK, pkt->tcp->ack, NULL, 0);
|
tx_tcp_pkt(ifp, pkt, TH_RST | TH_ACK, pkt->tcp->ack, NULL, 0);
|
||||||
} else if (pkt->tcp->flags & TH_SYN) {
|
} else if (pkt->tcp->flags & TH_SYN) {
|
||||||
@@ -604,7 +606,7 @@ static void rx_ip(struct mip_if *ifp, struct pkt *pkt) {
|
|||||||
} else if (pkt->ip->proto == 17) {
|
} else if (pkt->ip->proto == 17) {
|
||||||
pkt->udp = (struct udp *) (pkt->ip + 1);
|
pkt->udp = (struct udp *) (pkt->ip + 1);
|
||||||
if (pkt->pay.len < sizeof(*pkt->udp)) return;
|
if (pkt->pay.len < sizeof(*pkt->udp)) return;
|
||||||
// MG_DEBUG((" UDP %u %u -> %u\n", len, mg_htons(udp->sport),
|
// MG_DEBUG((" UDP %u %u -> %u", len, mg_htons(udp->sport),
|
||||||
// mg_htons(udp->dport)));
|
// mg_htons(udp->dport)));
|
||||||
mkpay(pkt, pkt->udp + 1);
|
mkpay(pkt, pkt->udp + 1);
|
||||||
if (pkt->udp->dport == mg_htons(68)) {
|
if (pkt->udp->dport == mg_htons(68)) {
|
||||||
@@ -626,7 +628,7 @@ static void rx_ip(struct mip_if *ifp, struct pkt *pkt) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void rx_ip6(struct mip_if *ifp, struct pkt *pkt) {
|
static void rx_ip6(struct mip_if *ifp, struct pkt *pkt) {
|
||||||
// MG_DEBUG(("IP %d\n", (int) len));
|
// MG_DEBUG(("IP %d", (int) len));
|
||||||
if (pkt->ip6->proto == 1 || pkt->ip6->proto == 58) {
|
if (pkt->ip6->proto == 1 || pkt->ip6->proto == 58) {
|
||||||
pkt->icmp = (struct icmp *) (pkt->ip6 + 1);
|
pkt->icmp = (struct icmp *) (pkt->ip6 + 1);
|
||||||
if (pkt->pay.len < sizeof(*pkt->icmp)) return;
|
if (pkt->pay.len < sizeof(*pkt->icmp)) return;
|
||||||
@@ -635,7 +637,7 @@ static void rx_ip6(struct mip_if *ifp, struct pkt *pkt) {
|
|||||||
} else if (pkt->ip->proto == 17) {
|
} else if (pkt->ip->proto == 17) {
|
||||||
pkt->udp = (struct udp *) (pkt->ip6 + 1);
|
pkt->udp = (struct udp *) (pkt->ip6 + 1);
|
||||||
if (pkt->pay.len < sizeof(*pkt->udp)) return;
|
if (pkt->pay.len < sizeof(*pkt->udp)) return;
|
||||||
// MG_DEBUG((" UDP %u %u -> %u\n", len, mg_htons(udp->sport),
|
// MG_DEBUG((" UDP %u %u -> %u", len, mg_htons(udp->sport),
|
||||||
// mg_htons(udp->dport)));
|
// mg_htons(udp->dport)));
|
||||||
mkpay(pkt, pkt->udp + 1);
|
mkpay(pkt, pkt->udp + 1);
|
||||||
}
|
}
|
||||||
@@ -666,7 +668,7 @@ static void mip_rx(struct mip_if *ifp, void *buf, size_t len) {
|
|||||||
mkpay(&pkt, pkt.ip + 1);
|
mkpay(&pkt, pkt.ip + 1);
|
||||||
rx_ip(ifp, &pkt);
|
rx_ip(ifp, &pkt);
|
||||||
} else {
|
} else {
|
||||||
MG_DEBUG((" Unknown eth type %x\n", mg_htons(pkt.eth->type)));
|
MG_DEBUG((" Unknown eth type %x", mg_htons(pkt.eth->type)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -674,13 +676,6 @@ static void mip_poll(struct mip_if *ifp, uint64_t uptime_ms) {
|
|||||||
if (ifp == NULL || ifp->driver == NULL) return;
|
if (ifp == NULL || ifp->driver == NULL) return;
|
||||||
bool expired_1000ms = mg_timer_expired(&ifp->timer_1000ms, 1000, uptime_ms);
|
bool expired_1000ms = mg_timer_expired(&ifp->timer_1000ms, 1000, uptime_ms);
|
||||||
|
|
||||||
if (ifp->ip == 0 && expired_1000ms) {
|
|
||||||
tx_dhcp_discover(ifp); // If IP not configured, send DHCP
|
|
||||||
} else if (ifp->use_dhcp == false && expired_1000ms &&
|
|
||||||
arp_cache_find(ifp, ifp->gw) == NULL) {
|
|
||||||
arp_ask(ifp, ifp->gw); // If GW's MAC address in not in ARP cache
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle physical interface up/down status
|
// Handle physical interface up/down status
|
||||||
if (expired_1000ms && ifp->driver->up) {
|
if (expired_1000ms && ifp->driver->up) {
|
||||||
bool up = ifp->driver->up(ifp->driver_data);
|
bool up = ifp->driver->up(ifp->driver_data);
|
||||||
@@ -693,6 +688,15 @@ static void mip_poll(struct mip_if *ifp, uint64_t uptime_ms) {
|
|||||||
onstatechange(ifp);
|
onstatechange(ifp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (ifp->state == MIP_STATE_DOWN) return;
|
||||||
|
// if (expired_1000ms) arp_cache_dump(ifp->arp_cache);
|
||||||
|
|
||||||
|
if (ifp->ip == 0 && expired_1000ms) {
|
||||||
|
tx_dhcp_discover(ifp); // If IP not configured, send DHCP
|
||||||
|
} else if (ifp->use_dhcp == false && expired_1000ms &&
|
||||||
|
arp_cache_find(ifp, ifp->gw) == NULL) {
|
||||||
|
arp_ask(ifp, ifp->gw); // If GW's MAC address in not in ARP cache
|
||||||
|
}
|
||||||
|
|
||||||
// Read data from the network
|
// Read data from the network
|
||||||
for (;;) {
|
for (;;) {
|
||||||
@@ -730,9 +734,11 @@ void mip_init(struct mg_mgr *mgr, struct mip_cfg *ipcfg,
|
|||||||
ifp->mgr = mgr;
|
ifp->mgr = mgr;
|
||||||
ifp->queue.buf = ifp->tx.buf + maxpktsize;
|
ifp->queue.buf = ifp->tx.buf + maxpktsize;
|
||||||
ifp->queue.len = qlen;
|
ifp->queue.len = qlen;
|
||||||
|
ifp->timer_1000ms = mg_millis();
|
||||||
|
arp_cache_init(ifp->arp_cache, MIP_ARP_ENTRIES, 12);
|
||||||
if (driver->setrx) driver->setrx(on_rx, ifp);
|
if (driver->setrx) driver->setrx(on_rx, ifp);
|
||||||
mgr->priv = ifp;
|
mgr->priv = ifp;
|
||||||
mgr->extraconnsize = sizeof(struct tcpstate);
|
mgr->extraconnsize = sizeof(struct connstate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -776,7 +782,7 @@ bool mg_open_listener(struct mg_connection *c, const char *url) {
|
|||||||
|
|
||||||
static void write_conn(struct mg_connection *c) {
|
static void write_conn(struct mg_connection *c) {
|
||||||
struct mip_if *ifp = (struct mip_if *) c->mgr->priv;
|
struct mip_if *ifp = (struct mip_if *) c->mgr->priv;
|
||||||
struct tcpstate *s = (struct tcpstate *) (c + 1);
|
struct connstate *s = (struct connstate *) (c + 1);
|
||||||
size_t sent, n = c->send.len, hdrlen = 14 + 24 /*max IP*/ + 60 /*max TCP*/;
|
size_t sent, n = c->send.len, hdrlen = 14 + 24 /*max IP*/ + 60 /*max TCP*/;
|
||||||
if (n + hdrlen > ifp->tx.len) n = ifp->tx.len - hdrlen;
|
if (n + hdrlen > ifp->tx.len) n = ifp->tx.len - hdrlen;
|
||||||
sent = tx_tcp(ifp, c->rem.ip, TH_PUSH | TH_ACK, c->loc.port, c->rem.port,
|
sent = tx_tcp(ifp, c->rem.ip, TH_PUSH | TH_ACK, c->loc.port, c->rem.port,
|
||||||
@@ -790,7 +796,8 @@ static void write_conn(struct mg_connection *c) {
|
|||||||
|
|
||||||
static void fin_conn(struct mg_connection *c) {
|
static void fin_conn(struct mg_connection *c) {
|
||||||
struct mip_if *ifp = (struct mip_if *) c->mgr->priv;
|
struct mip_if *ifp = (struct mip_if *) c->mgr->priv;
|
||||||
struct tcpstate *s = (struct tcpstate *) (c + 1);
|
struct connstate *s = (struct connstate *) (c + 1);
|
||||||
|
MG_INFO(("AAA"));
|
||||||
tx_tcp(ifp, c->rem.ip, TH_FIN | TH_ACK, c->loc.port, c->rem.port,
|
tx_tcp(ifp, c->rem.ip, TH_FIN | TH_ACK, c->loc.port, c->rem.port,
|
||||||
mg_htonl(s->seq), mg_htonl(s->ack), NULL, 0);
|
mg_htonl(s->seq), mg_htonl(s->ack), NULL, 0);
|
||||||
}
|
}
|
||||||
|
|||||||
+64
-57
@@ -6061,15 +6061,15 @@ static bool mip_driver_stm32_init(uint8_t *mac, void *userdata) {
|
|||||||
// NOTE(cpq): we do not use extended descriptor bit 7, and do not use
|
// NOTE(cpq): we do not use extended descriptor bit 7, and do not use
|
||||||
// hardware checksum. Therefore, descriptor size is 4, not 8
|
// hardware checksum. Therefore, descriptor size is 4, not 8
|
||||||
// ETH->DMABMR = BIT(13) | BIT(16) | BIT(22) | BIT(23) | BIT(25);
|
// ETH->DMABMR = BIT(13) | BIT(16) | BIT(22) | BIT(23) | BIT(25);
|
||||||
ETH->MACIMR = BIT(3) | BIT(9); // Mask timestamp & PMT IT
|
ETH->MACIMR = BIT(3) | BIT(9); // Mask timestamp & PMT IT
|
||||||
ETH->MACMIIAR = cr_guess(hclk_get()) << 2; // MDC clock
|
ETH->MACMIIAR = cr_guess(hclk_get()) << 2; // MDC clock
|
||||||
ETH->MACFCR = BIT(7); // Disable zero quarta pause
|
ETH->MACFCR = BIT(7); // Disable zero quarta pause
|
||||||
ETH->MACFFR = BIT(31); // Receive all
|
ETH->MACFFR = BIT(31); // Receive all
|
||||||
eth_write_phy(PHY_ADDR, PHY_BCR, BIT(15)); // Reset PHY
|
eth_write_phy(PHY_ADDR, PHY_BCR, BIT(15)); // Reset PHY
|
||||||
eth_write_phy(PHY_ADDR, PHY_BCR, BIT(12)); // Set autonegotiation
|
eth_write_phy(PHY_ADDR, PHY_BCR, BIT(12)); // Set autonegotiation
|
||||||
ETH->DMARDLAR = (uint32_t) (uintptr_t) s_rxdesc; // RX descriptors
|
ETH->DMARDLAR = (uint32_t) (uintptr_t) s_rxdesc; // RX descriptors
|
||||||
ETH->DMATDLAR = (uint32_t) (uintptr_t) s_txdesc; // RX descriptors
|
ETH->DMATDLAR = (uint32_t) (uintptr_t) s_txdesc; // RX descriptors
|
||||||
ETH->DMAIER = BIT(6) | BIT(16); // RIE, NISE
|
ETH->DMAIER = BIT(6) | BIT(16); // RIE, NISE
|
||||||
ETH->MACCR = BIT(2) | BIT(3) | BIT(11) | BIT(14); // RE, TE, Duplex, Fast
|
ETH->MACCR = BIT(2) | BIT(3) | BIT(11) | BIT(14); // RE, TE, Duplex, Fast
|
||||||
ETH->DMAOMR = BIT(1) | BIT(13) | BIT(21) | BIT(25); // SR, ST, TSF, RSF
|
ETH->DMAOMR = BIT(1) | BIT(13) | BIT(21) | BIT(25); // SR, ST, TSF, RSF
|
||||||
|
|
||||||
@@ -6134,8 +6134,8 @@ struct mip_driver mip_driver_stm32 = {.init = mip_driver_stm32_init,
|
|||||||
.setrx = mip_driver_stm32_setrx,
|
.setrx = mip_driver_stm32_setrx,
|
||||||
.up = mip_driver_stm32_up};
|
.up = mip_driver_stm32_up};
|
||||||
|
|
||||||
/* Calculate HCLK from clock settings,
|
// Calculate HCLK from clock settings,
|
||||||
valid for STM32F74xxx/75xxx (5.3) and STM32F42xxx/43xxx (6.3) */
|
// valid for STM32F74xxx/75xxx (5.3) and STM32F42xxx/43xxx (6.3)
|
||||||
static const uint8_t ahbptab[8] = {1, 2, 3, 4, 6, 7, 8, 9}; // log2(div)
|
static const uint8_t ahbptab[8] = {1, 2, 3, 4, 6, 7, 8, 9}; // log2(div)
|
||||||
struct rcc {
|
struct rcc {
|
||||||
volatile uint32_t CR, PLLCFGR, CFGR;
|
volatile uint32_t CR, PLLCFGR, CFGR;
|
||||||
@@ -6155,8 +6155,8 @@ static uint32_t hclk_get(void) {
|
|||||||
clk = MG_STM32_CLK_HSE;
|
clk = MG_STM32_CLK_HSE;
|
||||||
else
|
else
|
||||||
clk = MG_STM32_CLK_HSI;
|
clk = MG_STM32_CLK_HSI;
|
||||||
vco = (uint32_t)((uint64_t)(((uint32_t) clk * (uint32_t) n)) /
|
vco = (uint32_t) ((uint64_t) (((uint32_t) clk * (uint32_t) n)) /
|
||||||
((uint32_t) m));
|
((uint32_t) m));
|
||||||
clk = vco / p;
|
clk = vco / p;
|
||||||
} else {
|
} else {
|
||||||
clk = MG_STM32_CLK_HSI;
|
clk = MG_STM32_CLK_HSI;
|
||||||
@@ -6166,14 +6166,14 @@ static uint32_t hclk_get(void) {
|
|||||||
return ((uint32_t) clk) >> ahbptab[hpre - 8];
|
return ((uint32_t) clk) >> ahbptab[hpre - 8];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Guess CR from HCLK:
|
// Guess CR from HCLK. MDC clock is generated from HCLK (AHB); as per 802.3,
|
||||||
MDC clock is generated from HCLK (AHB); as per 802.3, it must not exceed 2.5MHz
|
// it must not exceed 2.5MHz As the AHB clock can be (and usually is) derived
|
||||||
As the AHB clock can be (and usually is) derived from the HSI (internal RC),
|
// from the HSI (internal RC), and it can go above specs, the datasheets
|
||||||
and it can go above specs, the datasheets specify a range of frequencies and
|
// specify a range of frequencies and activate one of a series of dividers to
|
||||||
activate one of a series of dividers to keep the MDC clock safely below 2.5MHz.
|
// keep the MDC clock safely below 2.5MHz. We guess a divider setting based on
|
||||||
We guess a divider setting based on HCLK with a +5% drift.
|
// HCLK with a +5% drift. If the user uses a different clock from our
|
||||||
If the user uses a different clock from our defaults, needs to set the macros on top
|
// defaults, needs to set the macros on top Valid for STM32F74xxx/75xxx
|
||||||
Valid for STM32F74xxx/75xxx (38.8.1) and STM32F42xxx/43xxx (33.8.1) (both 4.5% worst case drift) */
|
// (38.8.1) and STM32F42xxx/43xxx (33.8.1) (both 4.5% worst case drift)
|
||||||
#define CRDTAB_LEN 6
|
#define CRDTAB_LEN 6
|
||||||
static const uint8_t crdtab[CRDTAB_LEN][2] = {
|
static const uint8_t crdtab[CRDTAB_LEN][2] = {
|
||||||
// [{setting, div ratio},...]
|
// [{setting, div ratio},...]
|
||||||
@@ -6306,6 +6306,12 @@ struct mip_driver mip_driver_w5500 = {
|
|||||||
#endif
|
#endif
|
||||||
#define MIP_ARP_CS (2 + 12 * MIP_ARP_ENTRIES) // ARP cache size
|
#define MIP_ARP_CS (2 + 12 * MIP_ARP_ENTRIES) // ARP cache size
|
||||||
|
|
||||||
|
struct connstate {
|
||||||
|
uint32_t seq, ack; // TCP seq/ack counters
|
||||||
|
uint64_t timer; // Used to send ACKs
|
||||||
|
uint8_t mac[6]; // Peer MAC address
|
||||||
|
};
|
||||||
|
|
||||||
struct str {
|
struct str {
|
||||||
uint8_t *buf;
|
uint8_t *buf;
|
||||||
size_t len;
|
size_t len;
|
||||||
@@ -6527,10 +6533,18 @@ static void arp_cache_init(uint8_t *p, int n, int size) {
|
|||||||
p[1] = p[3 + (n - 1) * size] = 2;
|
p[1] = p[3 + (n - 1) * size] = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void arp_cache_dump(const uint8_t *p) {
|
||||||
|
MG_INFO(("ARP cache:"));
|
||||||
|
for (uint8_t i = 0, j = p[1]; i < MIP_ARP_ENTRIES; i++, j = p[j + 1]) {
|
||||||
|
MG_INFO((" %d.%d.%d.%d -> %x:%x:%x:%x:%x:%x", p[j + 2], p[j + 3], p[j + 4],
|
||||||
|
p[j + 5], p[j + 6], p[j + 7], p[j + 8], p[j + 9], p[j + 10],
|
||||||
|
p[j + 11]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static uint8_t *arp_cache_find(struct mip_if *ifp, uint32_t ip) {
|
static uint8_t *arp_cache_find(struct mip_if *ifp, uint32_t ip) {
|
||||||
uint8_t *p = ifp->arp_cache;
|
uint8_t *p = ifp->arp_cache;
|
||||||
if (ip == 0) return NULL;
|
if (ip == 0 || ip == 0xffffffffU) return NULL;
|
||||||
if (p[0] == 0 || p[1] == 0) arp_cache_init(p, MIP_ARP_ENTRIES, 12);
|
|
||||||
for (uint8_t i = 0, j = p[1]; i < MIP_ARP_ENTRIES; i++, j = p[j + 1]) {
|
for (uint8_t i = 0, j = p[1]; i < MIP_ARP_ENTRIES; i++, j = p[j + 1]) {
|
||||||
if (memcmp(p + j + 2, &ip, sizeof(ip)) == 0) {
|
if (memcmp(p + j + 2, &ip, sizeof(ip)) == 0) {
|
||||||
p[1] = j, p[0] = p[j]; // Found entry! Point list head to us
|
p[1] = j, p[0] = p[j]; // Found entry! Point list head to us
|
||||||
@@ -6574,9 +6588,9 @@ static void onstatechange(struct mip_if *ifp) {
|
|||||||
MG_INFO(("READY, IP: %s", mg_ntoa(&addr, buf, sizeof(buf))));
|
MG_INFO(("READY, IP: %s", mg_ntoa(&addr, buf, sizeof(buf))));
|
||||||
arp_ask(ifp, ifp->gw);
|
arp_ask(ifp, ifp->gw);
|
||||||
} else if (ifp->state == MIP_STATE_UP) {
|
} else if (ifp->state == MIP_STATE_UP) {
|
||||||
MG_ERROR(("Network up"));
|
MG_ERROR(("Link up"));
|
||||||
} else if (ifp->state == MIP_STATE_DOWN) {
|
} else if (ifp->state == MIP_STATE_DOWN) {
|
||||||
MG_ERROR(("Network down"));
|
MG_ERROR(("Link down"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6650,6 +6664,7 @@ static void tx_dhcp_request(struct mip_if *ifp, uint32_t src, uint32_t dst) {
|
|||||||
memcpy(opts + 14, &dst, sizeof(dst));
|
memcpy(opts + 14, &dst, sizeof(dst));
|
||||||
memcpy(opts + 20, &src, sizeof(src));
|
memcpy(opts + 20, &src, sizeof(src));
|
||||||
tx_dhcp(ifp, src, dst, opts, sizeof(opts));
|
tx_dhcp(ifp, src, dst, opts, sizeof(opts));
|
||||||
|
MG_DEBUG(("DHCP request sent"));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tx_dhcp_discover(struct mip_if *ifp) {
|
static void tx_dhcp_discover(struct mip_if *ifp) {
|
||||||
@@ -6659,6 +6674,7 @@ static void tx_dhcp_discover(struct mip_if *ifp) {
|
|||||||
255 // End of options
|
255 // End of options
|
||||||
};
|
};
|
||||||
tx_dhcp(ifp, 0, 0xffffffff, opts, sizeof(opts));
|
tx_dhcp(ifp, 0, 0xffffffff, opts, sizeof(opts));
|
||||||
|
MG_DEBUG(("DHCP discover sent"));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rx_arp(struct mip_if *ifp, struct pkt *pkt) {
|
static void rx_arp(struct mip_if *ifp, struct pkt *pkt) {
|
||||||
@@ -6703,7 +6719,7 @@ static void rx_dhcp(struct mip_if *ifp, struct pkt *pkt) {
|
|||||||
uint32_t ip = 0, gw = 0, mask = 0;
|
uint32_t ip = 0, gw = 0, mask = 0;
|
||||||
uint8_t *p = pkt->dhcp->options, *end = &pkt->raw.buf[pkt->raw.len];
|
uint8_t *p = pkt->dhcp->options, *end = &pkt->raw.buf[pkt->raw.len];
|
||||||
if (end < (uint8_t *) (pkt->dhcp + 1)) return;
|
if (end < (uint8_t *) (pkt->dhcp + 1)) return;
|
||||||
// MG_DEBUG(("DHCP %u\n", (unsigned) pkt->raw.len));
|
MG_DEBUG(("DHCP %u\n", (unsigned) pkt->raw.len));
|
||||||
while (p < end && p[0] != 255) {
|
while (p < end && p[0] != 255) {
|
||||||
if (p[0] == 1 && p[1] == sizeof(ifp->mask)) {
|
if (p[0] == 1 && p[1] == sizeof(ifp->mask)) {
|
||||||
memcpy(&mask, p + 2, sizeof(mask));
|
memcpy(&mask, p + 2, sizeof(mask));
|
||||||
@@ -6716,8 +6732,8 @@ static void rx_dhcp(struct mip_if *ifp, struct pkt *pkt) {
|
|||||||
p += p[1] + 2;
|
p += p[1] + 2;
|
||||||
}
|
}
|
||||||
if (ip && mask && gw && ifp->ip == 0) {
|
if (ip && mask && gw && ifp->ip == 0) {
|
||||||
// MG_DEBUG(("DHCP offer ip %#08lx mask %#08lx gw %#08lx\n",
|
// MG_DEBUG(("DHCP offer ip %#08lx mask %#08lx gw %#08lx\n", (long) ip,
|
||||||
// (long) ip, (long) mask, (long) gw));
|
// (long) mask, (long) gw));
|
||||||
arp_cache_add(ifp, pkt->dhcp->siaddr, ((struct eth *) pkt->raw.buf)->src);
|
arp_cache_add(ifp, pkt->dhcp->siaddr, ((struct eth *) pkt->raw.buf)->src);
|
||||||
ifp->ip = ip, ifp->gw = gw, ifp->mask = mask;
|
ifp->ip = ip, ifp->gw = gw, ifp->mask = mask;
|
||||||
ifp->state = MIP_STATE_READY;
|
ifp->state = MIP_STATE_READY;
|
||||||
@@ -6759,11 +6775,6 @@ static void rx_udp(struct mip_if *ifp, struct pkt *pkt) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct tcpstate {
|
|
||||||
uint32_t seq, ack;
|
|
||||||
time_t expire;
|
|
||||||
};
|
|
||||||
|
|
||||||
static size_t tx_tcp(struct mip_if *ifp, uint32_t dst_ip, uint8_t flags,
|
static size_t tx_tcp(struct mip_if *ifp, uint32_t dst_ip, uint8_t flags,
|
||||||
uint16_t sport, uint16_t dport, uint32_t seq, uint32_t ack,
|
uint16_t sport, uint16_t dport, uint32_t seq, uint32_t ack,
|
||||||
const void *buf, size_t len) {
|
const void *buf, size_t len) {
|
||||||
@@ -6800,7 +6811,7 @@ static size_t tx_tcp_pkt(struct mip_if *ifp, struct pkt *pkt, uint8_t flags,
|
|||||||
static struct mg_connection *accept_conn(struct mg_connection *lsn,
|
static struct mg_connection *accept_conn(struct mg_connection *lsn,
|
||||||
struct pkt *pkt) {
|
struct pkt *pkt) {
|
||||||
struct mg_connection *c = mg_alloc_conn(lsn->mgr);
|
struct mg_connection *c = mg_alloc_conn(lsn->mgr);
|
||||||
struct tcpstate *s = (struct tcpstate *) (c + 1);
|
struct connstate *s = (struct connstate *) (c + 1);
|
||||||
s->seq = mg_ntohl(pkt->tcp->ack), s->ack = mg_ntohl(pkt->tcp->seq);
|
s->seq = mg_ntohl(pkt->tcp->ack), s->ack = mg_ntohl(pkt->tcp->seq);
|
||||||
c->rem.ip = pkt->ip->src;
|
c->rem.ip = pkt->ip->src;
|
||||||
c->rem.port = pkt->tcp->sport;
|
c->rem.port = pkt->tcp->sport;
|
||||||
@@ -6819,8 +6830,8 @@ static struct mg_connection *accept_conn(struct mg_connection *lsn,
|
|||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool read_conn(struct mg_connection *c, struct pkt *pkt) {
|
static void read_conn(struct mg_connection *c, struct pkt *pkt) {
|
||||||
struct tcpstate *s = (struct tcpstate *) (c + 1);
|
struct connstate *s = (struct connstate *) (c + 1);
|
||||||
if (pkt->tcp->flags & TH_FIN) {
|
if (pkt->tcp->flags & TH_FIN) {
|
||||||
s->ack = mg_htonl(pkt->tcp->seq) + 1, s->seq = mg_htonl(pkt->tcp->ack);
|
s->ack = mg_htonl(pkt->tcp->seq) + 1, s->seq = mg_htonl(pkt->tcp->ack);
|
||||||
c->is_closing = 1;
|
c->is_closing = 1;
|
||||||
@@ -6836,9 +6847,7 @@ static bool read_conn(struct mg_connection *c, struct pkt *pkt) {
|
|||||||
c->recv.len += pkt->pay.len;
|
c->recv.len += pkt->pay.len;
|
||||||
struct mg_str evd = mg_str_n((char *) pkt->pay.buf, pkt->pay.len);
|
struct mg_str evd = mg_str_n((char *) pkt->pay.buf, pkt->pay.len);
|
||||||
mg_call(c, MG_EV_READ, &evd);
|
mg_call(c, MG_EV_READ, &evd);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rx_tcp(struct mip_if *ifp, struct pkt *pkt) {
|
static void rx_tcp(struct mip_if *ifp, struct pkt *pkt) {
|
||||||
@@ -6847,7 +6856,7 @@ static void rx_tcp(struct mip_if *ifp, struct pkt *pkt) {
|
|||||||
MG_INFO(("%lu %hhu %d", c ? c->id : 0, pkt->tcp->flags, (int) pkt->pay.len));
|
MG_INFO(("%lu %hhu %d", c ? c->id : 0, pkt->tcp->flags, (int) pkt->pay.len));
|
||||||
#endif
|
#endif
|
||||||
if (c != NULL && c->is_connecting && pkt->tcp->flags & (TH_SYN | TH_ACK)) {
|
if (c != NULL && c->is_connecting && pkt->tcp->flags & (TH_SYN | TH_ACK)) {
|
||||||
struct tcpstate *s = (struct tcpstate *) (c + 1);
|
struct connstate *s = (struct connstate *) (c + 1);
|
||||||
s->seq = mg_ntohl(pkt->tcp->ack), s->ack = mg_ntohl(pkt->tcp->seq) + 1;
|
s->seq = mg_ntohl(pkt->tcp->ack), s->ack = mg_ntohl(pkt->tcp->seq) + 1;
|
||||||
tx_tcp_pkt(ifp, pkt, TH_ACK, pkt->tcp->ack, NULL, 0);
|
tx_tcp_pkt(ifp, pkt, TH_ACK, pkt->tcp->ack, NULL, 0);
|
||||||
c->is_connecting = 0; // Client connected
|
c->is_connecting = 0; // Client connected
|
||||||
@@ -6860,14 +6869,7 @@ static void rx_tcp(struct mip_if *ifp, struct pkt *pkt) {
|
|||||||
mg_ntohl(pkt->ip->dst), mg_ntohs(pkt->tcp->dport)));
|
mg_ntohl(pkt->ip->dst), mg_ntohs(pkt->tcp->dport)));
|
||||||
mg_hexdump(pkt->pay.buf, pkt->pay.len);
|
mg_hexdump(pkt->pay.buf, pkt->pay.len);
|
||||||
#endif
|
#endif
|
||||||
if (read_conn(c, pkt)) {
|
read_conn(c, pkt);
|
||||||
// Send ACK immediately, no piggyback yet
|
|
||||||
// TODO() Set a timer and send ACK if timer expires and no segment was
|
|
||||||
// sent ? (clear timer on segment sent)
|
|
||||||
struct tcpstate *s = (struct tcpstate *) (c + 1);
|
|
||||||
tx_tcp(ifp, c->rem.ip, TH_ACK, c->loc.port, c->rem.port, mg_htonl(s->seq),
|
|
||||||
mg_htonl(s->ack), NULL, 0);
|
|
||||||
}
|
|
||||||
} else if ((c = getpeer(ifp->mgr, pkt, true)) == NULL) {
|
} else if ((c = getpeer(ifp->mgr, pkt, true)) == NULL) {
|
||||||
tx_tcp_pkt(ifp, pkt, TH_RST | TH_ACK, pkt->tcp->ack, NULL, 0);
|
tx_tcp_pkt(ifp, pkt, TH_RST | TH_ACK, pkt->tcp->ack, NULL, 0);
|
||||||
} else if (pkt->tcp->flags & TH_SYN) {
|
} else if (pkt->tcp->flags & TH_SYN) {
|
||||||
@@ -6963,13 +6965,6 @@ static void mip_poll(struct mip_if *ifp, uint64_t uptime_ms) {
|
|||||||
if (ifp == NULL || ifp->driver == NULL) return;
|
if (ifp == NULL || ifp->driver == NULL) return;
|
||||||
bool expired_1000ms = mg_timer_expired(&ifp->timer_1000ms, 1000, uptime_ms);
|
bool expired_1000ms = mg_timer_expired(&ifp->timer_1000ms, 1000, uptime_ms);
|
||||||
|
|
||||||
if (ifp->ip == 0 && expired_1000ms) {
|
|
||||||
tx_dhcp_discover(ifp); // If IP not configured, send DHCP
|
|
||||||
} else if (ifp->use_dhcp == false && expired_1000ms &&
|
|
||||||
arp_cache_find(ifp, ifp->gw) == NULL) {
|
|
||||||
arp_ask(ifp, ifp->gw); // If GW's MAC address in not in ARP cache
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle physical interface up/down status
|
// Handle physical interface up/down status
|
||||||
if (expired_1000ms && ifp->driver->up) {
|
if (expired_1000ms && ifp->driver->up) {
|
||||||
bool up = ifp->driver->up(ifp->driver_data);
|
bool up = ifp->driver->up(ifp->driver_data);
|
||||||
@@ -6982,6 +6977,15 @@ static void mip_poll(struct mip_if *ifp, uint64_t uptime_ms) {
|
|||||||
onstatechange(ifp);
|
onstatechange(ifp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (ifp->state == MIP_STATE_DOWN) return;
|
||||||
|
// if (expired_1000ms) arp_cache_dump(ifp->arp_cache);
|
||||||
|
|
||||||
|
if (ifp->ip == 0 && expired_1000ms) {
|
||||||
|
tx_dhcp_discover(ifp); // If IP not configured, send DHCP
|
||||||
|
} else if (ifp->use_dhcp == false && expired_1000ms &&
|
||||||
|
arp_cache_find(ifp, ifp->gw) == NULL) {
|
||||||
|
arp_ask(ifp, ifp->gw); // If GW's MAC address in not in ARP cache
|
||||||
|
}
|
||||||
|
|
||||||
// Read data from the network
|
// Read data from the network
|
||||||
for (;;) {
|
for (;;) {
|
||||||
@@ -7019,9 +7023,11 @@ void mip_init(struct mg_mgr *mgr, struct mip_cfg *ipcfg,
|
|||||||
ifp->mgr = mgr;
|
ifp->mgr = mgr;
|
||||||
ifp->queue.buf = ifp->tx.buf + maxpktsize;
|
ifp->queue.buf = ifp->tx.buf + maxpktsize;
|
||||||
ifp->queue.len = qlen;
|
ifp->queue.len = qlen;
|
||||||
|
ifp->timer_1000ms = mg_millis();
|
||||||
|
arp_cache_init(ifp->arp_cache, MIP_ARP_ENTRIES, 12);
|
||||||
if (driver->setrx) driver->setrx(on_rx, ifp);
|
if (driver->setrx) driver->setrx(on_rx, ifp);
|
||||||
mgr->priv = ifp;
|
mgr->priv = ifp;
|
||||||
mgr->extraconnsize = sizeof(struct tcpstate);
|
mgr->extraconnsize = sizeof(struct connstate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -7065,7 +7071,7 @@ bool mg_open_listener(struct mg_connection *c, const char *url) {
|
|||||||
|
|
||||||
static void write_conn(struct mg_connection *c) {
|
static void write_conn(struct mg_connection *c) {
|
||||||
struct mip_if *ifp = (struct mip_if *) c->mgr->priv;
|
struct mip_if *ifp = (struct mip_if *) c->mgr->priv;
|
||||||
struct tcpstate *s = (struct tcpstate *) (c + 1);
|
struct connstate *s = (struct connstate *) (c + 1);
|
||||||
size_t sent, n = c->send.len, hdrlen = 14 + 24 /*max IP*/ + 60 /*max TCP*/;
|
size_t sent, n = c->send.len, hdrlen = 14 + 24 /*max IP*/ + 60 /*max TCP*/;
|
||||||
if (n + hdrlen > ifp->tx.len) n = ifp->tx.len - hdrlen;
|
if (n + hdrlen > ifp->tx.len) n = ifp->tx.len - hdrlen;
|
||||||
sent = tx_tcp(ifp, c->rem.ip, TH_PUSH | TH_ACK, c->loc.port, c->rem.port,
|
sent = tx_tcp(ifp, c->rem.ip, TH_PUSH | TH_ACK, c->loc.port, c->rem.port,
|
||||||
@@ -7079,7 +7085,8 @@ static void write_conn(struct mg_connection *c) {
|
|||||||
|
|
||||||
static void fin_conn(struct mg_connection *c) {
|
static void fin_conn(struct mg_connection *c) {
|
||||||
struct mip_if *ifp = (struct mip_if *) c->mgr->priv;
|
struct mip_if *ifp = (struct mip_if *) c->mgr->priv;
|
||||||
struct tcpstate *s = (struct tcpstate *) (c + 1);
|
struct connstate *s = (struct connstate *) (c + 1);
|
||||||
|
MG_INFO(("AAA"));
|
||||||
tx_tcp(ifp, c->rem.ip, TH_FIN | TH_ACK, c->loc.port, c->rem.port,
|
tx_tcp(ifp, c->rem.ip, TH_FIN | TH_ACK, c->loc.port, c->rem.port,
|
||||||
mg_htonl(s->seq), mg_htonl(s->ack), NULL, 0);
|
mg_htonl(s->seq), mg_htonl(s->ack), NULL, 0);
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-6
@@ -834,15 +834,15 @@ int mg_http_status(const struct mg_http_message *hm) {
|
|||||||
// If a server sends data to the client using chunked encoding, Mongoose strips
|
// If a server sends data to the client using chunked encoding, Mongoose strips
|
||||||
// off the chunking prefix (hex length and \r\n) and suffix (\r\n), appends the
|
// off the chunking prefix (hex length and \r\n) and suffix (\r\n), appends the
|
||||||
// stripped data to the body, and fires the MG_EV_HTTP_CHUNK event. When zero
|
// stripped data to the body, and fires the MG_EV_HTTP_CHUNK event. When zero
|
||||||
// chunk is received, it fires MG_EV_HTTP_MSG, and the body is already have all
|
// chunk is received, we fire MG_EV_HTTP_MSG, and the body already has all
|
||||||
// chunking prefixes/suffixes stripped.
|
// chunking prefixes/suffixes stripped.
|
||||||
//
|
//
|
||||||
// If a server sends data without chunked encoding, we also fire MG_EV_CHUNK
|
// If a server sends data without chunked encoding, we also fire a series of
|
||||||
// and MG_EV_HTTP_MSG in the end.
|
// MG_EV_HTTP_CHUNK events for every received piece of data, and then we fire
|
||||||
|
// MG_EV_HTTP_MSG event in the end.
|
||||||
//
|
//
|
||||||
// We track the total processed body length in the c->pfn_data,
|
// We track total processed length in the c->pfn_data, which is a void *
|
||||||
// by using void * pointer to store size_t value.
|
// pointer: we store a size_t value there.
|
||||||
|
|
||||||
static bool getchunk(struct mg_str s, size_t *prefixlen, size_t *datalen) {
|
static bool getchunk(struct mg_str s, size_t *prefixlen, size_t *datalen) {
|
||||||
size_t i = 0, n;
|
size_t i = 0, n;
|
||||||
while (i < s.len && s.ptr[i] != '\r' && s.ptr[i] != '\n') i++;
|
while (i < s.len && s.ptr[i] != '\r' && s.ptr[i] != '\n') i++;
|
||||||
|
|||||||
Reference in new issue
Block a user