Home | History | Annotate | Download | only in slirp
      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 #ifdef LOG_ENABLED
     45 struct udpstat udpstat;
     46 #endif
     47 
     48 struct socket udb;
     49 
     50 static u_int8_t udp_tos(struct socket *so);
     51 static void udp_emu(struct socket *so, struct mbuf *m);
     52 
     53 /*
     54  * UDP protocol implementation.
     55  * Per RFC 768, August, 1980.
     56  */
     57 #ifndef	COMPAT_42
     58 #define UDPCKSUM 1
     59 #else
     60 #define UDPCKSUM 0 /* XXX */
     61 #endif
     62 
     63 struct	socket *udp_last_so = &udb;
     64 
     65 void
     66 udp_init(void)
     67 {
     68 	udb.so_next = udb.so_prev = &udb;
     69 }
     70 /* m->m_data  points at ip packet header
     71  * m->m_len   length ip packet
     72  * ip->ip_len length data (IPDU)
     73  */
     74 void
     75 udp_input(register struct mbuf *m, int iphlen)
     76 {
     77 	register struct ip *ip;
     78 	register struct udphdr *uh;
     79 /*	struct mbuf *opts = 0;*/
     80 	int len;
     81 	struct ip save_ip;
     82 	struct socket *so;
     83 
     84 	DEBUG_CALL("udp_input");
     85 	DEBUG_ARG("m = %lx", (long)m);
     86 	DEBUG_ARG("iphlen = %d", iphlen);
     87 
     88 	STAT(udpstat.udps_ipackets++);
     89 
     90 	/*
     91 	 * Strip IP options, if any; should skip this,
     92 	 * make available to user, and use on returned packets,
     93 	 * but we don't yet have a way to check the checksum
     94 	 * with options still present.
     95 	 */
     96 	if(iphlen > sizeof(struct ip)) {
     97 		ip_stripoptions(m, (struct mbuf *)0);
     98 		iphlen = sizeof(struct ip);
     99 	}
    100 
    101 	/*
    102 	 * Get IP and UDP header together in first mbuf.
    103 	 */
    104 	ip = mtod(m, struct ip *);
    105 	uh = (struct udphdr *)((caddr_t)ip + iphlen);
    106 
    107 	/*
    108 	 * Make mbuf data length reflect UDP length.
    109 	 * If not enough data to reflect UDP length, drop.
    110 	 */
    111 	len = ntohs((u_int16_t)uh->uh_ulen);
    112 
    113 	if (ip->ip_len != len) {
    114 		if (len > ip->ip_len) {
    115 			STAT(udpstat.udps_badlen++);
    116 			goto bad;
    117 		}
    118 		m_adj(m, len - ip->ip_len);
    119 		ip->ip_len = len;
    120 	}
    121 
    122 	/*
    123 	 * Save a copy of the IP header in case we want restore it
    124 	 * for sending an ICMP error message in response.
    125 	 */
    126 	save_ip = *ip;
    127 	save_ip.ip_len+= iphlen;         /* tcp_input subtracts this */
    128 
    129 	/*
    130 	 * Checksum extended UDP header and data.
    131 	 */
    132 	if (UDPCKSUM && uh->uh_sum) {
    133       memset(&((struct ipovly *)ip)->ih_mbuf, 0, sizeof(struct mbuf_ptr));
    134 	  ((struct ipovly *)ip)->ih_x1 = 0;
    135 	  ((struct ipovly *)ip)->ih_len = uh->uh_ulen;
    136 	  /* keep uh_sum for ICMP reply
    137 	   * uh->uh_sum = cksum(m, len + sizeof (struct ip));
    138 	   * if (uh->uh_sum) {
    139 	   */
    140 	  if(cksum(m, len + sizeof(struct ip))) {
    141 	    STAT(udpstat.udps_badsum++);
    142 	    goto bad;
    143 	  }
    144 	}
    145 
    146         /*
    147          *  handle DHCP/BOOTP
    148          */
    149         if (ntohs(uh->uh_dport) == BOOTP_SERVER) {
    150             bootp_input(m);
    151             goto bad;
    152         }
    153 
    154         if (slirp_restrict)
    155             goto bad;
    156 
    157         /*
    158          *  handle TFTP
    159          */
    160         if (ntohs(uh->uh_dport) == TFTP_SERVER) {
    161             tftp_input(m);
    162             goto bad;
    163         }
    164 
    165 	/*
    166 	 * Locate pcb for datagram.
    167 	 */
    168 	so = udp_last_so;
    169 	if (so->so_lport != uh->uh_sport ||
    170 	    so->so_laddr.s_addr != ip->ip_src.s_addr) {
    171 		struct socket *tmp;
    172 
    173 		for (tmp = udb.so_next; tmp != &udb; tmp = tmp->so_next) {
    174 			if (tmp->so_lport == uh->uh_sport &&
    175 			    tmp->so_laddr.s_addr == ip->ip_src.s_addr) {
    176 				tmp->so_faddr.s_addr = ip->ip_dst.s_addr;
    177 				tmp->so_fport = uh->uh_dport;
    178 				so = tmp;
    179 				break;
    180 			}
    181 		}
    182 		if (tmp == &udb) {
    183 		  so = NULL;
    184 		} else {
    185 		  STAT(udpstat.udpps_pcbcachemiss++);
    186 		  udp_last_so = so;
    187 		}
    188 	}
    189 
    190 	if (so == NULL) {
    191 	  /*
    192 	   * If there's no socket for this packet,
    193 	   * create one
    194 	   */
    195 	  if ((so = socreate()) == NULL) goto bad;
    196 	  if(udp_attach(so) == -1) {
    197 	    DEBUG_MISC((dfd," udp_attach errno = %d-%s\n",
    198 			errno,strerror(errno)));
    199 	    sofree(so);
    200 	    goto bad;
    201 	  }
    202 
    203 	  /*
    204 	   * Setup fields
    205 	   */
    206 	  /* udp_last_so = so; */
    207 	  so->so_laddr = ip->ip_src;
    208 	  so->so_lport = uh->uh_sport;
    209 
    210 	  if ((so->so_iptos = udp_tos(so)) == 0)
    211 	    so->so_iptos = ip->ip_tos;
    212 
    213 	  /*
    214 	   * XXXXX Here, check if it's in udpexec_list,
    215 	   * and if it is, do the fork_exec() etc.
    216 	   */
    217 	}
    218 
    219         so->so_faddr = ip->ip_dst; /* XXX */
    220         so->so_fport = uh->uh_dport; /* XXX */
    221 
    222 	iphlen += sizeof(struct udphdr);
    223 	m->m_len -= iphlen;
    224 	m->m_data += iphlen;
    225 
    226 	/*
    227 	 * Now we sendto() the packet.
    228 	 */
    229 	if (so->so_emu)
    230 	   udp_emu(so, m);
    231 
    232 	if(sosendto(so,m) == -1) {
    233 	  m->m_len += iphlen;
    234 	  m->m_data -= iphlen;
    235 	  *ip=save_ip;
    236 	  DEBUG_MISC((dfd,"udp tx errno = %d-%s\n",errno,strerror(errno)));
    237 	  icmp_error(m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,strerror(errno));
    238 	}
    239 
    240 	m_free(so->so_m);   /* used for ICMP if error on sorecvfrom */
    241 
    242 	/* restore the orig mbuf packet */
    243 	m->m_len += iphlen;
    244 	m->m_data -= iphlen;
    245 	*ip=save_ip;
    246 	so->so_m=m;         /* ICMP backup */
    247 
    248 	return;
    249 bad:
    250 	m_freem(m);
    251 	/* if (opts) m_freem(opts); */
    252 	return;
    253 }
    254 
    255 int udp_output2(struct socket *so, struct mbuf *m,
    256                 struct sockaddr_in *saddr, struct sockaddr_in *daddr,
    257                 int iptos)
    258 {
    259 	register struct udpiphdr *ui;
    260 	int error = 0;
    261 
    262 	DEBUG_CALL("udp_output");
    263 	DEBUG_ARG("so = %lx", (long)so);
    264 	DEBUG_ARG("m = %lx", (long)m);
    265 	DEBUG_ARG("saddr = %lx", (long)saddr->sin_addr.s_addr);
    266 	DEBUG_ARG("daddr = %lx", (long)daddr->sin_addr.s_addr);
    267 
    268 	/*
    269 	 * Adjust for header
    270 	 */
    271 	m->m_data -= sizeof(struct udpiphdr);
    272 	m->m_len += sizeof(struct udpiphdr);
    273 
    274 	/*
    275 	 * Fill in mbuf with extended UDP header
    276 	 * and addresses and length put into network format.
    277 	 */
    278 	ui = mtod(m, struct udpiphdr *);
    279     memset(&ui->ui_i.ih_mbuf, 0 , sizeof(struct mbuf_ptr));
    280 	ui->ui_x1 = 0;
    281 	ui->ui_pr = IPPROTO_UDP;
    282 	ui->ui_len = htons(m->m_len - sizeof(struct ip)); /* + sizeof (struct udphdr)); */
    283 	/* XXXXX Check for from-one-location sockets, or from-any-location sockets */
    284         ui->ui_src = saddr->sin_addr;
    285 	ui->ui_dst = daddr->sin_addr;
    286 	ui->ui_sport = saddr->sin_port;
    287 	ui->ui_dport = daddr->sin_port;
    288 	ui->ui_ulen = ui->ui_len;
    289 
    290 	/*
    291 	 * Stuff checksum and output datagram.
    292 	 */
    293 	ui->ui_sum = 0;
    294 	if (UDPCKSUM) {
    295 	    if ((ui->ui_sum = cksum(m, /* sizeof (struct udpiphdr) + */ m->m_len)) == 0)
    296 		ui->ui_sum = 0xffff;
    297 	}
    298 	((struct ip *)ui)->ip_len = m->m_len;
    299 
    300 	((struct ip *)ui)->ip_ttl = IPDEFTTL;
    301 	((struct ip *)ui)->ip_tos = iptos;
    302 
    303 	STAT(udpstat.udps_opackets++);
    304 
    305 	error = ip_output(so, m);
    306 
    307 	return (error);
    308 }
    309 
    310 int udp_output(struct socket *so, struct mbuf *m,
    311                struct sockaddr_in *addr)
    312 
    313 {
    314     struct sockaddr_in saddr, daddr;
    315 
    316     saddr = *addr;
    317     if ((so->so_faddr.s_addr & htonl(0xffffff00)) == special_addr.s_addr) {
    318         if ((so->so_faddr.s_addr & htonl(0x000000ff)) == htonl(0xff))
    319             saddr.sin_addr.s_addr = alias_addr.s_addr;
    320         else if (addr->sin_addr.s_addr == loopback_addr.s_addr ||
    321                  (ntohl(so->so_faddr.s_addr) & 0xff) != CTL_ALIAS)
    322             saddr.sin_addr.s_addr = so->so_faddr.s_addr;
    323     }
    324     daddr.sin_addr = so->so_laddr;
    325     daddr.sin_port = so->so_lport;
    326 
    327     return udp_output2(so, m, &saddr, &daddr, so->so_iptos);
    328 }
    329 
    330 int
    331 udp_attach(struct socket *so)
    332 {
    333   struct sockaddr_in addr;
    334 
    335   if((so->s = socket(AF_INET,SOCK_DGRAM,0)) != -1) {
    336     /*
    337      * Here, we bind() the socket.  Although not really needed
    338      * (sendto() on an unbound socket will bind it), it's done
    339      * here so that emulation of ytalk etc. don't have to do it
    340      */
    341     addr.sin_family = AF_INET;
    342     addr.sin_port = 0;
    343     addr.sin_addr.s_addr = INADDR_ANY;
    344     if(bind(so->s, (struct sockaddr *)&addr, sizeof(addr))<0) {
    345       int lasterrno=errno;
    346       closesocket(so->s);
    347       so->s=-1;
    348 #ifdef _WIN32
    349       WSASetLastError(lasterrno);
    350 #else
    351       errno=lasterrno;
    352 #endif
    353     } else {
    354       /* success, insert in queue */
    355       so->so_expire = curtime + SO_EXPIRE;
    356       insque(so,&udb);
    357     }
    358   }
    359   return(so->s);
    360 }
    361 
    362 void
    363 udp_detach(struct socket *so)
    364 {
    365 	closesocket(so->s);
    366 	/* if (so->so_m) m_free(so->so_m);    done by sofree */
    367 
    368 	sofree(so);
    369 }
    370 
    371 static const struct tos_t udptos[] = {
    372 	{0, 53, IPTOS_LOWDELAY, 0},			/* DNS */
    373 	{517, 517, IPTOS_LOWDELAY, EMU_TALK},	/* talk */
    374 	{518, 518, IPTOS_LOWDELAY, EMU_NTALK},	/* ntalk */
    375 	{0, 7648, IPTOS_LOWDELAY, EMU_CUSEEME},	/* Cu-Seeme */
    376 	{0, 0, 0, 0}
    377 };
    378 
    379 static u_int8_t
    380 udp_tos(struct socket *so)
    381 {
    382 	int i = 0;
    383 
    384 	while(udptos[i].tos) {
    385 		if ((udptos[i].fport && ntohs(so->so_fport) == udptos[i].fport) ||
    386 		    (udptos[i].lport && ntohs(so->so_lport) == udptos[i].lport)) {
    387 		    	so->so_emu = udptos[i].emu;
    388 			return udptos[i].tos;
    389 		}
    390 		i++;
    391 	}
    392 
    393 	return 0;
    394 }
    395 
    396 #ifdef EMULATE_TALK
    397 #include "talkd.h"
    398 #endif
    399 
    400 /*
    401  * Here, talk/ytalk/ntalk requests must be emulated
    402  */
    403 static void
    404 udp_emu(struct socket *so, struct mbuf *m)
    405 {
    406 	struct sockaddr_in addr;
    407 	socklen_t addrlen = sizeof(addr);
    408 #ifdef EMULATE_TALK
    409 	CTL_MSG_OLD *omsg;
    410 	CTL_MSG *nmsg;
    411 	char buff[sizeof(CTL_MSG)];
    412 	u_char type;
    413 
    414 struct talk_request {
    415 	struct talk_request *next;
    416 	struct socket *udp_so;
    417 	struct socket *tcp_so;
    418 } *req;
    419 
    420 	static struct talk_request *req_tbl = 0;
    421 
    422 #endif
    423 
    424 struct cu_header {
    425 	uint16_t	d_family;		// destination family
    426 	uint16_t	d_port;			// destination port
    427 	uint32_t	d_addr;			// destination address
    428 	uint16_t	s_family;		// source family
    429 	uint16_t	s_port;			// source port
    430 	uint32_t	so_addr;		// source address
    431 	uint32_t	seqn;			// sequence number
    432 	uint16_t	message;		// message
    433 	uint16_t	data_type;		// data type
    434 	uint16_t	pkt_len;		// packet length
    435 } *cu_head;
    436 
    437 	switch(so->so_emu) {
    438 
    439 #ifdef EMULATE_TALK
    440 	 case EMU_TALK:
    441 	 case EMU_NTALK:
    442 		/*
    443 		 * Talk emulation. We always change the ctl_addr to get
    444 		 * some answers from the daemon. When an ANNOUNCE comes,
    445 		 * we send LEAVE_INVITE to the local daemons. Also when a
    446 		 * DELETE comes, we send copies to the local daemons.
    447 		 */
    448 		if (getsockname(so->s, (struct sockaddr *)&addr, &addrlen) < 0)
    449 			return;
    450 
    451 #define	IS_OLD	(so->so_emu == EMU_TALK)
    452 
    453 #define COPY_MSG(dest, src) { dest->type = src->type; \
    454 			      dest->id_num = src->id_num; \
    455 			      dest->pid = src->pid; \
    456 			      dest->addr = src->addr; \
    457 			      dest->ctl_addr = src->ctl_addr; \
    458 			      memcpy(&dest->l_name, &src->l_name, NAME_SIZE_OLD); \
    459 			      memcpy(&dest->r_name, &src->r_name, NAME_SIZE_OLD); \
    460 	         	      memcpy(&dest->r_tty, &src->r_tty, TTY_SIZE); }
    461 
    462 #define OTOSIN(ptr, field) ((struct sockaddr_in *)&ptr->field)
    463 /* old_sockaddr to sockaddr_in */
    464 
    465 
    466 		if (IS_OLD) {  		/* old talk */
    467 			omsg = mtod(m, CTL_MSG_OLD*);
    468 			nmsg = (CTL_MSG *) buff;
    469 			type = omsg->type;
    470 			OTOSIN(omsg, ctl_addr)->sin_port = addr.sin_port;
    471 			OTOSIN(omsg, ctl_addr)->sin_addr = our_addr;
    472                         pstrcpy(omsg->l_name, NAME_SIZE_OLD, getlogin());
    473 		} else {		/* new talk */
    474 			omsg = (CTL_MSG_OLD *) buff;
    475 			nmsg = mtod(m, CTL_MSG *);
    476 			type = nmsg->type;
    477 			OTOSIN(nmsg, ctl_addr)->sin_port = addr.sin_port;
    478 			OTOSIN(nmsg, ctl_addr)->sin_addr = our_addr;
    479                         pstrcpy(nmsg->l_name, NAME_SIZE_OLD, getlogin());
    480 		}
    481 
    482 		if (type == LOOK_UP)
    483 			return;		/* for LOOK_UP this is enough */
    484 
    485 		if (IS_OLD) {		/* make a copy of the message */
    486 			COPY_MSG(nmsg, omsg);
    487 			nmsg->vers = 1;
    488 			nmsg->answer = 0;
    489 		} else
    490 			COPY_MSG(omsg, nmsg);
    491 
    492 		/*
    493 		 * If if is an ANNOUNCE message, we go through the
    494 		 * request table to see if a tcp port has already
    495 		 * been redirected for this socket. If not, we solisten()
    496 		 * a new socket and add this entry to the table.
    497 		 * The port number of the tcp socket and our IP
    498 		 * are put to the addr field of the message structures.
    499 		 * Then a LEAVE_INVITE is sent to both local daemon
    500 		 * ports, 517 and 518. This is why we have two copies
    501 		 * of the message, one in old talk and one in new talk
    502 		 * format.
    503 		 */
    504 
    505 		if (type == ANNOUNCE) {
    506 			int s;
    507 			u_short temp_port;
    508 
    509 			for(req = req_tbl; req; req = req->next)
    510 				if (so == req->udp_so)
    511 					break;  	/* found it */
    512 
    513 			if (!req) {	/* no entry for so, create new */
    514 				req = (struct talk_request *)
    515 					malloc(sizeof(struct talk_request));
    516 				req->udp_so = so;
    517 				req->tcp_so = solisten(0,
    518 					OTOSIN(omsg, addr)->sin_addr.s_addr,
    519 					OTOSIN(omsg, addr)->sin_port,
    520 					SS_FACCEPTONCE);
    521 				req->next = req_tbl;
    522 				req_tbl = req;
    523 			}
    524 
    525 			/* replace port number in addr field */
    526 			addrlen = sizeof(addr);
    527 			getsockname(req->tcp_so->s,
    528 					(struct sockaddr *) &addr,
    529 					&addrlen);
    530 			OTOSIN(omsg, addr)->sin_port = addr.sin_port;
    531 			OTOSIN(omsg, addr)->sin_addr = our_addr;
    532 			OTOSIN(nmsg, addr)->sin_port = addr.sin_port;
    533 			OTOSIN(nmsg, addr)->sin_addr = our_addr;
    534 
    535 			/* send LEAVE_INVITEs */
    536 			temp_port = OTOSIN(omsg, ctl_addr)->sin_port;
    537 			OTOSIN(omsg, ctl_addr)->sin_port = 0;
    538 			OTOSIN(nmsg, ctl_addr)->sin_port = 0;
    539 			omsg->type = nmsg->type = LEAVE_INVITE;
    540 
    541 			s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
    542 			addr.sin_addr = our_addr;
    543 			addr.sin_family = AF_INET;
    544 			addr.sin_port = htons(517);
    545 			sendto(s, (char *)omsg, sizeof(*omsg), 0,
    546 				(struct sockaddr *)&addr, sizeof(addr));
    547 			addr.sin_port = htons(518);
    548 			sendto(s, (char *)nmsg, sizeof(*nmsg), 0,
    549 				(struct sockaddr *) &addr, sizeof(addr));
    550 			closesocket(s) ;
    551 
    552 			omsg->type = nmsg->type = ANNOUNCE;
    553 			OTOSIN(omsg, ctl_addr)->sin_port = temp_port;
    554 			OTOSIN(nmsg, ctl_addr)->sin_port = temp_port;
    555 		}
    556 
    557 		/*
    558 		 * If it is a DELETE message, we send a copy to the
    559 		 * local daemons. Then we delete the entry corresponding
    560 		 * to our socket from the request table.
    561 		 */
    562 
    563 		if (type == DELETE) {
    564 			struct talk_request *temp_req, *req_next;
    565 			int s;
    566 			u_short temp_port;
    567 
    568 			temp_port = OTOSIN(omsg, ctl_addr)->sin_port;
    569 			OTOSIN(omsg, ctl_addr)->sin_port = 0;
    570 			OTOSIN(nmsg, ctl_addr)->sin_port = 0;
    571 
    572 			s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
    573 			addr.sin_addr = our_addr;
    574 			addr.sin_family = AF_INET;
    575 			addr.sin_port = htons(517);
    576 			sendto(s, (char *)omsg, sizeof(*omsg), 0,
    577 				(struct sockaddr *)&addr, sizeof(addr));
    578 			addr.sin_port = htons(518);
    579 			sendto(s, (char *)nmsg, sizeof(*nmsg), 0,
    580 				(struct sockaddr *)&addr, sizeof(addr));
    581 			closesocket(s);
    582 
    583 			OTOSIN(omsg, ctl_addr)->sin_port = temp_port;
    584 			OTOSIN(nmsg, ctl_addr)->sin_port = temp_port;
    585 
    586 			/* delete table entry */
    587 			if (so == req_tbl->udp_so) {
    588 				temp_req = req_tbl;
    589 				req_tbl = req_tbl->next;
    590 				free(temp_req);
    591 			} else {
    592 				temp_req = req_tbl;
    593 				for(req = req_tbl->next; req; req = req_next) {
    594 					req_next = req->next;
    595 					if (so == req->udp_so) {
    596 						temp_req->next = req_next;
    597 						free(req);
    598 						break;
    599 					} else {
    600 						temp_req = req;
    601 					}
    602 				}
    603 			}
    604 		}
    605 
    606 		return;
    607 #endif
    608 
    609 	case EMU_CUSEEME:
    610 
    611 		/*
    612 		 * Cu-SeeMe emulation.
    613 		 * Hopefully the packet is more that 16 bytes long. We don't
    614 		 * do any other tests, just replace the address and port
    615 		 * fields.
    616 		 */
    617 		if (m->m_len >= sizeof (*cu_head)) {
    618 			if (getsockname(so->s, (struct sockaddr *)&addr, &addrlen) < 0)
    619 				return;
    620 			cu_head = mtod(m, struct cu_header *);
    621 			cu_head->s_port = addr.sin_port;
    622 			cu_head->so_addr = our_addr.s_addr;
    623 		}
    624 
    625 		return;
    626 	}
    627 }
    628 
    629 struct socket *
    630 udp_listen(u_int port, u_int32_t laddr, u_int lport, int flags)
    631 {
    632 	struct sockaddr_in addr;
    633 	struct socket *so;
    634 	socklen_t addrlen = sizeof(struct sockaddr_in), opt = 1;
    635 
    636 	if ((so = socreate()) == NULL) {
    637 		free(so);
    638 		return NULL;
    639 	}
    640 	so->s = socket(AF_INET,SOCK_DGRAM,0);
    641 	so->so_expire = curtime + SO_EXPIRE;
    642 	insque(so,&udb);
    643 
    644 	addr.sin_family = AF_INET;
    645 	addr.sin_addr.s_addr = INADDR_ANY;
    646 	addr.sin_port = port;
    647 
    648 	if (bind(so->s,(struct sockaddr *)&addr, addrlen) < 0) {
    649 		udp_detach(so);
    650 		return NULL;
    651 	}
    652 	setsockopt(so->s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int));
    653 /*	setsockopt(so->s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int)); */
    654 
    655 	getsockname(so->s,(struct sockaddr *)&addr,&addrlen);
    656 	so->so_fport = addr.sin_port;
    657 	if (addr.sin_addr.s_addr == 0 || addr.sin_addr.s_addr == loopback_addr.s_addr)
    658 	   so->so_faddr = alias_addr;
    659 	else
    660 	   so->so_faddr = addr.sin_addr;
    661 
    662 	so->so_lport = lport;
    663 	so->so_laddr.s_addr = laddr;
    664 	if (flags != SS_FACCEPTONCE)
    665 	   so->so_expire = 0;
    666 
    667 	so->so_state = SS_ISFCONNECTED;
    668 
    669 	return so;
    670 }
    671