File:  [Qemu by Fabrice Bellard] / qemu / slirp / udp.c
Revision 1.1.1.10 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 19:02:46 2018 UTC (3 years, 1 month ago) by root
Branches: qemu, MAIN
CVS tags: qemu1001, qemu1000, qemu0151, HEAD
qemu 0.15.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: /* m->m_data  points at ip packet header
   53:  * m->m_len   length ip packet
   54:  * ip->ip_len length data (IPDU)
   55:  */
   56: void
   57: udp_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;
  224: bad:
  225: 	m_free(m);
  226: 	return;
  227: }
  228: 
  229: int 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: 
  280: int 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: 
  305: int
  306: udp_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: 
  315: void
  316: udp_detach(struct socket *so)
  317: {
  318: 	closesocket(so->s);
  319: 	sofree(so);
  320: }
  321: 
  322: static const struct tos_t udptos[] = {
  323: 	{0, 53, IPTOS_LOWDELAY, 0},			/* DNS */
  324: 	{0, 0, 0, 0}
  325: };
  326: 
  327: static uint8_t
  328: udp_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: 
  344: struct socket *
  345: udp_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: }

unix.superglobalmegacorp.com