File:  [Qemu by Fabrice Bellard] / qemu / slirp / udp.c
Revision 1.1.1.8 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 17:41:09 2018 UTC (2 years, 10 months ago) by root
Branches: qemu, MAIN
CVS tags: qemu0125, qemu0124, qemu0123, qemu0122, qemu0121, qemu0120, HEAD
qemu 0.12.0

    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 u_int8_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((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: 	}
  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:             bootp_input(m);
  125:             goto bad;
  126:         }
  127: 
  128:         if (slirp->restricted) {
  129:             goto bad;
  130:         }
  131: 
  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: 	 */
  143: 	so = slirp->udp_last_so;
  144: 	if (so->so_lport != uh->uh_sport ||
  145: 	    so->so_laddr.s_addr != ip->ip_src.s_addr) {
  146: 		struct socket *tmp;
  147: 
  148: 		for (tmp = slirp->udb.so_next; tmp != &slirp->udb;
  149: 		     tmp = tmp->so_next) {
  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: 		}
  156: 		if (tmp == &slirp->udb) {
  157: 		  so = NULL;
  158: 		} else {
  159: 		  slirp->udp_last_so = so;
  160: 		}
  161: 	}
  162: 
  163: 	if (so == NULL) {
  164: 	  /*
  165: 	   * If there's no socket for this packet,
  166: 	   * create one
  167: 	   */
  168: 	  so = socreate(slirp);
  169: 	  if (!so) {
  170: 	      goto bad;
  171: 	  }
  172: 	  if(udp_attach(so) == -1) {
  173: 	    DEBUG_MISC((dfd," udp_attach errno = %d-%s\n",
  174: 			errno,strerror(errno)));
  175: 	    sofree(so);
  176: 	    goto bad;
  177: 	  }
  178: 
  179: 	  /*
  180: 	   * Setup fields
  181: 	   */
  182: 	  so->so_laddr = ip->ip_src;
  183: 	  so->so_lport = uh->uh_sport;
  184: 
  185: 	  if ((so->so_iptos = udp_tos(so)) == 0)
  186: 	    so->so_iptos = ip->ip_tos;
  187: 
  188: 	  /*
  189: 	   * XXXXX Here, check if it's in udpexec_list,
  190: 	   * and if it is, do the fork_exec() etc.
  191: 	   */
  192: 	}
  193: 
  194:         so->so_faddr = ip->ip_dst; /* XXX */
  195:         so->so_fport = uh->uh_dport; /* XXX */
  196: 
  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)));
  209: 	  icmp_error(m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,strerror(errno));
  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: 
  226: int udp_output2(struct socket *so, struct mbuf *m,
  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);
  244: 
  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 *);
  250:     memset(&ui->ui_i.ih_mbuf, 0 , sizeof(struct mbuf_ptr));
  251: 	ui->ui_x1 = 0;
  252: 	ui->ui_pr = IPPROTO_UDP;
  253: 	ui->ui_len = htons(m->m_len - sizeof(struct ip));
  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;
  265: 	if ((ui->ui_sum = cksum(m, m->m_len)) == 0)
  266: 		ui->ui_sum = 0xffff;
  267: 	((struct ip *)ui)->ip_len = m->m_len;
  268: 
  269: 	((struct ip *)ui)->ip_ttl = IPDEFTTL;
  270: 	((struct ip *)ui)->ip_tos = iptos;
  271: 
  272: 	error = ip_output(so, m);
  273: 
  274: 	return (error);
  275: }
  276: 
  277: int udp_output(struct socket *so, struct mbuf *m,
  278:                struct sockaddr_in *addr)
  279: 
  280: {
  281:     Slirp *slirp = so->slirp;
  282:     struct sockaddr_in saddr, daddr;
  283: 
  284:     saddr = *addr;
  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:         }
  295:     }
  296:     daddr.sin_addr = so->so_laddr;
  297:     daddr.sin_port = so->so_lport;
  298: 
  299:     return udp_output2(so, m, &saddr, &daddr, so->so_iptos);
  300: }
  301: 
  302: int
  303: udp_attach(struct socket *so)
  304: {
  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);
  308:   }
  309:   return(so->s);
  310: }
  311: 
  312: void
  313: udp_detach(struct socket *so)
  314: {
  315: 	closesocket(so->s);
  316: 	sofree(so);
  317: }
  318: 
  319: static const struct tos_t udptos[] = {
  320: 	{0, 53, IPTOS_LOWDELAY, 0},			/* DNS */
  321: 	{0, 0, 0, 0}
  322: };
  323: 
  324: static u_int8_t
  325: udp_tos(struct socket *so)
  326: {
  327: 	int i = 0;
  328: 
  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: 	}
  337: 
  338: 	return 0;
  339: }
  340: 
  341: struct socket *
  342: udp_listen(Slirp *slirp, u_int32_t haddr, u_int hport, u_int32_t laddr,
  343:            u_int lport, int flags)
  344: {
  345: 	struct sockaddr_in addr;
  346: 	struct socket *so;
  347: 	socklen_t addrlen = sizeof(struct sockaddr_in), opt = 1;
  348: 
  349: 	so = socreate(slirp);
  350: 	if (!so) {
  351: 	    return NULL;
  352: 	}
  353: 	so->s = qemu_socket(AF_INET,SOCK_DGRAM,0);
  354: 	so->so_expire = curtime + SO_EXPIRE;
  355: 	insque(so, &slirp->udb);
  356: 
  357: 	addr.sin_family = AF_INET;
  358: 	addr.sin_addr.s_addr = haddr;
  359: 	addr.sin_port = hport;
  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));
  366: 
  367: 	getsockname(so->s,(struct sockaddr *)&addr,&addrlen);
  368: 	so->so_fport = addr.sin_port;
  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 {
  373: 	   so->so_faddr = addr.sin_addr;
  374: 	}
  375: 	so->so_lport = lport;
  376: 	so->so_laddr.s_addr = laddr;
  377: 	if (flags != SS_FACCEPTONCE)
  378: 	   so->so_expire = 0;
  379: 
  380: 	so->so_state &= SS_PERSISTENT_MASK;
  381: 	so->so_state |= SS_ISFCONNECTED | flags;
  382: 
  383: 	return so;
  384: }

unix.superglobalmegacorp.com