aboutsummaryrefslogtreecommitdiff
path: root/net/announce.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/announce.c')
-rw-r--r--net/announce.c68
1 files changed, 68 insertions, 0 deletions
diff --git a/net/announce.c b/net/announce.c
index 8876eb62b6..13ad9c2ba8 100644
--- a/net/announce.c
+++ b/net/announce.c
@@ -9,8 +9,10 @@
#include "qemu/osdep.h"
#include "qemu-common.h"
#include "net/announce.h"
+#include "net/net.h"
#include "qapi/clone-visitor.h"
#include "qapi/qapi-visit-net.h"
+#include "trace.h"
int64_t qemu_announce_timer_step(AnnounceTimer *timer)
{
@@ -58,3 +60,69 @@ void qemu_announce_timer_reset(AnnounceTimer *timer,
timer->type = type;
timer->tm = timer_new_ms(type, cb, opaque);
}
+
+#ifndef ETH_P_RARP
+#define ETH_P_RARP 0x8035
+#endif
+#define ARP_HTYPE_ETH 0x0001
+#define ARP_PTYPE_IP 0x0800
+#define ARP_OP_REQUEST_REV 0x3
+
+static int announce_self_create(uint8_t *buf,
+ uint8_t *mac_addr)
+{
+ /* Ethernet header. */
+ memset(buf, 0xff, 6); /* destination MAC addr */
+ memcpy(buf + 6, mac_addr, 6); /* source MAC addr */
+ *(uint16_t *)(buf + 12) = htons(ETH_P_RARP); /* ethertype */
+
+ /* RARP header. */
+ *(uint16_t *)(buf + 14) = htons(ARP_HTYPE_ETH); /* hardware addr space */
+ *(uint16_t *)(buf + 16) = htons(ARP_PTYPE_IP); /* protocol addr space */
+ *(buf + 18) = 6; /* hardware addr length (ethernet) */
+ *(buf + 19) = 4; /* protocol addr length (IPv4) */
+ *(uint16_t *)(buf + 20) = htons(ARP_OP_REQUEST_REV); /* opcode */
+ memcpy(buf + 22, mac_addr, 6); /* source hw addr */
+ memset(buf + 28, 0x00, 4); /* source protocol addr */
+ memcpy(buf + 32, mac_addr, 6); /* target hw addr */
+ memset(buf + 38, 0x00, 4); /* target protocol addr */
+
+ /* Padding to get up to 60 bytes (ethernet min packet size, minus FCS). */
+ memset(buf + 42, 0x00, 18);
+
+ return 60; /* len (FCS will be added by hardware) */
+}
+
+static void qemu_announce_self_iter(NICState *nic, void *opaque)
+{
+ uint8_t buf[60];
+ int len;
+
+ trace_qemu_announce_self_iter(qemu_ether_ntoa(&nic->conf->macaddr));
+ len = announce_self_create(buf, nic->conf->macaddr.a);
+
+ qemu_send_packet_raw(qemu_get_queue(nic), buf, len);
+}
+static void qemu_announce_self_once(void *opaque)
+{
+ AnnounceTimer *timer = (AnnounceTimer *)opaque;
+
+ qemu_foreach_nic(qemu_announce_self_iter, NULL);
+
+ if (--timer->round) {
+ qemu_announce_timer_step(timer);
+ } else {
+ qemu_announce_timer_del(timer);
+ }
+}
+
+void qemu_announce_self(AnnounceTimer *timer, AnnounceParameters *params)
+{
+ qemu_announce_timer_reset(timer, params, QEMU_CLOCK_REALTIME,
+ qemu_announce_self_once, timer);
+ if (params->rounds) {
+ qemu_announce_self_once(timer);
+ } else {
+ qemu_announce_timer_del(timer);
+ }
+}