15d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/*
25d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * Copyright (c) 1982, 1986, 1988, 1990, 1993
35d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *	The Regents of the University of California.  All rights reserved.
45d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *
55d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * Redistribution and use in source and binary forms, with or without
65d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * modification, are permitted provided that the following conditions
75d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * are met:
85d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * 1. Redistributions of source code must retain the above copyright
95d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *    notice, this list of conditions and the following disclaimer.
105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * 2. Redistributions in binary form must reproduce the above copyright
115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *    notice, this list of conditions and the following disclaimer in the
125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *    documentation and/or other materials provided with the distribution.
135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * 3. Neither the name of the University nor the names of its contributors
145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *    may be used to endorse or promote products derived from this software
155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *    without specific prior written permission.
165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *
175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * SUCH DAMAGE.
285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *
295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *	@(#)udp_usrreq.c	8.4 (Berkeley) 1/21/94
305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * udp_usrreq.c,v 1.4 1994/10/02 17:48:45 phk Exp
315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner */
325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/*
345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * Changes and additions relating to SLiRP
355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * Copyright (c) 1995 Danny Gasparovski.
365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *
375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * Please read the file COPYRIGHT for the
385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * terms and conditions of the copyright.
395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner */
405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <slirp.h>
425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "ip_icmp.h"
435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef LOG_ENABLED
455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstruct udpstat udpstat;
465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstruct socket udb;
495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic u_int8_t udp_tos(struct socket *so);
515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void udp_emu(struct socket *so, struct mbuf *m);
525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/*
545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * UDP protocol implementation.
555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * Per RFC 768, August, 1980.
565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner */
575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifndef	COMPAT_42
585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define UDPCKSUM 1
595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#else
605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define UDPCKSUM 0 /* XXX */
615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstruct	socket *udp_last_so = &udb;
645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid
665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerudp_init(void)
675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	udb.so_next = udb.so_prev = &udb;
695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* m->m_data  points at ip packet header
715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * m->m_len   length ip packet
725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * ip->ip_len length data (IPDU)
735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner */
745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid
755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerudp_input(register struct mbuf *m, int iphlen)
765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	register struct ip *ip;
785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	register struct udphdr *uh;
795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/*	struct mbuf *opts = 0;*/
805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	int len;
815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	struct ip save_ip;
825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	struct socket *so;
835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	DEBUG_CALL("udp_input");
855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	DEBUG_ARG("m = %lx", (long)m);
865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	DEBUG_ARG("iphlen = %d", iphlen);
875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	STAT(udpstat.udps_ipackets++);
895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	/*
915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	 * Strip IP options, if any; should skip this,
925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	 * make available to user, and use on returned packets,
935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	 * but we don't yet have a way to check the checksum
945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	 * with options still present.
955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	 */
965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	if(iphlen > sizeof(struct ip)) {
975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		ip_stripoptions(m, (struct mbuf *)0);
985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		iphlen = sizeof(struct ip);
995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	}
1005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	/*
1025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	 * Get IP and UDP header together in first mbuf.
1035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	 */
1045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	ip = mtod(m, struct ip *);
1055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	uh = (struct udphdr *)((caddr_t)ip + iphlen);
1065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	/*
1085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	 * Make mbuf data length reflect UDP length.
1095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	 * If not enough data to reflect UDP length, drop.
1105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	 */
1115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	len = ntohs((u_int16_t)uh->uh_ulen);
1125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	if (ip->ip_len != len) {
1145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		if (len > ip->ip_len) {
1155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			STAT(udpstat.udps_badlen++);
1165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			goto bad;
1175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		}
1185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		m_adj(m, len - ip->ip_len);
1195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		ip->ip_len = len;
1205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	}
1215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	/*
1235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	 * Save a copy of the IP header in case we want restore it
1245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	 * for sending an ICMP error message in response.
1255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	 */
1265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	save_ip = *ip;
1275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	save_ip.ip_len+= iphlen;         /* tcp_input subtracts this */
1285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	/*
1305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	 * Checksum extended UDP header and data.
1315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	 */
1325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	if (UDPCKSUM && uh->uh_sum) {
1335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner      memset(&((struct ipovly *)ip)->ih_mbuf, 0, sizeof(struct mbuf_ptr));
1345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	  ((struct ipovly *)ip)->ih_x1 = 0;
1355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	  ((struct ipovly *)ip)->ih_len = uh->uh_ulen;
1365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	  /* keep uh_sum for ICMP reply
1375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	   * uh->uh_sum = cksum(m, len + sizeof (struct ip));
1385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	   * if (uh->uh_sum) {
1395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	   */
1405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	  if(cksum(m, len + sizeof(struct ip))) {
1415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	    STAT(udpstat.udps_badsum++);
1425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	    goto bad;
1435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	  }
1445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	}
1455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        /*
1475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner         *  handle DHCP/BOOTP
1485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner         */
1495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (ntohs(uh->uh_dport) == BOOTP_SERVER) {
1505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            bootp_input(m);
1515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            goto bad;
1525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
1535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (slirp_restrict)
1555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            goto bad;
1565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        /*
1585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner         *  handle TFTP
1595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner         */
1605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (ntohs(uh->uh_dport) == TFTP_SERVER) {
1615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            tftp_input(m);
1625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            goto bad;
1635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
1645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	/*
1665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	 * Locate pcb for datagram.
1675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	 */
1685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	so = udp_last_so;
1695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	if (so->so_lport != uh->uh_sport ||
1705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	    so->so_laddr.s_addr != ip->ip_src.s_addr) {
1715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		struct socket *tmp;
1725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		for (tmp = udb.so_next; tmp != &udb; tmp = tmp->so_next) {
1745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			if (tmp->so_lport == uh->uh_sport &&
1755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			    tmp->so_laddr.s_addr == ip->ip_src.s_addr) {
1765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner				tmp->so_faddr.s_addr = ip->ip_dst.s_addr;
1775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner				tmp->so_fport = uh->uh_dport;
1785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner				so = tmp;
1795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner				break;
1805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			}
1815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		}
1825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		if (tmp == &udb) {
1835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		  so = NULL;
1845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		} else {
1855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		  STAT(udpstat.udpps_pcbcachemiss++);
1865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		  udp_last_so = so;
1875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		}
1885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	}
1895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	if (so == NULL) {
1915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	  /*
1925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	   * If there's no socket for this packet,
1935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	   * create one
1945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	   */
1955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	  if ((so = socreate()) == NULL) goto bad;
1965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	  if(udp_attach(so) == -1) {
1975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	    DEBUG_MISC((dfd," udp_attach errno = %d-%s\n",
1985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			errno,strerror(errno)));
1995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	    sofree(so);
2005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	    goto bad;
2015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	  }
2025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	  /*
2045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	   * Setup fields
2055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	   */
2065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	  /* udp_last_so = so; */
2075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	  so->so_laddr = ip->ip_src;
2085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	  so->so_lport = uh->uh_sport;
2095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	  if ((so->so_iptos = udp_tos(so)) == 0)
2115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	    so->so_iptos = ip->ip_tos;
2125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	  /*
2145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	   * XXXXX Here, check if it's in udpexec_list,
2155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	   * and if it is, do the fork_exec() etc.
2165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	   */
2175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	}
2185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        so->so_faddr = ip->ip_dst; /* XXX */
2205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        so->so_fport = uh->uh_dport; /* XXX */
2215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	iphlen += sizeof(struct udphdr);
2235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	m->m_len -= iphlen;
2245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	m->m_data += iphlen;
2255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	/*
2275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	 * Now we sendto() the packet.
2285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	 */
2295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	if (so->so_emu)
2305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	   udp_emu(so, m);
2315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	if(sosendto(so,m) == -1) {
2335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	  m->m_len += iphlen;
2345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	  m->m_data -= iphlen;
2355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	  *ip=save_ip;
2365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	  DEBUG_MISC((dfd,"udp tx errno = %d-%s\n",errno,strerror(errno)));
2375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	  icmp_error(m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,strerror(errno));
2385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	}
2395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	m_free(so->so_m);   /* used for ICMP if error on sorecvfrom */
2415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	/* restore the orig mbuf packet */
2435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	m->m_len += iphlen;
2445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	m->m_data -= iphlen;
2455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	*ip=save_ip;
2465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	so->so_m=m;         /* ICMP backup */
2475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	return;
2495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerbad:
2505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	m_freem(m);
2515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	/* if (opts) m_freem(opts); */
2525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	return;
2535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
2545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint udp_output2(struct socket *so, struct mbuf *m,
2565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                struct sockaddr_in *saddr, struct sockaddr_in *daddr,
2575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                int iptos)
2585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
2595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	register struct udpiphdr *ui;
2605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	int error = 0;
2615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	DEBUG_CALL("udp_output");
2635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	DEBUG_ARG("so = %lx", (long)so);
2645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	DEBUG_ARG("m = %lx", (long)m);
2655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	DEBUG_ARG("saddr = %lx", (long)saddr->sin_addr.s_addr);
2665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	DEBUG_ARG("daddr = %lx", (long)daddr->sin_addr.s_addr);
2675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	/*
2695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	 * Adjust for header
2705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	 */
2715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	m->m_data -= sizeof(struct udpiphdr);
2725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	m->m_len += sizeof(struct udpiphdr);
2735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	/*
2755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	 * Fill in mbuf with extended UDP header
2765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	 * and addresses and length put into network format.
2775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	 */
2785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	ui = mtod(m, struct udpiphdr *);
2795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    memset(&ui->ui_i.ih_mbuf, 0 , sizeof(struct mbuf_ptr));
2805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	ui->ui_x1 = 0;
2815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	ui->ui_pr = IPPROTO_UDP;
2825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	ui->ui_len = htons(m->m_len - sizeof(struct ip)); /* + sizeof (struct udphdr)); */
2835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	/* XXXXX Check for from-one-location sockets, or from-any-location sockets */
2845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        ui->ui_src = saddr->sin_addr;
2855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	ui->ui_dst = daddr->sin_addr;
2865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	ui->ui_sport = saddr->sin_port;
2875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	ui->ui_dport = daddr->sin_port;
2885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	ui->ui_ulen = ui->ui_len;
2895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	/*
2915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	 * Stuff checksum and output datagram.
2925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	 */
2935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	ui->ui_sum = 0;
2945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	if (UDPCKSUM) {
2955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	    if ((ui->ui_sum = cksum(m, /* sizeof (struct udpiphdr) + */ m->m_len)) == 0)
2965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		ui->ui_sum = 0xffff;
2975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	}
2985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	((struct ip *)ui)->ip_len = m->m_len;
2995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	((struct ip *)ui)->ip_ttl = IPDEFTTL;
3015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	((struct ip *)ui)->ip_tos = iptos;
3025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	STAT(udpstat.udps_opackets++);
3045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	error = ip_output(so, m);
3065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	return (error);
3085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
3095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint udp_output(struct socket *so, struct mbuf *m,
3115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner               struct sockaddr_in *addr)
3125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
3145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct sockaddr_in saddr, daddr;
3155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    saddr = *addr;
3175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if ((so->so_faddr.s_addr & htonl(0xffffff00)) == special_addr.s_addr) {
3185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if ((so->so_faddr.s_addr & htonl(0x000000ff)) == htonl(0xff))
3195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            saddr.sin_addr.s_addr = alias_addr.s_addr;
3205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        else if (addr->sin_addr.s_addr == loopback_addr.s_addr ||
3215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                 (ntohl(so->so_faddr.s_addr) & 0xff) != CTL_ALIAS)
3225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            saddr.sin_addr.s_addr = so->so_faddr.s_addr;
3235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
3245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    daddr.sin_addr = so->so_laddr;
3255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    daddr.sin_port = so->so_lport;
3265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return udp_output2(so, m, &saddr, &daddr, so->so_iptos);
3285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
3295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint
3315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerudp_attach(struct socket *so)
3325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
3335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner  struct sockaddr_in addr;
3345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner  if((so->s = socket(AF_INET,SOCK_DGRAM,0)) != -1) {
3365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /*
3375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     * Here, we bind() the socket.  Although not really needed
3385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     * (sendto() on an unbound socket will bind it), it's done
3395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     * here so that emulation of ytalk etc. don't have to do it
3405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     */
3415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    addr.sin_family = AF_INET;
3425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    addr.sin_port = 0;
3435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    addr.sin_addr.s_addr = INADDR_ANY;
3445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if(bind(so->s, (struct sockaddr *)&addr, sizeof(addr))<0) {
3455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner      int lasterrno=errno;
3465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner      closesocket(so->s);
3475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner      so->s=-1;
3485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef _WIN32
3495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner      WSASetLastError(lasterrno);
3505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#else
3515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner      errno=lasterrno;
3525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
3535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else {
3545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner      /* success, insert in queue */
3555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner      so->so_expire = curtime + SO_EXPIRE;
3565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner      insque(so,&udb);
3575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
3585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner  }
3595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner  return(so->s);
3605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
3615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid
3635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerudp_detach(struct socket *so)
3645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
3655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	closesocket(so->s);
3665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	/* if (so->so_m) m_free(so->so_m);    done by sofree */
3675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	sofree(so);
3695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
3705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic const struct tos_t udptos[] = {
3725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	{0, 53, IPTOS_LOWDELAY, 0},			/* DNS */
3735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	{517, 517, IPTOS_LOWDELAY, EMU_TALK},	/* talk */
3745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	{518, 518, IPTOS_LOWDELAY, EMU_NTALK},	/* ntalk */
3755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	{0, 7648, IPTOS_LOWDELAY, EMU_CUSEEME},	/* Cu-Seeme */
3765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	{0, 0, 0, 0}
3775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner};
3785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic u_int8_t
3805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerudp_tos(struct socket *so)
3815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
3825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	int i = 0;
3835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	while(udptos[i].tos) {
3855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		if ((udptos[i].fport && ntohs(so->so_fport) == udptos[i].fport) ||
3865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		    (udptos[i].lport && ntohs(so->so_lport) == udptos[i].lport)) {
3875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		    	so->so_emu = udptos[i].emu;
3885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			return udptos[i].tos;
3895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		}
3905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		i++;
3915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	}
3925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	return 0;
3945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
3955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef EMULATE_TALK
3975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "talkd.h"
3985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
3995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/*
4015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * Here, talk/ytalk/ntalk requests must be emulated
4025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner */
4035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void
4045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerudp_emu(struct socket *so, struct mbuf *m)
4055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
4065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	struct sockaddr_in addr;
4075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	socklen_t addrlen = sizeof(addr);
4085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef EMULATE_TALK
4095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	CTL_MSG_OLD *omsg;
4105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	CTL_MSG *nmsg;
4115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	char buff[sizeof(CTL_MSG)];
4125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	u_char type;
4135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstruct talk_request {
4155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	struct talk_request *next;
4165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	struct socket *udp_so;
4175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	struct socket *tcp_so;
4185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} *req;
4195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	static struct talk_request *req_tbl = 0;
4215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
4235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstruct cu_header {
4255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	uint16_t	d_family;		// destination family
4265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	uint16_t	d_port;			// destination port
4275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	uint32_t	d_addr;			// destination address
4285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	uint16_t	s_family;		// source family
4295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	uint16_t	s_port;			// source port
4305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	uint32_t	so_addr;		// source address
4315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	uint32_t	seqn;			// sequence number
4325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	uint16_t	message;		// message
4335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	uint16_t	data_type;		// data type
4345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	uint16_t	pkt_len;		// packet length
4355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} *cu_head;
4365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	switch(so->so_emu) {
4385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef EMULATE_TALK
4405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	 case EMU_TALK:
4415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	 case EMU_NTALK:
4425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		/*
4435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		 * Talk emulation. We always change the ctl_addr to get
4445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		 * some answers from the daemon. When an ANNOUNCE comes,
4455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		 * we send LEAVE_INVITE to the local daemons. Also when a
4465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		 * DELETE comes, we send copies to the local daemons.
4475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		 */
4485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		if (getsockname(so->s, (struct sockaddr *)&addr, &addrlen) < 0)
4495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			return;
4505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define	IS_OLD	(so->so_emu == EMU_TALK)
4525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define COPY_MSG(dest, src) { dest->type = src->type; \
4545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			      dest->id_num = src->id_num; \
4555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			      dest->pid = src->pid; \
4565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			      dest->addr = src->addr; \
4575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			      dest->ctl_addr = src->ctl_addr; \
4585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			      memcpy(&dest->l_name, &src->l_name, NAME_SIZE_OLD); \
4595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			      memcpy(&dest->r_name, &src->r_name, NAME_SIZE_OLD); \
4605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	         	      memcpy(&dest->r_tty, &src->r_tty, TTY_SIZE); }
4615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define OTOSIN(ptr, field) ((struct sockaddr_in *)&ptr->field)
4635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* old_sockaddr to sockaddr_in */
4645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		if (IS_OLD) {  		/* old talk */
4675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			omsg = mtod(m, CTL_MSG_OLD*);
4685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			nmsg = (CTL_MSG *) buff;
4695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			type = omsg->type;
4705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			OTOSIN(omsg, ctl_addr)->sin_port = addr.sin_port;
4715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			OTOSIN(omsg, ctl_addr)->sin_addr = our_addr;
4725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                        pstrcpy(omsg->l_name, NAME_SIZE_OLD, getlogin());
4735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		} else {		/* new talk */
4745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			omsg = (CTL_MSG_OLD *) buff;
4755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			nmsg = mtod(m, CTL_MSG *);
4765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			type = nmsg->type;
4775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			OTOSIN(nmsg, ctl_addr)->sin_port = addr.sin_port;
4785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			OTOSIN(nmsg, ctl_addr)->sin_addr = our_addr;
4795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                        pstrcpy(nmsg->l_name, NAME_SIZE_OLD, getlogin());
4805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		}
4815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		if (type == LOOK_UP)
4835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			return;		/* for LOOK_UP this is enough */
4845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		if (IS_OLD) {		/* make a copy of the message */
4865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			COPY_MSG(nmsg, omsg);
4875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			nmsg->vers = 1;
4885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			nmsg->answer = 0;
4895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		} else
4905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			COPY_MSG(omsg, nmsg);
4915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		/*
4935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		 * If if is an ANNOUNCE message, we go through the
4945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		 * request table to see if a tcp port has already
4955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		 * been redirected for this socket. If not, we solisten()
4965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		 * a new socket and add this entry to the table.
4975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		 * The port number of the tcp socket and our IP
4985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		 * are put to the addr field of the message structures.
4995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		 * Then a LEAVE_INVITE is sent to both local daemon
5005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		 * ports, 517 and 518. This is why we have two copies
5015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		 * of the message, one in old talk and one in new talk
5025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		 * format.
5035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		 */
5045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		if (type == ANNOUNCE) {
5065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			int s;
5075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			u_short temp_port;
5085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			for(req = req_tbl; req; req = req->next)
5105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner				if (so == req->udp_so)
5115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner					break;  	/* found it */
5125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			if (!req) {	/* no entry for so, create new */
5145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner				req = (struct talk_request *)
5155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner					malloc(sizeof(struct talk_request));
5165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner				req->udp_so = so;
5175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner				req->tcp_so = solisten(0,
5185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner					OTOSIN(omsg, addr)->sin_addr.s_addr,
5195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner					OTOSIN(omsg, addr)->sin_port,
5205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner					SS_FACCEPTONCE);
5215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner				req->next = req_tbl;
5225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner				req_tbl = req;
5235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			}
5245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			/* replace port number in addr field */
5265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			addrlen = sizeof(addr);
5275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			getsockname(req->tcp_so->s,
5285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner					(struct sockaddr *) &addr,
5295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner					&addrlen);
5305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			OTOSIN(omsg, addr)->sin_port = addr.sin_port;
5315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			OTOSIN(omsg, addr)->sin_addr = our_addr;
5325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			OTOSIN(nmsg, addr)->sin_port = addr.sin_port;
5335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			OTOSIN(nmsg, addr)->sin_addr = our_addr;
5345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			/* send LEAVE_INVITEs */
5365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			temp_port = OTOSIN(omsg, ctl_addr)->sin_port;
5375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			OTOSIN(omsg, ctl_addr)->sin_port = 0;
5385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			OTOSIN(nmsg, ctl_addr)->sin_port = 0;
5395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			omsg->type = nmsg->type = LEAVE_INVITE;
5405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
5425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			addr.sin_addr = our_addr;
5435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			addr.sin_family = AF_INET;
5445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			addr.sin_port = htons(517);
5455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			sendto(s, (char *)omsg, sizeof(*omsg), 0,
5465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner				(struct sockaddr *)&addr, sizeof(addr));
5475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			addr.sin_port = htons(518);
5485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			sendto(s, (char *)nmsg, sizeof(*nmsg), 0,
5495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner				(struct sockaddr *) &addr, sizeof(addr));
5505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			closesocket(s) ;
5515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			omsg->type = nmsg->type = ANNOUNCE;
5535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			OTOSIN(omsg, ctl_addr)->sin_port = temp_port;
5545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			OTOSIN(nmsg, ctl_addr)->sin_port = temp_port;
5555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		}
5565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		/*
5585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		 * If it is a DELETE message, we send a copy to the
5595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		 * local daemons. Then we delete the entry corresponding
5605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		 * to our socket from the request table.
5615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		 */
5625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		if (type == DELETE) {
5645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			struct talk_request *temp_req, *req_next;
5655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			int s;
5665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			u_short temp_port;
5675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			temp_port = OTOSIN(omsg, ctl_addr)->sin_port;
5695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			OTOSIN(omsg, ctl_addr)->sin_port = 0;
5705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			OTOSIN(nmsg, ctl_addr)->sin_port = 0;
5715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
5735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			addr.sin_addr = our_addr;
5745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			addr.sin_family = AF_INET;
5755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			addr.sin_port = htons(517);
5765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			sendto(s, (char *)omsg, sizeof(*omsg), 0,
5775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner				(struct sockaddr *)&addr, sizeof(addr));
5785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			addr.sin_port = htons(518);
5795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			sendto(s, (char *)nmsg, sizeof(*nmsg), 0,
5805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner				(struct sockaddr *)&addr, sizeof(addr));
5815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			closesocket(s);
5825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			OTOSIN(omsg, ctl_addr)->sin_port = temp_port;
5845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			OTOSIN(nmsg, ctl_addr)->sin_port = temp_port;
5855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			/* delete table entry */
5875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			if (so == req_tbl->udp_so) {
5885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner				temp_req = req_tbl;
5895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner				req_tbl = req_tbl->next;
5905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner				free(temp_req);
5915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			} else {
5925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner				temp_req = req_tbl;
5935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner				for(req = req_tbl->next; req; req = req_next) {
5945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner					req_next = req->next;
5955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner					if (so == req->udp_so) {
5965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner						temp_req->next = req_next;
5975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner						free(req);
5985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner						break;
5995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner					} else {
6005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner						temp_req = req;
6015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner					}
6025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner				}
6035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			}
6045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		}
6055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		return;
6075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
6085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	case EMU_CUSEEME:
6105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		/*
6125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		 * Cu-SeeMe emulation.
6135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		 * Hopefully the packet is more that 16 bytes long. We don't
6145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		 * do any other tests, just replace the address and port
6155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		 * fields.
6165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		 */
6175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		if (m->m_len >= sizeof (*cu_head)) {
6185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			if (getsockname(so->s, (struct sockaddr *)&addr, &addrlen) < 0)
6195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner				return;
6205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			cu_head = mtod(m, struct cu_header *);
6215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			cu_head->s_port = addr.sin_port;
6225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			cu_head->so_addr = our_addr.s_addr;
6235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		}
6245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		return;
6265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	}
6275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
6285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstruct socket *
6305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerudp_listen(u_int port, u_int32_t laddr, u_int lport, int flags)
6315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
6325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	struct sockaddr_in addr;
6335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	struct socket *so;
6345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	socklen_t addrlen = sizeof(struct sockaddr_in), opt = 1;
6355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	if ((so = socreate()) == NULL) {
6375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		free(so);
6385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		return NULL;
6395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	}
6405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	so->s = socket(AF_INET,SOCK_DGRAM,0);
6415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	so->so_expire = curtime + SO_EXPIRE;
6425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	insque(so,&udb);
6435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	addr.sin_family = AF_INET;
6455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	addr.sin_addr.s_addr = INADDR_ANY;
6465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	addr.sin_port = port;
6475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	if (bind(so->s,(struct sockaddr *)&addr, addrlen) < 0) {
6495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		udp_detach(so);
6505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		return NULL;
6515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	}
6525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	setsockopt(so->s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int));
6535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/*	setsockopt(so->s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int)); */
6545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	getsockname(so->s,(struct sockaddr *)&addr,&addrlen);
6565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	so->so_fport = addr.sin_port;
6575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	if (addr.sin_addr.s_addr == 0 || addr.sin_addr.s_addr == loopback_addr.s_addr)
6585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	   so->so_faddr = alias_addr;
6595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	else
6605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	   so->so_faddr = addr.sin_addr;
6615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	so->so_lport = lport;
6635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	so->so_laddr.s_addr = laddr;
6645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	if (flags != SS_FACCEPTONCE)
6655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	   so->so_expire = 0;
6665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	so->so_state = SS_ISFCONNECTED;
6685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	return so;
6705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
671