xref: /qemu/net/announce.c (revision 44b416ad62bf1068a9653fe066bd500fb9b0d88f)
150510ea2SDr. David Alan Gilbert /*
250510ea2SDr. David Alan Gilbert  *  Self-announce
350510ea2SDr. David Alan Gilbert  *  (c) 2017-2019 Red Hat, Inc.
450510ea2SDr. David Alan Gilbert  *
550510ea2SDr. David Alan Gilbert  * This work is licensed under the terms of the GNU GPL, version 2 or later.
650510ea2SDr. David Alan Gilbert  * See the COPYING file in the top-level directory.
750510ea2SDr. David Alan Gilbert  */
850510ea2SDr. David Alan Gilbert 
950510ea2SDr. David Alan Gilbert #include "qemu/osdep.h"
1050510ea2SDr. David Alan Gilbert #include "qemu-common.h"
1150510ea2SDr. David Alan Gilbert #include "net/announce.h"
127659505cSDr. David Alan Gilbert #include "net/net.h"
1350510ea2SDr. David Alan Gilbert #include "qapi/clone-visitor.h"
1450510ea2SDr. David Alan Gilbert #include "qapi/qapi-visit-net.h"
157659505cSDr. David Alan Gilbert #include "trace.h"
1650510ea2SDr. David Alan Gilbert 
1750510ea2SDr. David Alan Gilbert int64_t qemu_announce_timer_step(AnnounceTimer *timer)
1850510ea2SDr. David Alan Gilbert {
1950510ea2SDr. David Alan Gilbert     int64_t step;
2050510ea2SDr. David Alan Gilbert 
2150510ea2SDr. David Alan Gilbert     step =  timer->params.initial +
2250510ea2SDr. David Alan Gilbert             (timer->params.rounds - timer->round - 1) *
2350510ea2SDr. David Alan Gilbert             timer->params.step;
2450510ea2SDr. David Alan Gilbert 
2550510ea2SDr. David Alan Gilbert     if (step < 0 || step > timer->params.max) {
2650510ea2SDr. David Alan Gilbert         step = timer->params.max;
2750510ea2SDr. David Alan Gilbert     }
2850510ea2SDr. David Alan Gilbert     timer_mod(timer->tm, qemu_clock_get_ms(timer->type) + step);
2950510ea2SDr. David Alan Gilbert 
3050510ea2SDr. David Alan Gilbert     return step;
3150510ea2SDr. David Alan Gilbert }
3250510ea2SDr. David Alan Gilbert 
3350510ea2SDr. David Alan Gilbert void qemu_announce_timer_del(AnnounceTimer *timer)
3450510ea2SDr. David Alan Gilbert {
3550510ea2SDr. David Alan Gilbert     if (timer->tm) {
3650510ea2SDr. David Alan Gilbert         timer_del(timer->tm);
3750510ea2SDr. David Alan Gilbert         timer_free(timer->tm);
3850510ea2SDr. David Alan Gilbert         timer->tm = NULL;
3950510ea2SDr. David Alan Gilbert     }
4050510ea2SDr. David Alan Gilbert }
4150510ea2SDr. David Alan Gilbert 
4250510ea2SDr. David Alan Gilbert /*
4350510ea2SDr. David Alan Gilbert  * Under BQL/main thread
4450510ea2SDr. David Alan Gilbert  * Reset the timer to the given parameters/type/notifier.
4550510ea2SDr. David Alan Gilbert  */
4650510ea2SDr. David Alan Gilbert void qemu_announce_timer_reset(AnnounceTimer *timer,
4750510ea2SDr. David Alan Gilbert                                AnnounceParameters *params,
4850510ea2SDr. David Alan Gilbert                                QEMUClockType type,
4950510ea2SDr. David Alan Gilbert                                QEMUTimerCB *cb,
5050510ea2SDr. David Alan Gilbert                                void *opaque)
5150510ea2SDr. David Alan Gilbert {
5250510ea2SDr. David Alan Gilbert     /*
5350510ea2SDr. David Alan Gilbert      * We're under the BQL, so the current timer can't
5450510ea2SDr. David Alan Gilbert      * be firing, so we should be able to delete it.
5550510ea2SDr. David Alan Gilbert      */
5650510ea2SDr. David Alan Gilbert     qemu_announce_timer_del(timer);
5750510ea2SDr. David Alan Gilbert 
5850510ea2SDr. David Alan Gilbert     QAPI_CLONE_MEMBERS(AnnounceParameters, &timer->params, params);
5950510ea2SDr. David Alan Gilbert     timer->round = params->rounds;
6050510ea2SDr. David Alan Gilbert     timer->type = type;
6150510ea2SDr. David Alan Gilbert     timer->tm = timer_new_ms(type, cb, opaque);
6250510ea2SDr. David Alan Gilbert }
637659505cSDr. David Alan Gilbert 
647659505cSDr. David Alan Gilbert #ifndef ETH_P_RARP
657659505cSDr. David Alan Gilbert #define ETH_P_RARP 0x8035
667659505cSDr. David Alan Gilbert #endif
677659505cSDr. David Alan Gilbert #define ARP_HTYPE_ETH 0x0001
687659505cSDr. David Alan Gilbert #define ARP_PTYPE_IP 0x0800
697659505cSDr. David Alan Gilbert #define ARP_OP_REQUEST_REV 0x3
707659505cSDr. David Alan Gilbert 
717659505cSDr. David Alan Gilbert static int announce_self_create(uint8_t *buf,
727659505cSDr. David Alan Gilbert                                 uint8_t *mac_addr)
737659505cSDr. David Alan Gilbert {
747659505cSDr. David Alan Gilbert     /* Ethernet header. */
757659505cSDr. David Alan Gilbert     memset(buf, 0xff, 6);         /* destination MAC addr */
767659505cSDr. David Alan Gilbert     memcpy(buf + 6, mac_addr, 6); /* source MAC addr */
777659505cSDr. David Alan Gilbert     *(uint16_t *)(buf + 12) = htons(ETH_P_RARP); /* ethertype */
787659505cSDr. David Alan Gilbert 
797659505cSDr. David Alan Gilbert     /* RARP header. */
807659505cSDr. David Alan Gilbert     *(uint16_t *)(buf + 14) = htons(ARP_HTYPE_ETH); /* hardware addr space */
817659505cSDr. David Alan Gilbert     *(uint16_t *)(buf + 16) = htons(ARP_PTYPE_IP); /* protocol addr space */
827659505cSDr. David Alan Gilbert     *(buf + 18) = 6; /* hardware addr length (ethernet) */
837659505cSDr. David Alan Gilbert     *(buf + 19) = 4; /* protocol addr length (IPv4) */
847659505cSDr. David Alan Gilbert     *(uint16_t *)(buf + 20) = htons(ARP_OP_REQUEST_REV); /* opcode */
857659505cSDr. David Alan Gilbert     memcpy(buf + 22, mac_addr, 6); /* source hw addr */
867659505cSDr. David Alan Gilbert     memset(buf + 28, 0x00, 4);     /* source protocol addr */
877659505cSDr. David Alan Gilbert     memcpy(buf + 32, mac_addr, 6); /* target hw addr */
887659505cSDr. David Alan Gilbert     memset(buf + 38, 0x00, 4);     /* target protocol addr */
897659505cSDr. David Alan Gilbert 
907659505cSDr. David Alan Gilbert     /* Padding to get up to 60 bytes (ethernet min packet size, minus FCS). */
917659505cSDr. David Alan Gilbert     memset(buf + 42, 0x00, 18);
927659505cSDr. David Alan Gilbert 
937659505cSDr. David Alan Gilbert     return 60; /* len (FCS will be added by hardware) */
947659505cSDr. David Alan Gilbert }
957659505cSDr. David Alan Gilbert 
967659505cSDr. David Alan Gilbert static void qemu_announce_self_iter(NICState *nic, void *opaque)
977659505cSDr. David Alan Gilbert {
987659505cSDr. David Alan Gilbert     uint8_t buf[60];
997659505cSDr. David Alan Gilbert     int len;
1007659505cSDr. David Alan Gilbert 
1017659505cSDr. David Alan Gilbert     trace_qemu_announce_self_iter(qemu_ether_ntoa(&nic->conf->macaddr));
1027659505cSDr. David Alan Gilbert     len = announce_self_create(buf, nic->conf->macaddr.a);
1037659505cSDr. David Alan Gilbert 
1047659505cSDr. David Alan Gilbert     qemu_send_packet_raw(qemu_get_queue(nic), buf, len);
105*44b416adSDr. David Alan Gilbert 
106*44b416adSDr. David Alan Gilbert     /* if the NIC provides it's own announcement support, use it as well */
107*44b416adSDr. David Alan Gilbert     if (nic->ncs->info->announce) {
108*44b416adSDr. David Alan Gilbert         nic->ncs->info->announce(nic->ncs);
109*44b416adSDr. David Alan Gilbert     }
1107659505cSDr. David Alan Gilbert }
1117659505cSDr. David Alan Gilbert static void qemu_announce_self_once(void *opaque)
1127659505cSDr. David Alan Gilbert {
1137659505cSDr. David Alan Gilbert     AnnounceTimer *timer = (AnnounceTimer *)opaque;
1147659505cSDr. David Alan Gilbert 
1157659505cSDr. David Alan Gilbert     qemu_foreach_nic(qemu_announce_self_iter, NULL);
1167659505cSDr. David Alan Gilbert 
1177659505cSDr. David Alan Gilbert     if (--timer->round) {
1187659505cSDr. David Alan Gilbert         qemu_announce_timer_step(timer);
1197659505cSDr. David Alan Gilbert     } else {
1207659505cSDr. David Alan Gilbert         qemu_announce_timer_del(timer);
1217659505cSDr. David Alan Gilbert     }
1227659505cSDr. David Alan Gilbert }
1237659505cSDr. David Alan Gilbert 
1247659505cSDr. David Alan Gilbert void qemu_announce_self(AnnounceTimer *timer, AnnounceParameters *params)
1257659505cSDr. David Alan Gilbert {
1267659505cSDr. David Alan Gilbert     qemu_announce_timer_reset(timer, params, QEMU_CLOCK_REALTIME,
1277659505cSDr. David Alan Gilbert                               qemu_announce_self_once, timer);
1287659505cSDr. David Alan Gilbert     if (params->rounds) {
1297659505cSDr. David Alan Gilbert         qemu_announce_self_once(timer);
1307659505cSDr. David Alan Gilbert     } else {
1317659505cSDr. David Alan Gilbert         qemu_announce_timer_del(timer);
1327659505cSDr. David Alan Gilbert     }
1337659505cSDr. David Alan Gilbert }
134