cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

char-udp.c (7263B)


      1/*
      2 * QEMU System Emulator
      3 *
      4 * Copyright (c) 2003-2008 Fabrice Bellard
      5 *
      6 * Permission is hereby granted, free of charge, to any person obtaining a copy
      7 * of this software and associated documentation files (the "Software"), to deal
      8 * in the Software without restriction, including without limitation the rights
      9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     10 * copies of the Software, and to permit persons to whom the Software is
     11 * furnished to do so, subject to the following conditions:
     12 *
     13 * The above copyright notice and this permission notice shall be included in
     14 * all copies or substantial portions of the Software.
     15 *
     16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
     19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     22 * THE SOFTWARE.
     23 */
     24
     25#include "qemu/osdep.h"
     26#include "chardev/char.h"
     27#include "io/channel-socket.h"
     28#include "qapi/error.h"
     29#include "qemu/module.h"
     30#include "qemu/option.h"
     31
     32#include "chardev/char-io.h"
     33#include "qom/object.h"
     34
     35/***********************************************************/
     36/* UDP Net console */
     37
     38struct UdpChardev {
     39    Chardev parent;
     40    QIOChannel *ioc;
     41    uint8_t buf[CHR_READ_BUF_LEN];
     42    int bufcnt;
     43    int bufptr;
     44    int max_size;
     45};
     46typedef struct UdpChardev UdpChardev;
     47
     48DECLARE_INSTANCE_CHECKER(UdpChardev, UDP_CHARDEV,
     49                         TYPE_CHARDEV_UDP)
     50
     51/* Called with chr_write_lock held.  */
     52static int udp_chr_write(Chardev *chr, const uint8_t *buf, int len)
     53{
     54    UdpChardev *s = UDP_CHARDEV(chr);
     55
     56    return qio_channel_write(
     57        s->ioc, (const char *)buf, len, NULL);
     58}
     59
     60static void udp_chr_flush_buffer(UdpChardev *s)
     61{
     62    Chardev *chr = CHARDEV(s);
     63
     64    while (s->max_size > 0 && s->bufptr < s->bufcnt) {
     65        int n = MIN(s->max_size, s->bufcnt - s->bufptr);
     66        qemu_chr_be_write(chr, &s->buf[s->bufptr], n);
     67        s->bufptr += n;
     68        s->max_size = qemu_chr_be_can_write(chr);
     69    }
     70}
     71
     72static int udp_chr_read_poll(void *opaque)
     73{
     74    Chardev *chr = CHARDEV(opaque);
     75    UdpChardev *s = UDP_CHARDEV(opaque);
     76
     77    s->max_size = qemu_chr_be_can_write(chr);
     78
     79    /* If there were any stray characters in the queue process them
     80     * first
     81     */
     82    udp_chr_flush_buffer(s);
     83
     84    return s->max_size;
     85}
     86
     87static gboolean udp_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
     88{
     89    Chardev *chr = CHARDEV(opaque);
     90    UdpChardev *s = UDP_CHARDEV(opaque);
     91    ssize_t ret;
     92
     93    if (s->max_size == 0) {
     94        return TRUE;
     95    }
     96    ret = qio_channel_read(
     97        s->ioc, (char *)s->buf, sizeof(s->buf), NULL);
     98    if (ret <= 0) {
     99        remove_fd_in_watch(chr);
    100        return FALSE;
    101    }
    102    s->bufcnt = ret;
    103    s->bufptr = 0;
    104    udp_chr_flush_buffer(s);
    105
    106    return TRUE;
    107}
    108
    109static void udp_chr_update_read_handler(Chardev *chr)
    110{
    111    UdpChardev *s = UDP_CHARDEV(chr);
    112
    113    remove_fd_in_watch(chr);
    114    if (s->ioc) {
    115        chr->gsource = io_add_watch_poll(chr, s->ioc,
    116                                           udp_chr_read_poll,
    117                                           udp_chr_read, chr,
    118                                           chr->gcontext);
    119    }
    120}
    121
    122static void char_udp_finalize(Object *obj)
    123{
    124    Chardev *chr = CHARDEV(obj);
    125    UdpChardev *s = UDP_CHARDEV(obj);
    126
    127    remove_fd_in_watch(chr);
    128    if (s->ioc) {
    129        object_unref(OBJECT(s->ioc));
    130    }
    131    qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
    132}
    133
    134static void qemu_chr_parse_udp(QemuOpts *opts, ChardevBackend *backend,
    135                               Error **errp)
    136{
    137    const char *host = qemu_opt_get(opts, "host");
    138    const char *port = qemu_opt_get(opts, "port");
    139    const char *localaddr = qemu_opt_get(opts, "localaddr");
    140    const char *localport = qemu_opt_get(opts, "localport");
    141    bool has_local = false;
    142    SocketAddressLegacy *addr;
    143    ChardevUdp *udp;
    144
    145    backend->type = CHARDEV_BACKEND_KIND_UDP;
    146    if (host == NULL || strlen(host) == 0) {
    147        host = "localhost";
    148    }
    149    if (port == NULL || strlen(port) == 0) {
    150        error_setg(errp, "chardev: udp: remote port not specified");
    151        return;
    152    }
    153    if (localport == NULL || strlen(localport) == 0) {
    154        localport = "0";
    155    } else {
    156        has_local = true;
    157    }
    158    if (localaddr == NULL || strlen(localaddr) == 0) {
    159        localaddr = "";
    160    } else {
    161        has_local = true;
    162    }
    163
    164    udp = backend->u.udp.data = g_new0(ChardevUdp, 1);
    165    qemu_chr_parse_common(opts, qapi_ChardevUdp_base(udp));
    166
    167    addr = g_new0(SocketAddressLegacy, 1);
    168    addr->type = SOCKET_ADDRESS_TYPE_INET;
    169    addr->u.inet.data = g_new(InetSocketAddress, 1);
    170    *addr->u.inet.data = (InetSocketAddress) {
    171        .host = g_strdup(host),
    172        .port = g_strdup(port),
    173        .has_ipv4 = qemu_opt_get(opts, "ipv4"),
    174        .ipv4 = qemu_opt_get_bool(opts, "ipv4", 0),
    175        .has_ipv6 = qemu_opt_get(opts, "ipv6"),
    176        .ipv6 = qemu_opt_get_bool(opts, "ipv6", 0),
    177    };
    178    udp->remote = addr;
    179
    180    if (has_local) {
    181        udp->has_local = true;
    182        addr = g_new0(SocketAddressLegacy, 1);
    183        addr->type = SOCKET_ADDRESS_TYPE_INET;
    184        addr->u.inet.data = g_new(InetSocketAddress, 1);
    185        *addr->u.inet.data = (InetSocketAddress) {
    186            .host = g_strdup(localaddr),
    187            .port = g_strdup(localport),
    188        };
    189        udp->local = addr;
    190    }
    191}
    192
    193static void qmp_chardev_open_udp(Chardev *chr,
    194                                 ChardevBackend *backend,
    195                                 bool *be_opened,
    196                                 Error **errp)
    197{
    198    ChardevUdp *udp = backend->u.udp.data;
    199    SocketAddress *local_addr = socket_address_flatten(udp->local);
    200    SocketAddress *remote_addr = socket_address_flatten(udp->remote);
    201    QIOChannelSocket *sioc = qio_channel_socket_new();
    202    char *name;
    203    UdpChardev *s = UDP_CHARDEV(chr);
    204    int ret;
    205
    206    ret = qio_channel_socket_dgram_sync(sioc, local_addr, remote_addr, errp);
    207    qapi_free_SocketAddress(local_addr);
    208    qapi_free_SocketAddress(remote_addr);
    209    if (ret < 0) {
    210        object_unref(OBJECT(sioc));
    211        return;
    212    }
    213
    214    name = g_strdup_printf("chardev-udp-%s", chr->label);
    215    qio_channel_set_name(QIO_CHANNEL(sioc), name);
    216    g_free(name);
    217
    218    s->ioc = QIO_CHANNEL(sioc);
    219    /* be isn't opened until we get a connection */
    220    *be_opened = false;
    221}
    222
    223static void char_udp_class_init(ObjectClass *oc, void *data)
    224{
    225    ChardevClass *cc = CHARDEV_CLASS(oc);
    226
    227    cc->parse = qemu_chr_parse_udp;
    228    cc->open = qmp_chardev_open_udp;
    229    cc->chr_write = udp_chr_write;
    230    cc->chr_update_read_handler = udp_chr_update_read_handler;
    231}
    232
    233static const TypeInfo char_udp_type_info = {
    234    .name = TYPE_CHARDEV_UDP,
    235    .parent = TYPE_CHARDEV,
    236    .instance_size = sizeof(UdpChardev),
    237    .instance_finalize = char_udp_finalize,
    238    .class_init = char_udp_class_init,
    239};
    240
    241static void register_types(void)
    242{
    243    type_register_static(&char_udp_type_info);
    244}
    245
    246type_init(register_types);