1
2
3
4
5
6
7
8
9#include "qemu/osdep.h"
10#include "qemu-common.h"
11#include "net/announce.h"
12#include "net/net.h"
13#include "qapi/clone-visitor.h"
14#include "qapi/qapi-visit-net.h"
15#include "qapi/qapi-commands-net.h"
16#include "trace.h"
17
18static GData *named_timers;
19
20int64_t qemu_announce_timer_step(AnnounceTimer *timer)
21{
22 int64_t step;
23
24 step = timer->params.initial +
25 (timer->params.rounds - timer->round - 1) *
26 timer->params.step;
27
28 if (step < 0 || step > timer->params.max) {
29 step = timer->params.max;
30 }
31 timer_mod(timer->tm, qemu_clock_get_ms(timer->type) + step);
32
33 return step;
34}
35
36
37
38
39
40void qemu_announce_timer_del(AnnounceTimer *timer, bool free_named)
41{
42 bool free_timer = false;
43 if (timer->tm) {
44 timer_del(timer->tm);
45 timer_free(timer->tm);
46 timer->tm = NULL;
47 }
48 qapi_free_strList(timer->params.interfaces);
49 timer->params.interfaces = NULL;
50 if (free_named && timer->params.has_id) {
51 AnnounceTimer *list_timer;
52
53
54
55
56 list_timer = g_datalist_get_data(&named_timers, timer->params.id);
57 assert(timer == list_timer);
58 free_timer = true;
59 g_datalist_remove_data(&named_timers, timer->params.id);
60 }
61 trace_qemu_announce_timer_del(free_named, free_timer, timer->params.id);
62 g_free(timer->params.id);
63 timer->params.id = NULL;
64
65 if (free_timer) {
66 g_free(timer);
67 }
68}
69
70
71
72
73
74void qemu_announce_timer_reset(AnnounceTimer *timer,
75 AnnounceParameters *params,
76 QEMUClockType type,
77 QEMUTimerCB *cb,
78 void *opaque)
79{
80
81
82
83
84 qemu_announce_timer_del(timer, false);
85
86 QAPI_CLONE_MEMBERS(AnnounceParameters, &timer->params, params);
87 timer->round = params->rounds;
88 timer->type = type;
89 timer->tm = timer_new_ms(type, cb, opaque);
90}
91
92#ifndef ETH_P_RARP
93#define ETH_P_RARP 0x8035
94#endif
95#define ARP_HTYPE_ETH 0x0001
96#define ARP_PTYPE_IP 0x0800
97#define ARP_OP_REQUEST_REV 0x3
98
99static int announce_self_create(uint8_t *buf,
100 uint8_t *mac_addr)
101{
102
103 memset(buf, 0xff, 6);
104 memcpy(buf + 6, mac_addr, 6);
105 *(uint16_t *)(buf + 12) = htons(ETH_P_RARP);
106
107
108 *(uint16_t *)(buf + 14) = htons(ARP_HTYPE_ETH);
109 *(uint16_t *)(buf + 16) = htons(ARP_PTYPE_IP);
110 *(buf + 18) = 6;
111 *(buf + 19) = 4;
112 *(uint16_t *)(buf + 20) = htons(ARP_OP_REQUEST_REV);
113 memcpy(buf + 22, mac_addr, 6);
114 memset(buf + 28, 0x00, 4);
115 memcpy(buf + 32, mac_addr, 6);
116 memset(buf + 38, 0x00, 4);
117
118
119 memset(buf + 42, 0x00, 18);
120
121 return 60;
122}
123
124static void qemu_announce_self_iter(NICState *nic, void *opaque)
125{
126 AnnounceTimer *timer = opaque;
127 uint8_t buf[60];
128 int len;
129 bool skip;
130
131 if (timer->params.has_interfaces) {
132 strList *entry = timer->params.interfaces;
133
134 skip = true;
135
136 while (entry) {
137 if (!strcmp(entry->value, nic->ncs->name)) {
138
139 skip = false;
140 break;
141 }
142 entry = entry->next;
143 }
144 } else {
145 skip = false;
146 }
147
148 trace_qemu_announce_self_iter(timer->params.has_id ? timer->params.id : "_",
149 nic->ncs->name,
150 qemu_ether_ntoa(&nic->conf->macaddr), skip);
151
152 if (!skip) {
153 len = announce_self_create(buf, nic->conf->macaddr.a);
154
155 qemu_send_packet_raw(qemu_get_queue(nic), buf, len);
156
157
158 if (nic->ncs->info->announce) {
159 nic->ncs->info->announce(nic->ncs);
160 }
161 }
162}
163static void qemu_announce_self_once(void *opaque)
164{
165 AnnounceTimer *timer = (AnnounceTimer *)opaque;
166
167 qemu_foreach_nic(qemu_announce_self_iter, timer);
168
169 if (--timer->round) {
170 qemu_announce_timer_step(timer);
171 } else {
172 qemu_announce_timer_del(timer, true);
173 }
174}
175
176void qemu_announce_self(AnnounceTimer *timer, AnnounceParameters *params)
177{
178 qemu_announce_timer_reset(timer, params, QEMU_CLOCK_REALTIME,
179 qemu_announce_self_once, timer);
180 if (params->rounds) {
181 qemu_announce_self_once(timer);
182 } else {
183 qemu_announce_timer_del(timer, true);
184 }
185}
186
187void qmp_announce_self(AnnounceParameters *params, Error **errp)
188{
189 AnnounceTimer *named_timer;
190 if (!params->has_id) {
191 params->id = g_strdup("");
192 params->has_id = true;
193 }
194
195 named_timer = g_datalist_get_data(&named_timers, params->id);
196
197 if (!named_timer) {
198 named_timer = g_new0(AnnounceTimer, 1);
199 g_datalist_set_data(&named_timers, params->id, named_timer);
200 }
201
202 qemu_announce_self(named_timer, params);
203}
204