aboutgitcodebugslistschat
path: root/arp.c
diff options
context:
space:
mode:
Diffstat (limited to 'arp.c')
-rw-r--r--arp.c128
1 files changed, 94 insertions, 34 deletions
diff --git a/arp.c b/arp.c
index 93b22c5..ad088b1 100644
--- a/arp.c
+++ b/arp.c
@@ -31,58 +31,118 @@
#include "tap.h"
/**
- * arp() - Check if this is a supported ARP message, reply as needed
+ * ignore_arp() - Check if we should ignore this ARP message
* @c: Execution context
- * @p: Packet pool, single packet with Ethernet buffer
+ * @ah: ARP header
+ * @am: ARP message
*
- * Return: 1 if handled, -1 on failure
+ * Return: true if the ARP message should be ignored, false otherwise
*/
-int arp(const struct ctx *c, const struct pool *p)
+static bool ignore_arp(const struct ctx *c,
+ const struct arphdr *ah, const struct arpmsg *am)
{
- unsigned char swap[4];
- struct ethhdr *eh;
- struct arphdr *ah;
- struct arpmsg *am;
- size_t l2len;
-
- eh = packet_get(p, 0, 0, sizeof(*eh), NULL);
- ah = packet_get(p, 0, sizeof(*eh), sizeof(*ah), NULL);
- am = packet_get(p, 0, sizeof(*eh) + sizeof(*ah), sizeof(*am), NULL);
-
- if (!eh || !ah || !am)
- return -1;
-
if (ah->ar_hrd != htons(ARPHRD_ETHER) ||
ah->ar_pro != htons(ETH_P_IP) ||
ah->ar_hln != ETH_ALEN ||
ah->ar_pln != 4 ||
ah->ar_op != htons(ARPOP_REQUEST))
- return 1;
+ return true;
- /* Discard announcements (but not 0.0.0.0 "probes"): we might have the
- * same IP address, hide that.
- */
- if (memcmp(am->sip, (unsigned char[4]){ 0 }, sizeof(am->tip)) &&
+ /* Discard announcements, but not 0.0.0.0 "probes" */
+ if (memcmp(am->sip, &in4addr_any, sizeof(am->sip)) &&
!memcmp(am->sip, am->tip, sizeof(am->sip)))
- return 1;
+ return true;
- /* Don't resolve our own address, either. */
+ /* Don't resolve the guest's assigned address, either. */
if (!memcmp(am->tip, &c->ip4.addr, sizeof(am->tip)))
+ return true;
+
+ return false;
+}
+
+/**
+ * arp() - Check if this is a supported ARP message, reply as needed
+ * @c: Execution context
+ * @data: Single packet with Ethernet buffer
+ *
+ * Return: 1 if handled, -1 on failure
+ */
+int arp(const struct ctx *c, struct iov_tail *data)
+{
+ struct {
+ struct ethhdr eh;
+ struct arphdr ah;
+ struct arpmsg am;
+ } __attribute__((__packed__)) resp;
+ struct arphdr ah_storage;
+ struct ethhdr eh_storage;
+ struct arpmsg am_storage;
+ const struct ethhdr *eh;
+ const struct arphdr *ah;
+ const struct arpmsg *am;
+
+ eh = IOV_REMOVE_HEADER(data, eh_storage);
+ ah = IOV_REMOVE_HEADER(data, ah_storage);
+ am = IOV_REMOVE_HEADER(data, am_storage);
+ if (!eh || !ah || !am)
+ return -1;
+
+ if (ignore_arp(c, ah, am))
return 1;
- ah->ar_op = htons(ARPOP_REPLY);
- memcpy(am->tha, am->sha, sizeof(am->tha));
- memcpy(am->sha, c->mac, sizeof(am->sha));
+ /* Ethernet header */
+ resp.eh.h_proto = htons(ETH_P_ARP);
+ memcpy(resp.eh.h_dest, eh->h_source, sizeof(resp.eh.h_dest));
+ memcpy(resp.eh.h_source, c->our_tap_mac, sizeof(resp.eh.h_source));
- memcpy(swap, am->tip, sizeof(am->tip));
- memcpy(am->tip, am->sip, sizeof(am->tip));
- memcpy(am->sip, swap, sizeof(am->sip));
+ /* ARP header */
+ resp.ah.ar_op = htons(ARPOP_REPLY);
+ resp.ah.ar_hrd = ah->ar_hrd;
+ resp.ah.ar_pro = ah->ar_pro;
+ resp.ah.ar_hln = ah->ar_hln;
+ resp.ah.ar_pln = ah->ar_pln;
- l2len = sizeof(*eh) + sizeof(*ah) + sizeof(*am);
- memcpy(eh->h_dest, eh->h_source, sizeof(eh->h_dest));
- memcpy(eh->h_source, c->mac, sizeof(eh->h_source));
+ /* ARP message */
+ memcpy(resp.am.sha, c->our_tap_mac, sizeof(resp.am.sha));
+ memcpy(resp.am.sip, am->tip, sizeof(resp.am.sip));
+ memcpy(resp.am.tha, am->sha, sizeof(resp.am.tha));
+ memcpy(resp.am.tip, am->sip, sizeof(resp.am.tip));
- tap_send_single(c, eh, l2len);
+ tap_send_single(c, &resp, sizeof(resp));
return 1;
}
+
+/**
+ * arp_send_init_req() - Send initial ARP request to retrieve guest MAC address
+ * @c: Execution context
+ */
+void arp_send_init_req(const struct ctx *c)
+{
+ struct {
+ struct ethhdr eh;
+ struct arphdr ah;
+ struct arpmsg am;
+ } __attribute__((__packed__)) req;
+
+ /* Ethernet header */
+ req.eh.h_proto = htons(ETH_P_ARP);
+ memcpy(req.eh.h_dest, MAC_BROADCAST, sizeof(req.eh.h_dest));
+ memcpy(req.eh.h_source, c->our_tap_mac, sizeof(req.eh.h_source));
+
+ /* ARP header */
+ req.ah.ar_op = htons(ARPOP_REQUEST);
+ req.ah.ar_hrd = htons(ARPHRD_ETHER);
+ req.ah.ar_pro = htons(ETH_P_IP);
+ req.ah.ar_hln = ETH_ALEN;
+ req.ah.ar_pln = 4;
+
+ /* ARP message */
+ memcpy(req.am.sha, c->our_tap_mac, sizeof(req.am.sha));
+ memcpy(req.am.sip, &c->ip4.our_tap_addr, sizeof(req.am.sip));
+ memcpy(req.am.tha, MAC_BROADCAST, sizeof(req.am.tha));
+ memcpy(req.am.tip, &c->ip4.addr, sizeof(req.am.tip));
+
+ debug("Sending initial ARP request for guest MAC address");
+ tap_send_single(c, &req, sizeof(req));
+}