| /* | 
 |  * replay-net.c | 
 |  * | 
 |  * Copyright (c) 2010-2016 Institute for System Programming | 
 |  *                         of the Russian Academy of Sciences. | 
 |  * | 
 |  * This work is licensed under the terms of the GNU GPL, version 2 or later. | 
 |  * See the COPYING file in the top-level directory. | 
 |  * | 
 |  */ | 
 |  | 
 | #include "qemu/osdep.h" | 
 | #include "qemu/error-report.h" | 
 | #include "sysemu/replay.h" | 
 | #include "replay-internal.h" | 
 | #include "net/net.h" | 
 | #include "net/filter.h" | 
 | #include "qemu/iov.h" | 
 |  | 
 | struct ReplayNetState { | 
 |     NetFilterState *nfs; | 
 |     int id; | 
 | }; | 
 |  | 
 | typedef struct NetEvent { | 
 |     uint8_t id; | 
 |     uint32_t flags; | 
 |     uint8_t *data; | 
 |     size_t size; | 
 | } NetEvent; | 
 |  | 
 | static NetFilterState **network_filters; | 
 | static int network_filters_count; | 
 |  | 
 | ReplayNetState *replay_register_net(NetFilterState *nfs) | 
 | { | 
 |     ReplayNetState *rns = g_new0(ReplayNetState, 1); | 
 |     rns->nfs = nfs; | 
 |     rns->id = network_filters_count++; | 
 |     network_filters = g_realloc(network_filters, | 
 |                                 network_filters_count | 
 |                                     * sizeof(*network_filters)); | 
 |     network_filters[network_filters_count - 1] = nfs; | 
 |     return rns; | 
 | } | 
 |  | 
 | void replay_unregister_net(ReplayNetState *rns) | 
 | { | 
 |     network_filters[rns->id] = NULL; | 
 |     g_free(rns); | 
 | } | 
 |  | 
 | void replay_net_packet_event(ReplayNetState *rns, unsigned flags, | 
 |                              const struct iovec *iov, int iovcnt) | 
 | { | 
 |     NetEvent *event = g_new(NetEvent, 1); | 
 |     event->flags = flags; | 
 |     event->data = g_malloc(iov_size(iov, iovcnt)); | 
 |     event->size = iov_size(iov, iovcnt); | 
 |     event->id = rns->id; | 
 |     iov_to_buf(iov, iovcnt, 0, event->data, event->size); | 
 |  | 
 |     replay_add_event(REPLAY_ASYNC_EVENT_NET, event, NULL, 0); | 
 | } | 
 |  | 
 | void replay_event_net_run(void *opaque) | 
 | { | 
 |     NetEvent *event = opaque; | 
 |     struct iovec iov = { | 
 |         .iov_base = (void *)event->data, | 
 |         .iov_len = event->size | 
 |     }; | 
 |  | 
 |     assert(event->id < network_filters_count); | 
 |  | 
 |     qemu_netfilter_pass_to_next(network_filters[event->id]->netdev, | 
 |         event->flags, &iov, 1, network_filters[event->id]); | 
 |  | 
 |     g_free(event->data); | 
 |     g_free(event); | 
 | } | 
 |  | 
 | void replay_event_net_save(void *opaque) | 
 | { | 
 |     NetEvent *event = opaque; | 
 |  | 
 |     replay_put_byte(event->id); | 
 |     replay_put_dword(event->flags); | 
 |     replay_put_array(event->data, event->size); | 
 | } | 
 |  | 
 | void *replay_event_net_load(void) | 
 | { | 
 |     NetEvent *event = g_new(NetEvent, 1); | 
 |  | 
 |     event->id = replay_get_byte(); | 
 |     event->flags = replay_get_dword(); | 
 |     replay_get_array_alloc(&event->data, &event->size); | 
 |  | 
 |     return event; | 
 | } |