File:  [Qemu by Fabrice Bellard] / qemu / slirp / udp.c
Revision 1.1.1.11 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 19:51:40 2018 UTC (3 years, 3 months ago) by root
Branches: qemu, MAIN
CVS tags: qemu1101, HEAD
qemu 1.1.1

    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: 
   44: static uint8_t udp_tos(struct socket *so);
   45: 
   46: void
   47: udp_init(Slirp *slirp)
   48: {
   49:     slirp->udb.so_next = slirp->udb.so_prev = &slirp->udb;
   50:     slirp->udp_last_so = &slirp->udb;
   51: }
   52: 
   53: void udp_cleanup(Slirp *slirp)
   54: {
   55:     while (slirp->udb.so_next != &slirp->udb) {
   56:         udp_detach(slirp->udb.so_next);
   57:     }
   58: }
   59: 
   60: /* m->m_data  points at ip packet header
   61:  * m->m_len   length ip packet
   62:  * ip->ip_len length data (IPDU)
   63:  */
   64: void
   65: udp_input(register struct mbuf *m, int iphlen)
   66: {
   67: 	Slirp *slirp = m->slirp;
   68: 	register struct ip *ip;
   69: 	register struct udphdr *uh;
   70: 	int len;
   71: 	struct ip save_ip;
   72: 	struct socket *so;
   73: 
   74: 	DEBUG_CALL("udp_input");
   75: 	DEBUG_ARG("m = %lx", (long)m);
   76: 	DEBUG_ARG("iphlen = %d", iphlen);
   77: 
   78: 	/*
   79: 	 * Strip IP options, if any; should skip this,
   80: 	 * make available to user, and use on returned packets,
   81: 	 * but we don't yet have a way to check the checksum
   82: 	 * with options still present.
   83: 	 */
   84: 	if(iphlen > sizeof(struct ip)) {
   85: 		ip_stripoptions(m, (struct mbuf *)0);
   86: 		iphlen = sizeof(struct ip);
   87: 	}
   88: 
   89: 	/*
   90: 	 * Get IP and UDP header together in first mbuf.
   91: 	 */
   92: 	ip = mtod(m, struct ip *);
   93: 	uh = (struct udphdr *)((caddr_t)ip + iphlen);
   94: 
   95: 	/*
   96: 	 * Make mbuf data length reflect UDP length.
   97: 	 * If not enough data to reflect UDP length, drop.
   98: 	 */
   99: 	len = ntohs((uint16_t)uh->uh_ulen);
  100: 
  101: 	if (ip->ip_len != len) {
  102: 		if (len > ip->ip_len) {
  103: 			goto bad;
  104: 		}
  105: 		m_adj(m, len - ip->ip_len);
  106: 		ip->ip_len = len;
  107: 	}
  108: 
  109: 	/*
  110: 	 * Save a copy of the IP header in case we want restore it
  111: 	 * for sending an ICMP error message in response.
  112: 	 */
  113: 	save_ip = *ip;
  114: 	save_ip.ip_len+= iphlen;         /* tcp_input subtracts this */
  115: 
  116: 	/*
  117: 	 * Checksum extended UDP header and data.
  118: 	 */
  119: 	if (uh->uh_sum) {
  120:       memset(&((struct ipovly *)ip)->ih_mbuf, 0, sizeof(struct mbuf_ptr));
  121: 	  ((struct ipovly *)ip)->ih_x1 = 0;
  122: 	  ((struct ipovly *)ip)->ih_len = uh->uh_ulen;
  123: 	  if(cksum(m, len + sizeof(struct ip))) {
  124: 	    goto bad;
  125: 	  }
  126: 	}
  127: 
  128:         /*
  129:          *  handle DHCP/BOOTP
  130:          */
  131:         if (ntohs(uh->uh_dport) == BOOTP_SERVER &&
  132:             (ip->ip_dst.s_addr == slirp->vhost_addr.s_addr ||
  133:              ip->ip_dst.s_addr == 0xffffffff)) {
  134:                 bootp_input(m);
  135:                 goto bad;
  136:             }
  137: 
  138:         /*
  139:          *  handle TFTP
  140:          */
  141:         if (ntohs(uh->uh_dport) == TFTP_SERVER &&
  142:             ip->ip_dst.s_addr == slirp->vhost_addr.s_addr) {
  143:             tftp_input(m);
  144:             goto bad;
  145:         }
  146: 
  147:         if (slirp->restricted) {
  148:             goto bad;
  149:         }
  150: 
  151: 	/*
  152: 	 * Locate pcb for datagram.
  153: 	 */
  154: 	so = slirp->udp_last_so;
  155: 	if (so->so_lport != uh->uh_sport ||
  156: 	    so->so_laddr.s_addr != ip->ip_src.s_addr) {
  157: 		struct socket *tmp;
  158: 
  159: 		for (tmp = slirp->udb.so_next; tmp != &slirp->udb;
  160: 		     tmp = tmp->so_next) {
  161: 			if (tmp->so_lport == uh->uh_sport &&
  162: 			    tmp->so_laddr.s_addr == ip->ip_src.s_addr) {
  163: 				so = tmp;
  164: 				break;
  165: 			}
  166: 		}
  167: 		if (tmp == &slirp->udb) {
  168: 		  so = NULL;
  169: 		} else {
  170: 		  slirp->udp_last_so = so;
  171: 		}
  172: 	}
  173: 
  174: 	if (so == NULL) {
  175: 	  /*
  176: 	   * If there's no socket for this packet,
  177: 	   * create one
  178: 	   */
  179: 	  so = socreate(slirp);
  180: 	  if (!so) {
  181: 	      goto bad;
  182: 	  }
  183: 	  if(udp_attach(so) == -1) {
  184: 	    DEBUG_MISC((dfd," udp_attach errno = %d-%s\n",
  185: 			errno,strerror(errno)));
  186: 	    sofree(so);
  187: 	    goto bad;
  188: 	  }
  189: 
  190: 	  /*
  191: 	   * Setup fields
  192: 	   */
  193: 	  so->so_laddr = ip->ip_src;
  194: 	  so->so_lport = uh->uh_sport;
  195: 
  196: 	  if ((so->so_iptos = udp_tos(so)) == 0)
  197: 	    so->so_iptos = ip->ip_tos;
  198: 
  199: 	  /*
  200: 	   * XXXXX Here, check if it's in udpexec_list,
  201: 	   * and if it is, do the fork_exec() etc.
  202: 	   */
  203: 	}
  204: 
  205:         so->so_faddr = ip->ip_dst; /* XXX */
  206:         so->so_fport = uh->uh_dport; /* XXX */
  207: 
  208: 	iphlen += sizeof(struct udphdr);
  209: 	m->m_len -= iphlen;
  210: 	m->m_data += iphlen;
  211: 
  212: 	/*
  213: 	 * Now we sendto() the packet.
  214: 	 */
  215: 	if(sosendto(so,m) == -1) {
  216: 	  m->m_len += iphlen;
  217: 	  m->m_data -= iphlen;
  218: 	  *ip=save_ip;
  219: 	  DEBUG_MISC((dfd,"udp tx errno = %d-%s\n",errno,strerror(errno)));
  220: 	  icmp_error(m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,strerror(errno));
  221: 	}
  222: 
  223: 	m_free(so->so_m);   /* used for ICMP if error on sorecvfrom */
  224: 
  225: 	/* restore the orig mbuf packet */
  226: 	m->m_len += iphlen;
  227: 	m->m_data -= iphlen;
  228: 	*ip=save_ip;
  229: 	so->so_m=m;         /* ICMP backup */
  230: 
  231: 	return;
  232: bad:
  233: 	m_free(m);
  234: 	return;
  235: }
  236: 
  237: int udp_output2(struct socket *so, struct mbuf *m,
  238:                 struct sockaddr_in *saddr, struct sockaddr_in *daddr,
  239:                 int iptos)
  240: {
  241: 	register struct udpiphdr *ui;
  242: 	int error = 0;
  243: 
  244: 	DEBUG_CALL("udp_output");
  245: 	DEBUG_ARG("so = %lx", (long)so);
  246: 	DEBUG_ARG("m = %lx", (long)m);
  247: 	DEBUG_ARG("saddr = %lx", (long)saddr->sin_addr.s_addr);
  248: 	DEBUG_ARG("daddr = %lx", (long)daddr->sin_addr.s_addr);
  249: 
  250: 	/*
  251: 	 * Adjust for header
  252: 	 */
  253: 	m->m_data -= sizeof(struct udpiphdr);
  254: 	m->m_len += sizeof(struct udpiphdr);
  255: 
  256: 	/*
  257: 	 * Fill in mbuf with extended UDP header
  258: 	 * and addresses and length put into network format.
  259: 	 */
  260: 	ui = mtod(m, struct udpiphdr *);
  261:     memset(&ui->ui_i.ih_mbuf, 0 , sizeof(struct mbuf_ptr));
  262: 	ui->ui_x1 = 0;
  263: 	ui->ui_pr = IPPROTO_UDP;
  264: 	ui->ui_len = htons(m->m_len - sizeof(struct ip));
  265: 	/* XXXXX Check for from-one-location sockets, or from-any-location sockets */
  266:         ui->ui_src = saddr->sin_addr;
  267: 	ui->ui_dst = daddr->sin_addr;
  268: 	ui->ui_sport = saddr->sin_port;
  269: 	ui->ui_dport = daddr->sin_port;
  270: 	ui->ui_ulen = ui->ui_len;
  271: 
  272: 	/*
  273: 	 * Stuff checksum and output datagram.
  274: 	 */
  275: 	ui->ui_sum = 0;
  276: 	if ((ui->ui_sum = cksum(m, m->m_len)) == 0)
  277: 		ui->ui_sum = 0xffff;
  278: 	((struct ip *)ui)->ip_len = m->m_len;
  279: 
  280: 	((struct ip *)ui)->ip_ttl = IPDEFTTL;
  281: 	((struct ip *)ui)->ip_tos = iptos;
  282: 
  283: 	error = ip_output(so, m);
  284: 
  285: 	return (error);
  286: }
  287: 
  288: int udp_output(struct socket *so, struct mbuf *m,
  289:                struct sockaddr_in *addr)
  290: 
  291: {
  292:     Slirp *slirp = so->slirp;
  293:     struct sockaddr_in saddr, daddr;
  294: 
  295:     saddr = *addr;
  296:     if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) ==
  297:         slirp->vnetwork_addr.s_addr) {
  298:         uint32_t inv_mask = ~slirp->vnetwork_mask.s_addr;
  299: 
  300:         if ((so->so_faddr.s_addr & inv_mask) == inv_mask) {
  301:             saddr.sin_addr = slirp->vhost_addr;
  302:         } else if (addr->sin_addr.s_addr == loopback_addr.s_addr ||
  303:                    so->so_faddr.s_addr != slirp->vhost_addr.s_addr) {
  304:             saddr.sin_addr = so->so_faddr;
  305:         }
  306:     }
  307:     daddr.sin_addr = so->so_laddr;
  308:     daddr.sin_port = so->so_lport;
  309: 
  310:     return udp_output2(so, m, &saddr, &daddr, so->so_iptos);
  311: }
  312: 
  313: int
  314: udp_attach(struct socket *so)
  315: {
  316:   if((so->s = qemu_socket(AF_INET,SOCK_DGRAM,0)) != -1) {
  317:     so->so_expire = curtime + SO_EXPIRE;
  318:     insque(so, &so->slirp->udb);
  319:   }
  320:   return(so->s);
  321: }
  322: 
  323: void
  324: udp_detach(struct socket *so)
  325: {
  326: 	closesocket(so->s);
  327: 	sofree(so);
  328: }
  329: 
  330: static const struct tos_t udptos[] = {
  331: 	{0, 53, IPTOS_LOWDELAY, 0},			/* DNS */
  332: 	{0, 0, 0, 0}
  333: };
  334: 
  335: static uint8_t
  336: udp_tos(struct socket *so)
  337: {
  338: 	int i = 0;
  339: 
  340: 	while(udptos[i].tos) {
  341: 		if ((udptos[i].fport && ntohs(so->so_fport) == udptos[i].fport) ||
  342: 		    (udptos[i].lport && ntohs(so->so_lport) == udptos[i].lport)) {
  343: 		    	so->so_emu = udptos[i].emu;
  344: 			return udptos[i].tos;
  345: 		}
  346: 		i++;
  347: 	}
  348: 
  349: 	return 0;
  350: }
  351: 
  352: struct socket *
  353: udp_listen(Slirp *slirp, uint32_t haddr, u_int hport, uint32_t laddr,
  354:            u_int lport, int flags)
  355: {
  356: 	struct sockaddr_in addr;
  357: 	struct socket *so;
  358: 	socklen_t addrlen = sizeof(struct sockaddr_in), opt = 1;
  359: 
  360: 	so = socreate(slirp);
  361: 	if (!so) {
  362: 	    return NULL;
  363: 	}
  364: 	so->s = qemu_socket(AF_INET,SOCK_DGRAM,0);
  365: 	so->so_expire = curtime + SO_EXPIRE;
  366: 	insque(so, &slirp->udb);
  367: 
  368: 	addr.sin_family = AF_INET;
  369: 	addr.sin_addr.s_addr = haddr;
  370: 	addr.sin_port = hport;
  371: 
  372: 	if (bind(so->s,(struct sockaddr *)&addr, addrlen) < 0) {
  373: 		udp_detach(so);
  374: 		return NULL;
  375: 	}
  376: 	setsockopt(so->s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int));
  377: 
  378: 	getsockname(so->s,(struct sockaddr *)&addr,&addrlen);
  379: 	so->so_fport = addr.sin_port;
  380: 	if (addr.sin_addr.s_addr == 0 ||
  381: 	    addr.sin_addr.s_addr == loopback_addr.s_addr) {
  382: 	   so->so_faddr = slirp->vhost_addr;
  383: 	} else {
  384: 	   so->so_faddr = addr.sin_addr;
  385: 	}
  386: 	so->so_lport = lport;
  387: 	so->so_laddr.s_addr = laddr;
  388: 	if (flags != SS_FACCEPTONCE)
  389: 	   so->so_expire = 0;
  390: 
  391: 	so->so_state &= SS_PERSISTENT_MASK;
  392: 	so->so_state |= SS_ISFCONNECTED | flags;
  393: 
  394: 	return so;
  395: }

unix.superglobalmegacorp.com