qemu/slirp/udp.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 1982, 1986, 1988, 1990, 1993
   3 *      The Regents of the University of California.  All rights reserved.
   4 *
   5 * Redistribution and use in source and binary forms, with or without
   6 * modification, are permitted provided that the following conditions
   7 * are met:
   8 * 1. Redistributions of source code must retain the above copyright
   9 *    notice, this list of conditions and the following disclaimer.
  10 * 2. Redistributions in binary form must reproduce the above copyright
  11 *    notice, this list of conditions and the following disclaimer in the
  12 *    documentation and/or other materials provided with the distribution.
  13 * 3. Neither the name of the University nor the names of its contributors
  14 *    may be used to endorse or promote products derived from this software
  15 *    without specific prior written permission.
  16 *
  17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  27 * SUCH DAMAGE.
  28 *
  29 *      @(#)udp_usrreq.c        8.4 (Berkeley) 1/21/94
  30 * udp_usrreq.c,v 1.4 1994/10/02 17:48:45 phk Exp
  31 */
  32
  33/*
  34 * Changes and additions relating to SLiRP
  35 * Copyright (c) 1995 Danny Gasparovski.
  36 *
  37 * Please read the file COPYRIGHT for the
  38 * terms and conditions of the copyright.
  39 */
  40
  41#include <slirp.h>
  42#include "ip_icmp.h"
  43
  44static uint8_t udp_tos(struct socket *so);
  45
  46void
  47udp_init(Slirp *slirp)
  48{
  49    slirp->udb.so_next = slirp->udb.so_prev = &slirp->udb;
  50    slirp->udp_last_so = &slirp->udb;
  51}
  52/* m->m_data  points at ip packet header
  53 * m->m_len   length ip packet
  54 * ip->ip_len length data (IPDU)
  55 */
  56void
  57udp_input(register struct mbuf *m, int iphlen)
  58{
  59        Slirp *slirp = m->slirp;
  60        register struct ip *ip;
  61        register struct udphdr *uh;
  62        int len;
  63        struct ip save_ip;
  64        struct socket *so;
  65
  66        DEBUG_CALL("udp_input");
  67        DEBUG_ARG("m = %lx", (long)m);
  68        DEBUG_ARG("iphlen = %d", iphlen);
  69
  70        /*
  71         * Strip IP options, if any; should skip this,
  72         * make available to user, and use on returned packets,
  73         * but we don't yet have a way to check the checksum
  74         * with options still present.
  75         */
  76        if(iphlen > sizeof(struct ip)) {
  77                ip_stripoptions(m, (struct mbuf *)0);
  78                iphlen = sizeof(struct ip);
  79        }
  80
  81        /*
  82         * Get IP and UDP header together in first mbuf.
  83         */
  84        ip = mtod(m, struct ip *);
  85        uh = (struct udphdr *)((caddr_t)ip + iphlen);
  86
  87        /*
  88         * Make mbuf data length reflect UDP length.
  89         * If not enough data to reflect UDP length, drop.
  90         */
  91        len = ntohs((uint16_t)uh->uh_ulen);
  92
  93        if (ip->ip_len != len) {
  94                if (len > ip->ip_len) {
  95                        goto bad;
  96                }
  97                m_adj(m, len - ip->ip_len);
  98                ip->ip_len = len;
  99        }
 100
 101        /*
 102         * Save a copy of the IP header in case we want restore it
 103         * for sending an ICMP error message in response.
 104         */
 105        save_ip = *ip;
 106        save_ip.ip_len+= iphlen;         /* tcp_input subtracts this */
 107
 108        /*
 109         * Checksum extended UDP header and data.
 110         */
 111        if (uh->uh_sum) {
 112      memset(&((struct ipovly *)ip)->ih_mbuf, 0, sizeof(struct mbuf_ptr));
 113          ((struct ipovly *)ip)->ih_x1 = 0;
 114          ((struct ipovly *)ip)->ih_len = uh->uh_ulen;
 115          if(cksum(m, len + sizeof(struct ip))) {
 116            goto bad;
 117          }
 118        }
 119
 120        /*
 121         *  handle DHCP/BOOTP
 122         */
 123        if (ntohs(uh->uh_dport) == BOOTP_SERVER &&
 124            (ip->ip_dst.s_addr == slirp->vhost_addr.s_addr ||
 125             ip->ip_dst.s_addr == 0xffffffff)) {
 126                bootp_input(m);
 127                goto bad;
 128            }
 129
 130        /*
 131         *  handle TFTP
 132         */
 133        if (ntohs(uh->uh_dport) == TFTP_SERVER &&
 134            ip->ip_dst.s_addr == slirp->vhost_addr.s_addr) {
 135            tftp_input(m);
 136            goto bad;
 137        }
 138
 139        if (slirp->restricted) {
 140            goto bad;
 141        }
 142
 143        /*
 144         * Locate pcb for datagram.
 145         */
 146        so = slirp->udp_last_so;
 147        if (so->so_lport != uh->uh_sport ||
 148            so->so_laddr.s_addr != ip->ip_src.s_addr) {
 149                struct socket *tmp;
 150
 151                for (tmp = slirp->udb.so_next; tmp != &slirp->udb;
 152                     tmp = tmp->so_next) {
 153                        if (tmp->so_lport == uh->uh_sport &&
 154                            tmp->so_laddr.s_addr == ip->ip_src.s_addr) {
 155                                so = tmp;
 156                                break;
 157                        }
 158                }
 159                if (tmp == &slirp->udb) {
 160                  so = NULL;
 161                } else {
 162                  slirp->udp_last_so = so;
 163                }
 164        }
 165
 166        if (so == NULL) {
 167          /*
 168           * If there's no socket for this packet,
 169           * create one
 170           */
 171          so = socreate(slirp);
 172          if (!so) {
 173              goto bad;
 174          }
 175          if(udp_attach(so) == -1) {
 176            DEBUG_MISC((dfd," udp_attach errno = %d-%s\n",
 177                        errno,strerror(errno)));
 178            sofree(so);
 179            goto bad;
 180          }
 181
 182          /*
 183           * Setup fields
 184           */
 185          so->so_laddr = ip->ip_src;
 186          so->so_lport = uh->uh_sport;
 187
 188          if ((so->so_iptos = udp_tos(so)) == 0)
 189            so->so_iptos = ip->ip_tos;
 190
 191          /*
 192           * XXXXX Here, check if it's in udpexec_list,
 193           * and if it is, do the fork_exec() etc.
 194           */
 195        }
 196
 197        so->so_faddr = ip->ip_dst; /* XXX */
 198        so->so_fport = uh->uh_dport; /* XXX */
 199
 200        iphlen += sizeof(struct udphdr);
 201        m->m_len -= iphlen;
 202        m->m_data += iphlen;
 203
 204        /*
 205         * Now we sendto() the packet.
 206         */
 207        if(sosendto(so,m) == -1) {
 208          m->m_len += iphlen;
 209          m->m_data -= iphlen;
 210          *ip=save_ip;
 211          DEBUG_MISC((dfd,"udp tx errno = %d-%s\n",errno,strerror(errno)));
 212          icmp_error(m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,strerror(errno));
 213        }
 214
 215        m_free(so->so_m);   /* used for ICMP if error on sorecvfrom */
 216
 217        /* restore the orig mbuf packet */
 218        m->m_len += iphlen;
 219        m->m_data -= iphlen;
 220        *ip=save_ip;
 221        so->so_m=m;         /* ICMP backup */
 222
 223        return;
 224bad:
 225        m_free(m);
 226        return;
 227}
 228
 229int udp_output2(struct socket *so, struct mbuf *m,
 230                struct sockaddr_in *saddr, struct sockaddr_in *daddr,
 231                int iptos)
 232{
 233        register struct udpiphdr *ui;
 234        int error = 0;
 235
 236        DEBUG_CALL("udp_output");
 237        DEBUG_ARG("so = %lx", (long)so);
 238        DEBUG_ARG("m = %lx", (long)m);
 239        DEBUG_ARG("saddr = %lx", (long)saddr->sin_addr.s_addr);
 240        DEBUG_ARG("daddr = %lx", (long)daddr->sin_addr.s_addr);
 241
 242        /*
 243         * Adjust for header
 244         */
 245        m->m_data -= sizeof(struct udpiphdr);
 246        m->m_len += sizeof(struct udpiphdr);
 247
 248        /*
 249         * Fill in mbuf with extended UDP header
 250         * and addresses and length put into network format.
 251         */
 252        ui = mtod(m, struct udpiphdr *);
 253    memset(&ui->ui_i.ih_mbuf, 0 , sizeof(struct mbuf_ptr));
 254        ui->ui_x1 = 0;
 255        ui->ui_pr = IPPROTO_UDP;
 256        ui->ui_len = htons(m->m_len - sizeof(struct ip));
 257        /* XXXXX Check for from-one-location sockets, or from-any-location sockets */
 258        ui->ui_src = saddr->sin_addr;
 259        ui->ui_dst = daddr->sin_addr;
 260        ui->ui_sport = saddr->sin_port;
 261        ui->ui_dport = daddr->sin_port;
 262        ui->ui_ulen = ui->ui_len;
 263
 264        /*
 265         * Stuff checksum and output datagram.
 266         */
 267        ui->ui_sum = 0;
 268        if ((ui->ui_sum = cksum(m, m->m_len)) == 0)
 269                ui->ui_sum = 0xffff;
 270        ((struct ip *)ui)->ip_len = m->m_len;
 271
 272        ((struct ip *)ui)->ip_ttl = IPDEFTTL;
 273        ((struct ip *)ui)->ip_tos = iptos;
 274
 275        error = ip_output(so, m);
 276
 277        return (error);
 278}
 279
 280int udp_output(struct socket *so, struct mbuf *m,
 281               struct sockaddr_in *addr)
 282
 283{
 284    Slirp *slirp = so->slirp;
 285    struct sockaddr_in saddr, daddr;
 286
 287    saddr = *addr;
 288    if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) ==
 289        slirp->vnetwork_addr.s_addr) {
 290        uint32_t inv_mask = ~slirp->vnetwork_mask.s_addr;
 291
 292        if ((so->so_faddr.s_addr & inv_mask) == inv_mask) {
 293            saddr.sin_addr = slirp->vhost_addr;
 294        } else if (addr->sin_addr.s_addr == loopback_addr.s_addr ||
 295                   so->so_faddr.s_addr != slirp->vhost_addr.s_addr) {
 296            saddr.sin_addr = so->so_faddr;
 297        }
 298    }
 299    daddr.sin_addr = so->so_laddr;
 300    daddr.sin_port = so->so_lport;
 301
 302    return udp_output2(so, m, &saddr, &daddr, so->so_iptos);
 303}
 304
 305int
 306udp_attach(struct socket *so)
 307{
 308  if((so->s = qemu_socket(AF_INET,SOCK_DGRAM,0)) != -1) {
 309    so->so_expire = curtime + SO_EXPIRE;
 310    insque(so, &so->slirp->udb);
 311  }
 312  return(so->s);
 313}
 314
 315void
 316udp_detach(struct socket *so)
 317{
 318        closesocket(so->s);
 319        sofree(so);
 320}
 321
 322static const struct tos_t udptos[] = {
 323        {0, 53, IPTOS_LOWDELAY, 0},                     /* DNS */
 324        {0, 0, 0, 0}
 325};
 326
 327static uint8_t
 328udp_tos(struct socket *so)
 329{
 330        int i = 0;
 331
 332        while(udptos[i].tos) {
 333                if ((udptos[i].fport && ntohs(so->so_fport) == udptos[i].fport) ||
 334                    (udptos[i].lport && ntohs(so->so_lport) == udptos[i].lport)) {
 335                        so->so_emu = udptos[i].emu;
 336                        return udptos[i].tos;
 337                }
 338                i++;
 339        }
 340
 341        return 0;
 342}
 343
 344struct socket *
 345udp_listen(Slirp *slirp, uint32_t haddr, u_int hport, uint32_t laddr,
 346           u_int lport, int flags)
 347{
 348        struct sockaddr_in addr;
 349        struct socket *so;
 350        socklen_t addrlen = sizeof(struct sockaddr_in), opt = 1;
 351
 352        so = socreate(slirp);
 353        if (!so) {
 354            return NULL;
 355        }
 356        so->s = qemu_socket(AF_INET,SOCK_DGRAM,0);
 357        so->so_expire = curtime + SO_EXPIRE;
 358        insque(so, &slirp->udb);
 359
 360        addr.sin_family = AF_INET;
 361        addr.sin_addr.s_addr = haddr;
 362        addr.sin_port = hport;
 363
 364        if (bind(so->s,(struct sockaddr *)&addr, addrlen) < 0) {
 365                udp_detach(so);
 366                return NULL;
 367        }
 368        setsockopt(so->s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int));
 369
 370        getsockname(so->s,(struct sockaddr *)&addr,&addrlen);
 371        so->so_fport = addr.sin_port;
 372        if (addr.sin_addr.s_addr == 0 ||
 373            addr.sin_addr.s_addr == loopback_addr.s_addr) {
 374           so->so_faddr = slirp->vhost_addr;
 375        } else {
 376           so->so_faddr = addr.sin_addr;
 377        }
 378        so->so_lport = lport;
 379        so->so_laddr.s_addr = laddr;
 380        if (flags != SS_FACCEPTONCE)
 381           so->so_expire = 0;
 382
 383        so->so_state &= SS_PERSISTENT_MASK;
 384        so->so_state |= SS_ISFCONNECTED | flags;
 385
 386        return so;
 387}
 388