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