Annotation of qemu/slirp/udp.c, revision 1.1.1.8

1.1       root        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.
1.1.1.6   root       13:  * 3. Neither the name of the University nor the names of its contributors
1.1       root       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.
1.1.1.5   root       36:  *
                     37:  * Please read the file COPYRIGHT for the
1.1       root       38:  * terms and conditions of the copyright.
                     39:  */
                     40: 
                     41: #include <slirp.h>
                     42: #include "ip_icmp.h"
                     43: 
1.1.1.5   root       44: static u_int8_t udp_tos(struct socket *so);
                     45: 
1.1       root       46: void
1.1.1.7   root       47: udp_init(Slirp *slirp)
1.1       root       48: {
1.1.1.7   root       49:     slirp->udb.so_next = slirp->udb.so_prev = &slirp->udb;
                     50:     slirp->udp_last_so = &slirp->udb;
1.1       root       51: }
1.1.1.5   root       52: /* m->m_data  points at ip packet header
                     53:  * m->m_len   length ip packet
1.1       root       54:  * ip->ip_len length data (IPDU)
                     55:  */
                     56: void
1.1.1.7   root       57: udp_input(register struct mbuf *m, int iphlen)
1.1       root       58: {
1.1.1.7   root       59:        Slirp *slirp = m->slirp;
1.1       root       60:        register struct ip *ip;
                     61:        register struct udphdr *uh;
                     62:        int len;
1.1.1.5   root       63:        struct ip save_ip;
1.1       root       64:        struct socket *so;
1.1.1.5   root       65: 
1.1       root       66:        DEBUG_CALL("udp_input");
                     67:        DEBUG_ARG("m = %lx", (long)m);
                     68:        DEBUG_ARG("iphlen = %d", iphlen);
1.1.1.5   root       69: 
1.1       root       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((u_int16_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:        }
1.1.1.5   root      100: 
1.1       root      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:         */
1.1.1.5   root      105:        save_ip = *ip;
1.1       root      106:        save_ip.ip_len+= iphlen;         /* tcp_input subtracts this */
                    107: 
                    108:        /*
                    109:         * Checksum extended UDP header and data.
                    110:         */
1.1.1.7   root      111:        if (uh->uh_sum) {
1.1.1.6   root      112:       memset(&((struct ipovly *)ip)->ih_mbuf, 0, sizeof(struct mbuf_ptr));
1.1       root      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:             bootp_input(m);
                    125:             goto bad;
                    126:         }
                    127: 
1.1.1.7   root      128:         if (slirp->restricted) {
1.1.1.6   root      129:             goto bad;
1.1.1.7   root      130:         }
1.1.1.6   root      131: 
1.1       root      132:         /*
                    133:          *  handle TFTP
                    134:          */
                    135:         if (ntohs(uh->uh_dport) == TFTP_SERVER) {
                    136:             tftp_input(m);
                    137:             goto bad;
                    138:         }
                    139: 
                    140:        /*
                    141:         * Locate pcb for datagram.
                    142:         */
1.1.1.7   root      143:        so = slirp->udp_last_so;
1.1       root      144:        if (so->so_lport != uh->uh_sport ||
                    145:            so->so_laddr.s_addr != ip->ip_src.s_addr) {
                    146:                struct socket *tmp;
1.1.1.5   root      147: 
1.1.1.7   root      148:                for (tmp = slirp->udb.so_next; tmp != &slirp->udb;
                    149:                     tmp = tmp->so_next) {
1.1       root      150:                        if (tmp->so_lport == uh->uh_sport &&
                    151:                            tmp->so_laddr.s_addr == ip->ip_src.s_addr) {
                    152:                                so = tmp;
                    153:                                break;
                    154:                        }
                    155:                }
1.1.1.7   root      156:                if (tmp == &slirp->udb) {
1.1       root      157:                  so = NULL;
                    158:                } else {
1.1.1.7   root      159:                  slirp->udp_last_so = so;
1.1       root      160:                }
                    161:        }
1.1.1.5   root      162: 
1.1       root      163:        if (so == NULL) {
                    164:          /*
                    165:           * If there's no socket for this packet,
                    166:           * create one
                    167:           */
1.1.1.7   root      168:          so = socreate(slirp);
                    169:          if (!so) {
                    170:              goto bad;
                    171:          }
1.1       root      172:          if(udp_attach(so) == -1) {
1.1.1.5   root      173:            DEBUG_MISC((dfd," udp_attach errno = %d-%s\n",
1.1       root      174:                        errno,strerror(errno)));
                    175:            sofree(so);
                    176:            goto bad;
                    177:          }
1.1.1.5   root      178: 
1.1       root      179:          /*
                    180:           * Setup fields
                    181:           */
                    182:          so->so_laddr = ip->ip_src;
                    183:          so->so_lport = uh->uh_sport;
1.1.1.5   root      184: 
1.1       root      185:          if ((so->so_iptos = udp_tos(so)) == 0)
                    186:            so->so_iptos = ip->ip_tos;
1.1.1.5   root      187: 
1.1       root      188:          /*
                    189:           * XXXXX Here, check if it's in udpexec_list,
                    190:           * and if it is, do the fork_exec() etc.
                    191:           */
                    192:        }
                    193: 
1.1.1.4   root      194:         so->so_faddr = ip->ip_dst; /* XXX */
                    195:         so->so_fport = uh->uh_dport; /* XXX */
                    196: 
1.1       root      197:        iphlen += sizeof(struct udphdr);
                    198:        m->m_len -= iphlen;
                    199:        m->m_data += iphlen;
                    200: 
                    201:        /*
                    202:         * Now we sendto() the packet.
                    203:         */
                    204:        if(sosendto(so,m) == -1) {
                    205:          m->m_len += iphlen;
                    206:          m->m_data -= iphlen;
                    207:          *ip=save_ip;
                    208:          DEBUG_MISC((dfd,"udp tx errno = %d-%s\n",errno,strerror(errno)));
1.1.1.5   root      209:          icmp_error(m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,strerror(errno));
1.1       root      210:        }
                    211: 
                    212:        m_free(so->so_m);   /* used for ICMP if error on sorecvfrom */
                    213: 
                    214:        /* restore the orig mbuf packet */
                    215:        m->m_len += iphlen;
                    216:        m->m_data -= iphlen;
                    217:        *ip=save_ip;
                    218:        so->so_m=m;         /* ICMP backup */
                    219: 
                    220:        return;
                    221: bad:
                    222:        m_freem(m);
                    223:        return;
                    224: }
                    225: 
1.1.1.5   root      226: int udp_output2(struct socket *so, struct mbuf *m,
1.1       root      227:                 struct sockaddr_in *saddr, struct sockaddr_in *daddr,
                    228:                 int iptos)
                    229: {
                    230:        register struct udpiphdr *ui;
                    231:        int error = 0;
                    232: 
                    233:        DEBUG_CALL("udp_output");
                    234:        DEBUG_ARG("so = %lx", (long)so);
                    235:        DEBUG_ARG("m = %lx", (long)m);
                    236:        DEBUG_ARG("saddr = %lx", (long)saddr->sin_addr.s_addr);
                    237:        DEBUG_ARG("daddr = %lx", (long)daddr->sin_addr.s_addr);
                    238: 
                    239:        /*
                    240:         * Adjust for header
                    241:         */
                    242:        m->m_data -= sizeof(struct udpiphdr);
                    243:        m->m_len += sizeof(struct udpiphdr);
1.1.1.5   root      244: 
1.1       root      245:        /*
                    246:         * Fill in mbuf with extended UDP header
                    247:         * and addresses and length put into network format.
                    248:         */
                    249:        ui = mtod(m, struct udpiphdr *);
1.1.1.6   root      250:     memset(&ui->ui_i.ih_mbuf, 0 , sizeof(struct mbuf_ptr));
1.1       root      251:        ui->ui_x1 = 0;
                    252:        ui->ui_pr = IPPROTO_UDP;
1.1.1.7   root      253:        ui->ui_len = htons(m->m_len - sizeof(struct ip));
1.1       root      254:        /* XXXXX Check for from-one-location sockets, or from-any-location sockets */
                    255:         ui->ui_src = saddr->sin_addr;
                    256:        ui->ui_dst = daddr->sin_addr;
                    257:        ui->ui_sport = saddr->sin_port;
                    258:        ui->ui_dport = daddr->sin_port;
                    259:        ui->ui_ulen = ui->ui_len;
                    260: 
                    261:        /*
                    262:         * Stuff checksum and output datagram.
                    263:         */
                    264:        ui->ui_sum = 0;
1.1.1.7   root      265:        if ((ui->ui_sum = cksum(m, m->m_len)) == 0)
1.1       root      266:                ui->ui_sum = 0xffff;
                    267:        ((struct ip *)ui)->ip_len = m->m_len;
                    268: 
1.1.1.5   root      269:        ((struct ip *)ui)->ip_ttl = IPDEFTTL;
1.1       root      270:        ((struct ip *)ui)->ip_tos = iptos;
1.1.1.5   root      271: 
1.1       root      272:        error = ip_output(so, m);
1.1.1.5   root      273: 
1.1       root      274:        return (error);
                    275: }
                    276: 
1.1.1.5   root      277: int udp_output(struct socket *so, struct mbuf *m,
1.1       root      278:                struct sockaddr_in *addr)
                    279: 
                    280: {
1.1.1.7   root      281:     Slirp *slirp = so->slirp;
1.1       root      282:     struct sockaddr_in saddr, daddr;
                    283: 
                    284:     saddr = *addr;
1.1.1.7   root      285:     if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) ==
                    286:         slirp->vnetwork_addr.s_addr) {
                    287:         uint32_t inv_mask = ~slirp->vnetwork_mask.s_addr;
                    288: 
                    289:         if ((so->so_faddr.s_addr & inv_mask) == inv_mask) {
                    290:             saddr.sin_addr = slirp->vhost_addr;
                    291:         } else if (addr->sin_addr.s_addr == loopback_addr.s_addr ||
                    292:                    so->so_faddr.s_addr != slirp->vhost_addr.s_addr) {
                    293:             saddr.sin_addr = so->so_faddr;
                    294:         }
1.1.1.3   root      295:     }
1.1       root      296:     daddr.sin_addr = so->so_laddr;
                    297:     daddr.sin_port = so->so_lport;
1.1.1.5   root      298: 
1.1       root      299:     return udp_output2(so, m, &saddr, &daddr, so->so_iptos);
                    300: }
                    301: 
                    302: int
1.1.1.7   root      303: udp_attach(struct socket *so)
1.1       root      304: {
1.1.1.8 ! root      305:   if((so->s = qemu_socket(AF_INET,SOCK_DGRAM,0)) != -1) {
        !           306:     so->so_expire = curtime + SO_EXPIRE;
        !           307:     insque(so, &so->slirp->udb);
1.1       root      308:   }
                    309:   return(so->s);
                    310: }
                    311: 
                    312: void
1.1.1.7   root      313: udp_detach(struct socket *so)
1.1       root      314: {
                    315:        closesocket(so->s);
                    316:        sofree(so);
                    317: }
                    318: 
1.1.1.5   root      319: static const struct tos_t udptos[] = {
1.1       root      320:        {0, 53, IPTOS_LOWDELAY, 0},                     /* DNS */
                    321:        {0, 0, 0, 0}
                    322: };
                    323: 
1.1.1.5   root      324: static u_int8_t
                    325: udp_tos(struct socket *so)
1.1       root      326: {
                    327:        int i = 0;
1.1.1.5   root      328: 
1.1       root      329:        while(udptos[i].tos) {
                    330:                if ((udptos[i].fport && ntohs(so->so_fport) == udptos[i].fport) ||
                    331:                    (udptos[i].lport && ntohs(so->so_lport) == udptos[i].lport)) {
                    332:                        so->so_emu = udptos[i].emu;
                    333:                        return udptos[i].tos;
                    334:                }
                    335:                i++;
                    336:        }
1.1.1.5   root      337: 
1.1       root      338:        return 0;
                    339: }
                    340: 
                    341: struct socket *
1.1.1.7   root      342: udp_listen(Slirp *slirp, u_int32_t haddr, u_int hport, u_int32_t laddr,
                    343:            u_int lport, int flags)
1.1       root      344: {
                    345:        struct sockaddr_in addr;
                    346:        struct socket *so;
1.1.1.6   root      347:        socklen_t addrlen = sizeof(struct sockaddr_in), opt = 1;
1.1.1.5   root      348: 
1.1.1.7   root      349:        so = socreate(slirp);
                    350:        if (!so) {
                    351:            return NULL;
1.1       root      352:        }
1.1.1.8 ! root      353:        so->s = qemu_socket(AF_INET,SOCK_DGRAM,0);
1.1       root      354:        so->so_expire = curtime + SO_EXPIRE;
1.1.1.7   root      355:        insque(so, &slirp->udb);
1.1       root      356: 
                    357:        addr.sin_family = AF_INET;
1.1.1.7   root      358:        addr.sin_addr.s_addr = haddr;
                    359:        addr.sin_port = hport;
1.1       root      360: 
                    361:        if (bind(so->s,(struct sockaddr *)&addr, addrlen) < 0) {
                    362:                udp_detach(so);
                    363:                return NULL;
                    364:        }
                    365:        setsockopt(so->s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int));
1.1.1.5   root      366: 
1.1       root      367:        getsockname(so->s,(struct sockaddr *)&addr,&addrlen);
                    368:        so->so_fport = addr.sin_port;
1.1.1.7   root      369:        if (addr.sin_addr.s_addr == 0 ||
                    370:            addr.sin_addr.s_addr == loopback_addr.s_addr) {
                    371:           so->so_faddr = slirp->vhost_addr;
                    372:        } else {
1.1       root      373:           so->so_faddr = addr.sin_addr;
1.1.1.7   root      374:        }
1.1       root      375:        so->so_lport = lport;
                    376:        so->so_laddr.s_addr = laddr;
                    377:        if (flags != SS_FACCEPTONCE)
                    378:           so->so_expire = 0;
1.1.1.5   root      379: 
1.1.1.7   root      380:        so->so_state &= SS_PERSISTENT_MASK;
                    381:        so->so_state |= SS_ISFCONNECTED | flags;
1.1.1.5   root      382: 
1.1       root      383:        return so;
                    384: }

unix.superglobalmegacorp.com