1 /* 2 * Self-announce 3 * (c) 2017-2019 Red Hat, Inc. 4 * 5 * This work is licensed under the terms of the GNU GPL, version 2 or later. 6 * See the COPYING file in the top-level directory. 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 18 int64_t qemu_announce_timer_step(AnnounceTimer *timer) 19 { 20 int64_t step; 21 22 step = timer->params.initial + 23 (timer->params.rounds - timer->round - 1) * 24 timer->params.step; 25 26 if (step < 0 || step > timer->params.max) { 27 step = timer->params.max; 28 } 29 timer_mod(timer->tm, qemu_clock_get_ms(timer->type) + step); 30 31 return step; 32 } 33 34 void qemu_announce_timer_del(AnnounceTimer *timer) 35 { 36 if (timer->tm) { 37 timer_del(timer->tm); 38 timer_free(timer->tm); 39 timer->tm = NULL; 40 } 41 qapi_free_strList(timer->params.interfaces); 42 timer->params.interfaces = NULL; 43 } 44 45 /* 46 * Under BQL/main thread 47 * Reset the timer to the given parameters/type/notifier. 48 */ 49 void qemu_announce_timer_reset(AnnounceTimer *timer, 50 AnnounceParameters *params, 51 QEMUClockType type, 52 QEMUTimerCB *cb, 53 void *opaque) 54 { 55 /* 56 * We're under the BQL, so the current timer can't 57 * be firing, so we should be able to delete it. 58 */ 59 qemu_announce_timer_del(timer); 60 61 QAPI_CLONE_MEMBERS(AnnounceParameters, &timer->params, params); 62 timer->round = params->rounds; 63 timer->type = type; 64 timer->tm = timer_new_ms(type, cb, opaque); 65 } 66 67 #ifndef ETH_P_RARP 68 #define ETH_P_RARP 0x8035 69 #endif 70 #define ARP_HTYPE_ETH 0x0001 71 #define ARP_PTYPE_IP 0x0800 72 #define ARP_OP_REQUEST_REV 0x3 73 74 static int announce_self_create(uint8_t *buf, 75 uint8_t *mac_addr) 76 { 77 /* Ethernet header. */ 78 memset(buf, 0xff, 6); /* destination MAC addr */ 79 memcpy(buf + 6, mac_addr, 6); /* source MAC addr */ 80 *(uint16_t *)(buf + 12) = htons(ETH_P_RARP); /* ethertype */ 81 82 /* RARP header. */ 83 *(uint16_t *)(buf + 14) = htons(ARP_HTYPE_ETH); /* hardware addr space */ 84 *(uint16_t *)(buf + 16) = htons(ARP_PTYPE_IP); /* protocol addr space */ 85 *(buf + 18) = 6; /* hardware addr length (ethernet) */ 86 *(buf + 19) = 4; /* protocol addr length (IPv4) */ 87 *(uint16_t *)(buf + 20) = htons(ARP_OP_REQUEST_REV); /* opcode */ 88 memcpy(buf + 22, mac_addr, 6); /* source hw addr */ 89 memset(buf + 28, 0x00, 4); /* source protocol addr */ 90 memcpy(buf + 32, mac_addr, 6); /* target hw addr */ 91 memset(buf + 38, 0x00, 4); /* target protocol addr */ 92 93 /* Padding to get up to 60 bytes (ethernet min packet size, minus FCS). */ 94 memset(buf + 42, 0x00, 18); 95 96 return 60; /* len (FCS will be added by hardware) */ 97 } 98 99 static void qemu_announce_self_iter(NICState *nic, void *opaque) 100 { 101 AnnounceTimer *timer = opaque; 102 uint8_t buf[60]; 103 int len; 104 bool skip; 105 106 if (timer->params.has_interfaces) { 107 strList *entry = timer->params.interfaces; 108 /* Skip unless we find our name in the requested list */ 109 skip = true; 110 111 while (entry) { 112 if (!strcmp(entry->value, nic->ncs->name)) { 113 /* Found us */ 114 skip = false; 115 break; 116 } 117 entry = entry->next; 118 } 119 } else { 120 skip = false; 121 } 122 123 trace_qemu_announce_self_iter(nic->ncs->name, 124 qemu_ether_ntoa(&nic->conf->macaddr), skip); 125 126 if (!skip) { 127 len = announce_self_create(buf, nic->conf->macaddr.a); 128 129 qemu_send_packet_raw(qemu_get_queue(nic), buf, len); 130 131 /* if the NIC provides it's own announcement support, use it as well */ 132 if (nic->ncs->info->announce) { 133 nic->ncs->info->announce(nic->ncs); 134 } 135 } 136 } 137 static void qemu_announce_self_once(void *opaque) 138 { 139 AnnounceTimer *timer = (AnnounceTimer *)opaque; 140 141 qemu_foreach_nic(qemu_announce_self_iter, timer); 142 143 if (--timer->round) { 144 qemu_announce_timer_step(timer); 145 } else { 146 qemu_announce_timer_del(timer); 147 } 148 } 149 150 void qemu_announce_self(AnnounceTimer *timer, AnnounceParameters *params) 151 { 152 qemu_announce_timer_reset(timer, params, QEMU_CLOCK_REALTIME, 153 qemu_announce_self_once, timer); 154 if (params->rounds) { 155 qemu_announce_self_once(timer); 156 } else { 157 qemu_announce_timer_del(timer); 158 } 159 } 160 161 void qmp_announce_self(AnnounceParameters *params, Error **errp) 162 { 163 static AnnounceTimer announce_timer; 164 qemu_announce_self(&announce_timer, params); 165 } 166