+static void net_slirp_guest_error(const char *msg, void *opaque)
+{
+ qemu_log_mask(LOG_GUEST_ERROR, "%s", msg);
+}
+
+static int64_t net_slirp_clock_get_ns(void *opaque)
+{
+ return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+}
+
+static void *net_slirp_timer_new(SlirpTimerCb cb,
+ void *cb_opaque, void *opaque)
+{
+ return timer_new_full(NULL, QEMU_CLOCK_VIRTUAL,
+ SCALE_MS, QEMU_TIMER_ATTR_EXTERNAL,
+ cb, cb_opaque);
+}
+
+static void net_slirp_timer_free(void *timer, void *opaque)
+{
+ timer_del(timer);
+ timer_free(timer);
+}
+
+static void net_slirp_timer_mod(void *timer, int64_t expire_timer,
+ void *opaque)
+{
+ timer_mod(timer, expire_timer);
+}
+
+static void net_slirp_register_poll_fd(int fd, void *opaque)
+{
+ qemu_fd_register(fd);
+}
+
+static void net_slirp_unregister_poll_fd(int fd, void *opaque)
+{
+ /* no qemu_fd_unregister */
+}
+
+static void net_slirp_notify(void *opaque)
+{
+ qemu_notify_event();
+}
+
+static const SlirpCb slirp_cb = {
+ .send_packet = net_slirp_send_packet,
+ .guest_error = net_slirp_guest_error,
+ .clock_get_ns = net_slirp_clock_get_ns,
+ .timer_new = net_slirp_timer_new,
+ .timer_free = net_slirp_timer_free,
+ .timer_mod = net_slirp_timer_mod,
+ .register_poll_fd = net_slirp_register_poll_fd,
+ .unregister_poll_fd = net_slirp_unregister_poll_fd,
+ .notify = net_slirp_notify,
+};
+
+static int slirp_poll_to_gio(int events)
+{
+ int ret = 0;
+
+ if (events & SLIRP_POLL_IN) {
+ ret |= G_IO_IN;
+ }
+ if (events & SLIRP_POLL_OUT) {
+ ret |= G_IO_OUT;
+ }
+ if (events & SLIRP_POLL_PRI) {
+ ret |= G_IO_PRI;
+ }
+ if (events & SLIRP_POLL_ERR) {
+ ret |= G_IO_ERR;
+ }
+ if (events & SLIRP_POLL_HUP) {
+ ret |= G_IO_HUP;
+ }
+
+ return ret;
+}
+
+static int net_slirp_add_poll(int fd, int events, void *opaque)
+{
+ GArray *pollfds = opaque;
+ GPollFD pfd = {
+ .fd = fd,
+ .events = slirp_poll_to_gio(events),
+ };
+ int idx = pollfds->len;
+ g_array_append_val(pollfds, pfd);
+ return idx;
+}
+
+static int slirp_gio_to_poll(int events)
+{
+ int ret = 0;
+
+ if (events & G_IO_IN) {
+ ret |= SLIRP_POLL_IN;
+ }
+ if (events & G_IO_OUT) {
+ ret |= SLIRP_POLL_OUT;
+ }
+ if (events & G_IO_PRI) {
+ ret |= SLIRP_POLL_PRI;
+ }
+ if (events & G_IO_ERR) {
+ ret |= SLIRP_POLL_ERR;
+ }
+ if (events & G_IO_HUP) {
+ ret |= SLIRP_POLL_HUP;
+ }
+
+ return ret;
+}
+
+static int net_slirp_get_revents(int idx, void *opaque)
+{
+ GArray *pollfds = opaque;
+
+ return slirp_gio_to_poll(g_array_index(pollfds, GPollFD, idx).revents);
+}
+
+static void net_slirp_poll_notify(Notifier *notifier, void *data)
+{
+ MainLoopPoll *poll = data;
+ SlirpState *s = container_of(notifier, SlirpState, poll_notifier);
+
+ switch (poll->state) {
+ case MAIN_LOOP_POLL_FILL:
+ slirp_pollfds_fill(s->slirp, &poll->timeout,
+ net_slirp_add_poll, poll->pollfds);
+ break;
+ case MAIN_LOOP_POLL_OK:
+ case MAIN_LOOP_POLL_ERR:
+ slirp_pollfds_poll(s->slirp, poll->state == MAIN_LOOP_POLL_ERR,
+ net_slirp_get_revents, poll->pollfds);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+}
+