SLiRP overhaul

This commit is contained in:
RichardG867
2020-08-07 12:39:34 -03:00
parent 8208f1ff45
commit 8ca17a300d
97 changed files with 14123 additions and 13666 deletions

View File

@@ -46,6 +46,7 @@
#endif #endif
#define MIN(a, b) ((a) < (b) ? (a) : (b)) #define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define ABS(x) ((x) > 0 ? (x) : -(x)) #define ABS(x) ((x) > 0 ? (x) : -(x))
#define BCD8(x) ((((x) / 10) << 4) | ((x) % 10)) #define BCD8(x) ((((x) / 10) << 4) | ((x) % 10))
#define BCD16(x) ((((x) / 1000) << 12) | (((x) / 100) << 8) | BCD8(x)) #define BCD16(x) ((((x) / 1000) << 12) | (((x) / 100) << 8) | BCD8(x))

View File

@@ -1,121 +0,0 @@
/* bootp/dhcp defines */
#define BOOTP_SERVER 67
#define BOOTP_CLIENT 68
#define BOOTP_REQUEST 1
#define BOOTP_REPLY 2
#define RFC1533_COOKIE 99, 130, 83, 99
#define RFC1533_PAD 0
#define RFC1533_NETMASK 1
#define RFC1533_TIMEOFFSET 2
#define RFC1533_GATEWAY 3
#define RFC1533_TIMESERVER 4
#define RFC1533_IEN116NS 5
#define RFC1533_DNS 6
#define RFC1533_LOGSERVER 7
#define RFC1533_COOKIESERVER 8
#define RFC1533_LPRSERVER 9
#define RFC1533_IMPRESSSERVER 10
#define RFC1533_RESOURCESERVER 11
#define RFC1533_HOSTNAME 12
#define RFC1533_BOOTFILESIZE 13
#define RFC1533_MERITDUMPFILE 14
#define RFC1533_DOMAINNAME 15
#define RFC1533_SWAPSERVER 16
#define RFC1533_ROOTPATH 17
#define RFC1533_EXTENSIONPATH 18
#define RFC1533_IPFORWARDING 19
#define RFC1533_IPSOURCEROUTING 20
#define RFC1533_IPPOLICYFILTER 21
#define RFC1533_IPMAXREASSEMBLY 22
#define RFC1533_IPTTL 23
#define RFC1533_IPMTU 24
#define RFC1533_IPMTUPLATEAU 25
#define RFC1533_INTMTU 26
#define RFC1533_INTLOCALSUBNETS 27
#define RFC1533_INTBROADCAST 28
#define RFC1533_INTICMPDISCOVER 29
#define RFC1533_INTICMPRESPOND 30
#define RFC1533_INTROUTEDISCOVER 31
#define RFC1533_INTROUTESOLICIT 32
#define RFC1533_INTSTATICROUTES 33
#define RFC1533_LLTRAILERENCAP 34
#define RFC1533_LLARPCACHETMO 35
#define RFC1533_LLETHERNETENCAP 36
#define RFC1533_TCPTTL 37
#define RFC1533_TCPKEEPALIVETMO 38
#define RFC1533_TCPKEEPALIVEGB 39
#define RFC1533_NISDOMAIN 40
#define RFC1533_NISSERVER 41
#define RFC1533_NTPSERVER 42
#define RFC1533_VENDOR 43
#define RFC1533_NBNS 44
#define RFC1533_NBDD 45
#define RFC1533_NBNT 46
#define RFC1533_NBSCOPE 47
#define RFC1533_XFS 48
#define RFC1533_XDM 49
#define RFC2132_REQ_ADDR 50
#define RFC2132_LEASE_TIME 51
#define RFC2132_MSG_TYPE 53
#define RFC2132_SRV_ID 54
#define RFC2132_PARAM_LIST 55
#define RFC2132_MAX_SIZE 57
#define RFC2132_RENEWAL_TIME 58
#define RFC2132_REBIND_TIME 59
#define DHCPDISCOVER 1
#define DHCPOFFER 2
#define DHCPREQUEST 3
#define DHCPACK 5
#define RFC1533_VENDOR_MAJOR 0
#define RFC1533_VENDOR_MINOR 0
#define RFC1533_VENDOR_MAGIC 128
#define RFC1533_VENDOR_ADDPARM 129
#define RFC1533_VENDOR_ETHDEV 130
#define RFC1533_VENDOR_HOWTO 132
#define RFC1533_VENDOR_MNUOPTS 160
#define RFC1533_VENDOR_SELECTION 176
#define RFC1533_VENDOR_MOTD 184
#define RFC1533_VENDOR_NUMOFMOTD 8
#define RFC1533_VENDOR_IMG 192
#define RFC1533_VENDOR_NUMOFIMG 16
#define RFC1533_END 255
#define BOOTP_VENDOR_LEN 64
#define DHCP_OPT_LEN 312
#ifdef PRAGMA_PACK_SUPPORTED
#pragma pack(1)
#endif
struct bootp_t {
struct ip ip;
struct udphdr udp;
uint8_t bp_op;
uint8_t bp_htype;
uint8_t bp_hlen;
uint8_t bp_hops;
uint32_t bp_xid;
uint16_t bp_secs;
uint16_t unused;
struct in_addr bp_ciaddr;
struct in_addr bp_yiaddr;
struct in_addr bp_siaddr;
struct in_addr bp_giaddr;
uint8_t bp_hwaddr[16];
uint8_t bp_sname[64];
uint8_t bp_file[128];
uint8_t bp_vend[DHCP_OPT_LEN];
} PACKED__;
#ifdef PRAGMA_PACK_SUPPORTED
#pragma pack(PACK_END)
#endif
void bootp_input(struct SLIRPmbuf *m);

View File

@@ -1,9 +0,0 @@
/* Automatically generated by configure - do not modify */
#define CONFIG_QEMU_SHAREDIR "/c/Program Files/Qemu"
#define HOST_I386 1
#define HOST_LONG_BITS 32
#define CONFIG_WIN32 1
#define CONFIG_GDBSTUB 1
#define CONFIG_SLIRP 1
#define QEMU_VERSION "0.9.0"
#define CONFIG_UNAME_RELEASE ""

View File

@@ -1,9 +0,0 @@
/* Automatically generated by configure - do not modify */
#include "config-host.h"
#define CONFIG_QEMU_PREFIX "/usr/gnemul/qemu-i386"
#define TARGET_ARCH "i386"
#define TARGET_I386 1
#define USE_KQEMU 1
#define CONFIG_SOFTMMU 1
#define CONFIG_SDL 1
#define HAVE_STRDUP 1

View File

@@ -1,7 +0,0 @@
#define CTL_CMD 0
#define CTL_EXEC 1
#define CTL_ALIAS 2
#define CTL_DNS 3
#define CTL_SPECIAL "10.0.2.0"
#define CTL_LOCAL "10.0.2.15"

View File

@@ -1,49 +0,0 @@
/*
* Copyright (c) 1995 Danny Gasparovski.
*
* Please read the file COPYRIGHT for the
* terms and conditions of the copyright.
*/
#define PRN_STDERR 1
#define PRN_SPRINTF 2
extern FILE *dfd;
extern FILE *lfd;
extern int dostats;
extern int slirp_debug;
#define DBG_CALL 0x1
#define DBG_MISC 0x2
#define DBG_ERROR 0x4
#define DEBUG_DEFAULT DBG_CALL|DBG_MISC|DBG_ERROR
#ifdef SLIRP_DEBUG
#define DEBUG_CALL(x) if (slirp_debug & DBG_CALL) { fprintf(dfd, "%s...\n", x); fflush(dfd); }
#define DEBUG_ARG(x, y) if (slirp_debug & DBG_CALL) { fputc(' ', dfd); fprintf(dfd, x, y); fputc('\n', dfd); fflush(dfd); }
#define DEBUG_ARGS(x) if (slirp_debug & DBG_CALL) { fprintf x ; fflush(dfd); }
#define DEBUG_MISC(x) if (slirp_debug & DBG_MISC) { fprintf x ; fflush(dfd); }
#define DEBUG_ERROR(x) if (slirp_debug & DBG_ERROR) {fprintf x ; fflush(dfd); }
#else
#define DEBUG_CALL(x)
#define DEBUG_ARG(x, y)
#define DEBUG_ARGS(x)
#define DEBUG_MISC(x)
#define DEBUG_ERROR(x)
#endif
void debug_init _P((char *, int));
void allttystats _P((void));
void ipstats _P((void));
void vjstats _P((void));
void tcpstats _P((void));
void udpstats _P((void));
void icmpstats _P((void));
void mbufstats _P((void));
void sockstats _P((void));
void slirp_exit _P((int));

View File

@@ -1,65 +0,0 @@
/*
* Copyright (c) 1982, 1986, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)icmp_var.h 8.1 (Berkeley) 6/10/93
* icmp_var.h,v 1.4 1995/02/16 00:27:40 wollman Exp
*/
#ifndef _NETINET_ICMP_VAR_H_
#define _NETINET_ICMP_VAR_H_
/*
* Variables related to this implementation
* of the internet control message protocol.
*/
struct icmpstat {
/* statistics related to input messages processed */
u_long icps_received; /* #ICMP packets received */
u_long icps_tooshort; /* packet < ICMP_MINLEN */
u_long icps_checksum; /* bad checksum */
u_long icps_notsupp; /* #ICMP packets not supported */
u_long icps_badtype; /* #with bad type feild */
u_long icps_reflect; /* number of responses */
};
/*
* Names for ICMP sysctl objects
*/
#define ICMPCTL_MASKREPL 1 /* allow replies to netmask requests */
#define ICMPCTL_STATS 2 /* statistics (read-only) */
#define ICMPCTL_MAXID 3
#define ICMPCTL_NAMES { \
{ 0, 0 }, \
{ "maskrepl", CTLTYPE_INT }, \
{ "stats", CTLTYPE_STRUCT }, \
}
extern struct icmpstat icmpstat;
#endif

View File

@@ -1,50 +0,0 @@
/*
* Copyright (c) 1995 Danny Gasparovski.
*
* Please read the file COPYRIGHT for the
* terms and conditions of the copyright.
*/
#ifndef _IF_H_
#define _IF_H_
#define IF_COMPRESS 0x01 /* We want compression */
#define IF_NOCOMPRESS 0x02 /* Do not do compression */
#define IF_AUTOCOMP 0x04 /* Autodetect (default) */
#define IF_NOCIDCOMP 0x08 /* CID compression */
/* Needed for FreeBSD */
#undef if_mtu
extern int if_mtu;
extern int if_mru; /* MTU and MRU */
extern int if_comp; /* Flags for compression */
extern int if_maxlinkhdr;
extern int if_queued; /* Number of packets queued so far */
extern int if_thresh; /* Number of packets queued before we start sending
* (to prevent allocing too many SLIRPmbufs) */
extern struct SLIRPmbuf if_fastq; /* fast queue (for interactive data) */
extern struct SLIRPmbuf if_batchq; /* queue for non-interactive data */
extern struct SLIRPmbuf *next_m;
#define ifs_init(ifm) ((ifm)->ifs_next = (ifm)->ifs_prev = (ifm))
/* Interface statistics */
struct slirp_ifstats {
u_int out_pkts; /* Output packets */
u_int out_bytes; /* Output bytes */
u_int out_errpkts; /* Output Error Packets */
u_int out_errbytes; /* Output Error Bytes */
u_int in_pkts; /* Input packets */
u_int in_bytes; /* Input bytes */
u_int in_errpkts; /* Input Error Packets */
u_int in_errbytes; /* Input Error Bytes */
u_int bytes_saved; /* Number of bytes that compression "saved" */
/* ie: number of bytes that didn't need to be sent over the link
* because of compression */
u_int in_mbad; /* Bad incoming packets */
};
#endif

View File

@@ -1,362 +0,0 @@
/*
* Copyright (c) 1982, 1986, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)ip.h 8.1 (Berkeley) 6/10/93
* ip.h,v 1.3 1994/08/21 05:27:30 paul Exp
*/
#ifndef _IP_H_
#define _IP_H_
#ifdef WORDS_BIGENDIAN
# ifndef NTOHL
# define NTOHL(d)
# endif
# ifndef NTOHS
# define NTOHS(d)
# endif
# ifndef HTONL
# define HTONL(d)
# endif
# ifndef HTONS
# define HTONS(d)
# endif
#else
# ifndef NTOHL
# define NTOHL(d) ((d) = ntohl((d)))
# endif
# ifndef NTOHS
# define NTOHS(d) ((d) = ntohs((u_int16_t)(d)))
# endif
# ifndef HTONL
# define HTONL(d) ((d) = htonl((d)))
# endif
# ifndef HTONS
# define HTONS(d) ((d) = htons((u_int16_t)(d)))
# endif
#endif
typedef u_int32_t n_long; /* long as received from the net */
/*
* Definitions for internet protocol version 4.
* Per RFC 791, September 1981.
*/
#define IPVERSION 4
#if defined(_MSC_VER)
#pragma pack(push, 1)
#endif
/*
* Structure of an internet header, naked of options.
*/
#ifdef PRAGMA_PACK_SUPPORTED
#pragma pack(1)
#endif
struct ip {
#ifdef WORDS_BIGENDIAN
u_char ip_v:4, /* version */
ip_hl:4; /* header length */
#else
u_char ip_hl:4, /* header length */
ip_v:4; /* version */
#endif
u_int8_t ip_tos; /* type of service */
u_int16_t ip_len; /* total length */
u_int16_t ip_id; /* identification */
u_int16_t ip_off; /* fragment offset field */
#define IP_DF 0x4000 /* don't fragment flag */
#define IP_MF 0x2000 /* more fragments flag */
#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */
u_int8_t ip_ttl; /* time to live */
u_int8_t ip_p; /* protocol */
u_int16_t ip_sum; /* checksum */
struct in_addr ip_src,ip_dst; /* source and dest address */
} PACKED__;
#ifdef PRAGMA_PACK_SUPPORTED
#pragma pack(PACK_END) //WAS 0
#endif
#define IP_MAXPACKET 65535 /* maximum packet size */
/*
* Definitions for IP type of service (ip_tos)
*/
#define IPTOS_LOWDELAY 0x10
#define IPTOS_THROUGHPUT 0x08
#define IPTOS_RELIABILITY 0x04
/*
* Definitions for options.
*/
#define IPOPT_COPIED(o) ((o)&0x80)
#define IPOPT_CLASS(o) ((o)&0x60)
#define IPOPT_NUMBER(o) ((o)&0x1f)
#define IPOPT_CONTROL 0x00
#define IPOPT_RESERVED1 0x20
#define IPOPT_DEBMEAS 0x40
#define IPOPT_RESERVED2 0x60
#define IPOPT_EOL 0 /* end of option list */
#define IPOPT_NOP 1 /* no operation */
#define IPOPT_RR 7 /* record packet route */
#define IPOPT_TS 68 /* timestamp */
#define IPOPT_SECURITY 130 /* provide s,c,h,tcc */
#define IPOPT_LSRR 131 /* loose source route */
#define IPOPT_SATID 136 /* satnet id */
#define IPOPT_SSRR 137 /* strict source route */
/*
* Offsets to fields in options other than EOL and NOP.
*/
#define IPOPT_OPTVAL 0 /* option ID */
#define IPOPT_OLEN 1 /* option length */
#define IPOPT_OFFSET 2 /* offset within option */
#define IPOPT_MINOFF 4 /* min value of above */
/*
* Time stamp option structure.
*/
#ifdef PRAGMA_PACK_SUPPORTED
#pragma pack(1)
#endif
struct ip_timestamp {
u_int8_t ipt_code; /* IPOPT_TS */
u_int8_t ipt_len; /* size of structure (variable) */
u_int8_t ipt_ptr; /* index of current entry */
#ifdef WORDS_BIGENDIAN
u_char ipt_oflw:4, /* overflow counter */
ipt_flg:4; /* flags, see below */
#else
u_char ipt_flg:4, /* flags, see below */
ipt_oflw:4; /* overflow counter */
#endif
union ipt_timestamp {
n_long ipt_time[1];
struct ipt_ta {
struct in_addr ipt_addr;
n_long ipt_time;
} ipt_ta[1];
} ipt_timestamp;
} PACKED__;
#ifdef PRAGMA_PACK_SUPPORTED
#pragma pack(PACK_END)
#endif
/* flag bits for ipt_flg */
#define IPOPT_TS_TSONLY 0 /* timestamps only */
#define IPOPT_TS_TSANDADDR 1 /* timestamps and addresses */
#define IPOPT_TS_PRESPEC 3 /* specified modules only */
/* bits for security (not byte swapped) */
#define IPOPT_SECUR_UNCLASS 0x0000
#define IPOPT_SECUR_CONFID 0xf135
#define IPOPT_SECUR_EFTO 0x789a
#define IPOPT_SECUR_MMMM 0xbc4d
#define IPOPT_SECUR_RESTR 0xaf13
#define IPOPT_SECUR_SECRET 0xd788
#define IPOPT_SECUR_TOPSECRET 0x6bc5
/*
* Internet implementation parameters.
*/
#define MAXTTL 255 /* maximum time to live (seconds) */
#define IPDEFTTL 64 /* default ttl, from RFC 1340 */
#define IPFRAGTTL 60 /* time to live for frags, slowhz */
#define IPTTLDEC 1 /* subtracted when forwarding */
#define IP_MSS 576 /* default maximum segment size */
#ifdef HAVE_SYS_TYPES32_H /* Overcome some Solaris 2.x junk */
#include <sys/types32.h>
#else
#if SIZEOF_CHAR_P == 4
typedef SLIRPcaddr_t caddr32_t;
#else
typedef u_int32_t caddr32_t;
#endif
#endif
#if defined(__amd64__) || defined(__aarch64__)
typedef uintptr_t ipqp_32;
typedef uintptr_t ipasfragp_32;
#else
#if SIZEOF_CHAR_P == 4
typedef struct ipq *ipqp_32;
typedef struct ipasfrag *ipasfragp_32;
#else
typedef caddr32_t ipqp_32;
typedef caddr32_t ipasfragp_32;
#endif
#endif
/*
* Overlay for ip header used by other protocols (tcp, udp).
*/
#ifdef PRAGMA_PACK_SUPPORTED
#pragma pack(1)
#endif
struct ipovly {
#if defined(__amd64__) || defined(__aarch64__)
uintptr_t ih_next, ih_prev; /* for protocol sequence q's */
#else
caddr32_t ih_next, ih_prev; /* for protocol sequence q's */
#endif
u_int8_t ih_x1; /* (unused) */
u_int8_t ih_pr; /* protocol */
u_int16_t ih_len; /* protocol length */
struct in_addr ih_src; /* source internet address */
struct in_addr ih_dst; /* destination internet address */
} PACKED__;
#ifdef PRAGMA_PACK_SUPPORTED
#pragma pack(PACK_END)
#endif
#if defined(_MSC_VER)
#pragma pack(pop)
#endif
/*
* Ip reassembly queue structure. Each fragment
* being reassembled is attached to one of these structures.
* They are timed out after ipq_ttl drops to 0, and may also
* be reclaimed if memory becomes tight.
* size 28 bytes
*/
struct ipq {
#if defined(__amd64__) || defined(__aarch64__)
uintptr_t next,prev; /* to other reass headers */
#else
ipqp_32 next,prev; /* to other reass headers */
#endif
u_int8_t ipq_ttl; /* time for reass q to live */
u_int8_t ipq_p; /* protocol of this fragment */
u_int16_t ipq_id; /* sequence id for reassembly */
ipasfragp_32 ipq_next,ipq_prev;
/* to ip headers of fragments */
struct in_addr ipq_src,ipq_dst;
};
/*
* Ip header, when holding a fragment.
*
* Note: ipf_next must be at same offset as ipq_next above
*/
#ifdef PRAGMA_PACK_SUPPORTED
#pragma pack(1)
#endif
struct ipasfrag {
#ifdef WORDS_BIGENDIAN
u_char ip_v:4,
ip_hl:4;
#else
u_char ip_hl:4,
ip_v:4;
#endif
/* BUG : u_int changed to u_int8_t.
* sizeof(u_int)==4 on linux 2.0
*/
u_int8_t ipf_mff; /* XXX overlays ip_tos: use low bit
* to avoid destroying tos (PPPDTRuu);
* copied from (ip_off&IP_MF) */
u_int16_t ip_len;
u_int16_t ip_id;
u_int16_t ip_off;
u_int8_t ip_ttl;
u_int8_t ip_p;
u_int16_t ip_sum;
ipasfragp_32 ipf_next; /* next fragment */
ipasfragp_32 ipf_prev; /* previous fragment */
} PACKED__;
#ifdef PRAGMA_PACK_SUPPORTED
#pragma pack(PACK_END) //WAS 0
#endif
/*
* Structure stored in mbuf in inpcb.ip_options
* and passed to ip_output when ip options are in use.
* The actual length of the options (including ipopt_dst)
* is in m_len.
*/
#define MAX_IPOPTLEN 40
struct ipoption {
struct in_addr ipopt_dst; /* first-hop dst if source routed */
int8_t ipopt_list[MAX_IPOPTLEN]; /* options proper */
};
/*
* Structure attached to inpcb.ip_moptions and
* passed to ip_output when IP multicast options are in use.
*/
struct ipstat {
u_long ips_total; /* total packets received */
u_long ips_badsum; /* checksum bad */
u_long ips_tooshort; /* packet too short */
u_long ips_toosmall; /* not enough data */
u_long ips_badhlen; /* ip header length < data size */
u_long ips_badlen; /* ip length < ip header length */
u_long ips_fragments; /* fragments received */
u_long ips_fragdropped; /* frags dropped (dups, out of space) */
u_long ips_fragtimeout; /* fragments timed out */
u_long ips_forward; /* packets forwarded */
u_long ips_cantforward; /* packets rcvd for unreachable dest */
u_long ips_redirectsent; /* packets forwarded on same net */
u_long ips_noproto; /* unknown or unsupported protocol */
u_long ips_delivered; /* datagrams delivered to upper level*/
u_long ips_localout; /* total ip packets generated here */
u_long ips_odropped; /* lost packets due to nobufs, etc. */
u_long ips_reassembled; /* total packets reassembled ok */
u_long ips_fragmented; /* datagrams successfully fragmented */
u_long ips_ofragments; /* output fragments created */
u_long ips_cantfrag; /* don't fragment flag was set, etc. */
u_long ips_badoptions; /* error in option processing */
u_long ips_noroute; /* packets discarded due to no route */
u_long ips_badvers; /* ip version != 4 */
u_long ips_rawout; /* total raw ip packets generated */
u_long ips_unaligned; /* times the ip packet was not aligned */
};
extern struct ipstat ipstat;
extern struct ipq ipq; /* ip reass. queue */
extern u_int16_t ip_id; /* ip packet ctr, for ids */
extern int ip_defttl; /* default IP ttl */
#endif

View File

@@ -1,168 +0,0 @@
/*
* Copyright (c) 1982, 1986, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)ip_icmp.h 8.1 (Berkeley) 6/10/93
* ip_icmp.h,v 1.4 1995/05/30 08:09:43 rgrimes Exp
*/
#ifndef _NETINET_IP_ICMP_H_
#define _NETINET_IP_ICMP_H_
/*
* Interface Control Message Protocol Definitions.
* Per RFC 792, September 1981.
*/
typedef u_int32_t n_time;
/*
* Structure of an icmp header.
*/
#ifdef PRAGMA_PACK_SUPPORTED
#pragma pack(1)
#endif
struct icmp {
u_char icmp_type; /* type of message, see below */
u_char icmp_code; /* type sub code */
u_short icmp_cksum; /* ones complement cksum of struct */
union {
u_char ih_pptr; /* ICMP_PARAMPROB */
struct in_addr ih_gwaddr; /* ICMP_REDIRECT */
struct ih_idseq {
u_short icd_id;
u_short icd_seq;
} ih_idseq;
int ih_void;
/* ICMP_UNREACH_NEEDFRAG -- Path MTU Discovery (RFC1191) */
struct ih_pmtu {
u_short ipm_void;
u_short ipm_nextmtu;
} ih_pmtu;
} icmp_hun;
#define icmp_pptr icmp_hun.ih_pptr
#define icmp_gwaddr icmp_hun.ih_gwaddr
#define icmp_id icmp_hun.ih_idseq.icd_id
#define icmp_seq icmp_hun.ih_idseq.icd_seq
#define icmp_void icmp_hun.ih_void
#define icmp_pmvoid icmp_hun.ih_pmtu.ipm_void
#define icmp_nextmtu icmp_hun.ih_pmtu.ipm_nextmtu
union {
struct id_ts {
n_time its_otime;
n_time its_rtime;
n_time its_ttime;
} id_ts;
struct id_ip {
struct ip idi_ip;
/* options and then 64 bits of data */
} id_ip;
uint32_t id_mask;
char id_data[1];
} icmp_dun;
#define icmp_otime icmp_dun.id_ts.its_otime
#define icmp_rtime icmp_dun.id_ts.its_rtime
#define icmp_ttime icmp_dun.id_ts.its_ttime
#define icmp_ip icmp_dun.id_ip.idi_ip
#define icmp_mask icmp_dun.id_mask
#define icmp_data icmp_dun.id_data
} PACKED__;
#ifdef PRAGMA_PACK_SUPPORTED
#pragma pack(0)
#endif
/*
* Lower bounds on packet lengths for various types.
* For the error advice packets must first insure that the
* packet is large enought to contain the returned ip header.
* Only then can we do the check to see if 64 bits of packet
* data have been returned, since we need to check the returned
* ip header length.
*/
#define ICMP_MINLEN 8 /* abs minimum */
#define ICMP_TSLEN (8 + 3 * sizeof (n_time)) /* timestamp */
#define ICMP_MASKLEN 12 /* address mask */
#define ICMP_ADVLENMIN (8 + sizeof (struct ip) + 8) /* min */
#define ICMP_ADVLEN(p) (8 + ((p)->icmp_ip.ip_hl << 2) + 8)
/* N.B.: must separately check that ip_hl >= 5 */
/*
* Definition of type and code field values.
*/
#define ICMP_ECHOREPLY 0 /* echo reply */
#define ICMP_UNREACH 3 /* dest unreachable, codes: */
#define ICMP_UNREACH_NET 0 /* bad net */
#define ICMP_UNREACH_HOST 1 /* bad host */
#define ICMP_UNREACH_PROTOCOL 2 /* bad protocol */
#define ICMP_UNREACH_PORT 3 /* bad port */
#define ICMP_UNREACH_NEEDFRAG 4 /* IP_DF caused drop */
#define ICMP_UNREACH_SRCFAIL 5 /* src route failed */
#define ICMP_UNREACH_NET_UNKNOWN 6 /* unknown net */
#define ICMP_UNREACH_HOST_UNKNOWN 7 /* unknown host */
#define ICMP_UNREACH_ISOLATED 8 /* src host isolated */
#define ICMP_UNREACH_NET_PROHIB 9 /* prohibited access */
#define ICMP_UNREACH_HOST_PROHIB 10 /* ditto */
#define ICMP_UNREACH_TOSNET 11 /* bad tos for net */
#define ICMP_UNREACH_TOSHOST 12 /* bad tos for host */
#define ICMP_SOURCEQUENCH 4 /* packet lost, slow down */
#define ICMP_REDIRECT 5 /* shorter route, codes: */
#define ICMP_REDIRECT_NET 0 /* for network */
#define ICMP_REDIRECT_HOST 1 /* for host */
#define ICMP_REDIRECT_TOSNET 2 /* for tos and net */
#define ICMP_REDIRECT_TOSHOST 3 /* for tos and host */
#define ICMP_ECHO 8 /* echo service */
#define ICMP_ROUTERADVERT 9 /* router advertisement */
#define ICMP_ROUTERSOLICIT 10 /* router solicitation */
#define ICMP_TIMXCEED 11 /* time exceeded, code: */
#define ICMP_TIMXCEED_INTRANS 0 /* ttl==0 in transit */
#define ICMP_TIMXCEED_REASS 1 /* ttl==0 in reass */
#define ICMP_PARAMPROB 12 /* ip header bad */
#define ICMP_PARAMPROB_OPTABSENT 1 /* req. opt. absent */
#define ICMP_TSTAMP 13 /* timestamp request */
#define ICMP_TSTAMPREPLY 14 /* timestamp reply */
#define ICMP_IREQ 15 /* information request */
#define ICMP_IREQREPLY 16 /* information reply */
#define ICMP_MASKREQ 17 /* address mask request */
#define ICMP_MASKREPLY 18 /* address mask reply */
#define ICMP_MAXTYPE 18
#define ICMP_INFOTYPE(type) \
((type) == ICMP_ECHOREPLY || (type) == ICMP_ECHO || \
(type) == ICMP_ROUTERADVERT || (type) == ICMP_ROUTERSOLICIT || \
(type) == ICMP_TSTAMP || (type) == ICMP_TSTAMPREPLY || \
(type) == ICMP_IREQ || (type) == ICMP_IREQREPLY || \
(type) == ICMP_MASKREQ || (type) == ICMP_MASKREPLY)
void icmp_input _P((struct SLIRPmbuf *, int));
void icmp_error _P((struct SLIRPmbuf *, u_char, u_char, int, char *));
void icmp_reflect _P((struct SLIRPmbuf *));
#endif

View File

@@ -0,0 +1,24 @@
/* SPDX-License-Identifier: BSD-3-Clause */
#ifndef LIBSLIRP_VERSION_H_
#define LIBSLIRP_VERSION_H_
#ifdef __cplusplus
extern "C" {
#endif
#define SLIRP_MAJOR_VERSION 4
#define SLIRP_MINOR_VERSION 3
#define SLIRP_MICRO_VERSION 1
#define SLIRP_VERSION_STRING "4.3.1-git-86Box"
#define SLIRP_CHECK_VERSION(major,minor,micro) \
(SLIRP_MAJOR_VERSION > (major) || \
(SLIRP_MAJOR_VERSION == (major) && SLIRP_MINOR_VERSION > (minor)) || \
(SLIRP_MAJOR_VERSION == (major) && SLIRP_MINOR_VERSION == (minor) && \
SLIRP_MICRO_VERSION >= (micro)))
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* LIBSLIRP_VERSION_H_ */

View File

@@ -1,41 +1,175 @@
#ifndef _LIBSLIRP_H /* SPDX-License-Identifier: BSD-3-Clause */
#define _LIBSLIRP_H #ifndef LIBSLIRP_H
#define LIBSLIRP_H
#include <stdint.h>
#include <stdbool.h>
#include <sys/types.h>
#ifdef _WIN32 #ifdef _WIN32
#include <winsock2.h> #include <winsock2.h>
int inet_aton(const char *cp, struct in_addr *ia); #include <in6addr.h>
#else #else
#include <sys/select.h> #include <netinet/in.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#endif #endif
#include "libslirp-version.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
int slirp_init(void); typedef struct Slirp Slirp;
int slirp_select_fill(int *pnfds, enum {
fd_set *readfds, fd_set *writefds, fd_set *xfds); SLIRP_POLL_IN = 1 << 0,
SLIRP_POLL_OUT = 1 << 1,
SLIRP_POLL_PRI = 1 << 2,
SLIRP_POLL_ERR = 1 << 3,
SLIRP_POLL_HUP = 1 << 4,
};
void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds); typedef ssize_t (*SlirpReadCb)(void *buf, size_t len, void *opaque);
typedef ssize_t (*SlirpWriteCb)(const void *buf, size_t len, void *opaque);
typedef void (*SlirpTimerCb)(void *opaque);
typedef int (*SlirpAddPollCb)(int fd, int events, void *opaque);
typedef int (*SlirpGetREventsCb)(int idx, void *opaque);
void slirp_input(const uint8 *pkt, int pkt_len); /*
* Callbacks from slirp
*/
typedef struct SlirpCb {
/*
* Send an ethernet frame to the guest network. The opaque
* parameter is the one given to slirp_init(). The function
* doesn't need to send all the data and may return <len (no
* buffering is done on libslirp side, so the data will be dropped
* in this case). <0 reports an IO error.
*/
SlirpWriteCb send_packet;
/* Print a message for an error due to guest misbehavior. */
void (*guest_error)(const char *msg, void *opaque);
/* Return the virtual clock value in nanoseconds */
int64_t (*clock_get_ns)(void *opaque);
/* Create a new timer with the given callback and opaque data */
void *(*timer_new)(SlirpTimerCb cb, void *cb_opaque, void *opaque);
/* Remove and free a timer */
void (*timer_free)(void *timer, void *opaque);
/* Modify a timer to expire at @expire_time */
void (*timer_mod)(void *timer, int64_t expire_time, void *opaque);
/* Register a fd for future polling */
void (*register_poll_fd)(int fd, void *opaque);
/* Unregister a fd */
void (*unregister_poll_fd)(int fd, void *opaque);
/* Kick the io-thread, to signal that new events may be processed */
void (*notify)(void *opaque);
} SlirpCb;
/* you must provide the following functions: */ #define SLIRP_CONFIG_VERSION_MIN 1
int slirp_can_output(void); #define SLIRP_CONFIG_VERSION_MAX 3
void slirp_output(const uint8 *pkt, int pkt_len);
int slirp_redir(int is_udp, int host_port, typedef struct SlirpConfig {
struct in_addr guest_addr, int guest_port); /* Version must be provided */
int slirp_add_exec(int do_pty, const char *args, int addr_low_byte, uint32_t version;
int guest_port); /*
* Fields introduced in SlirpConfig version 1 begin
*/
int restricted;
bool in_enabled;
struct in_addr vnetwork;
struct in_addr vnetmask;
struct in_addr vhost;
bool in6_enabled;
struct in6_addr vprefix_addr6;
uint8_t vprefix_len;
struct in6_addr vhost6;
const char *vhostname;
const char *tftp_server_name;
const char *tftp_path;
const char *bootfile;
struct in_addr vdhcp_start;
struct in_addr vnameserver;
struct in6_addr vnameserver6;
const char **vdnssearch;
const char *vdomainname;
/* Default: IF_MTU_DEFAULT */
size_t if_mtu;
/* Default: IF_MRU_DEFAULT */
size_t if_mru;
/* Prohibit connecting to 127.0.0.1:* */
bool disable_host_loopback;
/*
* Enable emulation code (*warning*: this code isn't safe, it is not
* recommended to enable it)
*/
bool enable_emu;
/*
* Fields introduced in SlirpConfig version 2 begin
*/
struct sockaddr_in *outbound_addr;
struct sockaddr_in6 *outbound_addr6;
/*
* Fields introduced in SlirpConfig version 3 begin
*/
bool disable_dns; /* slirp will not redirect/serve any DNS packet */
} SlirpConfig;
extern const char *tftp_prefix; Slirp *slirp_new(const SlirpConfig *cfg, const SlirpCb *callbacks,
extern char slirp_hostname[33]; void *opaque);
/* slirp_init is deprecated in favor of slirp_new */
Slirp *slirp_init(int restricted, bool in_enabled, struct in_addr vnetwork,
struct in_addr vnetmask, struct in_addr vhost,
bool in6_enabled, struct in6_addr vprefix_addr6,
uint8_t vprefix_len, struct in6_addr vhost6,
const char *vhostname, const char *tftp_server_name,
const char *tftp_path, const char *bootfile,
struct in_addr vdhcp_start, struct in_addr vnameserver,
struct in6_addr vnameserver6, const char **vdnssearch,
const char *vdomainname, const SlirpCb *callbacks,
void *opaque);
void slirp_cleanup(Slirp *slirp);
void slirp_pollfds_fill(Slirp *slirp, uint32_t *timeout,
SlirpAddPollCb add_poll, void *opaque);
void slirp_pollfds_poll(Slirp *slirp, int select_error,
SlirpGetREventsCb get_revents, void *opaque);
void slirp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len);
int slirp_add_hostfwd(Slirp *slirp, int is_udp, struct in_addr host_addr,
int host_port, struct in_addr guest_addr, int guest_port);
int slirp_remove_hostfwd(Slirp *slirp, int is_udp, struct in_addr host_addr,
int host_port);
int slirp_add_exec(Slirp *slirp, const char *cmdline,
struct in_addr *guest_addr, int guest_port);
int slirp_add_unix(Slirp *slirp, const char *unixsock,
struct in_addr *guest_addr, int guest_port);
int slirp_add_guestfwd(Slirp *slirp, SlirpWriteCb write_cb, void *opaque,
struct in_addr *guest_addr, int guest_port);
/* remove entries added by slirp_add_exec, slirp_add_unix or slirp_add_guestfwd */
int slirp_remove_guestfwd(Slirp *slirp, struct in_addr guest_addr,
int guest_port);
char *slirp_connection_info(Slirp *slirp);
void slirp_socket_recv(Slirp *slirp, struct in_addr guest_addr, int guest_port,
const uint8_t *buf, int size);
size_t slirp_socket_can_recv(Slirp *slirp, struct in_addr guest_addr,
int guest_port);
void slirp_state_save(Slirp *s, SlirpWriteCb write_cb, void *opaque);
int slirp_state_load(Slirp *s, int version_id, SlirpReadCb read_cb,
void *opaque);
int slirp_state_version(void);
const char *slirp_version_string(void);
#ifdef __cplusplus #ifdef __cplusplus
} } /* extern "C" */
#endif #endif
#endif #endif /* LIBSLIRP_H */

View File

@@ -1,54 +0,0 @@
/*
* Copyright (c) 1995 Danny Gasparovski.
*
* Please read the file COPYRIGHT for the
* terms and conditions of the copyright.
*/
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
#define TOWRITEMAX 512
extern struct timeval tt;
extern int link_up;
extern int slirp_socket;
extern int slirp_socket_unit;
extern int slirp_socket_port;
extern u_int32_t slirp_socket_addr;
extern char *slirp_socket_passwd;
extern int ctty_closed;
/*
* Get the difference in 2 times from updtim()
* Allow for wraparound times, "just in case"
* x is the greater of the 2 (current time) and y is
* what it's being compared against.
*/
#define TIME_DIFF(x,y) (x)-(y) < 0 ? ~0-(y)+(x) : (x)-(y)
extern char *slirp_tty;
extern char *exec_shell;
extern u_int curtime;
extern fd_set *global_readfds, *global_writefds, *global_xfds;
extern struct in_addr ctl_addr;
extern struct in_addr special_addr;
extern struct in_addr alias_addr;
extern struct in_addr our_addr;
extern struct in_addr loopback_addr;
extern struct in_addr dns_addr;
extern char *username;
extern char *socket_path;
extern int towrite_max;
extern int ppp_exit;
extern int so_options;
extern int tcp_keepintvl;
extern uint8_t client_ethaddr[6];
#define PROTO_SLIP 0x1
#ifdef USE_PPP
#define PROTO_PPP 0x2
#endif
void if_encap(const uint8_t *ip_data, int ip_data_len);

View File

@@ -1,143 +0,0 @@
/*
* Copyright (c) 1982, 1986, 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)mbuf.h 8.3 (Berkeley) 1/21/94
* mbuf.h,v 1.9 1994/11/14 13:54:20 bde Exp
*/
#ifndef _MBUF_H_
#define _MBUF_H_
#define m_freem m_free
#define MINCSIZE 4096 /* Amount to increase mbuf if too small */
/*
* Macros for type conversion
* mtod(m,t) - convert mbuf pointer to data pointer of correct type
* dtom(x) - convert data pointer within mbuf to mbuf pointer (XXX)
*/
#define mtod(m,t) ((t)(m)->m_data)
/* #define dtom(x) ((struct SLIRPmbuf *)((int)(x) & ~(M_SIZE-1))) */
/* XXX About mbufs for slirp:
* Only one mbuf is ever used in a chain, for each "cell" of data.
* m_nextpkt points to the next packet, if fragmented.
* If the data is too large, the M_EXT is used, and a larger block
* is alloced. Therefore, m_free[m] must check for M_EXT and if set
* free the m_ext. This is inefficient memory-wise, but who cares.
*/
/* XXX should union some of these! */
/* header at beginning of each mbuf: */
struct m_hdr {
struct SLIRPmbuf *mh_next; /* Linked list of mbufs */
struct SLIRPmbuf *mh_prev;
struct SLIRPmbuf *mh_nextpkt; /* Next packet in queue/record */
struct SLIRPmbuf *mh_prevpkt; /* Flags aren't used in the output queue */
int mh_flags; /* Misc flags */
size_t mh_size; /* Size of data */
struct SLIRPsocket *mh_so;
SLIRPcaddr_t mh_data; /* Location of data */
int32_t mh_len; /* Amount of data in this mbuf */
};
/*
* How much room is in the mbuf, from m_data to the end of the mbuf
*/
#define M_ROOM(m) ((m->m_flags & M_EXT)? \
(((m)->m_ext + (m)->m_size) - (m)->m_data) \
: \
(((m)->m_dat + (m)->m_size) - (m)->m_data))
/*
* How much free room there is
*/
#define M_FREEROOM(m) (M_ROOM(m) - (m)->m_len)
#define M_TRAILINGSPACE M_FREEROOM
struct SLIRPmbuf {
struct m_hdr m_hdr;
union M_dat {
char m_dat_[1]; /* ANSI don't like 0 sized arrays */
char *m_ext_;
} M_dat;
};
#define m_next m_hdr.mh_next
#define m_prev m_hdr.mh_prev
#define m_nextpkt m_hdr.mh_nextpkt
#define m_prevpkt m_hdr.mh_prevpkt
#define m_flags m_hdr.mh_flags
#define m_len m_hdr.mh_len
#define m_data m_hdr.mh_data
#define m_size m_hdr.mh_size
#define m_dat M_dat.m_dat_
#define m_ext M_dat.m_ext_
#define m_so m_hdr.mh_so
#define ifq_prev m_prev
#define ifq_next m_next
#define ifs_prev m_prevpkt
#define ifs_next m_nextpkt
#define ifq_so m_so
#define M_EXT 0x01 /* m_ext points to more (malloced) data */
#define M_FREELIST 0x02 /* mbuf is on free list */
#define M_USEDLIST 0x04 /* XXX mbuf is on used list (for dtom()) */
#define M_DOFREE 0x08 /* when m_free is called on the mbuf, free()
* it rather than putting it on the free list */
/*
* Mbuf statistics. XXX
*/
struct mbstat {
int mbs_alloced; /* Number of mbufs allocated */
};
extern struct mbstat mbstat;
extern int mbuf_alloced;
extern struct SLIRPmbuf m_freelist, m_usedlist;
extern int mbuf_max;
void m_init _P((void));
void msize_init _P((void));
struct SLIRPmbuf * m_get _P((void));
void m_free _P((struct SLIRPmbuf *));
void m_cat _P((register struct SLIRPmbuf *, register struct SLIRPmbuf *));
void m_inc _P((struct SLIRPmbuf *, int));
void m_adj _P((struct SLIRPmbuf *, int));
int m_copy _P((struct SLIRPmbuf *, struct SLIRPmbuf *, int, int));
struct SLIRPmbuf * dtom _P((void *));
#endif

View File

@@ -1,87 +0,0 @@
/*
* Copyright (c) 1995 Danny Gasparovski.
*
* Please read the file COPYRIGHT for the
* terms and conditions of the copyright.
*/
#ifndef _MISC_H_
#define _MISC_H_
struct ex_list {
int ex_pty; /* Do we want a pty? */
int ex_addr; /* The last byte of the address */
int ex_fport; /* Port to telnet to */
char *ex_exec; /* Command line of what to exec */
struct ex_list *ex_next;
};
extern struct ex_list *exec_list;
extern u_int curtime, time_fasttimo, last_slowtimo, detach_time, detach_wait;
extern int (*lprint_print) _P((void *, const char *, va_list));
extern char *lprint_ptr, *lprint_ptr2, **lprint_arg;
extern struct sbuf *lprint_sb;
#ifndef HAVE_STRDUP
char *strdup _P((const char *));
#endif
void do_wait _P((int));
#define EMU_NONE 0x0
/* TCP emulations */
#define EMU_CTL 0x1
#define EMU_FTP 0x2
#define EMU_KSH 0x3
#define EMU_IRC 0x4
#define EMU_REALAUDIO 0x5
#define EMU_RLOGIN 0x6
#define EMU_IDENT 0x7
#define EMU_RSH 0x8
#define EMU_NOCONNECT 0x10 /* Don't connect */
/* UDP emulations */
#define EMU_TALK 0x1
#define EMU_NTALK 0x2
#define EMU_CUSEEME 0x3
struct tos_t {
u_int16_t lport;
u_int16_t fport;
u_int8_t tos;
u_int8_t emu;
};
struct emu_t {
u_int16_t lport;
u_int16_t fport;
u_int8_t tos;
u_int8_t emu;
struct emu_t *next;
};
extern struct emu_t *tcpemu;
extern int x_port, x_server, x_display;
int show_x _P((char *, struct SLIRPsocket *));
void redir_x _P((u_int32_t, int, int, int));
void getouraddr _P((void));
void slirp_insque _P((void *, void *));
void slirp_remque _P((void *));
int add_exec _P((struct ex_list **, int, char *, int, int));
int slirp_openpty _P((int *, int *));
int fork_exec _P((struct SLIRPsocket *, char *, int));
void snooze_hup _P((int));
void snooze _P((void));
void relay _P((int));
void add_emu _P((char *));
void u_sleep _P((int));
void fd_nonblock _P((int));
void fd_block _P((int));
int rsh_exec _P((struct SLIRPsocket *, struct SLIRPsocket *, char *, char *, char *));
#endif

View File

@@ -1,101 +0,0 @@
/*
* File: queue.h
* Author: Robert I. Pitts <rip@cs.bu.edu>
* Last Modified: March 9, 2000
* Topic: Queue - Array Implementation
* ----------------------------------------------------------------
*/
#ifndef _QUEUE_H
#define _QUEUE_H
/*
* Constants
* ---------
* ERROR_* These signal error conditions in queue functions
* and are used as exit codes for the program.
*/
#define ERROR_QUEUE 2
#define ERROR_MEMORY 3
/*
* Type: queueElementT
* -------------------
* This is the type of objects held in the queue.
*/
/*typedef char queueElementT;
typedef unsigned char *queueElementT;
*/
struct queuepacket{
int len;
unsigned char data[2000];
};
typedef struct queuepacket *queueElementT;
/*
* Type: queueADT
* --------------
* The actual implementation of a queue is completely
* hidden. Client will work with queueADT which is a
* pointer to underlying queueCDT.
*/
/*
* NOTE: need word struct below so that the compiler
* knows at least that a queueCDT will be some sort
* of struct.
*/
typedef struct queueCDT *queueADT;
/*
* Function: QueueCreate
* Usage: queue = QueueCreate();
* -------------------------
* A new empty queue is created and returned.
*/
queueADT QueueCreate(void);
/* Function: QueueDestroy
* Usage: QueueDestroy(queue);
* -----------------------
* This function frees all memory associated with
* the queue. "queue" may not be used again unless
* queue = QueueCreate() is called first.
*/
void QueueDestroy(queueADT queue);
/*
* Functions: QueueEnter, QueueDelete
* Usage: QueueEnter(queue, element);
* element = QueueDelete(queue);
* --------------------------------------------
* These are the fundamental queue operations that enter
* elements in and delete elements from the queue. A call
* to QueueDelete() on an empty queue or to QueueEnter()
* on a full queue is an error. Make use of QueueIsFull()
* and QueueIsEmpty() (see below) to avoid these errors.
*/
void QueueEnter(queueADT queue, queueElementT element);
queueElementT QueueDelete(queueADT queue);
/*
* Functions: QueueIsEmpty, QueueIsFull
* Usage: if (QueueIsEmpty(queue)) ...
* -----------------------------------
* These return a true/false value based on whether
* the queue is empty or full, respectively.
*/
int QueueIsEmpty(queueADT queue);
int QueueIsFull(queueADT queue);
int QueuePeek(queueADT queue);
#endif /* not defined _QUEUE_H */

View File

@@ -1,31 +0,0 @@
/*
* Copyright (c) 1995 Danny Gasparovski.
*
* Please read the file COPYRIGHT for the
* terms and conditions of the copyright.
*/
#ifndef _SBUF_H_
#define _SBUF_H_
#define sbflush(sb) sbdrop((sb),(sb)->sb_cc)
#define sbspace(sb) ((sb)->sb_datalen - (sb)->sb_cc)
struct sbuf {
u_int sb_cc; /* actual chars in buffer */
u_int sb_datalen; /* Length of data */
char *sb_wptr; /* write pointer. points to where the next
* bytes should be written in the sbuf */
char *sb_rptr; /* read pointer. points to where the next
* byte should be read from the sbuf */
char *sb_data; /* Actual data */
};
void sbfree _P((struct sbuf *));
void sbdrop _P((struct sbuf *, int));
void sbreserve _P((struct sbuf *, int));
void sbappend _P((struct SLIRPsocket *, struct SLIRPmbuf *));
void sbappendsb _P((struct sbuf *, struct SLIRPmbuf *));
void sbcopy _P((struct sbuf *, int, int, char *));
#endif

View File

@@ -1,441 +0,0 @@
#ifndef __COMMON_H__
#define __COMMON_H__
#define SLIRP_VERSION "Cockatrice special"
#define CONFIG_QEMU
#ifndef CONFIG_QEMU
#include "version.h"
#endif
#include "config.h"
#include "slirp_config.h"
#ifdef _WIN32
#ifdef __GNUC__ /* MINGW? */
# include <inttypes.h>
typedef uint8_t u_int8_t;
typedef uint16_t u_int16_t;
typedef uint32_t u_int32_t;
typedef uint64_t u_int64_t;
typedef char *SLIRPcaddr_t;
typedef int socklen_t;
typedef unsigned long ioctlsockopt_t;
#else
typedef unsigned char u_int8_t;
typedef char int8_t;
typedef unsigned char uint8_t;
typedef unsigned short u_int16_t;
typedef unsigned short uint16_t;
typedef short int16_t;
typedef unsigned int u_int32_t;
typedef unsigned int uint32_t;
typedef int int32_t;
typedef unsigned __int64 u_int64_t;
typedef char *SLIRPcaddr_t;
typedef int socklen_t;
typedef unsigned long ioctlsockopt_t;
#endif
# include <winsock2.h> /* needs to be on top otherwise, it'll pull in winsock1 */
# include <windows.h>
# include <sys/timeb.h>
# include <iphlpapi.h>
# define USE_FIONBIO 1
#ifndef EWOULDBLOCK
# define EWOULDBLOCK WSAEWOULDBLOCK
#endif
#ifndef EINPROGRESS
# define EINPROGRESS WSAEINPROGRESS
#endif
#ifndef ENOTCONN
# define ENOTCONN WSAENOTCONN
#endif
#ifndef EHOSTUNREACH
# define EHOSTUNREACH WSAEHOSTUNREACH
#endif
#ifndef ENETUNREACH
# define ENETUNREACH WSAENETUNREACH
#endif
#ifndef ECONNREFUSED
# define ECONNREFUSED WSAECONNREFUSED
#endif
/* Basilisk II Router defines those */
# define udp_read_completion slirp_udp_read_completion
# define write_udp slirp_write_udp
# define init_udp slirp_init_udp
# define final_udp slirp_final_udp
#else
# include <inttypes.h>
# define HAVE_STDINT_H
# define HAVE_STDLIB_H
# define HAVE_STRING_H
# define HAVE_UNISTD_H
# define HAVE_INET_ATON
typedef uint8_t u_int8_t;
typedef uint16_t u_int16_t;
typedef uint32_t u_int32_t;
typedef uint64_t u_int64_t;
typedef char *SLIRPcaddr_t;
typedef int ioctlsockopt_t;
# define ioctlsocket ioctl
# define closesocket(s) close(s)
# define O_BINARY 0
#endif
#include <sys/types.h>
#ifdef HAVE_SYS_BITYPES_H
# include <sys/bitypes.h>
#endif
#ifdef HAVE_STDINT_H
# include <stdint.h>
#endif
#ifndef _MSC_VER
#include <sys/time.h>
#else
#include <time.h>
#endif
#ifdef NEED_TYPEDEFS
typedef char int8_t;
typedef unsigned char u_int8_t;
# if SIZEOF_SHORT == 2
typedef short int16_t;
typedef unsigned short u_int16_t;
# else
# if SIZEOF_INT == 2
typedef int int16_t;
typedef unsigned int u_int16_t;
# else
#error Cannot find a type with sizeof() == 2
# endif
# endif
# if SIZEOF_SHORT == 4
typedef short int32_t;
typedef unsigned short u_int32_t;
# else
# if SIZEOF_INT == 4
typedef int int32_t;
typedef unsigned int u_int32_t;
# else
#error Cannot find a type with sizeof() == 4
# endif
# endif
#endif /* NEED_TYPEDEFS */
/* Basilisk II types glue */
typedef u_int8_t uint8;
typedef u_int16_t uint16;
typedef u_int32_t uint32;
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#ifdef HAVE_STDLIB_H
# include <stdlib.h>
#endif
#include <stdio.h>
#include <errno.h>
#ifndef HAVE_MEMMOVE
#define memmove(x, y, z) bcopy(y, x, z)
#endif
#if TIME_WITH_SYS_TIME
# include <sys/time.h>
# include <time.h>
#else
# if HAVE_SYS_TIME_H
# include <sys/time.h>
# else
# include <time.h>
# endif
#endif
#ifdef HAVE_STRING_H
# include <string.h>
#else
#ifndef _MSC_VER
# include <strings.h>
#else
#include <string.h>
#endif
#endif
#ifndef _WIN32
#include <sys/uio.h>
#endif
#ifndef _P
#ifndef NO_PROTOTYPES
# define _P(x) x
#else
# define _P(x) ()
#endif
#endif
#ifndef _WIN32
#include <netinet/in.h>
#include <arpa/inet.h>
#endif
#ifdef GETTIMEOFDAY_ONE_ARG
#define gettimeofday(x, y) gettimeofday(x)
#endif
/* Systems lacking strdup() definition in <string.h>. */
#if defined(ultrix)
char *strdup _P((const char *));
#endif
/* Systems lacking malloc() definition in <stdlib.h>. */
#if defined(ultrix) || defined(hcx)
void *malloc _P((size_t arg));
void free _P((void *ptr));
#endif
#ifndef HAVE_INET_ATON
int inet_aton _P((const char *cp, struct in_addr *ia));
#endif
#include <fcntl.h>
#ifndef NO_UNIX_SOCKETS
#include <sys/un.h>
#endif
#include <signal.h>
#ifdef HAVE_SYS_SIGNAL_H
# include <sys/signal.h>
#endif
#ifndef _WIN32
#include <sys/socket.h>
#endif
#if defined(HAVE_SYS_IOCTL_H)
# include <sys/ioctl.h>
#endif
#ifdef HAVE_SYS_SELECT_H
# include <sys/select.h>
#endif
#ifdef HAVE_SYS_WAIT_H
# include <sys/wait.h>
#endif
#ifdef HAVE_SYS_FILIO_H
# include <sys/filio.h>
#endif
#ifdef USE_PPP
#include <ppp/slirppp.h>
#endif
#ifdef __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
#include <sys/stat.h>
/* Avoid conflicting with the libc insque() and remque(), which
have different prototypes. */
#define insque slirp_insque
#define remque slirp_remque
#ifdef HAVE_SYS_STROPTS_H
#include <sys/stropts.h>
#endif
#include "debug.h"
#if defined __GNUC__
#define PACKED__ __attribute__ ((packed))
#elif defined __sgi
#define PRAGMA_PACK_SUPPORTED 1
#define PACK_END 0
#define PACKED__
#elif _MSC_VER
#define PACKED__
#else
#error "Packed attribute or pragma shall be supported"
#endif
#if defined(_MSC_VER)
#pragma pack(push, 1)
#endif
#include "ip.h"
#include "tcp.h"
#include "tcp_timer.h"
#include "tcp_var.h"
#include "tcpip.h"
#include "udp.h"
#include "icmp_var.h"
#include "mbuf.h"
#include "sbuf.h"
#include "socket.h"
#include "if.h"
#include "main.h"
#include "misc.h"
#include "ctl.h"
#ifdef USE_PPP
#include "ppp/pppd.h"
#include "ppp/ppp.h"
#endif
#include "bootp.h"
#include "tftp.h"
#include "libslirp.h"
extern struct ttys *ttys_unit[MAX_INTERFACES];
#ifndef NULL
#define NULL (void *)0
#endif
#ifndef FULL_BOLT
void if_start _P((void));
#else
void if_start _P((struct ttys *));
#endif
#ifdef BAD_SPRINTF
# define vsprintf vsprintf_len
# define sprintf sprintf_len
extern int vsprintf_len _P((char *, const char *, va_list));
extern int sprintf_len _P((char *, const char *, ...));
#endif
#ifdef DECLARE_SPRINTF
# ifndef BAD_SPRINTF
extern int vsprintf _P((char *, const char *, va_list));
# endif
extern int vfprintf _P((FILE *, const char *, va_list));
#endif
#ifndef HAVE_STRERROR
#ifndef _MSC_VER
extern char *strerror _P((int error));
#define HAVE_STRERROR
#endif
#endif
#ifndef HAVE_INDEX
char *index _P((const char *, int));
#endif
#ifndef HAVE_GETHOSTID
long gethostid _P((void));
#endif
void lprint _P((const char *, ...));
extern int do_echo;
#ifdef _MSC_VER
#define __inline
#endif
#if SIZEOF_CHAR_P == 4
# define insque_32 insque
# define remque_32 remque
#else
# ifdef NEED_QUE32_INLINE
extern __inline void insque_32 _P((void *, void *));
extern __inline void remque_32 _P((void *));
# else
extern void insque_32 _P((void *, void *));
extern void remque_32 _P((void *));
# endif
#endif
#ifndef _WIN32
#include <netdb.h>
#endif
#define DEFAULT_BAUD 115200
/* cksum.c */
int cksum(struct SLIRPmbuf *m, int len);
/* if.c */
void if_init _P((void));
void if_output _P((struct SLIRPsocket *, struct SLIRPmbuf *));
/* ip_input.c */
void ip_init _P((void));
void ip_input _P((struct SLIRPmbuf *));
struct ip * ip_reass _P((register struct ipasfrag *, register struct ipq *));
void ip_freef _P((struct ipq *));
void ip_enq _P((register struct ipasfrag *, register struct ipasfrag *));
void ip_deq _P((register struct ipasfrag *));
void ip_slowtimo _P((void));
void ip_stripoptions _P((register struct SLIRPmbuf *, struct SLIRPmbuf *));
/* ip_output.c */
int ip_output _P((struct SLIRPsocket *, struct SLIRPmbuf *));
/* tcp_input.c */
int tcp_reass _P((register struct tcpcb *, register struct tcpiphdr *, struct SLIRPmbuf *));
void tcp_input _P((register struct SLIRPmbuf *, int, struct SLIRPsocket *));
void tcp_dooptions _P((struct tcpcb *, u_char *, int, struct tcpiphdr *));
void tcp_xmit_timer _P((register struct tcpcb *, int));
int tcp_mss _P((register struct tcpcb *, u_int));
/* tcp_output.c */
int tcp_output _P((register struct tcpcb *));
void tcp_setpersist _P((register struct tcpcb *));
/* tcp_subr.c */
void tcp_init _P((void));
void tcp_template _P((struct tcpcb *));
void tcp_respond _P((struct tcpcb *, register struct tcpiphdr *, register struct SLIRPmbuf *, tcp_seq, tcp_seq, int));
struct tcpcb * tcp_newtcpcb _P((struct SLIRPsocket *));
struct tcpcb * tcp_close _P((register struct tcpcb *));
void tcp_drain _P((void));
void tcp_sockclosed _P((struct tcpcb *));
int tcp_fconnect _P((struct SLIRPsocket *));
void tcp_connect _P((struct SLIRPsocket *));
int tcp_attach _P((struct SLIRPsocket *));
u_int8_t tcp_tos _P((struct SLIRPsocket *));
int tcp_emu _P((struct SLIRPsocket *, struct SLIRPmbuf *));
int tcp_ctl _P((struct SLIRPsocket *));
struct tcpcb *tcp_drop(struct tcpcb *tp, int err);
#if defined(_MSC_VER)
#pragma pack(pop)
#endif
#ifdef USE_PPP
#define MIN_MRU MINMRU
#define MAX_MRU MAXMRU
#else
#define MIN_MRU 128
#define MAX_MRU 16384
#endif
#ifndef _WIN32
#define min(x,y) ((x) < (y) ? (x) : (y))
#define max(x,y) ((x) > (y) ? (x) : (y))
#endif
#ifdef _WIN32
#undef errno
#define errno (WSAGetLastError())
#endif
#define PROBE_CONN
#endif

View File

@@ -1,135 +0,0 @@
/*
* User definable configuration options
*/
/* Undefine if you don't want talk emulation */
#undef EMULATE_TALK
/* Define if you want the connection to be probed */
/* XXX Not working yet, so ignore this for now */
#undef PROBE_CONN
/* Define to 1 if you want KEEPALIVE timers */
#define DO_KEEPALIVE 0
/* Define to MAX interfaces you expect to use at once */
/* MAX_INTERFACES determines the max. TOTAL number of interfaces (SLIP and PPP) */
/* MAX_PPP_INTERFACES determines max. number of PPP interfaces */
#define MAX_INTERFACES 1
#define MAX_PPP_INTERFACES 1
/* Define if you want slirp's socket in /tmp */
/* XXXXXX Do this in ./configure */
#undef USE_TMPSOCKET
/* Define if you want slirp to use cfsetXspeed() on the terminal */
#undef DO_CFSETSPEED
/* Define this if you want slirp to write to the tty as fast as it can */
/* This should only be set if you are using load-balancing, slirp does a */
/* pretty good job on single modems already, and seting this will make */
/* interactive sessions less responsive */
/* XXXXX Talk about having fast modem as unit 0 */
#undef FULL_BOLT
/*
* Define if you want slirp to use less CPU
* You will notice a small lag in interactive sessions, but it's not that bad
* Things like Netscape/ftp/etc. are completely unaffected
* This is mainly for sysadmins who have many slirp users
*/
#undef USE_LOWCPU
/* Define this if your compiler doesn't like prototypes */
#ifndef __STDC__
#define NO_PROTOTYPES
#endif
/*********************************************************/
/*
* Autoconf defined configuration options
* You shouldn't need to touch any of these
*/
/* Ignore this */
#undef DUMMY_PPP
/* XXX: Define according to how time.h should be included */
#undef TIME_WITH_SYS_TIME
#define TIME_WITH_SYS_TIME 0
#undef HAVE_SYS_TIME_H
/* Define if your sprintf returns char * instead of int */
#undef BAD_SPRINTF
/* Define if you have readv */
#undef HAVE_READV
/* Define if iovec needs to be declared */
#undef DECLARE_IOVEC
#ifdef _WIN32
#define DECLARE_IOVEC
#endif
/* Define if a declaration of sprintf/fprintf is needed */
#undef DECLARE_SPRINTF
/* Define if you have sys/stropts.h */
#undef HAVE_SYS_STROPTS_H
/* Define if your compiler doesn't like prototypes */
#undef NO_PROTOTYPES
/* Define if you don't have u_int32_t etc. typedef'd */
#undef NEED_TYPEDEFS
#ifdef __sun__
#define NEED_TYPEDEFS
#endif
/* Define to sizeof(char *) */
#define SIZEOF_CHAR_P SIZEOF_VOID_P
/* Define if you have random() */
#undef HAVE_RANDOM
/* Define if you have srandom() */
#undef HAVE_SRANDOM
/* Define if you have setenv */
#undef HAVE_SETENV
/* Define if you have index() */
#undef HAVE_INDEX
/* Define if you have bcmp() */
#undef HAVE_BCMP
/* Define if you have drand48 */
#undef HAVE_DRAND48
/* Define if you have memmove */
#define HAVE_MEMMOVE
/* Define if you have gethostid */
#undef HAVE_GETHOSTID
/* Define if you DON'T have unix-domain sockets */
#undef NO_UNIX_SOCKETS
#ifdef _WIN32
#define NO_UNIX_SOCKETS
#endif
/* Define if gettimeofday only takes one argument */
#undef GETTIMEOFDAY_ONE_ARG
/* Define if you have revoke() */
#undef HAVE_REVOKE
/* Define if you have the sysv method of opening pty's (/dev/ptmx, etc.) */
#undef HAVE_GRANTPT
/* Define if you have fchmod */
#undef HAVE_FCHMOD
/* Define if you have <sys/type32.h> */
#undef HAVE_SYS_TYPES32_H

View File

@@ -1,104 +0,0 @@
/*
* Copyright (c) 1995 Danny Gasparovski.
*
* Please read the file COPYRIGHT for the
* terms and conditions of the copyright.
*/
/* MINE */
#ifndef _SLIRP_SOCKET_H_
#define _SLIRP_SOCKET_H_
#define SO_EXPIRE 240000
#define SO_EXPIREFAST 10000
/*
* Our socket structure
*/
struct SLIRPsocket {
struct SLIRPsocket *so_next,*so_prev; /* For a linked list of sockets */
int s; /* The actual socket */
/* XXX union these with not-yet-used sbuf params */
struct SLIRPmbuf *so_m; /* Pointer to the original SYN packet,
* for non-blocking connect()'s, and
* PING reply's */
struct tcpiphdr *so_ti; /* Pointer to the original ti within
* so_mconn, for non-blocking connections */
int so_urgc;
struct in_addr so_faddr; /* foreign host table entry */
struct in_addr so_laddr; /* local host table entry */
u_int16_t so_fport; /* foreign port */
u_int16_t so_lport; /* local port */
u_int8_t so_iptos; /* Type of service */
u_int8_t so_emu; /* Is the socket emulated? */
u_char so_type; /* Type of socket, UDP or TCP */
int so_state; /* internal state flags SS_*, below */
struct tcpcb *so_tcpcb; /* pointer to TCP protocol control block */
u_int so_expire; /* When the socket will expire */
int so_queued; /* Number of packets queued from this socket */
int so_nqueued; /* Number of packets queued in a row
* Used to determine when to "downgrade" a session
* from fastq to batchq */
struct sbuf so_rcv; /* Receive buffer */
struct sbuf so_snd; /* Send buffer */
void * extra; /* Extra pointer */
};
/*
* Socket state bits. (peer means the host on the Internet,
* local host means the host on the other end of the modem)
*/
#define SS_NOFDREF 0x001 /* No fd reference */
#define SS_ISFCONNECTING 0x002 /* Socket is connecting to peer (non-blocking connect()'s) */
#define SS_ISFCONNECTED 0x004 /* Socket is connected to peer */
#define SS_FCANTRCVMORE 0x008 /* Socket can't receive more from peer (for half-closes) */
#define SS_FCANTSENDMORE 0x010 /* Socket can't send more to peer (for half-closes) */
/* #define SS_ISFDISCONNECTED 0x020*/ /* Socket has disconnected from peer, in 2MSL state */
#define SS_FWDRAIN 0x040 /* We received a FIN, drain data and set SS_FCANTSENDMORE */
#define SS_CTL 0x080
#define SS_FACCEPTCONN 0x100 /* Socket is accepting connections from a host on the internet */
#define SS_FACCEPTONCE 0x200 /* If set, the SS_FACCEPTCONN socket will die after one accept */
extern struct SLIRPsocket tcb;
#if defined(DECLARE_IOVEC) && !defined(HAVE_READV)
struct iovec {
char *iov_base;
size_t iov_len;
};
#endif
void so_init _P((void));
struct SLIRPsocket * solookup _P((struct SLIRPsocket *, struct in_addr, u_int, struct in_addr, u_int));
struct SLIRPsocket * socreate _P((void));
void sofree _P((struct SLIRPsocket *));
int soread _P((struct SLIRPsocket *));
void sorecvoob _P((struct SLIRPsocket *));
int sosendoob _P((struct SLIRPsocket *));
int sowrite _P((struct SLIRPsocket *));
void sorecvfrom _P((struct SLIRPsocket *));
int sosendto _P((struct SLIRPsocket *, struct SLIRPmbuf *));
struct SLIRPsocket * solisten _P((u_int, u_int32_t, u_int, int));
void sorwakeup _P((struct SLIRPsocket *));
void sowwakeup _P((struct SLIRPsocket *));
void soisfconnecting _P((register struct SLIRPsocket *));
void soisfconnected _P((register struct SLIRPsocket *));
void sofcantrcvmore _P((struct SLIRPsocket *));
void sofcantsendmore _P((struct SLIRPsocket *));
void soisfdisconnected _P((struct SLIRPsocket *));
void sofwdrain _P((struct SLIRPsocket *));
#endif /* _SOCKET_H_ */

View File

@@ -1,185 +0,0 @@
/*
* Copyright (c) 1982, 1986, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)tcp.h 8.1 (Berkeley) 6/10/93
* tcp.h,v 1.3 1994/08/21 05:27:34 paul Exp
*/
#ifndef _TCP_H_
#define _TCP_H_
#if defined(__amd64__) || defined(__aarch64__)
typedef uintptr_t tcp_seq;
#else
typedef u_int32_t tcp_seq;
#endif
#define PR_SLOWHZ 2 /* 2 slow timeouts per second (approx) */
#define PR_FASTHZ 5 /* 5 fast timeouts per second (not important) */
extern int tcp_rcvspace;
extern int tcp_sndspace;
extern struct SLIRPsocket *tcp_last_so;
#define TCP_SNDSPACE 8192
#define TCP_RCVSPACE 8192
/*
* TCP header.
* Per RFC 793, September, 1981.
*/
#ifdef PRAGMA_PACK_SUPPORTED
#pragma pack(1)
#endif
struct tcphdr {
u_int16_t th_sport; /* source port */
u_int16_t th_dport; /* destination port */
tcp_seq th_seq; /* sequence number */
tcp_seq th_ack; /* acknowledgement number */
#ifdef WORDS_BIGENDIAN
u_char th_off:4, /* data offset */
th_x2:4; /* (unused) */
#else
u_char th_x2:4, /* (unused) */
th_off:4; /* data offset */
#endif
u_int8_t th_flags;
#define TH_FIN 0x01
#define TH_SYN 0x02
#define TH_RST 0x04
#define TH_PUSH 0x08
#define TH_ACK 0x10
#define TH_URG 0x20
u_int16_t th_win; /* window */
u_int16_t th_sum; /* checksum */
u_int16_t th_urp; /* urgent pointer */
} PACKED__;
#ifdef PRAGMA_PACK_SUPPORTED
#pragma pack(PACK_END)
#endif
#include "tcp_var.h"
#define TCPOPT_EOL 0
#define TCPOPT_NOP 1
#define TCPOPT_MAXSEG 2
#define TCPOLEN_MAXSEG 4
#define TCPOPT_WINDOW 3
#define TCPOLEN_WINDOW 3
#define TCPOPT_SACK_PERMITTED 4 /* Experimental */
#define TCPOLEN_SACK_PERMITTED 2
#define TCPOPT_SACK 5 /* Experimental */
#define TCPOPT_TIMESTAMP 8
#define TCPOLEN_TIMESTAMP 10
#define TCPOLEN_TSTAMP_APPA (TCPOLEN_TIMESTAMP+2) /* appendix A */
#define TCPOPT_TSTAMP_HDR \
(TCPOPT_NOP<<24|TCPOPT_NOP<<16|TCPOPT_TIMESTAMP<<8|TCPOLEN_TIMESTAMP)
/*
* Default maximum segment size for TCP.
* With an IP MSS of 576, this is 536,
* but 512 is probably more convenient.
* This should be defined as MIN(512, IP_MSS - sizeof (struct tcpiphdr)).
*
* We make this 1460 because we only care about Ethernet in the qemu context.
*/
#define TCP_MSS 1460
#define TCP_MAXWIN 65535 /* largest value for (unscaled) window */
#define TCP_MAX_WINSHIFT 14 /* maximum window shift */
/*
* User-settable options (used with setsockopt).
*
* We don't use the system headers on unix because we have conflicting
* local structures. We can't avoid the system definitions on Windows,
* so we undefine them.
*/
#undef TCP_NODELAY
#define TCP_NODELAY 0x01 /* don't delay send to coalesce packets */
#undef TCP_MAXSEG
/* #define TCP_MAXSEG 0x02 */ /* set maximum segment size */
/*
* TCP FSM state definitions.
* Per RFC793, September, 1981.
*/
#define TCP_NSTATES 11
#define TCPS_CLOSED 0 /* closed */
#define TCPS_LISTEN 1 /* listening for connection */
#define TCPS_SYN_SENT 2 /* active, have sent syn */
#define TCPS_SYN_RECEIVED 3 /* have send and received syn */
/* states < TCPS_ESTABLISHED are those where connections not established */
#define TCPS_ESTABLISHED 4 /* established */
#define TCPS_CLOSE_WAIT 5 /* rcvd fin, waiting for close */
/* states > TCPS_CLOSE_WAIT are those where user has closed */
#define TCPS_FIN_WAIT_1 6 /* have closed, sent fin */
#define TCPS_CLOSING 7 /* closed xchd FIN; await FIN ACK */
#define TCPS_LAST_ACK 8 /* had fin and close; await FIN ACK */
/* states > TCPS_CLOSE_WAIT && < TCPS_FIN_WAIT_2 await ACK of FIN */
#define TCPS_FIN_WAIT_2 9 /* have closed, fin is acked */
#define TCPS_TIME_WAIT 10 /* in 2*msl quiet wait after close */
#define TCPS_HAVERCVDSYN(s) ((s) >= TCPS_SYN_RECEIVED)
#define TCPS_HAVEESTABLISHED(s) ((s) >= TCPS_ESTABLISHED)
#define TCPS_HAVERCVDFIN(s) ((s) >= TCPS_TIME_WAIT)
/*
* TCP sequence numbers are 32 bit integers operated
* on with modular arithmetic. These macros can be
* used to compare such integers.
*/
#define SEQ_LT(a,b) ((int)((a)-(b)) < 0)
#define SEQ_LEQ(a,b) ((int)((a)-(b)) <= 0)
#define SEQ_GT(a,b) ((int)((a)-(b)) > 0)
#define SEQ_GEQ(a,b) ((int)((a)-(b)) >= 0)
/*
* Macros to initialize tcp sequence numbers for
* send and receive from initial send and receive
* sequence numbers.
*/
#define tcp_rcvseqinit(tp) \
(tp)->rcv_adv = (tp)->rcv_nxt = (tp)->irs + 1
#define tcp_sendseqinit(tp) \
(tp)->snd_una = (tp)->snd_nxt = (tp)->snd_max = (tp)->snd_up = (tp)->iss
#define TCP_ISSINCR (125*1024) /* increment for tcp_iss each second */
extern tcp_seq tcp_iss; /* tcp initial send seq # */
extern char *tcpstates[];
#endif

View File

@@ -1,138 +0,0 @@
/*
* Copyright (c) 1982, 1986, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)tcp_timer.h 8.1 (Berkeley) 6/10/93
* tcp_timer.h,v 1.4 1994/08/21 05:27:38 paul Exp
*/
#ifndef _TCP_TIMER_H_
#define _TCP_TIMER_H_
/*
* Definitions of the TCP timers. These timers are counted
* down PR_SLOWHZ times a second.
*/
#define TCPT_NTIMERS 4
#define TCPT_REXMT 0 /* retransmit */
#define TCPT_PERSIST 1 /* retransmit persistence */
#define TCPT_KEEP 2 /* keep alive */
#define TCPT_2MSL 3 /* 2*msl quiet time timer */
/*
* The TCPT_REXMT timer is used to force retransmissions.
* The TCP has the TCPT_REXMT timer set whenever segments
* have been sent for which ACKs are expected but not yet
* received. If an ACK is received which advances tp->snd_una,
* then the retransmit timer is cleared (if there are no more
* outstanding segments) or reset to the base value (if there
* are more ACKs expected). Whenever the retransmit timer goes off,
* we retransmit one unacknowledged segment, and do a backoff
* on the retransmit timer.
*
* The TCPT_PERSIST timer is used to keep window size information
* flowing even if the window goes shut. If all previous transmissions
* have been acknowledged (so that there are no retransmissions in progress),
* and the window is too small to bother sending anything, then we start
* the TCPT_PERSIST timer. When it expires, if the window is nonzero,
* we go to transmit state. Otherwise, at intervals send a single byte
* into the peer's window to force him to update our window information.
* We do this at most as often as TCPT_PERSMIN time intervals,
* but no more frequently than the current estimate of round-trip
* packet time. The TCPT_PERSIST timer is cleared whenever we receive
* a window update from the peer.
*
* The TCPT_KEEP timer is used to keep connections alive. If an
* connection is idle (no segments received) for TCPTV_KEEP_INIT amount of time,
* but not yet established, then we drop the connection. Once the connection
* is established, if the connection is idle for TCPTV_KEEP_IDLE time
* (and keepalives have been enabled on the socket), we begin to probe
* the connection. We force the peer to send us a segment by sending:
* <SEQ=SND.UNA-1><ACK=RCV.NXT><CTL=ACK>
* This segment is (deliberately) outside the window, and should elicit
* an ack segment in response from the peer. If, despite the TCPT_KEEP
* initiated segments we cannot elicit a response from a peer in TCPT_MAXIDLE
* amount of time probing, then we drop the connection.
*/
/*
* Time constants.
*/
#define TCPTV_MSL ( 5*PR_SLOWHZ) /* max seg lifetime (hah!) */
#define TCPTV_SRTTBASE 0 /* base roundtrip time;
if 0, no idea yet */
#define TCPTV_SRTTDFLT ( 3*PR_SLOWHZ) /* assumed RTT if no info */
#define TCPTV_PERSMIN ( 5*PR_SLOWHZ) /* retransmit persistence */
#define TCPTV_PERSMAX ( 60*PR_SLOWHZ) /* maximum persist interval */
#define TCPTV_KEEP_INIT ( 75*PR_SLOWHZ) /* initial connect keep alive */
#define TCPTV_KEEP_IDLE (120*60*PR_SLOWHZ) /* dflt time before probing */
#define TCPTV_KEEPINTVL ( 75*PR_SLOWHZ) /* default probe interval */
#define TCPTV_KEEPCNT 8 /* max probes before drop */
#define TCPTV_MIN ( 1*PR_SLOWHZ) /* minimum allowable value */
/* #define TCPTV_REXMTMAX ( 64*PR_SLOWHZ) */ /* max allowable REXMT value */
#define TCPTV_REXMTMAX ( 12*PR_SLOWHZ) /* max allowable REXMT value */
#define TCP_LINGERTIME 120 /* linger at most 2 minutes */
#define TCP_MAXRXTSHIFT 12 /* maximum retransmits */
#ifdef TCPTIMERS
char *tcptimers[] =
{ "REXMT", "PERSIST", "KEEP", "2MSL" };
#endif
/*
* Force a time value to be in a certain range.
*/
#define TCPT_RANGESET(tv, value, tvmin, tvmax) { \
(tv) = (value); \
if ((tv) < (tvmin)) \
(tv) = (tvmin); \
else if ((tv) > (tvmax)) \
(tv) = (tvmax); \
}
extern int tcp_keepidle; /* time before keepalive probes begin */
extern int tcp_keepintvl; /* time between keepalive probes */
extern int tcp_maxidle; /* time to drop after starting probes */
extern int tcp_ttl; /* time to live for TCP segs */
extern int tcp_backoff[];
struct tcpcb;
void tcp_fasttimo _P((void));
void tcp_slowtimo _P((void));
void tcp_canceltimers _P((struct tcpcb *));
struct tcpcb * tcp_timers _P((register struct tcpcb *, int));
#endif

View File

@@ -1,256 +0,0 @@
/*
* Copyright (c) 1982, 1986, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)tcp_var.h 8.3 (Berkeley) 4/10/94
* tcp_var.h,v 1.3 1994/08/21 05:27:39 paul Exp
*/
#ifndef _TCP_VAR_H_
#define _TCP_VAR_H_
#include "tcpip.h"
#include "tcp_timer.h"
#if defined(__amd64__) || defined(__aarch64__)
typedef uintptr_t tcpiphdrp_32;
#else
#if SIZEOF_CHAR_P == 4
typedef struct tcpiphdr *tcpiphdrp_32;
#else
typedef u_int32_t tcpiphdrp_32;
#endif
#endif
/*
* Tcp control block, one per tcp; fields:
*/
struct tcpcb {
tcpiphdrp_32 seg_next; /* sequencing queue */
tcpiphdrp_32 seg_prev;
short t_state; /* state of this connection */
short t_timer[TCPT_NTIMERS]; /* tcp timers */
short t_rxtshift; /* log(2) of rexmt exp. backoff */
short t_rxtcur; /* current retransmit value */
short t_dupacks; /* consecutive dup acks recd */
u_short t_maxseg; /* maximum segment size */
char t_force; /* 1 if forcing out a byte */
u_short t_flags;
#define TF_ACKNOW 0x0001 /* ack peer immediately */
#define TF_DELACK 0x0002 /* ack, but try to delay it */
#define TF_NODELAY 0x0004 /* don't delay packets to coalesce */
#define TF_NOOPT 0x0008 /* don't use tcp options */
#define TF_SENTFIN 0x0010 /* have sent FIN */
#define TF_REQ_SCALE 0x0020 /* have/will request window scaling */
#define TF_RCVD_SCALE 0x0040 /* other side has requested scaling */
#define TF_REQ_TSTMP 0x0080 /* have/will request timestamps */
#define TF_RCVD_TSTMP 0x0100 /* a timestamp was received in SYN */
#define TF_SACK_PERMIT 0x0200 /* other side said I could SACK */
/* Make it static for now */
/* struct tcpiphdr *t_template; / * skeletal packet for transmit */
struct tcpiphdr t_template;
struct SLIRPsocket *t_socket; /* back pointer to socket */
/*
* The following fields are used as in the protocol specification.
* See RFC783, Dec. 1981, page 21.
*/
/* send sequence variables */
tcp_seq snd_una; /* send unacknowledged */
tcp_seq snd_nxt; /* send next */
tcp_seq snd_up; /* send urgent pointer */
tcp_seq snd_wl1; /* window update seg seq number */
tcp_seq snd_wl2; /* window update seg ack number */
tcp_seq iss; /* initial send sequence number */
u_int32_t snd_wnd; /* send window */
/* receive sequence variables */
u_int32_t rcv_wnd; /* receive window */
tcp_seq rcv_nxt; /* receive next */
tcp_seq rcv_up; /* receive urgent pointer */
tcp_seq irs; /* initial receive sequence number */
/*
* Additional variables for this implementation.
*/
/* receive variables */
tcp_seq rcv_adv; /* advertised window */
/* retransmit variables */
tcp_seq snd_max; /* highest sequence number sent;
* used to recognize retransmits
*/
/* congestion control (for slow start, source quench, retransmit after loss) */
u_int32_t snd_cwnd; /* congestion-controlled window */
u_int32_t snd_ssthresh; /* snd_cwnd size threshold for
* for slow start exponential to
* linear switch
*/
/*
* transmit timing stuff. See below for scale of srtt and rttvar.
* "Variance" is actually smoothed difference.
*/
short t_idle; /* inactivity time */
short t_rtt; /* round trip time */
tcp_seq t_rtseq; /* sequence number being timed */
short t_srtt; /* smoothed round-trip time */
short t_rttvar; /* variance in round-trip time */
u_short t_rttmin; /* minimum rtt allowed */
u_int32_t max_sndwnd; /* largest window peer has offered */
/* out-of-band data */
char t_oobflags; /* have some */
char t_iobc; /* input character */
#define TCPOOB_HAVEDATA 0x01
#define TCPOOB_HADDATA 0x02
short t_softerror; /* possible error not yet reported */
/* RFC 1323 variables */
u_char snd_scale; /* window scaling for send window */
u_char rcv_scale; /* window scaling for recv window */
u_char request_r_scale; /* pending window scaling */
u_char requested_s_scale;
u_int32_t ts_recent; /* timestamp echo data */
u_int32_t ts_recent_age; /* when last updated */
tcp_seq last_ack_sent;
};
#define sototcpcb(so) ((so)->so_tcpcb)
/*
* The smoothed round-trip time and estimated variance
* are stored as fixed point numbers scaled by the values below.
* For convenience, these scales are also used in smoothing the average
* (smoothed = (1/scale)sample + ((scale-1)/scale)smoothed).
* With these scales, srtt has 3 bits to the right of the binary point,
* and thus an "ALPHA" of 0.875. rttvar has 2 bits to the right of the
* binary point, and is smoothed with an ALPHA of 0.75.
*/
#define TCP_RTT_SCALE 8 /* multiplier for srtt; 3 bits frac. */
#define TCP_RTT_SHIFT 3 /* shift for srtt; 3 bits frac. */
#define TCP_RTTVAR_SCALE 4 /* multiplier for rttvar; 2 bits */
#define TCP_RTTVAR_SHIFT 2 /* multiplier for rttvar; 2 bits */
/*
* The initial retransmission should happen at rtt + 4 * rttvar.
* Because of the way we do the smoothing, srtt and rttvar
* will each average +1/2 tick of bias. When we compute
* the retransmit timer, we want 1/2 tick of rounding and
* 1 extra tick because of +-1/2 tick uncertainty in the
* firing of the timer. The bias will give us exactly the
* 1.5 tick we need. But, because the bias is
* statistical, we have to test that we don't drop below
* the minimum feasible timer (which is 2 ticks).
* This macro assumes that the value of TCP_RTTVAR_SCALE
* is the same as the multiplier for rttvar.
*/
#define TCP_REXMTVAL(tp) \
(((tp)->t_srtt >> TCP_RTT_SHIFT) + (tp)->t_rttvar)
/* XXX
* We want to avoid doing m_pullup on incoming packets but that
* means avoiding dtom on the tcp reassembly code. That in turn means
* keeping an mbuf pointer in the reassembly queue (since we might
* have a cluster). As a quick hack, the source & destination
* port numbers (which are no longer needed once we've located the
* tcpcb) are overlayed with an mbuf pointer.
*/
#if defined(__amd64__) || defined(__aarch64__)
typedef uintptr_t mbufp_32;
#else
#if SIZEOF_CHAR_P == 4
typedef struct SLIRPmbuf *mbufp_32;
#else
typedef u_int32_t mbufp_32;
#endif
#endif
#define REASS_MBUF(ti) (*(mbufp_32 *)&((ti)->ti_t))
/*
* TCP statistics.
* Many of these should be kept per connection,
* but that's inconvenient at the moment.
*/
struct tcpstat {
u_long tcps_connattempt; /* connections initiated */
u_long tcps_accepts; /* connections accepted */
u_long tcps_connects; /* connections established */
u_long tcps_drops; /* connections dropped */
u_long tcps_conndrops; /* embryonic connections dropped */
u_long tcps_closed; /* conn. closed (includes drops) */
u_long tcps_segstimed; /* segs where we tried to get rtt */
u_long tcps_rttupdated; /* times we succeeded */
u_long tcps_delack; /* delayed acks sent */
u_long tcps_timeoutdrop; /* conn. dropped in rxmt timeout */
u_long tcps_rexmttimeo; /* retransmit timeouts */
u_long tcps_persisttimeo; /* persist timeouts */
u_long tcps_keeptimeo; /* keepalive timeouts */
u_long tcps_keepprobe; /* keepalive probes sent */
u_long tcps_keepdrops; /* connections dropped in keepalive */
u_long tcps_sndtotal; /* total packets sent */
u_long tcps_sndpack; /* data packets sent */
u_long tcps_sndbyte; /* data bytes sent */
u_long tcps_sndrexmitpack; /* data packets retransmitted */
u_long tcps_sndrexmitbyte; /* data bytes retransmitted */
u_long tcps_sndacks; /* ack-only packets sent */
u_long tcps_sndprobe; /* window probes sent */
u_long tcps_sndurg; /* packets sent with URG only */
u_long tcps_sndwinup; /* window update-only packets sent */
u_long tcps_sndctrl; /* control (SYN|FIN|RST) packets sent */
u_long tcps_rcvtotal; /* total packets received */
u_long tcps_rcvpack; /* packets received in sequence */
u_long tcps_rcvbyte; /* bytes received in sequence */
u_long tcps_rcvbadsum; /* packets received with ccksum errs */
u_long tcps_rcvbadoff; /* packets received with bad offset */
/* u_long tcps_rcvshort; */ /* packets received too short */
u_long tcps_rcvduppack; /* duplicate-only packets received */
u_long tcps_rcvdupbyte; /* duplicate-only bytes received */
u_long tcps_rcvpartduppack; /* packets with some duplicate data */
u_long tcps_rcvpartdupbyte; /* dup. bytes in part-dup. packets */
u_long tcps_rcvoopack; /* out-of-order packets received */
u_long tcps_rcvoobyte; /* out-of-order bytes received */
u_long tcps_rcvpackafterwin; /* packets with data after window */
u_long tcps_rcvbyteafterwin; /* bytes rcvd after window */
u_long tcps_rcvafterclose; /* packets rcvd after "close" */
u_long tcps_rcvwinprobe; /* rcvd window probe packets */
u_long tcps_rcvdupack; /* rcvd duplicate acks */
u_long tcps_rcvacktoomuch; /* rcvd acks for unsent data */
u_long tcps_rcvackpack; /* rcvd ack packets */
u_long tcps_rcvackbyte; /* bytes acked by rcvd acks */
u_long tcps_rcvwinupd; /* rcvd window update packets */
/* u_long tcps_pawsdrop; */ /* segments dropped due to PAWS */
u_long tcps_predack; /* times hdr predict ok for acks */
u_long tcps_preddat; /* times hdr predict ok for data pkts */
u_long tcps_socachemiss; /* tcp_last_so misses */
u_long tcps_didnuttin; /* Times tcp_output didn't do anything XXX */
};
extern struct tcpstat tcpstat; /* tcp statistics */
extern u_int32_t tcp_now; /* for RFC 1323 timestamps */
#endif

View File

@@ -1,70 +0,0 @@
/*
* Copyright (c) 1982, 1986, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)tcpip.h 8.1 (Berkeley) 6/10/93
* tcpip.h,v 1.3 1994/08/21 05:27:40 paul Exp
*/
#ifndef _TCPIP_H_
#define _TCPIP_H_
/*
* Tcp+ip header, after ip options removed.
*/
struct tcpiphdr {
struct ipovly ti_i; /* overlaid ip structure */
struct tcphdr ti_t; /* tcp header */
};
#define ti_next ti_i.ih_next
#define ti_prev ti_i.ih_prev
#define ti_x1 ti_i.ih_x1
#define ti_pr ti_i.ih_pr
#define ti_len ti_i.ih_len
#define ti_src ti_i.ih_src
#define ti_dst ti_i.ih_dst
#define ti_sport ti_t.th_sport
#define ti_dport ti_t.th_dport
#define ti_seq ti_t.th_seq
#define ti_ack ti_t.th_ack
#define ti_x2 ti_t.th_x2
#define ti_off ti_t.th_off
#define ti_flags ti_t.th_flags
#define ti_win ti_t.th_win
#define ti_sum ti_t.th_sum
#define ti_urp ti_t.th_urp
/*
* Just a clean way to get to the first byte
* of the packet
*/
struct tcpiphdr_2 {
struct tcpiphdr dummy;
char first_char;
};
#endif

View File

@@ -1,40 +0,0 @@
/* tftp defines */
#define TFTP_SESSIONS_MAX 3
#define TFTP_SERVER 69
#define TFTP_RRQ 1
#define TFTP_WRQ 2
#define TFTP_DATA 3
#define TFTP_ACK 4
#define TFTP_ERROR 5
#define TFTP_FILENAME_MAX 512
#ifdef PRAGMA_PACK_SUPPORTED
#pragma pack(1)
#endif
struct tftp_t {
struct ip ip;
struct udphdr udp;
u_int16_t tp_op;
union {
struct {
u_int16_t tp_block_nr;
u_int8_t tp_buf[512];
} tp_data;
struct {
u_int16_t tp_error_code;
u_int8_t tp_msg[512];
} tp_error;
u_int8_t tp_buf[512 + 2];
} x;
} PACKED__;
#ifdef PRAGMA_PACK_SUPPORTED
#pragma pack(PACK_END)
#endif
void tftp_input(struct SLIRPmbuf *m);

View File

@@ -1,114 +0,0 @@
/*
* Copyright (c) 1982, 1986, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)udp.h 8.1 (Berkeley) 6/10/93
* udp.h,v 1.3 1994/08/21 05:27:41 paul Exp
*/
#ifndef _UDP_H_
#define _UDP_H_
#define UDP_TTL 0x60
#define UDP_UDPDATALEN 16192
extern struct SLIRPsocket *udp_last_so;
/*
* Udp protocol header.
* Per RFC 768, September, 1981.
*/
#ifdef PRAGMA_PACK_SUPPORTED
#pragma pack(1)
#endif
struct udphdr {
u_int16_t uh_sport; /* source port */
u_int16_t uh_dport; /* destination port */
int16_t uh_ulen; /* udp length */
u_int16_t uh_sum; /* udp checksum */
} PACKED__;
#ifdef PRAGMA_PACK_SUPPORTED
#pragma pack(PACK_END)
#endif
/*
* UDP kernel structures and variables.
*/
struct udpiphdr {
struct ipovly ui_i; /* overlaid ip structure */
struct udphdr ui_u; /* udp header */
};
#define ui_next ui_i.ih_next
#define ui_prev ui_i.ih_prev
#define ui_x1 ui_i.ih_x1
#define ui_pr ui_i.ih_pr
#define ui_len ui_i.ih_len
#define ui_src ui_i.ih_src
#define ui_dst ui_i.ih_dst
#define ui_sport ui_u.uh_sport
#define ui_dport ui_u.uh_dport
#define ui_ulen ui_u.uh_ulen
#define ui_sum ui_u.uh_sum
struct udpstat {
/* input statistics: */
u_long udps_ipackets; /* total input packets */
u_long udps_hdrops; /* packet shorter than header */
u_long udps_badsum; /* checksum error */
u_long udps_badlen; /* data length larger than packet */
u_long udps_noport; /* no socket on port */
u_long udps_noportbcast; /* of above, arrived as broadcast */
u_long udps_fullsock; /* not delivered, input socket full */
u_long udpps_pcbcachemiss; /* input packets missing pcb cache */
/* output statistics: */
u_long udps_opackets; /* total output packets */
};
/*
* Names for UDP sysctl objects
*/
#define UDPCTL_CHECKSUM 1 /* checksum UDP packets */
#define UDPCTL_MAXID 2
extern struct udpstat udpstat;
extern struct SLIRPsocket udb;
struct SLIRPmbuf;
void udp_init _P((void));
void udp_input _P((register struct SLIRPmbuf *, int));
int udp_output _P((struct SLIRPsocket *, struct SLIRPmbuf *, struct sockaddr_in *));
int udp_attach _P((struct SLIRPsocket *));
void udp_detach _P((struct SLIRPsocket *));
u_int8_t udp_tos _P((struct SLIRPsocket *));
void udp_emu _P((struct SLIRPsocket *, struct SLIRPmbuf *));
struct SLIRPsocket * udp_listen _P((u_int, u_int32_t, u_int, int));
int udp_output2(struct SLIRPsocket *so, struct SLIRPmbuf *m,
struct sockaddr_in *saddr, struct sockaddr_in *daddr,
int iptos);
#endif

260
src/include/tinyglib.h Normal file
View File

@@ -0,0 +1,260 @@
/*
* 86Box A hypervisor and IBM PC system emulator that specializes in
* running old operating systems and software designed for IBM
* PC systems and compatibles from 1981 through fairly recent
* system designs based on the PCI bus.
*
* This file is part of the 86Box distribution.
*
* Minimal reimplementation of GLib for libslirp.
*
*
*
* Author: RichardG, <richardg867@gmail.com>
*
* Copyright 2020 RichardG.
*/
#ifndef TINYGLIB_H
# define TINYGLIB_H
/* Define this to bypass TinyGLib and use full GLib instead. */
#ifdef TINYGLIB_USE_GLIB
#include <glib.h>
#else
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define HAVE_STDARG_H
#include <86box/86box.h>
/* Definitions */
#define G_LITTLE_ENDIAN 1234
#define G_BIG_ENDIAN 4321
#define G_PDP_ENDIAN 3412
#ifdef __BYTE_ORDER__
# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
# define G_BYTE_ORDER G_LITTLE_ENDIAN
# elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
# define G_BYTE_ORDER G_BIG_ENDIAN
# elif __BYTE_ORDER__ == __ORDER_PDP_ENDIAN__
# define G_BYTE_ORDER G_PDP_ENDIAN
# endif
#endif
#if !defined(G_BYTE_ORDER)
/* Safe to assume LE for MSVC, as Windows is LE on all architectures. */
# define G_BYTE_ORDER G_LITTLE_ENDIAN
#endif
#ifdef _WIN32
# define G_OS_WIN32 1
#else
# define G_OS_UNIX 1
#endif
#define G_SPAWN_SEARCH_PATH 0
#if defined(__LP64__) || defined(__LLP64__)
# define GLIB_SIZEOF_VOID_P 8
#else
# define GLIB_SIZEOF_VOID_P 4
#endif
#ifdef __LP64__
# define GLIB_SIZEOF_LONG 8
# define GLIB_SIZEOF_SIZE_T 8
# define GLIB_SIZEOF_SSIZE_T 8
#else
# define GLIB_SIZEOF_LONG 4
# define GLIB_SIZEOF_SIZE_T 4
# define GLIB_SIZEOF_SSIZE_T 4
#endif
/* Types */
#define gboolean int
#define gchar char
#define gint int
#define gint16 int16_t
#define gint32 int32_t
#define gint64 int64_t
#define glong long
#define GPid void *
#define gpointer void *
#define gsize size_t
#define GSpawnFlags void *
#define GSpawnChildSetupFunc void *
#define gssize ssize_t
#define GString char
#define GStrv char **
#define guint unsigned int
#define guint16 uint16_t
#define guint32 uint32_t
#define guint64 uint64_t
typedef struct _GDebugKey {
char key[32];
int val;
} GDebugKey;
typedef struct _GError {
char message[1];
} GError;
typedef struct _GRand {
uint8_t dummy;
} GRand;
/* Functions */
/* Inlining everything is not the best idea, but it keeps TinyGLib
contained to this header file without producing compiler warnings. */
/* Must be a function, as libslirp redefines it as a macro. */
inline gboolean
g_spawn_async_with_fds(const gchar *working_directory, gchar **argv,
gchar **envp, GSpawnFlags flags,
GSpawnChildSetupFunc child_setup,
gpointer user_data, GPid *child_pid, gint stdin_fd,
gint stdout_fd, gint stderr_fd, GError **error)
{
return 0;
}
/* Needs bounds checking, but not really used by libslirp. */
inline GString *
g_string_new(gchar *base)
{
char *ret = malloc(4096);
if (base)
strcpy(ret, base);
return ret;
}
inline gchar *
g_string_free(GString *string, gboolean free_segment)
{
return (free_segment ? NULL : string);
}
/* Implementation borrowed from GLib itself. */
inline gchar *
g_strstr_len(const gchar *haystack, gssize haystack_len, const gchar *needle)
{
if (haystack_len < 0)
return strstr(haystack, needle);
else {
const gchar *p = haystack;
gsize needle_len = strlen(needle);
gsize haystack_len_unsigned = haystack_len;
const gchar *end;
gsize i;
if (needle_len == 0)
return (gchar *) haystack;
if (haystack_len_unsigned < needle_len)
return NULL;
end = haystack + haystack_len - needle_len;
while (p <= end && *p) {
for (i = 0; i < needle_len; i++)
if (p[i] != needle[i])
goto next;
return (gchar *)p;
next:
p++;
}
return NULL;
}
}
/* Implementation borrowed from GLib itself. */
inline guint
g_strv_length(gchar **str_array)
{
guint i = 0;
while (str_array[i] != NULL)
++i;
return i;
}
/* Macros */
#define tinyglib_pclog(f, s, ...) pclog("TinyGLib " f "(): " s "\n", ##__VA_ARGS__)
#define GLIB_CHECK_VERSION(a, b, c) 1
#ifdef __GNUC__
# define G_GNUC_PRINTF(format_idx, arg_idx) __attribute__((__format__ (__printf__, format_idx, arg_idx)))
#else
# define G_GNUC_PRINTF(format_idx, arg_idx)
#endif
#define G_N_ELEMENTS(arr) (sizeof(arr) / sizeof((arr)[0]))
#define G_STATIC_ASSERT(e) /* this should probably do something */
#define G_UNLIKELY(e) (e)
#define g_assert(e) do { if (!(e)) fatal("TinyGLib g_assert(" #e ")\n"); } while (0)
#ifdef __GNUC__
# define g_assert_not_reached __builtin_unreachable
#else
# ifdef _MSC_VER
# define g_assert_not_reached() __assume(0)
# else
# define g_assert_not_reached()
# endif
#endif
#define g_critical(s, ...) fatal("TinyGLib g_critical(): " s "\n", ##__VA_ARGS__)
#ifdef TINYGLIB_DEBUG
# define g_debug(s, ...) tinyglib_pclog("g_debug", s, ##__VA_ARGS__)
#else
# define g_debug(s, ...)
#endif
#define g_error(s, ...) tinyglib_pclog("g_error", s, ##__VA_ARGS__)
#define g_error_free(err)
#define g_malloc0(s) calloc(1, s)
#define g_new(t, n) (t *) malloc(sizeof(t) * n)
#define g_new0(t, n) (t *) calloc(n, sizeof(t))
#ifdef TINYGLIB_DEBUG
# define g_parse_debug_string(s, k, n) ((!!sizeof(k)) * -1) /* unimplemented; always enables all debug flags */
#else
# define g_parse_debug_string(s, k, n) (!sizeof(k))
#endif
#define g_rand_int_range(r, min, max) (rand() % (max + 1 - min) + min)
#define g_rand_new() calloc(1, sizeof(GRand))
#define g_return_val_if_fail(e, v) if (!(e)) return (v)
#define g_shell_parse_argv(a, b, c, d) !!(sizeof(b)) /* unimplemented */
#define g_warn_if_fail(e) do { if (!(e)) pclog("TinyGLib g_warn_if_fail(" #e ")\n"); } while (0)
#define g_warn_if_reached() pclog("TinyGLib g_warn_if_reached()\n")
#define g_warning(s, ...) tinyglib_pclog("g_warning", s, ##__VA_ARGS__)
/* Remapped functions */
#define g_free free
#define g_getenv getenv
#define g_malloc malloc
#define g_rand_free free
#define g_realloc realloc
#define g_snprintf snprintf
#define g_strdup strdup
#define g_strerror strerror
#define g_strfreev free
#define g_string_append_printf sprintf /* unimplemented */
#define g_vsnprintf vsnprintf
#endif
#endif

View File

@@ -1,48 +1,23 @@
/* /*
* VARCem Virtual ARchaeological Computer EMulator. * 86Box A hypervisor and IBM PC system emulator that specializes in
* An emulator of (mostly) x86-based PC systems and devices, * running old operating systems and software designed for IBM
* using the ISA,EISA,VLB,MCA and PCI system buses, roughly * PC systems and compatibles from 1981 through fairly recent
* spanning the era between 1981 and 1995. * system designs based on the PCI bus.
* *
* This file is part of the VARCem Project. * This file is part of the 86Box distribution.
* *
* Handle SLiRP library processing. * Handle SLiRP library processing.
* *
* Some of the code was borrowed from libvdeslirp
* <https://github.com/virtualsquare/libvdeslirp>
* *
* *
* Author: Fred N. van Kempen, <decwiz@yahoo.com> *
* Authors: Fred N. van Kempen, <decwiz@yahoo.com>
* RichardG, <richardg867@gmail.com>
* *
* Copyright 2017-2019 Fred N. van Kempen. * Copyright 2017-2019 Fred N. van Kempen.
* * Copyright 2020 RichardG.
* Redistribution and use in source and binary forms, with
* or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the entire
* above notice, this list of conditions and the following
* disclaimer.
*
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names
* of its contributors may be used to endorse or promote
* products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include <stdarg.h> #include <stdarg.h>
#include <stdint.h> #include <stdint.h>
@@ -50,19 +25,49 @@
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <wchar.h> #include <wchar.h>
#include <slirp/libslirp.h>
#define HAVE_STDARG_H #define HAVE_STDARG_H
#include <slirp/slirp.h>
#include <slirp/queue.h>
#include <86box/86box.h> #include <86box/86box.h>
#include <86box/device.h> #include <86box/device.h>
#include <86box/plat.h> #include <86box/plat.h>
#include <86box/network.h> #include <86box/network.h>
#include <86box/machine.h>
#include <86box/timer.h>
#include <86box/config.h>
static volatile queueADT slirpq; /* SLiRP library handle */ /* SLiRP can use poll() or select() for socket polling. While poll() is
static volatile thread_t *poll_tid; better, it's slow and limited on Windows, so use select() there. */
static const netcard_t *poll_card; /* netcard attached to us */ #ifndef _WIN32
static event_t *poll_state; # define SLIRP_USE_POLL 1
#endif
#ifdef SLIRP_USE_POLL
# ifdef _WIN32
# include <winsock2.h>
# define poll WSAPoll
# else
# include <poll.h>
# endif
#endif
typedef struct {
Slirp *slirp;
void *mac;
const netcard_t *card; /* netcard attached to us */
volatile thread_t *poll_tid;
event_t *poll_state;
uint8_t stop;
#ifdef SLIRP_USE_POLL
uint32_t pfd_len, pfd_size;
struct pollfd *pfd;
#else
uint32_t nfds;
fd_set rfds, wfds, xfds;
#endif
} slirp_t;
static slirp_t *slirp;
#ifdef ENABLE_SLIRP_LOG #ifdef ENABLE_SLIRP_LOG
@@ -86,98 +91,290 @@ slirp_log(const char *fmt, ...)
static void static void
slirp_tic(void) net_slirp_guest_error(const char *msg, void *opaque)
{ {
int ret2, nfds; slirp_log("SLiRP: guest_error: %s\n", msg);
struct timeval tv; }
fd_set rfds, wfds, xfds;
int tmo;
static int64_t
net_slirp_clock_get_ns(void *opaque)
{
return (TIMER_USEC ? (tsc / (TIMER_USEC / 1000)) : 0);
}
static void *
net_slirp_timer_new(SlirpTimerCb cb, void *cb_opaque, void *opaque)
{
pc_timer_t *timer = malloc(sizeof(pc_timer_t));
timer_add(timer, cb, cb_opaque, 0);
return timer;
}
static void
net_slirp_timer_free(void *timer, void *opaque)
{
timer_stop(timer);
}
static void
net_slirp_timer_mod(void *timer, int64_t expire_timer, void *opaque)
{
timer_set_delay_u64(timer, expire_timer);
}
static void
net_slirp_register_poll_fd(int fd, void *opaque)
{
(void) fd;
(void) opaque;
}
static void
net_slirp_unregister_poll_fd(int fd, void *opaque)
{
(void) fd;
(void) opaque;
}
static void
net_slirp_notify(void *opaque)
{
(void) opaque;
}
int
net_slirp_send_packet(const void *qp, size_t pkt_len, void *opaque)
{
slirp_t *slirp = (slirp_t *) opaque;
uint8_t *mac = slirp->mac;
uint32_t mac_cmp32[2];
uint16_t mac_cmp16[2];
if (!(slirp->card->set_link_state && slirp->card->set_link_state(slirp->card->priv)) && !(slirp->card->wait && slirp->card->wait(slirp->card->priv))) {
slirp_log("SLiRP: received %d-byte packet\n", pkt_len);
/* Received MAC. */
mac_cmp32[0] = *(uint32_t *) (((uint8_t *) qp) + 6);
mac_cmp16[0] = *(uint16_t *) (((uint8_t *) qp) + 10);
/* Local MAC. */
mac_cmp32[1] = *(uint32_t *) mac;
mac_cmp16[1] = *(uint16_t *) (mac + 4);
if ((mac_cmp32[0] != mac_cmp32[1]) ||
(mac_cmp16[0] != mac_cmp16[1])) {
network_queue_put(0, slirp->card->priv, (uint8_t *) qp, pkt_len);
}
return pkt_len;
} else {
slirp_log("SLiRP: ignored %d-byte packet\n", pkt_len);
}
return 0;
}
static int
net_slirp_add_poll(int fd, int events, void *opaque)
{
slirp_t *slirp = (slirp_t *) opaque;
#ifdef SLIRP_USE_POLL
if (slirp->pfd_len >= slirp->pfd_size) {
int newsize = slirp->pfd_size + 16;
struct pollfd *new = realloc(slirp->pfd, newsize * sizeof(struct pollfd));
if (new) {
slirp->pfd = new;
slirp->pfd_size = newsize;
}
}
if ((slirp->pfd_len < slirp->pfd_size)) {
int idx = slirp->pfd_len++;
slirp->pfd[idx].fd = fd;
int pevents = 0;
if (events & SLIRP_POLL_IN) pevents |= POLLIN;
if (events & SLIRP_POLL_OUT) pevents |= POLLOUT;
# ifndef _WIN32
/* Windows does not support some events. */
if (events & SLIRP_POLL_ERR) pevents |= POLLERR;
if (events & SLIRP_POLL_PRI) pevents |= POLLPRI;
if (events & SLIRP_POLL_HUP) pevents |= POLLHUP;
# endif
slirp->pfd[idx].events = pevents;
return idx;
} else
return -1;
#else
if (events & SLIRP_POLL_IN)
FD_SET(fd, &slirp->rfds);
if (events & SLIRP_POLL_OUT)
FD_SET(fd, &slirp->wfds);
if (events & SLIRP_POLL_PRI)
FD_SET(fd, &slirp->xfds);
if (fd > slirp->nfds)
slirp->nfds = fd;
return fd;
#endif
}
static int
net_slirp_get_revents(int idx, void *opaque)
{
slirp_t *slirp = (slirp_t *) opaque;
int ret = 0;
#ifdef SLIRP_USE_POLL
int events = slirp->pfd[idx].revents;
if (events & POLLIN) ret |= SLIRP_POLL_IN;
if (events & POLLOUT) ret |= SLIRP_POLL_OUT;
if (events & POLLPRI) ret |= SLIRP_POLL_PRI;
if (events & POLLERR) ret |= SLIRP_POLL_ERR;
if (events & POLLHUP) ret |= SLIRP_POLL_HUP;
#else
if (FD_ISSET(idx, &slirp->rfds))
ret |= SLIRP_POLL_IN;
if (FD_ISSET(idx, &slirp->wfds))
ret |= SLIRP_POLL_OUT;
if (FD_ISSET(idx, &slirp->xfds))
ret |= SLIRP_POLL_PRI;
#endif
return ret;
}
static void
slirp_tic(slirp_t *slirp)
{
int ret2;
uint32_t tmo;
/* Let SLiRP create a list of all open sockets. */ /* Let SLiRP create a list of all open sockets. */
nfds = -1; #ifdef SLIRP_USE_POLL
FD_ZERO(&rfds); tmo = -1;
FD_ZERO(&wfds); slirp->pfd_len = 0;
FD_ZERO(&xfds); #else
tmo = slirp_select_fill(&nfds, &rfds, &wfds, &xfds); /* this can crash */ slirp->nfds = -1;
FD_ZERO(&slirp->rfds);
FD_ZERO(&slirp->wfds);
FD_ZERO(&slirp->xfds);
#endif
slirp_pollfds_fill(slirp->slirp, &tmo, net_slirp_add_poll, slirp);
/* Now wait for something to happen, or at most 'tmo' usec. */
#ifdef SLIRP_USE_POLL
ret2 = poll(slirp->pfd, slirp->pfd_len, tmo);
#else
if (tmo < 0) if (tmo < 0)
tmo = 500; tmo = 500;
struct timeval tv;
tv.tv_sec = 0; tv.tv_sec = 0;
tv.tv_usec = tmo; tv.tv_usec = tmo;
/* Now wait for something to happen, or at most 'tmo' usec. */ ret2 = select(slirp->nfds + 1, &slirp->rfds, &slirp->wfds, &slirp->xfds, &tv);
ret2 = select(nfds+1, &rfds, &wfds, &xfds, &tv); #endif
/* If something happened, let SLiRP handle it. */ /* If something happened, let SLiRP handle it. */
if (ret2 >= 0) slirp_pollfds_poll(slirp->slirp, (ret2 <= 0), net_slirp_get_revents, slirp);
slirp_select_poll(&rfds, &wfds, &xfds);
} }
static const SlirpCb slirp_cb = {
.send_packet = net_slirp_send_packet,
.guest_error = net_slirp_guest_error,
.clock_get_ns = net_slirp_clock_get_ns,
.timer_new = net_slirp_timer_new,
.timer_free = net_slirp_timer_free,
.timer_mod = net_slirp_timer_mod,
.register_poll_fd = net_slirp_register_poll_fd,
.unregister_poll_fd = net_slirp_unregister_poll_fd,
.notify = net_slirp_notify
};
/* Handle the receiving of frames. */ /* Handle the receiving of frames. */
static void static void
poll_thread(void *arg) poll_thread(void *arg)
{ {
uint8_t *mac = (uint8_t *)arg; slirp_t *slirp = (slirp_t *) arg;
struct queuepacket *qp;
uint32_t mac_cmp32[2];
uint16_t mac_cmp16[2];
event_t *evt; event_t *evt;
int data_valid = 0;
int tx; int tx;
slirp_log("SLiRP: initializing...\n");
/* Set the IP addresses to use. */
struct in_addr net = { .s_addr = htonl(0x0a000200) }; /* 10.0.2.0 */
struct in_addr mask = { .s_addr = htonl(0xffffff00) }; /* 255.255.255.0 */
struct in_addr host = { .s_addr = htonl(0x0a000202) }; /* 10.0.2.2 */
struct in_addr dhcp = { .s_addr = htonl(0x0a00020f) }; /* 10.0.2.15 */
struct in_addr dns = { .s_addr = htonl(0x0a000203) }; /* 10.0.2.3 */
struct in_addr bind = { .s_addr = htonl(0x00000000) }; /* 0.0.0.0 */
struct in6_addr ipv6dummy; /* contents don't matter; we're not doing IPv6 */
/* Initialize SLiRP. */
slirp->slirp = slirp_init(0, 1, net, mask, host, 0, ipv6dummy, 0, ipv6dummy, NULL, NULL, NULL, NULL, dhcp, dns, ipv6dummy, NULL, NULL, &slirp_cb, arg);
if (!slirp->slirp) {
slirp_log("SLiRP: initialization failed\n");
return;
}
/* Set up port forwarding. */
int udp, from, to, i = 0;
char *category = "SLiRP Port Forwarding";
char key[16];
while (1) {
sprintf(key, "%d_udp", i);
udp = config_get_int(category, key, 0);
sprintf(key, "%d_from", i);
from = config_get_int(category, key, 0);
if (from < 1)
break;
sprintf(key, "%d_to", i);
to = config_get_int(category, key, from);
if (slirp_add_hostfwd(slirp->slirp, udp, bind, from, dhcp, to) == 0)
pclog("SLiRP: Forwarded %s port host:%d to guest:%d\n", udp ? "UDP" : "TCP", from, to);
else
pclog("SLiRP: Failed to forward %s port host:%d to guest:%d\n", udp ? "UDP" : "TCP", from, to);
i++;
}
/* Start polling. */
slirp_log("SLiRP: polling started.\n"); slirp_log("SLiRP: polling started.\n");
thread_set_event(poll_state); thread_set_event(slirp->poll_state);
/* Create a waitable event. */ /* Create a waitable event. */
evt = thread_create_event(); evt = thread_create_event();
while (slirpq != NULL) { while (!slirp->stop) {
/* Request ownership of the queue. */ /* Request ownership of the queue. */
network_wait(1); network_wait(1);
/* Wait for a poll request. */ /* Wait for a poll request. */
network_poll(); network_poll();
/* See if there is any work. */ /* Stop processing if asked to. */
slirp_tic(); if (slirp->stop) break;
/* Our queue may have been nuked.. */ /* See if there is any work. */
if (slirpq == NULL) break; slirp_tic(slirp);
/* Wait for the next packet to arrive. */ /* Wait for the next packet to arrive. */
tx = network_tx_queue_check(); tx = network_tx_queue_check();
data_valid = 0;
if ((!network_get_wait() && !(poll_card->set_link_state && poll_card->set_link_state(poll_card->priv)) && !(poll_card->wait && poll_card->wait(poll_card->priv))) && (QueuePeek(slirpq) != 0)) {
/* Grab a packet from the queue. */
qp = QueueDelete(slirpq);
slirp_log("SLiRP: inQ:%d got a %dbyte packet @%08lx\n",
QueuePeek(slirpq), qp->len, qp);
/* Received MAC. */
mac_cmp32[0] = *(uint32_t *)(((uint8_t *)qp->data)+6);
mac_cmp16[0] = *(uint16_t *)(((uint8_t *)qp->data)+10);
/* Local MAC. */
mac_cmp32[1] = *(uint32_t *)mac;
mac_cmp16[1] = *(uint16_t *)(mac+4);
if ((mac_cmp32[0] != mac_cmp32[1]) ||
(mac_cmp16[0] != mac_cmp16[1])) {
network_queue_put(0, poll_card->priv, (uint8_t *)qp->data, qp->len);
data_valid = 1;
}
/* Done with this one. */
free(qp);
}
if (tx) if (tx)
network_do_tx(); network_do_tx();
/* If we did not get anything, wait a while. */ /* If we did not get anything, wait a while. */
if (!data_valid && !tx) if (!tx)
thread_wait_event(evt, 10); thread_wait_event(evt, 10);
/* Release ownership of the queue. */ /* Release ownership of the queue. */
@@ -185,11 +382,16 @@ poll_thread(void *arg)
} }
/* No longer needed. */ /* No longer needed. */
if (evt != NULL) if (evt)
thread_destroy_event(evt); thread_destroy_event(evt);
slirp_log("SLiRP: polling stopped.\n"); slirp_log("SLiRP: polling stopped.\n");
thread_set_event(poll_state); thread_set_event(slirp->poll_state);
/* Free here instead of immediately freeing the global slirp on the main
thread to avoid a race condition. */
slirp_cleanup(slirp->slirp);
free(slirp);
} }
@@ -197,20 +399,7 @@ poll_thread(void *arg)
int int
net_slirp_init(void) net_slirp_init(void)
{ {
slirp_log("SLiRP: initializing..\n"); return 0;
if (slirp_init() != 0) {
slirp_log("SLiRP could not be initialized!\n");
return(-1);
}
slirpq = QueueCreate();
poll_tid = NULL;
poll_state = NULL;
poll_card = NULL;
return(0);
} }
@@ -218,49 +407,52 @@ net_slirp_init(void)
int int
net_slirp_reset(const netcard_t *card, uint8_t *mac) net_slirp_reset(const netcard_t *card, uint8_t *mac)
{ {
slirp_t *new_slirp = malloc(sizeof(slirp_t));
memset(new_slirp, 0, sizeof(slirp_t));
new_slirp->mac = mac;
new_slirp->card = card;
#ifdef SLIRP_USE_POLL
new_slirp->pfd_size = 16 * sizeof(struct pollfd);
new_slirp->pfd = malloc(new_slirp->pfd_size);
memset(new_slirp->pfd, 0, new_slirp->pfd_size);
#endif
/* Save the callback info. */ /* Save the callback info. */
poll_card = card; slirp = new_slirp;
slirp_log("SLiRP: creating thread..\n"); slirp_log("SLiRP: creating thread...\n");
poll_state = thread_create_event(); slirp->poll_state = thread_create_event();
poll_tid = thread_create(poll_thread, mac); slirp->poll_tid = thread_create(poll_thread, new_slirp);
thread_wait_event(poll_state, -1); thread_wait_event(slirp->poll_state, -1);
return(0); return 0;
} }
void void
net_slirp_close(void) net_slirp_close(void)
{ {
queueADT sl; if (!slirp)
if (slirpq == NULL)
return; return;
slirp_log("SLiRP: closing.\n"); slirp_log("SLiRP: closing\n");
/* Tell the polling thread to shut down. */ /* Tell the polling thread to shut down. */
sl = slirpq; slirpq = NULL; slirp->stop = 1;
/* Tell the thread to terminate. */ /* Tell the thread to terminate. */
if (poll_tid != NULL) { if (slirp->poll_tid) {
network_busy(0); network_busy(0);
/* Wait for the thread to finish. */ /* Wait for the thread to finish. */
slirp_log("SLiRP: waiting for thread to end...\n"); slirp_log("SLiRP: waiting for thread to end...\n");
thread_wait_event(poll_state, -1); thread_wait_event(slirp->poll_state, -1);
slirp_log("SLiRP: thread ended\n"); slirp_log("SLiRP: thread ended\n");
thread_destroy_event(poll_state); thread_destroy_event(slirp->poll_state);
poll_tid = NULL;
poll_state = NULL;
poll_card = NULL;
} }
/* OK, now shut down SLiRP itself. */ /* Shutdown work is done by the thread on its local copy of slirp. */
QueueDestroy(sl); slirp = NULL;
slirp_exit(0);
} }
@@ -268,31 +460,25 @@ net_slirp_close(void)
void void
net_slirp_in(uint8_t *pkt, int pkt_len) net_slirp_in(uint8_t *pkt, int pkt_len)
{ {
if (slirpq == NULL) if (!slirp || !slirp->slirp)
return; return;
slirp_input((const uint8_t *)pkt, pkt_len); slirp_log("SLiRP: sending %d-byte packet\n", pkt_len);
slirp_input(slirp->slirp, (const uint8_t *) pkt, pkt_len);
} }
/* Needed by SLiRP library. */ /* Stub functions to stand in for the parts of libslirp we skip compiling. */
void void ncsi_input(void *slirp, const uint8_t *pkt, int pkt_len) {}
slirp_output(const uint8_t *pkt, int pkt_len) void ip6_init(void *slirp) {}
{ void ip6_cleanup(void *slirp) {}
struct queuepacket *qp; void ip6_input(void *m) {}
void in6_compute_ethaddr(struct in6_addr ip, uint8_t *eth) {}
if (slirpq != NULL) { bool in6_equal(const void *a, const void *b) { return 0; }
qp = (struct queuepacket *)malloc(sizeof(struct queuepacket)); int ip6_output(void *so, void *m, int fast) { return 0; }
qp->len = pkt_len; int udp6_output(void *so, void *m, void *saddr, void *daddr) { return 0; }
memcpy(qp->data, pkt, pkt_len); void icmp6_send_error(void *m, uint8_t type, uint8_t code) {}
QueueEnter(slirpq, qp); void ndp_send_ns(void *slirp, struct in6_addr addr) {}
} bool ndp_table_search(void *slirp, struct in6_addr ip_addr, uint8_t *out_ethaddr) { return 0; }
} void tftp_input(void *srcsas, void *m) {}
/* Needed by SLiRP library. */
int
slirp_can_output(void)
{
return((slirpq != NULL)?1:0);
}

View File

@@ -1,61 +0,0 @@
Slirp was written by Danny Gasparovski.
Copyright (c), 1995,1996 All Rights Reserved.
Slirp is maintained by Kelly Price <tygris+slirp@erols.com>
Slirp is free software; "free" as in you don't have to pay for it, and you
are free to do whatever you want with it. I do not accept any donations,
monetary or otherwise, for Slirp. Instead, I would ask you to pass this
potential donation to your favorite charity. In fact, I encourage
*everyone* who finds Slirp useful to make a small donation to their
favorite charity (for example, GreenPeace). This is not a requirement, but
a suggestion from someone who highly values the service they provide.
The copyright terms and conditions:
---BEGIN---
Copyright (c) 1995,1996 Danny Gasparovski. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
DANNY GASPAROVSKI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---END---
This basically means you can do anything you want with the software, except
1) call it your own, and 2) claim warranty on it. There is no warranty for
this software. None. Nada. If you lose a million dollars while using
Slirp, that's your loss not mine. So, ***USE AT YOUR OWN RISK!***.
If these conditions cannot be met due to legal restrictions (E.g. where it
is against the law to give out Software without warranty), you must cease
using the software and delete all copies you have.
Slirp uses code that is copyrighted by the following people/organizations:
Juha Pirkola.
Gregory M. Christy.
The Regents of the University of California.
Carnegie Mellon University.
The Australian National University.
RSA Data Security, Inc.
Please read the top of each source file for the details on the various
copyrights.

View File

@@ -1 +0,0 @@
qemu 0.9.0 (2007/02/05)

View File

@@ -0,0 +1,92 @@
/* SPDX-License-Identifier: MIT */
/*
* ARP table
*
* Copyright (c) 2011 AdaCore
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "slirp.h"
#include <string.h>
void arp_table_add(Slirp *slirp, uint32_t ip_addr,
const uint8_t ethaddr[ETH_ALEN])
{
const uint32_t broadcast_addr =
~slirp->vnetwork_mask.s_addr | slirp->vnetwork_addr.s_addr;
ArpTable *arptbl = &slirp->arp_table;
int i;
DEBUG_CALL("arp_table_add");
DEBUG_ARG("ip = %s", inet_ntoa((struct in_addr){ .s_addr = ip_addr }));
DEBUG_ARG("hw addr = %02x:%02x:%02x:%02x:%02x:%02x", ethaddr[0], ethaddr[1],
ethaddr[2], ethaddr[3], ethaddr[4], ethaddr[5]);
if (ip_addr == 0 || ip_addr == 0xffffffff || ip_addr == broadcast_addr) {
/* Do not register broadcast addresses */
return;
}
/* Search for an entry */
for (i = 0; i < ARP_TABLE_SIZE; i++) {
if (arptbl->table[i].ar_sip == ip_addr) {
/* Update the entry */
memcpy(arptbl->table[i].ar_sha, ethaddr, ETH_ALEN);
return;
}
}
/* No entry found, create a new one */
arptbl->table[arptbl->next_victim].ar_sip = ip_addr;
memcpy(arptbl->table[arptbl->next_victim].ar_sha, ethaddr, ETH_ALEN);
arptbl->next_victim = (arptbl->next_victim + 1) % ARP_TABLE_SIZE;
}
bool arp_table_search(Slirp *slirp, uint32_t ip_addr,
uint8_t out_ethaddr[ETH_ALEN])
{
const uint32_t broadcast_addr =
~slirp->vnetwork_mask.s_addr | slirp->vnetwork_addr.s_addr;
ArpTable *arptbl = &slirp->arp_table;
int i;
DEBUG_CALL("arp_table_search");
DEBUG_ARG("ip = %s", inet_ntoa((struct in_addr){ .s_addr = ip_addr }));
/* If broadcast address */
if (ip_addr == 0 || ip_addr == 0xffffffff || ip_addr == broadcast_addr) {
/* return Ethernet broadcast address */
memset(out_ethaddr, 0xff, ETH_ALEN);
return 1;
}
for (i = 0; i < ARP_TABLE_SIZE; i++) {
if (arptbl->table[i].ar_sip == ip_addr) {
memcpy(out_ethaddr, arptbl->table[i].ar_sha, ETH_ALEN);
DEBUG_ARG("found hw addr = %02x:%02x:%02x:%02x:%02x:%02x",
out_ethaddr[0], out_ethaddr[1], out_ethaddr[2],
out_ethaddr[3], out_ethaddr[4], out_ethaddr[5]);
return 1;
}
}
return 0;
}

View File

@@ -1,8 +1,9 @@
/* SPDX-License-Identifier: MIT */
/* /*
* QEMU BOOTP/DHCP server * QEMU BOOTP/DHCP server
* *
* Copyright (c) 2004 Fabrice Bellard * Copyright (c) 2004 Fabrice Bellard
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights * in the Software without restriction, including without limitation the rights
@@ -23,76 +24,92 @@
*/ */
#include "slirp.h" #include "slirp.h"
#if defined(_WIN32)
/* Windows ntohl() returns an u_long value.
* Add a type cast to match the format strings. */
#define ntohl(n) ((uint32_t)ntohl(n))
#endif
/* XXX: only DHCP is supported */ /* XXX: only DHCP is supported */
#define NB_ADDR 16
#define START_ADDR 15
#define LEASE_TIME (24 * 3600) #define LEASE_TIME (24 * 3600)
typedef struct {
uint8_t allocated;
uint8_t macaddr[6];
} BOOTPClient;
BOOTPClient bootp_clients[NB_ADDR];
static const uint8_t rfc1533_cookie[] = { RFC1533_COOKIE }; static const uint8_t rfc1533_cookie[] = { RFC1533_COOKIE };
static BOOTPClient *get_new_addr(struct in_addr *paddr) #define DPRINTF(fmt, ...) DEBUG_CALL(fmt, ##__VA_ARGS__)
static BOOTPClient *get_new_addr(Slirp *slirp, struct in_addr *paddr,
const uint8_t *macaddr)
{ {
BOOTPClient *bc; BOOTPClient *bc;
int i; int i;
for(i = 0; i < NB_ADDR; i++) { for (i = 0; i < NB_BOOTP_CLIENTS; i++) {
if (!bootp_clients[i].allocated) bc = &slirp->bootp_clients[i];
if (!bc->allocated || !memcmp(macaddr, bc->macaddr, 6))
goto found; goto found;
} }
return NULL; return NULL;
found: found:
bc = &bootp_clients[i]; bc = &slirp->bootp_clients[i];
bc->allocated = 1; bc->allocated = 1;
paddr->s_addr = htonl(ntohl(special_addr.s_addr) | (i + START_ADDR)); paddr->s_addr = slirp->vdhcp_startaddr.s_addr + htonl(i);
return bc; return bc;
} }
static BOOTPClient *find_addr(struct in_addr *paddr, const uint8_t *macaddr) static BOOTPClient *request_addr(Slirp *slirp, const struct in_addr *paddr,
const uint8_t *macaddr)
{
uint32_t req_addr = ntohl(paddr->s_addr);
uint32_t dhcp_addr = ntohl(slirp->vdhcp_startaddr.s_addr);
BOOTPClient *bc;
if (req_addr >= dhcp_addr && req_addr < (dhcp_addr + NB_BOOTP_CLIENTS)) {
bc = &slirp->bootp_clients[req_addr - dhcp_addr];
if (!bc->allocated || !memcmp(macaddr, bc->macaddr, 6)) {
bc->allocated = 1;
return bc;
}
}
return NULL;
}
static BOOTPClient *find_addr(Slirp *slirp, struct in_addr *paddr,
const uint8_t *macaddr)
{ {
BOOTPClient *bc; BOOTPClient *bc;
int i; int i;
for(i = 0; i < NB_ADDR; i++) { for (i = 0; i < NB_BOOTP_CLIENTS; i++) {
if (!memcmp(macaddr, bootp_clients[i].macaddr, 6)) if (!memcmp(macaddr, slirp->bootp_clients[i].macaddr, 6))
goto found; goto found;
} }
return NULL; return NULL;
found: found:
bc = &bootp_clients[i]; bc = &slirp->bootp_clients[i];
bc->allocated = 1; bc->allocated = 1;
paddr->s_addr = htonl(ntohl(special_addr.s_addr) | (i + START_ADDR)); paddr->s_addr = slirp->vdhcp_startaddr.s_addr + htonl(i);
return bc; return bc;
} }
static void dhcp_decode(const uint8_t *buf, int size, static void dhcp_decode(const struct bootp_t *bp, int *pmsg_type,
int *pmsg_type) struct in_addr *preq_addr)
{ {
const uint8_t *p, *p_end; const uint8_t *p, *p_end;
int len, tag; int len, tag;
*pmsg_type = 0; *pmsg_type = 0;
preq_addr->s_addr = htonl(0L);
p = buf; p = bp->bp_vend;
p_end = buf + size; p_end = p + DHCP_OPT_LEN;
if (size < 5)
return;
if (memcmp(p, rfc1533_cookie, 4) != 0) if (memcmp(p, rfc1533_cookie, 4) != 0)
return; return;
p += 4; p += 4;
while (p < p_end) { while (p < p_end) {
tag = p[0]; tag = p[0];
if (tag == RFC1533_PAD) { if (tag == RFC1533_PAD) {
p++; p++;
} else if (tag == RFC1533_END) { } else if (tag == RFC1533_END) {
break; break;
} else { } else {
@@ -100,57 +117,99 @@ static void dhcp_decode(const uint8_t *buf, int size,
if (p >= p_end) if (p >= p_end)
break; break;
len = *p++; len = *p++;
if (p + len > p_end) {
break;
}
DPRINTF("dhcp: tag=%d len=%d\n", tag, len);
switch(tag) { switch (tag) {
case RFC2132_MSG_TYPE: case RFC2132_MSG_TYPE:
if (len >= 1) if (len >= 1)
*pmsg_type = p[0]; *pmsg_type = p[0];
break; break;
case RFC2132_REQ_ADDR:
if (len >= 4) {
memcpy(&(preq_addr->s_addr), p, 4);
}
break;
default: default:
break; break;
} }
p += len; p += len;
} }
} }
if (*pmsg_type == DHCPREQUEST && preq_addr->s_addr == htonl(0L) &&
bp->bp_ciaddr.s_addr) {
memcpy(&(preq_addr->s_addr), &bp->bp_ciaddr, 4);
}
} }
static void bootp_reply(struct bootp_t *bp) static void bootp_reply(Slirp *slirp, const struct bootp_t *bp)
{ {
BOOTPClient *bc; BOOTPClient *bc = NULL;
struct SLIRPmbuf *m; struct mbuf *m;
struct bootp_t *rbp; struct bootp_t *rbp;
struct sockaddr_in saddr, daddr; struct sockaddr_in saddr, daddr;
struct in_addr dns_addr; struct in_addr preq_addr;
int dhcp_msg_type, val; int dhcp_msg_type, val;
uint8_t *q; uint8_t *q;
uint8_t *end;
uint8_t client_ethaddr[ETH_ALEN];
/* extract exact DHCP msg type */ /* extract exact DHCP msg type */
dhcp_decode(bp->bp_vend, DHCP_OPT_LEN, &dhcp_msg_type); dhcp_decode(bp, &dhcp_msg_type, &preq_addr);
DPRINTF("bootp packet op=%d msgtype=%d", bp->bp_op, dhcp_msg_type);
if (preq_addr.s_addr != htonl(0L))
DPRINTF(" req_addr=%08" PRIx32 "\n", ntohl(preq_addr.s_addr));
else {
DPRINTF("\n");
}
if (dhcp_msg_type == 0) if (dhcp_msg_type == 0)
dhcp_msg_type = DHCPREQUEST; /* Force reply for old BOOTP clients */ dhcp_msg_type = DHCPREQUEST; /* Force reply for old BOOTP clients */
if (dhcp_msg_type != DHCPDISCOVER && if (dhcp_msg_type != DHCPDISCOVER && dhcp_msg_type != DHCPREQUEST)
dhcp_msg_type != DHCPREQUEST)
return; return;
/* XXX: this is a hack to get the client mac address */
memcpy(client_ethaddr, bp->bp_hwaddr, 6); /* Get client's hardware address from bootp request */
memcpy(client_ethaddr, bp->bp_hwaddr, ETH_ALEN);
if ((m = m_get()) == NULL)
m = m_get(slirp);
if (!m) {
return; return;
m->m_data += if_maxlinkhdr; }
m->m_data += IF_MAXLINKHDR;
rbp = (struct bootp_t *)m->m_data; rbp = (struct bootp_t *)m->m_data;
m->m_data += sizeof(struct udpiphdr); m->m_data += sizeof(struct udpiphdr);
memset(rbp, 0, sizeof(struct bootp_t)); memset(rbp, 0, sizeof(struct bootp_t));
if (dhcp_msg_type == DHCPDISCOVER) { if (dhcp_msg_type == DHCPDISCOVER) {
new_addr: if (preq_addr.s_addr != htonl(0L)) {
bc = get_new_addr(&daddr.sin_addr); bc = request_addr(slirp, &preq_addr, client_ethaddr);
if (!bc) if (bc) {
return; daddr.sin_addr = preq_addr;
memcpy(bc->macaddr, client_ethaddr, 6); }
}
if (!bc) {
new_addr:
bc = get_new_addr(slirp, &daddr.sin_addr, client_ethaddr);
if (!bc) {
DPRINTF("no address left\n");
return;
}
}
memcpy(bc->macaddr, client_ethaddr, ETH_ALEN);
} else if (preq_addr.s_addr != htonl(0L)) {
bc = request_addr(slirp, &preq_addr, client_ethaddr);
if (bc) {
daddr.sin_addr = preq_addr;
memcpy(bc->macaddr, client_ethaddr, ETH_ALEN);
} else {
/* DHCPNAKs should be sent to broadcast */
daddr.sin_addr.s_addr = 0xffffffff;
}
} else { } else {
bc = find_addr(&daddr.sin_addr, bp->bp_hwaddr); bc = find_addr(slirp, &daddr.sin_addr, bp->bp_hwaddr);
if (!bc) { if (!bc) {
/* if never assigned, behaves as if it was already /* if never assigned, behaves as if it was already
assigned (windows fix because it remembers its address) */ assigned (windows fix because it remembers its address) */
@@ -158,7 +217,10 @@ static void bootp_reply(struct bootp_t *bp)
} }
} }
saddr.sin_addr.s_addr = htonl(ntohl(special_addr.s_addr) | CTL_ALIAS); /* Update ARP table for this IP address */
arp_table_add(slirp, daddr.sin_addr.s_addr, client_ethaddr);
saddr.sin_addr = slirp->vhost_addr;
saddr.sin_port = htons(BOOTP_SERVER); saddr.sin_port = htons(BOOTP_SERVER);
daddr.sin_port = htons(BOOTP_CLIENT); daddr.sin_port = htons(BOOTP_CLIENT);
@@ -167,27 +229,36 @@ static void bootp_reply(struct bootp_t *bp)
rbp->bp_xid = bp->bp_xid; rbp->bp_xid = bp->bp_xid;
rbp->bp_htype = 1; rbp->bp_htype = 1;
rbp->bp_hlen = 6; rbp->bp_hlen = 6;
memcpy(rbp->bp_hwaddr, bp->bp_hwaddr, 6); memcpy(rbp->bp_hwaddr, bp->bp_hwaddr, ETH_ALEN);
rbp->bp_yiaddr = daddr.sin_addr; /* Client IP address */ rbp->bp_yiaddr = daddr.sin_addr; /* Client IP address */
rbp->bp_siaddr = saddr.sin_addr; /* Server IP address */ rbp->bp_siaddr = saddr.sin_addr; /* Server IP address */
q = rbp->bp_vend; q = rbp->bp_vend;
end = (uint8_t *)&rbp[1];
memcpy(q, rfc1533_cookie, 4); memcpy(q, rfc1533_cookie, 4);
q += 4; q += 4;
if (dhcp_msg_type == DHCPDISCOVER) { if (bc) {
*q++ = RFC2132_MSG_TYPE; DPRINTF("%s addr=%08" PRIx32 "\n",
*q++ = 1; (dhcp_msg_type == DHCPDISCOVER) ? "offered" : "ack'ed",
*q++ = DHCPOFFER; ntohl(daddr.sin_addr.s_addr));
} else if (dhcp_msg_type == DHCPREQUEST) {
*q++ = RFC2132_MSG_TYPE; if (dhcp_msg_type == DHCPDISCOVER) {
*q++ = 1; *q++ = RFC2132_MSG_TYPE;
*q++ = DHCPACK; *q++ = 1;
} *q++ = DHCPOFFER;
} else /* DHCPREQUEST */ {
if (dhcp_msg_type == DHCPDISCOVER || *q++ = RFC2132_MSG_TYPE;
dhcp_msg_type == DHCPREQUEST) { *q++ = 1;
*q++ = DHCPACK;
}
if (slirp->bootp_filename) {
g_assert(strlen(slirp->bootp_filename) < sizeof(rbp->bp_file));
strcpy(rbp->bp_file, slirp->bootp_filename);
}
*q++ = RFC2132_SRV_ID; *q++ = RFC2132_SRV_ID;
*q++ = 4; *q++ = 4;
memcpy(q, &saddr.sin_addr, 4); memcpy(q, &saddr.sin_addr, 4);
@@ -195,48 +266,104 @@ static void bootp_reply(struct bootp_t *bp)
*q++ = RFC1533_NETMASK; *q++ = RFC1533_NETMASK;
*q++ = 4; *q++ = 4;
*q++ = 0xff; memcpy(q, &slirp->vnetwork_mask, 4);
*q++ = 0xff;
*q++ = 0xff;
*q++ = 0x00;
*q++ = RFC1533_GATEWAY;
*q++ = 4;
memcpy(q, &saddr.sin_addr, 4);
q += 4;
*q++ = RFC1533_DNS;
*q++ = 4;
dns_addr.s_addr = htonl(ntohl(special_addr.s_addr) | CTL_DNS);
memcpy(q, &dns_addr, 4);
q += 4; q += 4;
if (!slirp->restricted) {
*q++ = RFC1533_GATEWAY;
*q++ = 4;
memcpy(q, &saddr.sin_addr, 4);
q += 4;
*q++ = RFC1533_DNS;
*q++ = 4;
memcpy(q, &slirp->vnameserver_addr, 4);
q += 4;
}
*q++ = RFC2132_LEASE_TIME; *q++ = RFC2132_LEASE_TIME;
*q++ = 4; *q++ = 4;
val = htonl(LEASE_TIME); val = htonl(LEASE_TIME);
memcpy(q, &val, 4); memcpy(q, &val, 4);
q += 4; q += 4;
if (*slirp_hostname) { if (*slirp->client_hostname) {
val = strlen(slirp_hostname); val = strlen(slirp->client_hostname);
*q++ = RFC1533_HOSTNAME; if (q + val + 2 >= end) {
*q++ = val; g_warning("DHCP packet size exceeded, "
memcpy(q, slirp_hostname, val); "omitting host name option.");
q += val; } else {
*q++ = RFC1533_HOSTNAME;
*q++ = val;
memcpy(q, slirp->client_hostname, val);
q += val;
}
} }
if (slirp->vdomainname) {
val = strlen(slirp->vdomainname);
if (q + val + 2 >= end) {
g_warning("DHCP packet size exceeded, "
"omitting domain name option.");
} else {
*q++ = RFC1533_DOMAINNAME;
*q++ = val;
memcpy(q, slirp->vdomainname, val);
q += val;
}
}
if (slirp->tftp_server_name) {
val = strlen(slirp->tftp_server_name);
if (q + val + 2 >= end) {
g_warning("DHCP packet size exceeded, "
"omitting tftp-server-name option.");
} else {
*q++ = RFC2132_TFTP_SERVER_NAME;
*q++ = val;
memcpy(q, slirp->tftp_server_name, val);
q += val;
}
}
if (slirp->vdnssearch) {
val = slirp->vdnssearch_len;
if (q + val >= end) {
g_warning("DHCP packet size exceeded, "
"omitting domain-search option.");
} else {
memcpy(q, slirp->vdnssearch, val);
q += val;
}
}
} else {
static const char nak_msg[] = "requested address not available";
DPRINTF("nak'ed addr=%08" PRIx32 "\n", ntohl(preq_addr.s_addr));
*q++ = RFC2132_MSG_TYPE;
*q++ = 1;
*q++ = DHCPNAK;
*q++ = RFC2132_MESSAGE;
*q++ = sizeof(nak_msg) - 1;
memcpy(q, nak_msg, sizeof(nak_msg) - 1);
q += sizeof(nak_msg) - 1;
} }
*q++ = RFC1533_END; assert(q < end);
*q = RFC1533_END;
m->m_len = sizeof(struct bootp_t) -
sizeof(struct ip) - sizeof(struct udphdr); daddr.sin_addr.s_addr = 0xffffffffu;
udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
m->m_len = sizeof(struct bootp_t) - sizeof(struct ip) - sizeof(struct udphdr);
udp_output(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
} }
void bootp_input(struct SLIRPmbuf *m) void bootp_input(struct mbuf *m)
{ {
struct bootp_t *bp = mtod(m, struct bootp_t *); struct bootp_t *bp = mtod(m, struct bootp_t *);
if (bp->bp_op == BOOTP_REQUEST) { if (bp->bp_op == BOOTP_REQUEST) {
bootp_reply(bp); bootp_reply(m->slirp, bp);
} }
} }

View File

@@ -1,98 +1,101 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/* bootp/dhcp defines */ /* bootp/dhcp defines */
#define BOOTP_SERVER 67 #ifndef SLIRP_BOOTP_H
#define BOOTP_CLIENT 68 #define SLIRP_BOOTP_H
#define BOOTP_REQUEST 1 #define BOOTP_SERVER 67
#define BOOTP_REPLY 2 #define BOOTP_CLIENT 68
#define RFC1533_COOKIE 99, 130, 83, 99 #define BOOTP_REQUEST 1
#define RFC1533_PAD 0 #define BOOTP_REPLY 2
#define RFC1533_NETMASK 1
#define RFC1533_TIMEOFFSET 2 #define RFC1533_COOKIE 99, 130, 83, 99
#define RFC1533_GATEWAY 3 #define RFC1533_PAD 0
#define RFC1533_TIMESERVER 4 #define RFC1533_NETMASK 1
#define RFC1533_IEN116NS 5 #define RFC1533_TIMEOFFSET 2
#define RFC1533_DNS 6 #define RFC1533_GATEWAY 3
#define RFC1533_LOGSERVER 7 #define RFC1533_TIMESERVER 4
#define RFC1533_COOKIESERVER 8 #define RFC1533_IEN116NS 5
#define RFC1533_LPRSERVER 9 #define RFC1533_DNS 6
#define RFC1533_IMPRESSSERVER 10 #define RFC1533_LOGSERVER 7
#define RFC1533_RESOURCESERVER 11 #define RFC1533_COOKIESERVER 8
#define RFC1533_HOSTNAME 12 #define RFC1533_LPRSERVER 9
#define RFC1533_BOOTFILESIZE 13 #define RFC1533_IMPRESSSERVER 10
#define RFC1533_MERITDUMPFILE 14 #define RFC1533_RESOURCESERVER 11
#define RFC1533_DOMAINNAME 15 #define RFC1533_HOSTNAME 12
#define RFC1533_SWAPSERVER 16 #define RFC1533_BOOTFILESIZE 13
#define RFC1533_ROOTPATH 17 #define RFC1533_MERITDUMPFILE 14
#define RFC1533_EXTENSIONPATH 18 #define RFC1533_DOMAINNAME 15
#define RFC1533_IPFORWARDING 19 #define RFC1533_SWAPSERVER 16
#define RFC1533_IPSOURCEROUTING 20 #define RFC1533_ROOTPATH 17
#define RFC1533_IPPOLICYFILTER 21 #define RFC1533_EXTENSIONPATH 18
#define RFC1533_IPMAXREASSEMBLY 22 #define RFC1533_IPFORWARDING 19
#define RFC1533_IPTTL 23 #define RFC1533_IPSOURCEROUTING 20
#define RFC1533_IPMTU 24 #define RFC1533_IPPOLICYFILTER 21
#define RFC1533_IPMTUPLATEAU 25 #define RFC1533_IPMAXREASSEMBLY 22
#define RFC1533_INTMTU 26 #define RFC1533_IPTTL 23
#define RFC1533_INTLOCALSUBNETS 27 #define RFC1533_IPMTU 24
#define RFC1533_INTBROADCAST 28 #define RFC1533_IPMTUPLATEAU 25
#define RFC1533_INTICMPDISCOVER 29 #define RFC1533_INTMTU 26
#define RFC1533_INTICMPRESPOND 30 #define RFC1533_INTLOCALSUBNETS 27
#define RFC1533_INTBROADCAST 28
#define RFC1533_INTICMPDISCOVER 29
#define RFC1533_INTICMPRESPOND 30
#define RFC1533_INTROUTEDISCOVER 31 #define RFC1533_INTROUTEDISCOVER 31
#define RFC1533_INTROUTESOLICIT 32 #define RFC1533_INTROUTESOLICIT 32
#define RFC1533_INTSTATICROUTES 33 #define RFC1533_INTSTATICROUTES 33
#define RFC1533_LLTRAILERENCAP 34 #define RFC1533_LLTRAILERENCAP 34
#define RFC1533_LLARPCACHETMO 35 #define RFC1533_LLARPCACHETMO 35
#define RFC1533_LLETHERNETENCAP 36 #define RFC1533_LLETHERNETENCAP 36
#define RFC1533_TCPTTL 37 #define RFC1533_TCPTTL 37
#define RFC1533_TCPKEEPALIVETMO 38 #define RFC1533_TCPKEEPALIVETMO 38
#define RFC1533_TCPKEEPALIVEGB 39 #define RFC1533_TCPKEEPALIVEGB 39
#define RFC1533_NISDOMAIN 40 #define RFC1533_NISDOMAIN 40
#define RFC1533_NISSERVER 41 #define RFC1533_NISSERVER 41
#define RFC1533_NTPSERVER 42 #define RFC1533_NTPSERVER 42
#define RFC1533_VENDOR 43 #define RFC1533_VENDOR 43
#define RFC1533_NBNS 44 #define RFC1533_NBNS 44
#define RFC1533_NBDD 45 #define RFC1533_NBDD 45
#define RFC1533_NBNT 46 #define RFC1533_NBNT 46
#define RFC1533_NBSCOPE 47 #define RFC1533_NBSCOPE 47
#define RFC1533_XFS 48 #define RFC1533_XFS 48
#define RFC1533_XDM 49 #define RFC1533_XDM 49
#define RFC2132_REQ_ADDR 50 #define RFC2132_REQ_ADDR 50
#define RFC2132_LEASE_TIME 51 #define RFC2132_LEASE_TIME 51
#define RFC2132_MSG_TYPE 53 #define RFC2132_MSG_TYPE 53
#define RFC2132_SRV_ID 54 #define RFC2132_SRV_ID 54
#define RFC2132_PARAM_LIST 55 #define RFC2132_PARAM_LIST 55
#define RFC2132_MAX_SIZE 57 #define RFC2132_MESSAGE 56
#define RFC2132_RENEWAL_TIME 58 #define RFC2132_MAX_SIZE 57
#define RFC2132_REBIND_TIME 59 #define RFC2132_RENEWAL_TIME 58
#define RFC2132_REBIND_TIME 59
#define RFC2132_TFTP_SERVER_NAME 66
#define DHCPDISCOVER 1 #define DHCPDISCOVER 1
#define DHCPOFFER 2 #define DHCPOFFER 2
#define DHCPREQUEST 3 #define DHCPREQUEST 3
#define DHCPACK 5 #define DHCPACK 5
#define DHCPNAK 6
#define RFC1533_VENDOR_MAJOR 0 #define RFC1533_VENDOR_MAJOR 0
#define RFC1533_VENDOR_MINOR 0 #define RFC1533_VENDOR_MINOR 0
#define RFC1533_VENDOR_MAGIC 128 #define RFC1533_VENDOR_MAGIC 128
#define RFC1533_VENDOR_ADDPARM 129 #define RFC1533_VENDOR_ADDPARM 129
#define RFC1533_VENDOR_ETHDEV 130 #define RFC1533_VENDOR_ETHDEV 130
#define RFC1533_VENDOR_HOWTO 132 #define RFC1533_VENDOR_HOWTO 132
#define RFC1533_VENDOR_MNUOPTS 160 #define RFC1533_VENDOR_MNUOPTS 160
#define RFC1533_VENDOR_SELECTION 176 #define RFC1533_VENDOR_SELECTION 176
#define RFC1533_VENDOR_MOTD 184 #define RFC1533_VENDOR_MOTD 184
#define RFC1533_VENDOR_NUMOFMOTD 8 #define RFC1533_VENDOR_NUMOFMOTD 8
#define RFC1533_VENDOR_IMG 192 #define RFC1533_VENDOR_IMG 192
#define RFC1533_VENDOR_NUMOFIMG 16 #define RFC1533_VENDOR_NUMOFIMG 16
#define RFC1533_END 255 #define RFC1533_END 255
#define BOOTP_VENDOR_LEN 64 #define BOOTP_VENDOR_LEN 64
#define DHCP_OPT_LEN 312 #define DHCP_OPT_LEN 312
#ifdef PRAGMA_PACK_SUPPORTED
#pragma pack(1)
#endif
struct bootp_t { struct bootp_t {
struct ip ip; struct ip ip;
@@ -110,12 +113,17 @@ struct bootp_t {
struct in_addr bp_giaddr; struct in_addr bp_giaddr;
uint8_t bp_hwaddr[16]; uint8_t bp_hwaddr[16];
uint8_t bp_sname[64]; uint8_t bp_sname[64];
uint8_t bp_file[128]; char bp_file[128];
uint8_t bp_vend[DHCP_OPT_LEN]; uint8_t bp_vend[DHCP_OPT_LEN];
} PACKED__; };
typedef struct {
uint16_t allocated;
uint8_t macaddr[6];
} BOOTPClient;
#define NB_BOOTP_CLIENTS 16
void bootp_input(struct mbuf *m);
#ifdef PRAGMA_PACK_SUPPORTED
#pragma pack(PACK_END)
#endif #endif
void bootp_input(struct SLIRPmbuf *m);

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/* /*
* Copyright (c) 1988, 1992, 1993 * Copyright (c) 1988, 1992, 1993
* The Regents of the University of California. All rights reserved. * The Regents of the University of California. All rights reserved.
@@ -37,101 +38,142 @@
* *
* This routine is very heavily used in the network * This routine is very heavily used in the network
* code and should be modified for each CPU to be as fast as possible. * code and should be modified for each CPU to be as fast as possible.
* *
* XXX Since we will never span more than 1 SLIRPmbuf, we can optimise this * XXX Since we will never span more than 1 mbuf, we can optimise this
*/ */
#define ADDCARRY(x) (x > 65535 ? x -= 65535 : x) #define ADDCARRY(x) (x > 65535 ? x -= 65535 : x)
#define REDUCE {l_util.l = sum; sum = l_util.s[0] + l_util.s[1]; ADDCARRY(sum);} #define REDUCE \
{ \
l_util.l = sum; \
sum = l_util.s[0] + l_util.s[1]; \
(void)ADDCARRY(sum); \
}
int cksum(struct SLIRPmbuf *m, int len) int cksum(struct mbuf *m, int len)
{ {
register u_int16_t *w; register uint16_t *w;
register int sum = 0; register int sum = 0;
register int mlen = 0; register int mlen = 0;
int byte_swapped = 0; int byte_swapped = 0;
union {
uint8_t c[2];
uint16_t s;
} s_util;
union {
uint16_t s[2];
uint32_t l;
} l_util;
if (m->m_len == 0)
goto cont;
w = mtod(m, uint16_t *);
mlen = m->m_len;
if (len < mlen)
mlen = len;
len -= mlen;
/*
* Force to even boundary.
*/
if ((1 & (uintptr_t)w) && (mlen > 0)) {
REDUCE;
sum <<= 8;
s_util.c[0] = *(uint8_t *)w;
w = (uint16_t *)((int8_t *)w + 1);
mlen--;
byte_swapped = 1;
}
/*
* Unroll the loop to make overhead from
* branches &c small.
*/
while ((mlen -= 32) >= 0) {
sum += w[0];
sum += w[1];
sum += w[2];
sum += w[3];
sum += w[4];
sum += w[5];
sum += w[6];
sum += w[7];
sum += w[8];
sum += w[9];
sum += w[10];
sum += w[11];
sum += w[12];
sum += w[13];
sum += w[14];
sum += w[15];
w += 16;
}
mlen += 32;
while ((mlen -= 8) >= 0) {
sum += w[0];
sum += w[1];
sum += w[2];
sum += w[3];
w += 4;
}
mlen += 8;
if (mlen == 0 && byte_swapped == 0)
goto cont;
REDUCE;
while ((mlen -= 2) >= 0) {
sum += *w++;
}
if (byte_swapped) {
REDUCE;
sum <<= 8;
if (mlen == -1) {
s_util.c[1] = *(uint8_t *)w;
sum += s_util.s;
mlen = 0;
} else
mlen = -1;
} else if (mlen == -1)
s_util.c[0] = *(uint8_t *)w;
union {
u_int8_t c[2];
u_int16_t s;
} s_util;
union {
u_int16_t s[2];
u_int32_t l;
} l_util;
if (m->m_len == 0)
goto cont;
w = mtod(m, u_int16_t *);
mlen = m->m_len;
if (len < mlen)
mlen = len;
len -= mlen;
/*
* Force to even boundary.
*/
if ((1 & (intptr_t) w) && (mlen > 0)) {
REDUCE;
sum <<= 8;
s_util.c[0] = *(u_int8_t *)w;
w = (u_int16_t *)((int8_t *)w + 1);
mlen--;
byte_swapped = 1;
}
/*
* Unroll the loop to make overhead from
* branches &c small.
*/
while ((mlen -= 32) >= 0) {
sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7];
sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11];
sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15];
w += 16;
}
mlen += 32;
while ((mlen -= 8) >= 0) {
sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
w += 4;
}
mlen += 8;
if (mlen == 0 && byte_swapped == 0)
goto cont;
REDUCE;
while ((mlen -= 2) >= 0) {
sum += *w++;
}
if (byte_swapped) {
REDUCE;
sum <<= 8;
byte_swapped = 0;
if (mlen == -1) {
s_util.c[1] = *(u_int8_t *)w;
sum += s_util.s;
mlen = 0;
} else
mlen = -1;
} else if (mlen == -1)
s_util.c[0] = *(u_int8_t *)w;
cont: cont:
#ifdef SLIRP_DEBUG if (len) {
if (len) { DEBUG_ERROR("cksum: out of data");
DEBUG_ERROR((dfd, "cksum: out of data\n")); DEBUG_ERROR(" len = %d", len);
DEBUG_ERROR((dfd, " len = %d\n", len)); }
} if (mlen == -1) {
#endif /* The last mbuf has odd # of bytes. Follow the
if (mlen == -1) { standard (the odd byte may be shifted left by 8 bits
/* The last SLIRPmbuf has odd # of bytes. Follow the or not as determined by endian-ness of the machine) */
standard (the odd byte may be shifted left by 8 bits s_util.c[1] = 0;
or not as determined by endian-ness of the machine) */ sum += s_util.s;
s_util.c[1] = 0; }
sum += s_util.s; REDUCE;
} return (~sum & 0xffff);
REDUCE; }
return (~sum & 0xffff);
int ip6_cksum(struct mbuf *m)
{
/* TODO: Optimize this by being able to pass the ip6_pseudohdr to cksum
* separately from the mbuf */
struct ip6 save_ip, *ip = mtod(m, struct ip6 *);
struct ip6_pseudohdr *ih = mtod(m, struct ip6_pseudohdr *);
int sum;
save_ip = *ip;
ih->ih_src = save_ip.ip_src;
ih->ih_dst = save_ip.ip_dst;
ih->ih_pl = htonl((uint32_t)ntohs(save_ip.ip_pl));
ih->ih_zero_hi = 0;
ih->ih_zero_lo = 0;
ih->ih_nh = save_ip.ip_nh;
sum = cksum(m, ((int)sizeof(struct ip6_pseudohdr)) + ntohl(ih->ih_pl));
*ip = save_ip;
return sum;
} }

View File

@@ -1,9 +0,0 @@
/* Automatically generated by configure - do not modify */
#define CONFIG_QEMU_SHAREDIR "/c/Program Files/Qemu"
#define HOST_I386 1
#define HOST_LONG_BITS 32
#define CONFIG_WIN32 1
#define CONFIG_GDBSTUB 1
#define CONFIG_SLIRP 1
#define QEMU_VERSION "0.9.0"
#define CONFIG_UNAME_RELEASE ""

View File

@@ -1,9 +0,0 @@
/* Automatically generated by configure - do not modify */
#include "config-host.h"
#define CONFIG_QEMU_PREFIX "/usr/gnemul/qemu-i386"
#define TARGET_ARCH "i386"
#define TARGET_I386 1
#define USE_KQEMU 1
#define CONFIG_SOFTMMU 1
#define CONFIG_SDL 1
#define HAVE_STRDUP 1

View File

@@ -1,7 +0,0 @@
#define CTL_CMD 0
#define CTL_EXEC 1
#define CTL_ALIAS 2
#define CTL_DNS 3
#define CTL_SPECIAL "10.0.2.0"
#define CTL_LOCAL "10.0.2.15"

View File

@@ -1,445 +0,0 @@
/*
* Copyright (c) 1995 Danny Gasparovski.
* Portions copyright (c) 2000 Kelly Price.
*
* Please read the file COPYRIGHT for the
* terms and conditions of the copyright.
*/
#ifndef _WIN32
# include <unistd.h>
#endif
#include "slirp.h"
FILE *dfd = NULL;
#ifdef SLIRP_DEBUG
int dostats = 1;
#else
int dostats = 0;
#endif
int slirp_debug = 0;
#ifndef _MSC_VER
extern char *strerror _P((int));
#endif
/* Carry over one item from main.c so that the tty's restored.
* Only done when the tty being used is /dev/tty --RedWolf */
extern struct termios slirp_tty_settings;
extern int slirp_tty_restore;
void
debug_init(file, dbg)
char *file;
int dbg;
{
/* Close the old debugging file */
if (dfd)
fclose(dfd);
dfd = fopen(file,"w");
if (dfd != NULL) {
#if 1
fprintf(dfd,"Slirp %s - Debugging Started.\n", SLIRP_VERSION);
#endif
fprintf(dfd,"Debugging Started level %i.\r\n",dbg);
fflush(dfd);
slirp_debug = dbg;
} else {
lprint("Error: Debugging file \"%s\" could not be opened: %s\r\n",
file, strerror(errno));
}
}
/*
* Dump a packet in the same format as tcpdump -x
*/
#ifdef SLIRP_DEBUG
void
dump_packet(dat, n)
void *dat;
int n;
{
u_char *pptr = (u_char *)dat;
int j,k;
n /= 16;
n++;
DEBUG_MISC((dfd, "PACKET DUMPED: \n"));
for(j = 0; j < n; j++) {
for(k = 0; k < 6; k++)
DEBUG_MISC((dfd, "%02x ", *pptr++));
DEBUG_MISC((dfd, "\n"));
fflush(dfd);
}
}
#endif
#if 0
/*
* Statistic routines
*
* These will print statistics to the screen, the debug file (dfd), or
* a buffer, depending on "type", so that the stats can be sent over
* the link as well.
*/
void
ttystats(ttyp)
struct ttys *ttyp;
{
struct slirp_ifstats *is = &ttyp->ifstats;
char buff[512];
lprint(" \r\n");
if (if_comp & IF_COMPRESS)
strcpy(buff, "on");
else if (if_comp & IF_NOCOMPRESS)
strcpy(buff, "off");
else
strcpy(buff, "off (for now)");
lprint("Unit %d:\r\n", ttyp->unit);
lprint(" using %s encapsulation (VJ compression is %s)\r\n", (
#ifdef USE_PPP
ttyp->proto==PROTO_PPP?"PPP":
#endif
"SLIP"), buff);
lprint(" %d baudrate\r\n", ttyp->baud);
lprint(" interface is %s\r\n", ttyp->up?"up":"down");
lprint(" using fd %d, guardian pid is %d\r\n", ttyp->fd, ttyp->pid);
#ifndef FULL_BOLT
lprint(" towrite is %d bytes\r\n", ttyp->towrite);
#endif
if (ttyp->zeros)
lprint(" %d zeros have been typed\r\n", ttyp->zeros);
else if (ttyp->ones)
lprint(" %d ones have been typed\r\n", ttyp->ones);
lprint("Interface stats:\r\n");
lprint(" %6d output packets sent (%d bytes)\r\n", is->out_pkts, is->out_bytes);
lprint(" %6d output packets dropped (%d bytes)\r\n", is->out_errpkts, is->out_errbytes);
lprint(" %6d input packets received (%d bytes)\r\n", is->in_pkts, is->in_bytes);
lprint(" %6d input packets dropped (%d bytes)\r\n", is->in_errpkts, is->in_errbytes);
lprint(" %6d bad input packets\r\n", is->in_mbad);
}
void
allttystats()
{
struct ttys *ttyp;
for (ttyp = ttys; ttyp; ttyp = ttyp->next)
ttystats(ttyp);
}
#endif
void
ipstats()
{
lprint(" \r\n");
lprint("IP stats:\r\n");
lprint(" %6d total packets received (%d were unaligned)\r\n",
ipstat.ips_total, ipstat.ips_unaligned);
lprint(" %6d with incorrect version\r\n", ipstat.ips_badvers);
lprint(" %6d with bad header checksum\r\n", ipstat.ips_badsum);
lprint(" %6d with length too short (len < sizeof(iphdr))\r\n", ipstat.ips_tooshort);
lprint(" %6d with length too small (len < ip->len)\r\n", ipstat.ips_toosmall);
lprint(" %6d with bad header length\r\n", ipstat.ips_badhlen);
lprint(" %6d with bad packet length\r\n", ipstat.ips_badlen);
lprint(" %6d fragments received\r\n", ipstat.ips_fragments);
lprint(" %6d fragments dropped\r\n", ipstat.ips_fragdropped);
lprint(" %6d fragments timed out\r\n", ipstat.ips_fragtimeout);
lprint(" %6d packets reassembled ok\r\n", ipstat.ips_reassembled);
lprint(" %6d outgoing packets fragmented\r\n", ipstat.ips_fragmented);
lprint(" %6d total outgoing fragments\r\n", ipstat.ips_ofragments);
lprint(" %6d with bad protocol field\r\n", ipstat.ips_noproto);
lprint(" %6d total packets delivered\r\n", ipstat.ips_delivered);
}
#if 0
void
vjstats()
{
lprint(" \r\n");
lprint("VJ compression stats:\r\n");
lprint(" %6d outbound packets (%d compressed)\r\n",
comp_s.sls_packets, comp_s.sls_compressed);
lprint(" %6d searches for connection stats (%d misses)\r\n",
comp_s.sls_searches, comp_s.sls_misses);
lprint(" %6d inbound uncompressed packets\r\n", comp_s.sls_uncompressedin);
lprint(" %6d inbound compressed packets\r\n", comp_s.sls_compressedin);
lprint(" %6d inbound unknown type packets\r\n", comp_s.sls_errorin);
lprint(" %6d inbound packets tossed due to error\r\n", comp_s.sls_tossed);
}
#endif
void
tcpstats()
{
lprint(" \r\n");
lprint("TCP stats:\r\n");
lprint(" %6d packets sent\r\n", tcpstat.tcps_sndtotal);
lprint(" %6d data packets (%d bytes)\r\n",
tcpstat.tcps_sndpack, tcpstat.tcps_sndbyte);
lprint(" %6d data packets retransmitted (%d bytes)\r\n",
tcpstat.tcps_sndrexmitpack, tcpstat.tcps_sndrexmitbyte);
lprint(" %6d ack-only packets (%d delayed)\r\n",
tcpstat.tcps_sndacks, tcpstat.tcps_delack);
lprint(" %6d URG only packets\r\n", tcpstat.tcps_sndurg);
lprint(" %6d window probe packets\r\n", tcpstat.tcps_sndprobe);
lprint(" %6d window update packets\r\n", tcpstat.tcps_sndwinup);
lprint(" %6d control (SYN/FIN/RST) packets\r\n", tcpstat.tcps_sndctrl);
lprint(" %6d times tcp_output did nothing\r\n", tcpstat.tcps_didnuttin);
lprint(" %6d packets received\r\n", tcpstat.tcps_rcvtotal);
lprint(" %6d acks (for %d bytes)\r\n",
tcpstat.tcps_rcvackpack, tcpstat.tcps_rcvackbyte);
lprint(" %6d duplicate acks\r\n", tcpstat.tcps_rcvdupack);
lprint(" %6d acks for unsent data\r\n", tcpstat.tcps_rcvacktoomuch);
lprint(" %6d packets received in sequence (%d bytes)\r\n",
tcpstat.tcps_rcvpack, tcpstat.tcps_rcvbyte);
lprint(" %6d completely duplicate packets (%d bytes)\r\n",
tcpstat.tcps_rcvduppack, tcpstat.tcps_rcvdupbyte);
lprint(" %6d packets with some duplicate data (%d bytes duped)\r\n",
tcpstat.tcps_rcvpartduppack, tcpstat.tcps_rcvpartdupbyte);
lprint(" %6d out-of-order packets (%d bytes)\r\n",
tcpstat.tcps_rcvoopack, tcpstat.tcps_rcvoobyte);
lprint(" %6d packets of data after window (%d bytes)\r\n",
tcpstat.tcps_rcvpackafterwin, tcpstat.tcps_rcvbyteafterwin);
lprint(" %6d window probes\r\n", tcpstat.tcps_rcvwinprobe);
lprint(" %6d window update packets\r\n", tcpstat.tcps_rcvwinupd);
lprint(" %6d packets received after close\r\n", tcpstat.tcps_rcvafterclose);
lprint(" %6d discarded for bad checksums\r\n", tcpstat.tcps_rcvbadsum);
lprint(" %6d discarded for bad header offset fields\r\n",
tcpstat.tcps_rcvbadoff);
lprint(" %6d connection requests\r\n", tcpstat.tcps_connattempt);
lprint(" %6d connection accepts\r\n", tcpstat.tcps_accepts);
lprint(" %6d connections established (including accepts)\r\n", tcpstat.tcps_connects);
lprint(" %6d connections closed (including %d drop)\r\n",
tcpstat.tcps_closed, tcpstat.tcps_drops);
lprint(" %6d embryonic connections dropped\r\n", tcpstat.tcps_conndrops);
lprint(" %6d segments we tried to get rtt (%d succeeded)\r\n",
tcpstat.tcps_segstimed, tcpstat.tcps_rttupdated);
lprint(" %6d retransmit timeouts\r\n", tcpstat.tcps_rexmttimeo);
lprint(" %6d connections dropped by rxmt timeout\r\n",
tcpstat.tcps_timeoutdrop);
lprint(" %6d persist timeouts\r\n", tcpstat.tcps_persisttimeo);
lprint(" %6d keepalive timeouts\r\n", tcpstat.tcps_keeptimeo);
lprint(" %6d keepalive probes sent\r\n", tcpstat.tcps_keepprobe);
lprint(" %6d connections dropped by keepalive\r\n", tcpstat.tcps_keepdrops);
lprint(" %6d correct ACK header predictions\r\n", tcpstat.tcps_predack);
lprint(" %6d correct data packet header predictions\n", tcpstat.tcps_preddat);
lprint(" %6d TCP cache misses\r\n", tcpstat.tcps_socachemiss);
/* lprint(" Packets received too short: %d\r\n", tcpstat.tcps_rcvshort); */
/* lprint(" Segments dropped due to PAWS: %d\r\n", tcpstat.tcps_pawsdrop); */
}
void
udpstats()
{
lprint(" \r\n");
lprint("UDP stats:\r\n");
lprint(" %6d datagrams received\r\n", udpstat.udps_ipackets);
lprint(" %6d with packets shorter than header\r\n", udpstat.udps_hdrops);
lprint(" %6d with bad checksums\r\n", udpstat.udps_badsum);
lprint(" %6d with data length larger than packet\r\n", udpstat.udps_badlen);
lprint(" %6d UDP socket cache misses\r\n", udpstat.udpps_pcbcachemiss);
lprint(" %6d datagrams sent\r\n", udpstat.udps_opackets);
}
void
icmpstats()
{
lprint(" \r\n");
lprint("ICMP stats:\r\n");
lprint(" %6d ICMP packets received\r\n", icmpstat.icps_received);
lprint(" %6d were too short\r\n", icmpstat.icps_tooshort);
lprint(" %6d with bad checksums\r\n", icmpstat.icps_checksum);
lprint(" %6d with type not supported\r\n", icmpstat.icps_notsupp);
lprint(" %6d with bad type feilds\r\n", icmpstat.icps_badtype);
lprint(" %6d ICMP packets sent in reply\r\n", icmpstat.icps_reflect);
}
void
mbufstats()
{
struct SLIRPmbuf *m;
int i;
lprint(" \r\n");
lprint("Mbuf stats:\r\n");
lprint(" %6d mbufs allocated (%d max)\r\n", mbuf_alloced, mbuf_max);
i = 0;
for (m = m_freelist.m_next; m != &m_freelist; m = m->m_next)
i++;
lprint(" %6d mbufs on free list\r\n", i);
i = 0;
for (m = m_usedlist.m_next; m != &m_usedlist; m = m->m_next)
i++;
lprint(" %6d mbufs on used list\r\n", i);
lprint(" %6d mbufs queued as packets\r\n\r\n", if_queued);
}
void sockstats(void)
{
char buff[256];
int n;
struct SLIRPsocket *so;
lprint(" \r\n");
lprint(
"Proto[state] Sock Local Address, Port Remote Address, Port RecvQ SendQ\r\n");
for (so = tcb.so_next; so != &tcb; so = so->so_next) {
n = sprintf(buff, "tcp[%s]", so->so_tcpcb?tcpstates[so->so_tcpcb->t_state]:"NONE");
while (n < 17)
buff[n++] = ' ';
buff[17] = 0;
lprint("%s %3d %15s %5d ",
buff, so->s,
inet_ntoa(so->so_laddr), ntohs(so->so_lport));
lprint("%15s %5d %5d %5d\r\n",
inet_ntoa(so->so_faddr), ntohs(so->so_fport),
so->so_rcv.sb_cc, so->so_snd.sb_cc);
}
for (so = udb.so_next; so != &udb; so = so->so_next) {
n = sprintf(buff, "udp[%d sec]", (so->so_expire - curtime) / 1000);
while (n < 17)
buff[n++] = ' ';
buff[17] = 0;
lprint("%s %3d %15s %5d ",
buff, so->s,
inet_ntoa(so->so_laddr), ntohs(so->so_lport));
lprint("%15s %5d %5d %5d\r\n",
inet_ntoa(so->so_faddr), ntohs(so->so_fport),
so->so_rcv.sb_cc, so->so_snd.sb_cc);
}
}
void printf_sockstats(void)
{
char buff[256];
int n;
struct SLIRPsocket *so;
printf(" \r\n");
printf(
"Proto[state] Sock Local Address, Port Remote Address, Port RecvQ SendQ\r\n");
for (so = tcb.so_next; so != &tcb; so = so->so_next) {
n = sprintf(buff, "tcp[%s]", so->so_tcpcb?tcpstates[so->so_tcpcb->t_state]:"NONE");
while (n < 17)
buff[n++] = ' ';
buff[17] = 0;
printf("%s %3d %15s %5d ",
buff, so->s,
inet_ntoa(so->so_laddr), ntohs(so->so_lport));
printf("%15s %5d %5d %5d\r\n",
inet_ntoa(so->so_faddr), ntohs(so->so_fport),
so->so_rcv.sb_cc, so->so_snd.sb_cc);
}
for (so = udb.so_next; so != &udb; so = so->so_next) {
n = sprintf(buff, "udp[%d sec]", (so->so_expire - curtime) / 1000);
while (n < 17)
buff[n++] = ' ';
buff[17] = 0;
printf("%s %3d %15s %5d ",
buff, so->s,
inet_ntoa(so->so_laddr), ntohs(so->so_lport));
printf("%15s %5d %5d %5d\r\n",
inet_ntoa(so->so_faddr), ntohs(so->so_fport),
so->so_rcv.sb_cc, so->so_snd.sb_cc);
}
printf("\n\n");
}
//Simple code to purge and close open sockets.
//This way we can open/close/open/close..
void purgesocks(void)
{
struct SLIRPsocket *so;
for (so = tcb.so_next; so != &tcb; so = so->so_next) {
closesocket(so->s); //close the socket
}
}
#if 1
void
slirp_exit(exit_status)
int exit_status;
{
// struct ttys *ttyp;
DEBUG_CALL("slirp_exit");
DEBUG_ARG("exit_status = %d", exit_status);
if (dostats) {
lprint_print = (int (*) _P((void *, const char *, va_list)))vfprintf;
if (!dfd)
debug_init("slirp_stats", 0xf);
lprint_arg = (char **)&dfd;
ipstats();
tcpstats();
udpstats();
icmpstats();
mbufstats();
sockstats();
fclose(dfd);
// allttystats();
// vjstats();
}
// for (ttyp = ttys; ttyp; ttyp = ttyp->next)
// tty_detached(ttyp, 1);
// if (slirp_forked) {
// /* Menendez time */
// if (kill(getppid(), SIGQUIT) < 0)
// lprint("Couldn't kill parent process %ld!\n",
// (long) getppid());
// }
/* Restore the terminal if we gotta */
// if(slirp_tty_restore)
// tcsetattr(0,TCSANOW, &slirp_tty_settings); /* NOW DAMMIT! */
// exit(exit_status);
//This will iterate though the sockets, and close them all (think redirects)
//PCem will have SLiRP open, close several times, which trips up SLiRP
//So for now I go through the sockets and close them
purgesocks();
}
#endif

View File

@@ -1,49 +1,51 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/* /*
* Copyright (c) 1995 Danny Gasparovski. * Copyright (c) 1995 Danny Gasparovski.
*
* Please read the file COPYRIGHT for the
* terms and conditions of the copyright.
*/ */
#define PRN_STDERR 1 #ifndef DEBUG_H_
#define PRN_SPRINTF 2 #define DEBUG_H_
#define DBG_CALL (1 << 0)
#define DBG_MISC (1 << 1)
#define DBG_ERROR (1 << 2)
#define DBG_TFTP (1 << 3)
extern FILE *dfd;
extern FILE *lfd;
extern int dostats;
extern int slirp_debug; extern int slirp_debug;
#define DBG_CALL 0x1 #define DEBUG_CALL(fmt, ...) \
#define DBG_MISC 0x2 do { \
#define DBG_ERROR 0x4 if (G_UNLIKELY(slirp_debug & DBG_CALL)) { \
#define DEBUG_DEFAULT DBG_CALL|DBG_MISC|DBG_ERROR g_debug(fmt "...", ##__VA_ARGS__); \
} \
} while (0)
#ifdef SLIRP_DEBUG #define DEBUG_ARG(fmt, ...) \
#define DEBUG_CALL(x) if (slirp_debug & DBG_CALL) { fprintf(dfd, "%s...\n", x); fflush(dfd); } do { \
#define DEBUG_ARG(x, y) if (slirp_debug & DBG_CALL) { fputc(' ', dfd); fprintf(dfd, x, y); fputc('\n', dfd); fflush(dfd); } if (G_UNLIKELY(slirp_debug & DBG_CALL)) { \
#define DEBUG_ARGS(x) if (slirp_debug & DBG_CALL) { fprintf x ; fflush(dfd); } g_debug(" " fmt, ##__VA_ARGS__); \
#define DEBUG_MISC(x) if (slirp_debug & DBG_MISC) { fprintf x ; fflush(dfd); } } \
#define DEBUG_ERROR(x) if (slirp_debug & DBG_ERROR) {fprintf x ; fflush(dfd); } } while (0)
#define DEBUG_MISC(fmt, ...) \
do { \
if (G_UNLIKELY(slirp_debug & DBG_MISC)) { \
g_debug(fmt, ##__VA_ARGS__); \
} \
} while (0)
#else #define DEBUG_ERROR(fmt, ...) \
do { \
if (G_UNLIKELY(slirp_debug & DBG_ERROR)) { \
g_debug(fmt, ##__VA_ARGS__); \
} \
} while (0)
#define DEBUG_CALL(x) #define DEBUG_TFTP(fmt, ...) \
#define DEBUG_ARG(x, y) do { \
#define DEBUG_ARGS(x) if (G_UNLIKELY(slirp_debug & DBG_TFTP)) { \
#define DEBUG_MISC(x) g_debug(fmt, ##__VA_ARGS__); \
#define DEBUG_ERROR(x) } \
} while (0)
#endif
void debug_init _P((char *, int));
void allttystats _P((void));
void ipstats _P((void));
void vjstats _P((void));
void tcpstats _P((void));
void udpstats _P((void));
void icmpstats _P((void));
void mbufstats _P((void));
void sockstats _P((void));
void slirp_exit _P((int));
#endif /* DEBUG_H_ */

224
src/network/slirp/dhcpv6.c Normal file
View File

@@ -0,0 +1,224 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/*
* SLIRP stateless DHCPv6
*
* We only support stateless DHCPv6, e.g. for network booting.
* See RFC 3315, RFC 3736, RFC 3646 and RFC 5970 for details.
*
* Copyright 2016 Thomas Huth, Red Hat Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "slirp.h"
#include "dhcpv6.h"
/* DHCPv6 message types */
#define MSGTYPE_REPLY 7
#define MSGTYPE_INFO_REQUEST 11
/* DHCPv6 option types */
#define OPTION_CLIENTID 1
#define OPTION_IAADDR 5
#define OPTION_ORO 6
#define OPTION_DNS_SERVERS 23
#define OPTION_BOOTFILE_URL 59
struct requested_infos {
uint8_t *client_id;
int client_id_len;
bool want_dns;
bool want_boot_url;
};
/**
* Analyze the info request message sent by the client to see what data it
* provided and what it wants to have. The information is gathered in the
* "requested_infos" struct. Note that client_id (if provided) points into
* the odata region, thus the caller must keep odata valid as long as it
* needs to access the requested_infos struct.
*/
static int dhcpv6_parse_info_request(Slirp *slirp, uint8_t *odata, int olen,
struct requested_infos *ri)
{
int i, req_opt;
while (olen > 4) {
/* Parse one option */
int option = odata[0] << 8 | odata[1];
int len = odata[2] << 8 | odata[3];
if (len + 4 > olen) {
slirp->cb->guest_error("Guest sent bad DHCPv6 packet!",
slirp->opaque);
return -E2BIG;
}
switch (option) {
case OPTION_IAADDR:
/* According to RFC3315, we must discard requests with IA option */
return -EINVAL;
case OPTION_CLIENTID:
if (len > 256) {
/* Avoid very long IDs which could cause problems later */
return -E2BIG;
}
ri->client_id = odata + 4;
ri->client_id_len = len;
break;
case OPTION_ORO: /* Option request option */
if (len & 1) {
return -EINVAL;
}
/* Check which options the client wants to have */
for (i = 0; i < len; i += 2) {
req_opt = odata[4 + i] << 8 | odata[4 + i + 1];
switch (req_opt) {
case OPTION_DNS_SERVERS:
ri->want_dns = true;
break;
case OPTION_BOOTFILE_URL:
ri->want_boot_url = true;
break;
default:
DEBUG_MISC("dhcpv6: Unsupported option request %d",
req_opt);
}
}
break;
default:
DEBUG_MISC("dhcpv6 info req: Unsupported option %d, len=%d", option,
len);
}
odata += len + 4;
olen -= len + 4;
}
return 0;
}
/**
* Handle information request messages
*/
static void dhcpv6_info_request(Slirp *slirp, struct sockaddr_in6 *srcsas,
uint32_t xid, uint8_t *odata, int olen)
{
struct requested_infos ri = { NULL };
struct sockaddr_in6 sa6, da6;
struct mbuf *m;
uint8_t *resp;
if (dhcpv6_parse_info_request(slirp, odata, olen, &ri) < 0) {
return;
}
m = m_get(slirp);
if (!m) {
return;
}
memset(m->m_data, 0, m->m_size);
m->m_data += IF_MAXLINKHDR;
resp = (uint8_t *)m->m_data + sizeof(struct ip6) + sizeof(struct udphdr);
/* Fill in response */
*resp++ = MSGTYPE_REPLY;
*resp++ = (uint8_t)(xid >> 16);
*resp++ = (uint8_t)(xid >> 8);
*resp++ = (uint8_t)xid;
if (ri.client_id) {
*resp++ = OPTION_CLIENTID >> 8; /* option-code high byte */
*resp++ = OPTION_CLIENTID; /* option-code low byte */
*resp++ = ri.client_id_len >> 8; /* option-len high byte */
*resp++ = ri.client_id_len; /* option-len low byte */
memcpy(resp, ri.client_id, ri.client_id_len);
resp += ri.client_id_len;
}
if (ri.want_dns) {
*resp++ = OPTION_DNS_SERVERS >> 8; /* option-code high byte */
*resp++ = OPTION_DNS_SERVERS; /* option-code low byte */
*resp++ = 0; /* option-len high byte */
*resp++ = 16; /* option-len low byte */
memcpy(resp, &slirp->vnameserver_addr6, 16);
resp += 16;
}
if (ri.want_boot_url) {
uint8_t *sa = slirp->vhost_addr6.s6_addr;
int slen, smaxlen;
*resp++ = OPTION_BOOTFILE_URL >> 8; /* option-code high byte */
*resp++ = OPTION_BOOTFILE_URL; /* option-code low byte */
smaxlen = (uint8_t *)m->m_data + slirp->if_mtu - (resp + 2);
slen = slirp_fmt((char *)resp + 2, smaxlen,
"tftp://[%02x%02x:%02x%02x:%02x%02x:%02x%02x:"
"%02x%02x:%02x%02x:%02x%02x:%02x%02x]/%s",
sa[0], sa[1], sa[2], sa[3], sa[4], sa[5], sa[6], sa[7],
sa[8], sa[9], sa[10], sa[11], sa[12], sa[13], sa[14],
sa[15], slirp->bootp_filename);
*resp++ = slen >> 8; /* option-len high byte */
*resp++ = slen; /* option-len low byte */
resp += slen;
}
sa6.sin6_addr = slirp->vhost_addr6;
sa6.sin6_port = DHCPV6_SERVER_PORT;
da6.sin6_addr = srcsas->sin6_addr;
da6.sin6_port = srcsas->sin6_port;
m->m_data += sizeof(struct ip6) + sizeof(struct udphdr);
m->m_len = resp - (uint8_t *)m->m_data;
udp6_output(NULL, m, &sa6, &da6);
}
/**
* Handle DHCPv6 messages sent by the client
*/
void dhcpv6_input(struct sockaddr_in6 *srcsas, struct mbuf *m)
{
uint8_t *data = (uint8_t *)m->m_data + sizeof(struct udphdr);
int data_len = m->m_len - sizeof(struct udphdr);
uint32_t xid;
if (data_len < 4) {
return;
}
xid = ntohl(*(uint32_t *)data) & 0xffffff;
switch (data[0]) {
case MSGTYPE_INFO_REQUEST:
dhcpv6_info_request(m->slirp, srcsas, xid, &data[4], data_len - 4);
break;
default:
DEBUG_MISC("dhcpv6_input: Unsupported message type 0x%x", data[0]);
}
}

View File

@@ -0,0 +1,68 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/*
* Definitions and prototypes for SLIRP stateless DHCPv6
*
* Copyright 2016 Thomas Huth, Red Hat Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef SLIRP_DHCPV6_H
#define SLIRP_DHCPV6_H
#define DHCPV6_SERVER_PORT 547
#define ALLDHCP_MULTICAST \
{ \
.s6_addr = { \
0xff, \
0x02, \
0x00, \
0x00, \
0x00, \
0x00, \
0x00, \
0x00, \
0x00, \
0x00, \
0x00, \
0x00, \
0x00, \
0x01, \
0x00, \
0x02 \
} \
}
#define in6_dhcp_multicast(a) in6_equal(a, &(struct in6_addr)ALLDHCP_MULTICAST)
void dhcpv6_input(struct sockaddr_in6 *srcsas, struct mbuf *m);
#endif

View File

@@ -0,0 +1,306 @@
/* SPDX-License-Identifier: MIT */
/*
* Domain search option for DHCP (RFC 3397)
*
* Copyright (c) 2012 Klaus Stengel
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "slirp.h"
static const uint8_t RFC3397_OPT_DOMAIN_SEARCH = 119;
static const uint8_t MAX_OPT_LEN = 255;
static const uint8_t OPT_HEADER_LEN = 2;
static const uint8_t REFERENCE_LEN = 2;
struct compact_domain;
typedef struct compact_domain {
struct compact_domain *self;
struct compact_domain *refdom;
uint8_t *labels;
size_t len;
size_t common_octets;
} CompactDomain;
static size_t domain_suffix_diffoff(const CompactDomain *a,
const CompactDomain *b)
{
size_t la = a->len, lb = b->len;
uint8_t *da = a->labels + la, *db = b->labels + lb;
size_t i, lm = (la < lb) ? la : lb;
for (i = 0; i < lm; i++) {
da--;
db--;
if (*da != *db) {
break;
}
}
return i;
}
static int domain_suffix_ord(const void *cva, const void *cvb)
{
const CompactDomain *a = cva, *b = cvb;
size_t la = a->len, lb = b->len;
size_t doff = domain_suffix_diffoff(a, b);
uint8_t ca = a->labels[la - doff];
uint8_t cb = b->labels[lb - doff];
if (ca < cb) {
return -1;
}
if (ca > cb) {
return 1;
}
if (la < lb) {
return -1;
}
if (la > lb) {
return 1;
}
return 0;
}
static size_t domain_common_label(CompactDomain *a, CompactDomain *b)
{
size_t res, doff = domain_suffix_diffoff(a, b);
uint8_t *first_eq_pos = a->labels + (a->len - doff);
uint8_t *label = a->labels;
while (*label && label < first_eq_pos) {
label += *label + 1;
}
res = a->len - (label - a->labels);
/* only report if it can help to reduce the packet size */
return (res > REFERENCE_LEN) ? res : 0;
}
static void domain_fixup_order(CompactDomain *cd, size_t n)
{
size_t i;
for (i = 0; i < n; i++) {
CompactDomain *cur = cd + i, *next = cd[i].self;
while (!cur->common_octets) {
CompactDomain *tmp = next->self; /* backup target value */
next->self = cur;
cur->common_octets++;
cur = next;
next = tmp;
}
}
}
static void domain_mklabels(CompactDomain *cd, const char *input)
{
uint8_t *len_marker = cd->labels;
uint8_t *output = len_marker; /* pre-incremented */
const char *in = input;
char cur_chr;
size_t len = 0;
if (cd->len == 0) {
goto fail;
}
cd->len++;
do {
cur_chr = *in++;
if (cur_chr == '.' || cur_chr == '\0') {
len = output - len_marker;
if ((len == 0 && cur_chr == '.') || len >= 64) {
goto fail;
}
*len_marker = len;
output++;
len_marker = output;
} else {
output++;
*output = cur_chr;
}
} while (cur_chr != '\0');
/* ensure proper zero-termination */
if (len != 0) {
*len_marker = 0;
cd->len++;
}
return;
fail:
g_warning("failed to parse domain name '%s'\n", input);
cd->len = 0;
}
static void domain_mkxrefs(CompactDomain *doms, CompactDomain *last,
size_t depth)
{
CompactDomain *i = doms, *target = doms;
do {
if (i->labels < target->labels) {
target = i;
}
} while (i++ != last);
for (i = doms; i != last; i++) {
CompactDomain *group_last;
size_t next_depth;
if (i->common_octets == depth) {
continue;
}
next_depth = -1;
for (group_last = i; group_last != last; group_last++) {
size_t co = group_last->common_octets;
if (co <= depth) {
break;
}
if (co < next_depth) {
next_depth = co;
}
}
domain_mkxrefs(i, group_last, next_depth);
i = group_last;
if (i == last) {
break;
}
}
if (depth == 0) {
return;
}
i = doms;
do {
if (i != target && i->refdom == NULL) {
i->refdom = target;
i->common_octets = depth;
}
} while (i++ != last);
}
static size_t domain_compactify(CompactDomain *domains, size_t n)
{
uint8_t *start = domains->self->labels, *outptr = start;
size_t i;
for (i = 0; i < n; i++) {
CompactDomain *cd = domains[i].self;
CompactDomain *rd = cd->refdom;
if (rd != NULL) {
size_t moff = (rd->labels - start) + (rd->len - cd->common_octets);
if (moff < 0x3FFFu) {
cd->len -= cd->common_octets - 2;
cd->labels[cd->len - 1] = moff & 0xFFu;
cd->labels[cd->len - 2] = 0xC0u | (moff >> 8);
}
}
if (cd->labels != outptr) {
memmove(outptr, cd->labels, cd->len);
cd->labels = outptr;
}
outptr += cd->len;
}
return outptr - start;
}
int translate_dnssearch(Slirp *s, const char **names)
{
size_t blocks, bsrc_start, bsrc_end, bdst_start;
size_t i, num_domains, memreq = 0;
uint8_t *result = NULL, *outptr;
CompactDomain *domains = NULL;
num_domains = g_strv_length((GStrv)(void *)names);
if (num_domains == 0) {
return -2;
}
domains = g_malloc(num_domains * sizeof(*domains));
for (i = 0; i < num_domains; i++) {
size_t nlen = strlen(names[i]);
memreq += nlen + 2; /* 1 zero octet + 1 label length octet */
domains[i].self = domains + i;
domains[i].len = nlen;
domains[i].common_octets = 0;
domains[i].refdom = NULL;
}
/* reserve extra 2 header bytes for each 255 bytes of output */
memreq += DIV_ROUND_UP(memreq, MAX_OPT_LEN) * OPT_HEADER_LEN;
result = g_malloc(memreq * sizeof(*result));
outptr = result;
for (i = 0; i < num_domains; i++) {
domains[i].labels = outptr;
domain_mklabels(domains + i, names[i]);
outptr += domains[i].len;
}
if (outptr == result) {
g_free(domains);
g_free(result);
return -1;
}
qsort(domains, num_domains, sizeof(*domains), domain_suffix_ord);
domain_fixup_order(domains, num_domains);
for (i = 1; i < num_domains; i++) {
size_t cl = domain_common_label(domains + i - 1, domains + i);
domains[i - 1].common_octets = cl;
}
domain_mkxrefs(domains, domains + num_domains - 1, 0);
memreq = domain_compactify(domains, num_domains);
blocks = DIV_ROUND_UP(memreq, MAX_OPT_LEN);
bsrc_end = memreq;
bsrc_start = (blocks - 1) * MAX_OPT_LEN;
bdst_start = bsrc_start + blocks * OPT_HEADER_LEN;
memreq += blocks * OPT_HEADER_LEN;
while (blocks--) {
size_t len = bsrc_end - bsrc_start;
memmove(result + bdst_start, result + bsrc_start, len);
result[bdst_start - 2] = RFC3397_OPT_DOMAIN_SEARCH;
result[bdst_start - 1] = len;
bsrc_end = bsrc_start;
bsrc_start -= MAX_OPT_LEN;
bdst_start -= MAX_OPT_LEN + OPT_HEADER_LEN;
}
g_free(domains);
s->vdnssearch = result;
s->vdnssearch_len = memreq;
return 0;
}

View File

@@ -1,65 +0,0 @@
/*
* Copyright (c) 1982, 1986, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)icmp_var.h 8.1 (Berkeley) 6/10/93
* icmp_var.h,v 1.4 1995/02/16 00:27:40 wollman Exp
*/
#ifndef _NETINET_ICMP_VAR_H_
#define _NETINET_ICMP_VAR_H_
/*
* Variables related to this implementation
* of the internet control message protocol.
*/
struct icmpstat {
/* statistics related to input messages processed */
u_long icps_received; /* #ICMP packets received */
u_long icps_tooshort; /* packet < ICMP_MINLEN */
u_long icps_checksum; /* bad checksum */
u_long icps_notsupp; /* #ICMP packets not supported */
u_long icps_badtype; /* #with bad type feild */
u_long icps_reflect; /* number of responses */
};
/*
* Names for ICMP sysctl objects
*/
#define ICMPCTL_MASKREPL 1 /* allow replies to netmask requests */
#define ICMPCTL_STATS 2 /* statistics (read-only) */
#define ICMPCTL_MAXID 3
#define ICMPCTL_NAMES { \
{ 0, 0 }, \
{ "maskrepl", CTLTYPE_INT }, \
{ "stats", CTLTYPE_STRUCT }, \
}
extern struct icmpstat icmpstat;
#endif

View File

@@ -1,322 +1,213 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/* /*
* Copyright (c) 1995 Danny Gasparovski. * Copyright (c) 1995 Danny Gasparovski.
*
* Please read the file COPYRIGHT for the
* terms and conditions of the copyright.
*/ */
#include "slirp.h" #include "slirp.h"
int if_mtu, if_mru; static void ifs_insque(struct mbuf *ifm, struct mbuf *ifmhead)
int if_comp;
int if_maxlinkhdr;
int if_queued = 0; /* Number of packets queued so far */
int if_thresh = 10; /* Number of packets queued before we start sending
* (to prevent allocing too many SLIRPmbufs) */
struct SLIRPmbuf if_fastq; /* fast queue (for interactive data) */
struct SLIRPmbuf if_batchq; /* queue for non-interactive data */
struct SLIRPmbuf *next_m; /* Pointer to next SLIRPmbuf to output */
#define ifs_init(ifm) ((ifm)->ifs_next = (ifm)->ifs_prev = (ifm))
void
ifs_insque(ifm, ifmhead)
struct SLIRPmbuf *ifm, *ifmhead;
{ {
ifm->ifs_next = ifmhead->ifs_next; ifm->ifs_next = ifmhead->ifs_next;
ifmhead->ifs_next = ifm; ifmhead->ifs_next = ifm;
ifm->ifs_prev = ifmhead; ifm->ifs_prev = ifmhead;
ifm->ifs_next->ifs_prev = ifm; ifm->ifs_next->ifs_prev = ifm;
} }
void static void ifs_remque(struct mbuf *ifm)
ifs_remque(ifm)
struct SLIRPmbuf *ifm;
{ {
ifm->ifs_prev->ifs_next = ifm->ifs_next; ifm->ifs_prev->ifs_next = ifm->ifs_next;
ifm->ifs_next->ifs_prev = ifm->ifs_prev; ifm->ifs_next->ifs_prev = ifm->ifs_prev;
} }
void void if_init(Slirp *slirp)
if_init()
{ {
#if 0 slirp->if_fastq.qh_link = slirp->if_fastq.qh_rlink = &slirp->if_fastq;
/* slirp->if_batchq.qh_link = slirp->if_batchq.qh_rlink = &slirp->if_batchq;
* Set if_maxlinkhdr to 48 because it's 40 bytes for TCP/IP,
* and 8 bytes for PPP, but need to have it on an 8byte boundary
*/
#ifdef USE_PPP
if_maxlinkhdr = 48;
#else
if_maxlinkhdr = 40;
#endif
#else
/* 2 for alignment, 14 for ethernet, 40 for TCP/IP */
if_maxlinkhdr = 2 + 14 + 40;
#endif
if_mtu = 1500;
if_mru = 1500;
if_comp = IF_AUTOCOMP;
if_fastq.ifq_next = if_fastq.ifq_prev = &if_fastq;
if_batchq.ifq_next = if_batchq.ifq_prev = &if_batchq;
// sl_compress_init(&comp_s);
next_m = &if_batchq;
} }
#if 0
/*
* This shouldn't be needed since the modem is blocking and
* we don't expect any signals, but what the hell..
*/
inline int
writen(fd, bptr, n)
int fd;
char *bptr;
int n;
{
int ret;
int total;
/* This should succeed most of the time */
ret = send(fd, bptr, n,0);
if (ret == n || ret <= 0)
return ret;
/* Didn't write everything, go into the loop */
total = ret;
while (n > total) {
ret = send(fd, bptr+total, n-total,0);
if (ret <= 0)
return ret;
total += ret;
}
return total;
}
/*
* if_input - read() the tty, do "top level" processing (ie: check for any escapes),
* and pass onto (*ttyp->if_input)
*
* XXXXX Any zeros arriving by themselves are NOT placed into the arriving packet.
*/
#define INBUFF_SIZE 2048 /* XXX */
void
if_input(ttyp)
struct ttys *ttyp;
{
u_char if_inbuff[INBUFF_SIZE];
int if_n;
DEBUG_CALL("if_input");
DEBUG_ARG("ttyp = %lx", (long)ttyp);
if_n = recv(ttyp->fd, (char *)if_inbuff, INBUFF_SIZE,0);
DEBUG_MISC((dfd, " read %d bytes\n", if_n));
if (if_n <= 0) {
if (if_n == 0 || (errno != EINTR && errno != EAGAIN)) {
if (ttyp->up)
link_up--;
tty_detached(ttyp, 0);
}
return;
}
if (if_n == 1) {
if (*if_inbuff == '0') {
ttyp->ones = 0;
if (++ttyp->zeros >= 5)
slirp_exit(0);
return;
}
if (*if_inbuff == '1') {
ttyp->zeros = 0;
if (++ttyp->ones >= 5)
tty_detached(ttyp, 0);
return;
}
}
ttyp->ones = ttyp->zeros = 0;
(*ttyp->if_input)(ttyp, if_inbuff, if_n);
}
#endif
/* /*
* if_output: Queue packet into an output queue. * if_output: Queue packet into an output queue.
* There are 2 output queue's, if_fastq and if_batchq. * There are 2 output queue's, if_fastq and if_batchq.
* Each output queue is a doubly linked list of double linked lists * Each output queue is a doubly linked list of double linked lists
* of SLIRPmbufs, each list belonging to one "session" (socket). This * of mbufs, each list belonging to one "session" (socket). This
* way, we can output packets fairly by sending one packet from each * way, we can output packets fairly by sending one packet from each
* session, instead of all the packets from one session, then all packets * session, instead of all the packets from one session, then all packets
* from the next session, etc. Packets on the if_fastq get absolute * from the next session, etc. Packets on the if_fastq get absolute
* priority, but if one session hogs the link, it gets "downgraded" * priority, but if one session hogs the link, it gets "downgraded"
* to the batchq until it runs out of packets, then it'll return * to the batchq until it runs out of packets, then it'll return
* to the fastq (eg. if the user does an ls -alR in a telnet session, * to the fastq (eg. if the user does an ls -alR in a telnet session,
* it'll temporarily get downgraded to the batchq) * it'll temporarily get downgraded to the batchq)
*/ */
void void if_output(struct socket *so, struct mbuf *ifm)
if_output(so, ifm)
struct SLIRPsocket *so;
struct SLIRPmbuf *ifm;
{ {
struct SLIRPmbuf *ifq; Slirp *slirp = ifm->slirp;
int on_fastq = 1; struct mbuf *ifq;
int on_fastq = 1;
DEBUG_CALL("if_output");
DEBUG_ARG("so = %lx", (long)so);
DEBUG_ARG("ifm = %lx", (long)ifm);
/*
* First remove the SLIRPmbuf from m_usedlist,
* since we're gonna use m_next and m_prev ourselves
* XXX Shouldn't need this, gotta change dtom() etc.
*/
if (ifm->m_flags & M_USEDLIST) {
remque(ifm);
ifm->m_flags &= ~M_USEDLIST;
}
/*
* See if there's already a batchq list for this session.
* This can include an interactive session, which should go on fastq,
* but gets too greedy... hence it'll be downgraded from fastq to batchq.
* We mustn't put this packet back on the fastq (or we'll send it out of order)
* XXX add cache here?
*/
for (ifq = if_batchq.ifq_prev; ifq != &if_batchq; ifq = ifq->ifq_prev) {
if (so == ifq->ifq_so) {
/* A match! */
ifm->ifq_so = so;
ifs_insque(ifm, ifq->ifs_prev);
goto diddit;
}
}
/* No match, check which queue to put it on */
if (so && (so->so_iptos & IPTOS_LOWDELAY)) {
ifq = if_fastq.ifq_prev;
on_fastq = 1;
/*
* Check if this packet is a part of the last
* packet's session
*/
if (ifq->ifq_so == so) {
ifm->ifq_so = so;
ifs_insque(ifm, ifq->ifs_prev);
goto diddit;
}
} else
ifq = if_batchq.ifq_prev;
/* Create a new doubly linked list for this session */
ifm->ifq_so = so;
ifs_init(ifm);
insque(ifm, ifq);
diddit:
++if_queued;
if (so) {
/* Update *_queued */
so->so_queued++;
so->so_nqueued++;
/*
* Check if the interactive session should be downgraded to
* the batchq. A session is downgraded if it has queued 6
* packets without pausing, and at least 3 of those packets
* have been sent over the link
* (XXX These are arbitrary numbers, probably not optimal..)
*/
if (on_fastq && ((so->so_nqueued >= 6) &&
(so->so_nqueued - so->so_queued) >= 3)) {
/* Remove from current queue... */
remque(ifm->ifs_next);
/* ...And insert in the new. That'll teach ya! */
insque(ifm->ifs_next, &if_batchq);
}
}
#ifndef FULL_BOLT DEBUG_CALL("if_output");
/* DEBUG_ARG("so = %p", so);
* This prevents us from malloc()ing too many SLIRPmbufs DEBUG_ARG("ifm = %p", ifm);
*/
if (link_up) { /*
/* if_start will check towrite */ * First remove the mbuf from m_usedlist,
if_start(); * since we're gonna use m_next and m_prev ourselves
} * XXX Shouldn't need this, gotta change dtom() etc.
#endif */
if (ifm->m_flags & M_USEDLIST) {
remque(ifm);
ifm->m_flags &= ~M_USEDLIST;
}
/*
* See if there's already a batchq list for this session.
* This can include an interactive session, which should go on fastq,
* but gets too greedy... hence it'll be downgraded from fastq to batchq.
* We mustn't put this packet back on the fastq (or we'll send it out of
* order)
* XXX add cache here?
*/
if (so) {
for (ifq = (struct mbuf *)slirp->if_batchq.qh_rlink;
(struct quehead *)ifq != &slirp->if_batchq; ifq = ifq->ifq_prev) {
if (so == ifq->ifq_so) {
/* A match! */
ifm->ifq_so = so;
ifs_insque(ifm, ifq->ifs_prev);
goto diddit;
}
}
}
/* No match, check which queue to put it on */
if (so && (so->so_iptos & IPTOS_LOWDELAY)) {
ifq = (struct mbuf *)slirp->if_fastq.qh_rlink;
on_fastq = 1;
/*
* Check if this packet is a part of the last
* packet's session
*/
if (ifq->ifq_so == so) {
ifm->ifq_so = so;
ifs_insque(ifm, ifq->ifs_prev);
goto diddit;
}
} else {
ifq = (struct mbuf *)slirp->if_batchq.qh_rlink;
}
/* Create a new doubly linked list for this session */
ifm->ifq_so = so;
ifs_init(ifm);
insque(ifm, ifq);
diddit:
if (so) {
/* Update *_queued */
so->so_queued++;
so->so_nqueued++;
/*
* Check if the interactive session should be downgraded to
* the batchq. A session is downgraded if it has queued 6
* packets without pausing, and at least 3 of those packets
* have been sent over the link
* (XXX These are arbitrary numbers, probably not optimal..)
*/
if (on_fastq &&
((so->so_nqueued >= 6) && (so->so_nqueued - so->so_queued) >= 3)) {
/* Remove from current queue... */
remque(ifm->ifs_next);
/* ...And insert in the new. That'll teach ya! */
insque(ifm->ifs_next, &slirp->if_batchq);
}
}
/*
* This prevents us from malloc()ing too many mbufs
*/
if_start(ifm->slirp);
} }
/* /*
* Send a packet * Send one packet from each session.
* We choose a packet based on it's position in the output queues;
* If there are packets on the fastq, they are sent FIFO, before * If there are packets on the fastq, they are sent FIFO, before
* everything else. Otherwise we choose the first packet from the * everything else. Then we choose the first packet from each
* batchq and send it. the next packet chosen will be from the session * batchq session (socket) and send it.
* after this one, then the session after that one, and so on.. So, * For example, if there are 3 ftp sessions fighting for bandwidth,
* for example, if there are 3 ftp session's fighting for bandwidth,
* one packet will be sent from the first session, then one packet * one packet will be sent from the first session, then one packet
* from the second session, then one packet from the third, then back * from the second session, then one packet from the third.
* to the first, etc. etc.
*/ */
void void if_start(Slirp *slirp)
if_start(void)
{ {
struct SLIRPmbuf *ifm, *ifqt; uint64_t now = slirp->cb->clock_get_ns(slirp->opaque);
bool from_batchq = false;
DEBUG_CALL("if_start"); struct mbuf *ifm, *ifm_next, *ifqt;
if (if_queued == 0)
return; /* Nothing to do */
again:
/* check if we can really output */
if (!slirp_can_output())
return;
/* DEBUG_CALL("if_start");
* See which queue to get next packet from
* If there's something in the fastq, select it immediately
*/
if (if_fastq.ifq_next != &if_fastq) {
ifm = if_fastq.ifq_next;
} else {
/* Nothing on fastq, see if next_m is valid */
if (next_m != &if_batchq)
ifm = next_m;
else
ifm = if_batchq.ifq_next;
/* Set which packet to send on next iteration */
next_m = ifm->ifq_next;
}
/* Remove it from the queue */
ifqt = ifm->ifq_prev;
remque(ifm);
--if_queued;
/* If there are more packets for this session, re-queue them */
if (ifm->ifs_next != /* ifm->ifs_prev != */ ifm) {
insque(ifm->ifs_next, ifqt);
ifs_remque(ifm);
}
/* Update so_queued */
if (ifm->ifq_so) {
if (--ifm->ifq_so->so_queued == 0)
/* If there's no more queued, reset nqueued */
ifm->ifq_so->so_nqueued = 0;
}
/* Encapsulate the packet for sending */
if_encap((uint8_t*)ifm->m_data, ifm->m_len);
m_free(ifm); if (slirp->if_start_busy) {
return;
}
slirp->if_start_busy = true;
if (if_queued) struct mbuf *batch_head = NULL;
goto again; if (slirp->if_batchq.qh_link != &slirp->if_batchq) {
batch_head = (struct mbuf *)slirp->if_batchq.qh_link;
}
if (slirp->if_fastq.qh_link != &slirp->if_fastq) {
ifm_next = (struct mbuf *)slirp->if_fastq.qh_link;
} else if (batch_head) {
/* Nothing on fastq, pick up from batchq */
ifm_next = batch_head;
from_batchq = true;
} else {
ifm_next = NULL;
}
while (ifm_next) {
ifm = ifm_next;
ifm_next = ifm->ifq_next;
if ((struct quehead *)ifm_next == &slirp->if_fastq) {
/* No more packets in fastq, switch to batchq */
ifm_next = batch_head;
from_batchq = true;
}
if ((struct quehead *)ifm_next == &slirp->if_batchq) {
/* end of batchq */
ifm_next = NULL;
}
/* Try to send packet unless it already expired */
if (ifm->expiration_date >= now && !if_encap(slirp, ifm)) {
/* Packet is delayed due to pending ARP or NDP resolution */
continue;
}
/* Remove it from the queue */
ifqt = ifm->ifq_prev;
remque(ifm);
/* If there are more packets for this session, re-queue them */
if (ifm->ifs_next != ifm) {
struct mbuf *next = ifm->ifs_next;
insque(next, ifqt);
ifs_remque(ifm);
if (!from_batchq) {
ifm_next = next;
}
}
/* Update so_queued */
if (ifm->ifq_so && --ifm->ifq_so->so_queued == 0) {
/* If there's no more queued, reset nqueued */
ifm->ifq_so->so_nqueued = 0;
}
m_free(ifm);
}
slirp->if_start_busy = false;
} }

View File

@@ -1,50 +1,25 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/* /*
* Copyright (c) 1995 Danny Gasparovski. * Copyright (c) 1995 Danny Gasparovski.
*
* Please read the file COPYRIGHT for the
* terms and conditions of the copyright.
*/ */
#ifndef _IF_H_ #ifndef IF_H
#define _IF_H_ #define IF_H
#define IF_COMPRESS 0x01 /* We want compression */ #define IF_COMPRESS 0x01 /* We want compression */
#define IF_NOCOMPRESS 0x02 /* Do not do compression */ #define IF_NOCOMPRESS 0x02 /* Do not do compression */
#define IF_AUTOCOMP 0x04 /* Autodetect (default) */ #define IF_AUTOCOMP 0x04 /* Autodetect (default) */
#define IF_NOCIDCOMP 0x08 /* CID compression */ #define IF_NOCIDCOMP 0x08 /* CID compression */
/* Needed for FreeBSD */ #define IF_MTU_DEFAULT 1500
#undef if_mtu #define IF_MTU_MIN 68
extern int if_mtu; #define IF_MTU_MAX 65521
extern int if_mru; /* MTU and MRU */ #define IF_MRU_DEFAULT 1500
extern int if_comp; /* Flags for compression */ #define IF_MRU_MIN 68
extern int if_maxlinkhdr; #define IF_MRU_MAX 65521
extern int if_queued; /* Number of packets queued so far */ #define IF_COMP IF_AUTOCOMP /* Flags for compression */
extern int if_thresh; /* Number of packets queued before we start sending
* (to prevent allocing too many SLIRPmbufs) */
extern struct SLIRPmbuf if_fastq; /* fast queue (for interactive data) */ /* 2 for alignment, 14 for ethernet */
extern struct SLIRPmbuf if_batchq; /* queue for non-interactive data */ #define IF_MAXLINKHDR (2 + ETH_HLEN)
extern struct SLIRPmbuf *next_m;
#define ifs_init(ifm) ((ifm)->ifs_next = (ifm)->ifs_prev = (ifm))
/* Interface statistics */
struct slirp_ifstats {
u_int out_pkts; /* Output packets */
u_int out_bytes; /* Output bytes */
u_int out_errpkts; /* Output Error Packets */
u_int out_errbytes; /* Output Error Bytes */
u_int in_pkts; /* Input packets */
u_int in_bytes; /* Input bytes */
u_int in_errpkts; /* Input Error Packets */
u_int in_errbytes; /* Input Error Bytes */
u_int bytes_saved; /* Number of bytes that compression "saved" */
/* ie: number of bytes that didn't need to be sent over the link
* because of compression */
u_int in_mbad; /* Bad incoming packets */
};
#endif #endif

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/* /*
* Copyright (c) 1982, 1986, 1993 * Copyright (c) 1982, 1986, 1993
* The Regents of the University of California. All rights reserved. * The Regents of the University of California. All rights reserved.
@@ -30,225 +31,178 @@
* ip.h,v 1.3 1994/08/21 05:27:30 paul Exp * ip.h,v 1.3 1994/08/21 05:27:30 paul Exp
*/ */
#ifndef _IP_H_ #ifndef IP_H
#define _IP_H_ #define IP_H
#ifdef WORDS_BIGENDIAN #include <tinyglib.h>
# ifndef NTOHL
# define NTOHL(d) #if G_BYTE_ORDER == G_BIG_ENDIAN
# endif #undef NTOHL
# ifndef NTOHS #undef NTOHS
# define NTOHS(d) #undef HTONL
# endif #undef HTONS
# ifndef HTONL #define NTOHL(d)
# define HTONL(d) #define NTOHS(d)
# endif #define HTONL(d)
# ifndef HTONS #define HTONS(d)
# define HTONS(d)
# endif
#else #else
# ifndef NTOHL #ifndef NTOHL
# define NTOHL(d) ((d) = ntohl((d))) #define NTOHL(d) ((d) = ntohl((d)))
# endif #endif
# ifndef NTOHS #ifndef NTOHS
# define NTOHS(d) ((d) = ntohs((u_int16_t)(d))) #define NTOHS(d) ((d) = ntohs((uint16_t)(d)))
# endif #endif
# ifndef HTONL #ifndef HTONL
# define HTONL(d) ((d) = htonl((d))) #define HTONL(d) ((d) = htonl((d)))
# endif #endif
# ifndef HTONS #ifndef HTONS
# define HTONS(d) ((d) = htons((u_int16_t)(d))) #define HTONS(d) ((d) = htons((uint16_t)(d)))
# endif #endif
#endif #endif
typedef u_int32_t n_long; /* long as received from the net */ typedef uint32_t n_long; /* long as received from the net */
/* /*
* Definitions for internet protocol version 4. * Definitions for internet protocol version 4.
* Per RFC 791, September 1981. * Per RFC 791, September 1981.
*/ */
#define IPVERSION 4 #define IPVERSION 4
#if defined(_MSC_VER)
#pragma pack(push, 1)
#endif
/* /*
* Structure of an internet header, naked of options. * Structure of an internet header, naked of options.
*/ */
#ifdef PRAGMA_PACK_SUPPORTED
#pragma pack(1)
#endif
struct ip { struct ip {
#ifdef WORDS_BIGENDIAN #if G_BYTE_ORDER == G_BIG_ENDIAN
u_char ip_v:4, /* version */ uint8_t ip_v : 4, /* version */
ip_hl:4; /* header length */ ip_hl : 4; /* header length */
#else #else
u_char ip_hl:4, /* header length */ uint8_t ip_hl : 4, /* header length */
ip_v:4; /* version */ ip_v : 4; /* version */
#endif #endif
u_int8_t ip_tos; /* type of service */ uint8_t ip_tos; /* type of service */
u_int16_t ip_len; /* total length */ uint16_t ip_len; /* total length */
u_int16_t ip_id; /* identification */ uint16_t ip_id; /* identification */
u_int16_t ip_off; /* fragment offset field */ uint16_t ip_off; /* fragment offset field */
#define IP_DF 0x4000 /* don't fragment flag */ #define IP_DF 0x4000 /* don't fragment flag */
#define IP_MF 0x2000 /* more fragments flag */ #define IP_MF 0x2000 /* more fragments flag */
#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */ #define IP_OFFMASK 0x1fff /* mask for fragmenting bits */
u_int8_t ip_ttl; /* time to live */ uint8_t ip_ttl; /* time to live */
u_int8_t ip_p; /* protocol */ uint8_t ip_p; /* protocol */
u_int16_t ip_sum; /* checksum */ uint16_t ip_sum; /* checksum */
struct in_addr ip_src,ip_dst; /* source and dest address */ struct in_addr ip_src, ip_dst; /* source and dest address */
} PACKED__; } SLIRP_PACKED;
#ifdef PRAGMA_PACK_SUPPORTED #define IP_MAXPACKET 65535 /* maximum packet size */
#pragma pack(PACK_END) //WAS 0
#endif
#define IP_MAXPACKET 65535 /* maximum packet size */
/* /*
* Definitions for IP type of service (ip_tos) * Definitions for IP type of service (ip_tos)
*/ */
#define IPTOS_LOWDELAY 0x10 #define IPTOS_LOWDELAY 0x10
#define IPTOS_THROUGHPUT 0x08 #define IPTOS_THROUGHPUT 0x08
#define IPTOS_RELIABILITY 0x04 #define IPTOS_RELIABILITY 0x04
/* /*
* Definitions for options. * Definitions for options.
*/ */
#define IPOPT_COPIED(o) ((o)&0x80) #define IPOPT_COPIED(o) ((o)&0x80)
#define IPOPT_CLASS(o) ((o)&0x60) #define IPOPT_CLASS(o) ((o)&0x60)
#define IPOPT_NUMBER(o) ((o)&0x1f) #define IPOPT_NUMBER(o) ((o)&0x1f)
#define IPOPT_CONTROL 0x00 #define IPOPT_CONTROL 0x00
#define IPOPT_RESERVED1 0x20 #define IPOPT_RESERVED1 0x20
#define IPOPT_DEBMEAS 0x40 #define IPOPT_DEBMEAS 0x40
#define IPOPT_RESERVED2 0x60 #define IPOPT_RESERVED2 0x60
#define IPOPT_EOL 0 /* end of option list */ #define IPOPT_EOL 0 /* end of option list */
#define IPOPT_NOP 1 /* no operation */ #define IPOPT_NOP 1 /* no operation */
#define IPOPT_RR 7 /* record packet route */ #define IPOPT_RR 7 /* record packet route */
#define IPOPT_TS 68 /* timestamp */ #define IPOPT_TS 68 /* timestamp */
#define IPOPT_SECURITY 130 /* provide s,c,h,tcc */ #define IPOPT_SECURITY 130 /* provide s,c,h,tcc */
#define IPOPT_LSRR 131 /* loose source route */ #define IPOPT_LSRR 131 /* loose source route */
#define IPOPT_SATID 136 /* satnet id */ #define IPOPT_SATID 136 /* satnet id */
#define IPOPT_SSRR 137 /* strict source route */ #define IPOPT_SSRR 137 /* strict source route */
/* /*
* Offsets to fields in options other than EOL and NOP. * Offsets to fields in options other than EOL and NOP.
*/ */
#define IPOPT_OPTVAL 0 /* option ID */ #define IPOPT_OPTVAL 0 /* option ID */
#define IPOPT_OLEN 1 /* option length */ #define IPOPT_OLEN 1 /* option length */
#define IPOPT_OFFSET 2 /* offset within option */ #define IPOPT_OFFSET 2 /* offset within option */
#define IPOPT_MINOFF 4 /* min value of above */ #define IPOPT_MINOFF 4 /* min value of above */
/* /*
* Time stamp option structure. * Time stamp option structure.
*/ */
#ifdef PRAGMA_PACK_SUPPORTED struct ip_timestamp {
#pragma pack(1) uint8_t ipt_code; /* IPOPT_TS */
#endif uint8_t ipt_len; /* size of structure (variable) */
uint8_t ipt_ptr; /* index of current entry */
struct ip_timestamp { #if G_BYTE_ORDER == G_BIG_ENDIAN
u_int8_t ipt_code; /* IPOPT_TS */ uint8_t ipt_oflw : 4, /* overflow counter */
u_int8_t ipt_len; /* size of structure (variable) */ ipt_flg : 4; /* flags, see below */
u_int8_t ipt_ptr; /* index of current entry */
#ifdef WORDS_BIGENDIAN
u_char ipt_oflw:4, /* overflow counter */
ipt_flg:4; /* flags, see below */
#else #else
u_char ipt_flg:4, /* flags, see below */ uint8_t ipt_flg : 4, /* flags, see below */
ipt_oflw:4; /* overflow counter */ ipt_oflw : 4; /* overflow counter */
#endif
union ipt_timestamp {
n_long ipt_time[1];
struct ipt_ta {
struct in_addr ipt_addr;
n_long ipt_time;
} ipt_ta[1];
} ipt_timestamp;
} PACKED__;
#ifdef PRAGMA_PACK_SUPPORTED
#pragma pack(PACK_END)
#endif #endif
union ipt_timestamp {
n_long ipt_time[1];
struct ipt_ta {
struct in_addr ipt_addr;
n_long ipt_time;
} ipt_ta[1];
} ipt_timestamp;
} SLIRP_PACKED;
/* flag bits for ipt_flg */ /* flag bits for ipt_flg */
#define IPOPT_TS_TSONLY 0 /* timestamps only */ #define IPOPT_TS_TSONLY 0 /* timestamps only */
#define IPOPT_TS_TSANDADDR 1 /* timestamps and addresses */ #define IPOPT_TS_TSANDADDR 1 /* timestamps and addresses */
#define IPOPT_TS_PRESPEC 3 /* specified modules only */ #define IPOPT_TS_PRESPEC 3 /* specified modules only */
/* bits for security (not byte swapped) */ /* bits for security (not byte swapped) */
#define IPOPT_SECUR_UNCLASS 0x0000 #define IPOPT_SECUR_UNCLASS 0x0000
#define IPOPT_SECUR_CONFID 0xf135 #define IPOPT_SECUR_CONFID 0xf135
#define IPOPT_SECUR_EFTO 0x789a #define IPOPT_SECUR_EFTO 0x789a
#define IPOPT_SECUR_MMMM 0xbc4d #define IPOPT_SECUR_MMMM 0xbc4d
#define IPOPT_SECUR_RESTR 0xaf13 #define IPOPT_SECUR_RESTR 0xaf13
#define IPOPT_SECUR_SECRET 0xd788 #define IPOPT_SECUR_SECRET 0xd788
#define IPOPT_SECUR_TOPSECRET 0x6bc5 #define IPOPT_SECUR_TOPSECRET 0x6bc5
/* /*
* Internet implementation parameters. * Internet implementation parameters.
*/ */
#define MAXTTL 255 /* maximum time to live (seconds) */ #define MAXTTL 255 /* maximum time to live (seconds) */
#define IPDEFTTL 64 /* default ttl, from RFC 1340 */ #define IPDEFTTL 64 /* default ttl, from RFC 1340 */
#define IPFRAGTTL 60 /* time to live for frags, slowhz */ #define IPFRAGTTL 60 /* time to live for frags, slowhz */
#define IPTTLDEC 1 /* subtracted when forwarding */ #define IPTTLDEC 1 /* subtracted when forwarding */
#define IP_MSS 576 /* default maximum segment size */ #define IP_MSS 576 /* default maximum segment size */
#ifdef HAVE_SYS_TYPES32_H /* Overcome some Solaris 2.x junk */ #if GLIB_SIZEOF_VOID_P == 4
#include <sys/types32.h> struct mbuf_ptr {
struct mbuf *mptr;
uint32_t dummy;
} SLIRP_PACKED;
#else #else
#if SIZEOF_CHAR_P == 4 struct mbuf_ptr {
typedef SLIRPcaddr_t caddr32_t; struct mbuf *mptr;
#else } SLIRP_PACKED;
typedef u_int32_t caddr32_t;
#endif
#endif
#if defined(__amd64__) || defined(__aarch64__)
typedef uintptr_t ipqp_32;
typedef uintptr_t ipasfragp_32;
#else
#if SIZEOF_CHAR_P == 4
typedef struct ipq *ipqp_32;
typedef struct ipasfrag *ipasfragp_32;
#else
typedef caddr32_t ipqp_32;
typedef caddr32_t ipasfragp_32;
#endif
#endif #endif
struct qlink {
void *next, *prev;
};
/* /*
* Overlay for ip header used by other protocols (tcp, udp). * Overlay for ip header used by other protocols (tcp, udp).
*/ */
#ifdef PRAGMA_PACK_SUPPORTED
#pragma pack(1)
#endif
struct ipovly { struct ipovly {
#if defined(__amd64__) || defined(__aarch64__) struct mbuf_ptr ih_mbuf; /* backpointer to mbuf */
uintptr_t ih_next, ih_prev; /* for protocol sequence q's */ uint8_t ih_x1; /* (unused) */
#else uint8_t ih_pr; /* protocol */
caddr32_t ih_next, ih_prev; /* for protocol sequence q's */ uint16_t ih_len; /* protocol length */
#endif struct in_addr ih_src; /* source internet address */
u_int8_t ih_x1; /* (unused) */ struct in_addr ih_dst; /* destination internet address */
u_int8_t ih_pr; /* protocol */ } SLIRP_PACKED;
u_int16_t ih_len; /* protocol length */
struct in_addr ih_src; /* source internet address */
struct in_addr ih_dst; /* destination internet address */
} PACKED__;
#ifdef PRAGMA_PACK_SUPPORTED
#pragma pack(PACK_END)
#endif
#if defined(_MSC_VER)
#pragma pack(pop)
#endif
/* /*
* Ip reassembly queue structure. Each fragment * Ip reassembly queue structure. Each fragment
@@ -258,105 +212,31 @@ struct ipovly {
* size 28 bytes * size 28 bytes
*/ */
struct ipq { struct ipq {
#if defined(__amd64__) || defined(__aarch64__) struct qlink frag_link; /* to ip headers of fragments */
uintptr_t next,prev; /* to other reass headers */ struct qlink ip_link; /* to other reass headers */
#else uint8_t ipq_ttl; /* time for reass q to live */
ipqp_32 next,prev; /* to other reass headers */ uint8_t ipq_p; /* protocol of this fragment */
#endif uint16_t ipq_id; /* sequence id for reassembly */
u_int8_t ipq_ttl; /* time for reass q to live */ struct in_addr ipq_src, ipq_dst;
u_int8_t ipq_p; /* protocol of this fragment */
u_int16_t ipq_id; /* sequence id for reassembly */
ipasfragp_32 ipq_next,ipq_prev;
/* to ip headers of fragments */
struct in_addr ipq_src,ipq_dst;
}; };
/* /*
* Ip header, when holding a fragment. * Ip header, when holding a fragment.
* *
* Note: ipf_next must be at same offset as ipq_next above * Note: ipf_link must be at same offset as frag_link above
*/ */
#ifdef PRAGMA_PACK_SUPPORTED struct ipasfrag {
#pragma pack(1) struct qlink ipf_link;
#endif struct ip ipf_ip;
struct ipasfrag {
#ifdef WORDS_BIGENDIAN
u_char ip_v:4,
ip_hl:4;
#else
u_char ip_hl:4,
ip_v:4;
#endif
/* BUG : u_int changed to u_int8_t.
* sizeof(u_int)==4 on linux 2.0
*/
u_int8_t ipf_mff; /* XXX overlays ip_tos: use low bit
* to avoid destroying tos (PPPDTRuu);
* copied from (ip_off&IP_MF) */
u_int16_t ip_len;
u_int16_t ip_id;
u_int16_t ip_off;
u_int8_t ip_ttl;
u_int8_t ip_p;
u_int16_t ip_sum;
ipasfragp_32 ipf_next; /* next fragment */
ipasfragp_32 ipf_prev; /* previous fragment */
} PACKED__;
#ifdef PRAGMA_PACK_SUPPORTED
#pragma pack(PACK_END) //WAS 0
#endif
/*
* Structure stored in mbuf in inpcb.ip_options
* and passed to ip_output when ip options are in use.
* The actual length of the options (including ipopt_dst)
* is in m_len.
*/
#define MAX_IPOPTLEN 40
struct ipoption {
struct in_addr ipopt_dst; /* first-hop dst if source routed */
int8_t ipopt_list[MAX_IPOPTLEN]; /* options proper */
}; };
/* G_STATIC_ASSERT(offsetof(struct ipq, frag_link) ==
* Structure attached to inpcb.ip_moptions and offsetof(struct ipasfrag, ipf_link));
* passed to ip_output when IP multicast options are in use.
*/
struct ipstat { #define ipf_off ipf_ip.ip_off
u_long ips_total; /* total packets received */ #define ipf_tos ipf_ip.ip_tos
u_long ips_badsum; /* checksum bad */ #define ipf_len ipf_ip.ip_len
u_long ips_tooshort; /* packet too short */ #define ipf_next ipf_link.next
u_long ips_toosmall; /* not enough data */ #define ipf_prev ipf_link.prev
u_long ips_badhlen; /* ip header length < data size */
u_long ips_badlen; /* ip length < ip header length */
u_long ips_fragments; /* fragments received */
u_long ips_fragdropped; /* frags dropped (dups, out of space) */
u_long ips_fragtimeout; /* fragments timed out */
u_long ips_forward; /* packets forwarded */
u_long ips_cantforward; /* packets rcvd for unreachable dest */
u_long ips_redirectsent; /* packets forwarded on same net */
u_long ips_noproto; /* unknown or unsupported protocol */
u_long ips_delivered; /* datagrams delivered to upper level*/
u_long ips_localout; /* total ip packets generated here */
u_long ips_odropped; /* lost packets due to nobufs, etc. */
u_long ips_reassembled; /* total packets reassembled ok */
u_long ips_fragmented; /* datagrams successfully fragmented */
u_long ips_ofragments; /* output fragments created */
u_long ips_cantfrag; /* don't fragment flag was set, etc. */
u_long ips_badoptions; /* error in option processing */
u_long ips_noroute; /* packets discarded due to no route */
u_long ips_badvers; /* ip version != 4 */
u_long ips_rawout; /* total raw ip packets generated */
u_long ips_unaligned; /* times the ip packet was not aligned */
};
extern struct ipstat ipstat;
extern struct ipq ipq; /* ip reass. queue */
extern u_int16_t ip_id; /* ip packet ctr, for ids */
extern int ip_defttl; /* default IP ttl */
#endif #endif

214
src/network/slirp/ip6.h Normal file
View File

@@ -0,0 +1,214 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/*
* Copyright (c) 2013
* Guillaume Subiron, Yann Bordenave, Serigne Modou Wagne.
*/
#ifndef SLIRP_IP6_H
#define SLIRP_IP6_H
#include <tinyglib.h>
#include <string.h>
#define ALLNODES_MULTICAST \
{ \
.s6_addr = { \
0xff, \
0x02, \
0x00, \
0x00, \
0x00, \
0x00, \
0x00, \
0x00, \
0x00, \
0x00, \
0x00, \
0x00, \
0x00, \
0x00, \
0x00, \
0x01 \
} \
}
#define SOLICITED_NODE_PREFIX \
{ \
.s6_addr = { \
0xff, \
0x02, \
0x00, \
0x00, \
0x00, \
0x00, \
0x00, \
0x00, \
0x00, \
0x00, \
0x00, \
0x01, \
0xff, \
0x00, \
0x00, \
0x00 \
} \
}
#define LINKLOCAL_ADDR \
{ \
.s6_addr = { \
0xfe, \
0x80, \
0x00, \
0x00, \
0x00, \
0x00, \
0x00, \
0x00, \
0x00, \
0x00, \
0x00, \
0x00, \
0x00, \
0x00, \
0x00, \
0x02 \
} \
}
#define ZERO_ADDR \
{ \
.s6_addr = { \
0x00, \
0x00, \
0x00, \
0x00, \
0x00, \
0x00, \
0x00, \
0x00, \
0x00, \
0x00, \
0x00, \
0x00, \
0x00, \
0x00, \
0x00, \
0x00 \
} \
}
static inline bool in6_equal(const struct in6_addr *a, const struct in6_addr *b)
{
return memcmp(a, b, sizeof(*a)) == 0;
}
static inline bool in6_equal_net(const struct in6_addr *a,
const struct in6_addr *b, int prefix_len)
{
if (memcmp(a, b, prefix_len / 8) != 0) {
return 0;
}
if (prefix_len % 8 == 0) {
return 1;
}
return a->s6_addr[prefix_len / 8] >> (8 - (prefix_len % 8)) ==
b->s6_addr[prefix_len / 8] >> (8 - (prefix_len % 8));
}
static inline bool in6_equal_mach(const struct in6_addr *a,
const struct in6_addr *b, int prefix_len)
{
if (memcmp(&(a->s6_addr[DIV_ROUND_UP(prefix_len, 8)]),
&(b->s6_addr[DIV_ROUND_UP(prefix_len, 8)]),
16 - DIV_ROUND_UP(prefix_len, 8)) != 0) {
return 0;
}
if (prefix_len % 8 == 0) {
return 1;
}
return (a->s6_addr[prefix_len / 8] &
((1U << (8 - (prefix_len % 8))) - 1)) ==
(b->s6_addr[prefix_len / 8] & ((1U << (8 - (prefix_len % 8))) - 1));
}
#define in6_equal_router(a) \
((in6_equal_net(a, &slirp->vprefix_addr6, slirp->vprefix_len) && \
in6_equal_mach(a, &slirp->vhost_addr6, slirp->vprefix_len)) || \
(in6_equal_net(a, &(struct in6_addr)LINKLOCAL_ADDR, 64) && \
in6_equal_mach(a, &slirp->vhost_addr6, 64)))
#define in6_equal_dns(a) \
((in6_equal_net(a, &slirp->vprefix_addr6, slirp->vprefix_len) && \
in6_equal_mach(a, &slirp->vnameserver_addr6, slirp->vprefix_len)) || \
(in6_equal_net(a, &(struct in6_addr)LINKLOCAL_ADDR, 64) && \
in6_equal_mach(a, &slirp->vnameserver_addr6, 64)))
#define in6_equal_host(a) (in6_equal_router(a) || in6_equal_dns(a))
#define in6_solicitednode_multicast(a) \
(in6_equal_net(a, &(struct in6_addr)SOLICITED_NODE_PREFIX, 104))
#define in6_zero(a) (in6_equal(a, &(struct in6_addr)ZERO_ADDR))
/* Compute emulated host MAC address from its ipv6 address */
static inline void in6_compute_ethaddr(struct in6_addr ip,
uint8_t eth[ETH_ALEN])
{
eth[0] = 0x52;
eth[1] = 0x56;
memcpy(&eth[2], &ip.s6_addr[16 - (ETH_ALEN - 2)], ETH_ALEN - 2);
}
/*
* Definitions for internet protocol version 6.
* Per RFC 2460, December 1998.
*/
#define IP6VERSION 6
#define IP6_HOP_LIMIT 255
/*
* Structure of an internet header, naked of options.
*/
struct ip6 {
#if G_BYTE_ORDER == G_BIG_ENDIAN
uint32_t ip_v : 4, /* version */
ip_tc_hi : 4, /* traffic class */
ip_tc_lo : 4, ip_fl_hi : 4, /* flow label */
ip_fl_lo : 16;
#else
uint32_t ip_tc_hi : 4, ip_v : 4, ip_fl_hi : 4, ip_tc_lo : 4, ip_fl_lo : 16;
#endif
uint16_t ip_pl; /* payload length */
uint8_t ip_nh; /* next header */
uint8_t ip_hl; /* hop limit */
struct in6_addr ip_src, ip_dst; /* source and dest address */
};
/*
* IPv6 pseudo-header used by upper-layer protocols
*/
struct ip6_pseudohdr {
struct in6_addr ih_src; /* source internet address */
struct in6_addr ih_dst; /* destination internet address */
uint32_t ih_pl; /* upper-layer packet length */
uint16_t ih_zero_hi; /* zero */
uint8_t ih_zero_lo; /* zero */
uint8_t ih_nh; /* next header */
};
/*
* We don't want to mark these ip6 structs as packed as they are naturally
* correctly aligned; instead assert that there is no stray padding.
* If we marked the struct as packed then we would be unable to take
* the address of any of the fields in it.
*/
G_STATIC_ASSERT(sizeof(struct ip6) == 40);
G_STATIC_ASSERT(sizeof(struct ip6_pseudohdr) == 40);
#endif

View File

@@ -0,0 +1,433 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/*
* Copyright (c) 2013
* Guillaume Subiron, Yann Bordenave, Serigne Modou Wagne.
*/
#include "slirp.h"
#include "ip6_icmp.h"
#define NDP_Interval \
g_rand_int_range(slirp->grand, NDP_MinRtrAdvInterval, NDP_MaxRtrAdvInterval)
static void ra_timer_handler(void *opaque)
{
Slirp *slirp = opaque;
slirp->cb->timer_mod(slirp->ra_timer,
slirp->cb->clock_get_ns(slirp->opaque) / SCALE_MS +
NDP_Interval,
slirp->opaque);
ndp_send_ra(slirp);
}
void icmp6_init(Slirp *slirp)
{
if (!slirp->in6_enabled) {
return;
}
slirp->ra_timer =
slirp->cb->timer_new(ra_timer_handler, slirp, slirp->opaque);
slirp->cb->timer_mod(slirp->ra_timer,
slirp->cb->clock_get_ns(slirp->opaque) / SCALE_MS +
NDP_Interval,
slirp->opaque);
}
void icmp6_cleanup(Slirp *slirp)
{
if (!slirp->in6_enabled) {
return;
}
slirp->cb->timer_free(slirp->ra_timer, slirp->opaque);
}
static void icmp6_send_echoreply(struct mbuf *m, Slirp *slirp, struct ip6 *ip,
struct icmp6 *icmp)
{
struct mbuf *t = m_get(slirp);
t->m_len = sizeof(struct ip6) + ntohs(ip->ip_pl);
memcpy(t->m_data, m->m_data, t->m_len);
/* IPv6 Packet */
struct ip6 *rip = mtod(t, struct ip6 *);
rip->ip_dst = ip->ip_src;
rip->ip_src = ip->ip_dst;
/* ICMPv6 packet */
t->m_data += sizeof(struct ip6);
struct icmp6 *ricmp = mtod(t, struct icmp6 *);
ricmp->icmp6_type = ICMP6_ECHO_REPLY;
ricmp->icmp6_cksum = 0;
/* Checksum */
t->m_data -= sizeof(struct ip6);
ricmp->icmp6_cksum = ip6_cksum(t);
ip6_output(NULL, t, 0);
}
void icmp6_send_error(struct mbuf *m, uint8_t type, uint8_t code)
{
Slirp *slirp = m->slirp;
struct mbuf *t;
struct ip6 *ip = mtod(m, struct ip6 *);
char addrstr[INET6_ADDRSTRLEN];
DEBUG_CALL("icmp6_send_error");
DEBUG_ARG("type = %d, code = %d", type, code);
if (IN6_IS_ADDR_MULTICAST(&ip->ip_src) || in6_zero(&ip->ip_src)) {
/* TODO icmp error? */
return;
}
t = m_get(slirp);
/* IPv6 packet */
struct ip6 *rip = mtod(t, struct ip6 *);
rip->ip_src = (struct in6_addr)LINKLOCAL_ADDR;
rip->ip_dst = ip->ip_src;
inet_ntop(AF_INET6, &rip->ip_dst, addrstr, INET6_ADDRSTRLEN);
DEBUG_ARG("target = %s", addrstr);
rip->ip_nh = IPPROTO_ICMPV6;
const int error_data_len = MIN(
m->m_len, slirp->if_mtu - (sizeof(struct ip6) + ICMP6_ERROR_MINLEN));
rip->ip_pl = htons(ICMP6_ERROR_MINLEN + error_data_len);
t->m_len = sizeof(struct ip6) + ntohs(rip->ip_pl);
/* ICMPv6 packet */
t->m_data += sizeof(struct ip6);
struct icmp6 *ricmp = mtod(t, struct icmp6 *);
ricmp->icmp6_type = type;
ricmp->icmp6_code = code;
ricmp->icmp6_cksum = 0;
switch (type) {
case ICMP6_UNREACH:
case ICMP6_TIMXCEED:
ricmp->icmp6_err.unused = 0;
break;
case ICMP6_TOOBIG:
ricmp->icmp6_err.mtu = htonl(slirp->if_mtu);
break;
case ICMP6_PARAMPROB:
/* TODO: Handle this case */
break;
default:
g_assert_not_reached();
}
t->m_data += ICMP6_ERROR_MINLEN;
memcpy(t->m_data, m->m_data, error_data_len);
/* Checksum */
t->m_data -= ICMP6_ERROR_MINLEN;
t->m_data -= sizeof(struct ip6);
ricmp->icmp6_cksum = ip6_cksum(t);
ip6_output(NULL, t, 0);
}
/*
* Send NDP Router Advertisement
*/
void ndp_send_ra(Slirp *slirp)
{
DEBUG_CALL("ndp_send_ra");
/* Build IPv6 packet */
struct mbuf *t = m_get(slirp);
struct ip6 *rip = mtod(t, struct ip6 *);
size_t pl_size = 0;
struct in6_addr addr;
uint32_t scope_id;
rip->ip_src = (struct in6_addr)LINKLOCAL_ADDR;
rip->ip_dst = (struct in6_addr)ALLNODES_MULTICAST;
rip->ip_nh = IPPROTO_ICMPV6;
/* Build ICMPv6 packet */
t->m_data += sizeof(struct ip6);
struct icmp6 *ricmp = mtod(t, struct icmp6 *);
ricmp->icmp6_type = ICMP6_NDP_RA;
ricmp->icmp6_code = 0;
ricmp->icmp6_cksum = 0;
/* NDP */
ricmp->icmp6_nra.chl = NDP_AdvCurHopLimit;
ricmp->icmp6_nra.M = NDP_AdvManagedFlag;
ricmp->icmp6_nra.O = NDP_AdvOtherConfigFlag;
ricmp->icmp6_nra.reserved = 0;
ricmp->icmp6_nra.lifetime = htons(NDP_AdvDefaultLifetime);
ricmp->icmp6_nra.reach_time = htonl(NDP_AdvReachableTime);
ricmp->icmp6_nra.retrans_time = htonl(NDP_AdvRetransTime);
t->m_data += ICMP6_NDP_RA_MINLEN;
pl_size += ICMP6_NDP_RA_MINLEN;
/* Source link-layer address (NDP option) */
struct ndpopt *opt = mtod(t, struct ndpopt *);
opt->ndpopt_type = NDPOPT_LINKLAYER_SOURCE;
opt->ndpopt_len = NDPOPT_LINKLAYER_LEN / 8;
in6_compute_ethaddr(rip->ip_src, opt->ndpopt_linklayer);
t->m_data += NDPOPT_LINKLAYER_LEN;
pl_size += NDPOPT_LINKLAYER_LEN;
/* Prefix information (NDP option) */
struct ndpopt *opt2 = mtod(t, struct ndpopt *);
opt2->ndpopt_type = NDPOPT_PREFIX_INFO;
opt2->ndpopt_len = NDPOPT_PREFIXINFO_LEN / 8;
opt2->ndpopt_prefixinfo.prefix_length = slirp->vprefix_len;
opt2->ndpopt_prefixinfo.L = 1;
opt2->ndpopt_prefixinfo.A = 1;
opt2->ndpopt_prefixinfo.reserved1 = 0;
opt2->ndpopt_prefixinfo.valid_lt = htonl(NDP_AdvValidLifetime);
opt2->ndpopt_prefixinfo.pref_lt = htonl(NDP_AdvPrefLifetime);
opt2->ndpopt_prefixinfo.reserved2 = 0;
opt2->ndpopt_prefixinfo.prefix = slirp->vprefix_addr6;
t->m_data += NDPOPT_PREFIXINFO_LEN;
pl_size += NDPOPT_PREFIXINFO_LEN;
/* Prefix information (NDP option) */
if (get_dns6_addr(&addr, &scope_id) >= 0) {
/* Host system does have an IPv6 DNS server, announce our proxy. */
struct ndpopt *opt3 = mtod(t, struct ndpopt *);
opt3->ndpopt_type = NDPOPT_RDNSS;
opt3->ndpopt_len = NDPOPT_RDNSS_LEN / 8;
opt3->ndpopt_rdnss.reserved = 0;
opt3->ndpopt_rdnss.lifetime = htonl(2 * NDP_MaxRtrAdvInterval);
opt3->ndpopt_rdnss.addr = slirp->vnameserver_addr6;
t->m_data += NDPOPT_RDNSS_LEN;
pl_size += NDPOPT_RDNSS_LEN;
}
rip->ip_pl = htons(pl_size);
t->m_data -= sizeof(struct ip6) + pl_size;
t->m_len = sizeof(struct ip6) + pl_size;
/* ICMPv6 Checksum */
ricmp->icmp6_cksum = ip6_cksum(t);
ip6_output(NULL, t, 0);
}
/*
* Send NDP Neighbor Solitication
*/
void ndp_send_ns(Slirp *slirp, struct in6_addr addr)
{
char addrstr[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, &addr, addrstr, INET6_ADDRSTRLEN);
DEBUG_CALL("ndp_send_ns");
DEBUG_ARG("target = %s", addrstr);
/* Build IPv6 packet */
struct mbuf *t = m_get(slirp);
struct ip6 *rip = mtod(t, struct ip6 *);
rip->ip_src = slirp->vhost_addr6;
rip->ip_dst = (struct in6_addr)SOLICITED_NODE_PREFIX;
memcpy(&rip->ip_dst.s6_addr[13], &addr.s6_addr[13], 3);
rip->ip_nh = IPPROTO_ICMPV6;
rip->ip_pl = htons(ICMP6_NDP_NS_MINLEN + NDPOPT_LINKLAYER_LEN);
t->m_len = sizeof(struct ip6) + ntohs(rip->ip_pl);
/* Build ICMPv6 packet */
t->m_data += sizeof(struct ip6);
struct icmp6 *ricmp = mtod(t, struct icmp6 *);
ricmp->icmp6_type = ICMP6_NDP_NS;
ricmp->icmp6_code = 0;
ricmp->icmp6_cksum = 0;
/* NDP */
ricmp->icmp6_nns.reserved = 0;
ricmp->icmp6_nns.target = addr;
/* Build NDP option */
t->m_data += ICMP6_NDP_NS_MINLEN;
struct ndpopt *opt = mtod(t, struct ndpopt *);
opt->ndpopt_type = NDPOPT_LINKLAYER_SOURCE;
opt->ndpopt_len = NDPOPT_LINKLAYER_LEN / 8;
in6_compute_ethaddr(slirp->vhost_addr6, opt->ndpopt_linklayer);
/* ICMPv6 Checksum */
t->m_data -= ICMP6_NDP_NA_MINLEN;
t->m_data -= sizeof(struct ip6);
ricmp->icmp6_cksum = ip6_cksum(t);
ip6_output(NULL, t, 1);
}
/*
* Send NDP Neighbor Advertisement
*/
static void ndp_send_na(Slirp *slirp, struct ip6 *ip, struct icmp6 *icmp)
{
/* Build IPv6 packet */
struct mbuf *t = m_get(slirp);
struct ip6 *rip = mtod(t, struct ip6 *);
rip->ip_src = icmp->icmp6_nns.target;
if (in6_zero(&ip->ip_src)) {
rip->ip_dst = (struct in6_addr)ALLNODES_MULTICAST;
} else {
rip->ip_dst = ip->ip_src;
}
rip->ip_nh = IPPROTO_ICMPV6;
rip->ip_pl = htons(ICMP6_NDP_NA_MINLEN + NDPOPT_LINKLAYER_LEN);
t->m_len = sizeof(struct ip6) + ntohs(rip->ip_pl);
/* Build ICMPv6 packet */
t->m_data += sizeof(struct ip6);
struct icmp6 *ricmp = mtod(t, struct icmp6 *);
ricmp->icmp6_type = ICMP6_NDP_NA;
ricmp->icmp6_code = 0;
ricmp->icmp6_cksum = 0;
/* NDP */
ricmp->icmp6_nna.R = NDP_IsRouter;
ricmp->icmp6_nna.S = !IN6_IS_ADDR_MULTICAST(&rip->ip_dst);
ricmp->icmp6_nna.O = 1;
ricmp->icmp6_nna.reserved_hi = 0;
ricmp->icmp6_nna.reserved_lo = 0;
ricmp->icmp6_nna.target = icmp->icmp6_nns.target;
/* Build NDP option */
t->m_data += ICMP6_NDP_NA_MINLEN;
struct ndpopt *opt = mtod(t, struct ndpopt *);
opt->ndpopt_type = NDPOPT_LINKLAYER_TARGET;
opt->ndpopt_len = NDPOPT_LINKLAYER_LEN / 8;
in6_compute_ethaddr(ricmp->icmp6_nna.target, opt->ndpopt_linklayer);
/* ICMPv6 Checksum */
t->m_data -= ICMP6_NDP_NA_MINLEN;
t->m_data -= sizeof(struct ip6);
ricmp->icmp6_cksum = ip6_cksum(t);
ip6_output(NULL, t, 0);
}
/*
* Process a NDP message
*/
static void ndp_input(struct mbuf *m, Slirp *slirp, struct ip6 *ip,
struct icmp6 *icmp)
{
m->m_len += ETH_HLEN;
m->m_data -= ETH_HLEN;
struct ethhdr *eth = mtod(m, struct ethhdr *);
m->m_len -= ETH_HLEN;
m->m_data += ETH_HLEN;
switch (icmp->icmp6_type) {
case ICMP6_NDP_RS:
DEBUG_CALL(" type = Router Solicitation");
if (ip->ip_hl == 255 && icmp->icmp6_code == 0 &&
ntohs(ip->ip_pl) >= ICMP6_NDP_RS_MINLEN) {
/* Gratuitous NDP */
ndp_table_add(slirp, ip->ip_src, eth->h_source);
ndp_send_ra(slirp);
}
break;
case ICMP6_NDP_RA:
DEBUG_CALL(" type = Router Advertisement");
slirp->cb->guest_error("Warning: guest sent NDP RA, but shouldn't",
slirp->opaque);
break;
case ICMP6_NDP_NS:
DEBUG_CALL(" type = Neighbor Solicitation");
if (ip->ip_hl == 255 && icmp->icmp6_code == 0 &&
!IN6_IS_ADDR_MULTICAST(&icmp->icmp6_nns.target) &&
ntohs(ip->ip_pl) >= ICMP6_NDP_NS_MINLEN &&
(!in6_zero(&ip->ip_src) ||
in6_solicitednode_multicast(&ip->ip_dst))) {
if (in6_equal_host(&icmp->icmp6_nns.target)) {
/* Gratuitous NDP */
ndp_table_add(slirp, ip->ip_src, eth->h_source);
ndp_send_na(slirp, ip, icmp);
}
}
break;
case ICMP6_NDP_NA:
DEBUG_CALL(" type = Neighbor Advertisement");
if (ip->ip_hl == 255 && icmp->icmp6_code == 0 &&
ntohs(ip->ip_pl) >= ICMP6_NDP_NA_MINLEN &&
!IN6_IS_ADDR_MULTICAST(&icmp->icmp6_nna.target) &&
(!IN6_IS_ADDR_MULTICAST(&ip->ip_dst) || icmp->icmp6_nna.S == 0)) {
ndp_table_add(slirp, ip->ip_src, eth->h_source);
}
break;
case ICMP6_NDP_REDIRECT:
DEBUG_CALL(" type = Redirect");
slirp->cb->guest_error(
"Warning: guest sent NDP REDIRECT, but shouldn't", slirp->opaque);
break;
}
}
/*
* Process a received ICMPv6 message.
*/
void icmp6_input(struct mbuf *m)
{
struct icmp6 *icmp;
struct ip6 *ip = mtod(m, struct ip6 *);
Slirp *slirp = m->slirp;
int hlen = sizeof(struct ip6);
DEBUG_CALL("icmp6_input");
DEBUG_ARG("m = %p", m);
DEBUG_ARG("m_len = %d", m->m_len);
if (ntohs(ip->ip_pl) < ICMP6_MINLEN) {
goto end;
}
if (ip6_cksum(m)) {
goto end;
}
m->m_len -= hlen;
m->m_data += hlen;
icmp = mtod(m, struct icmp6 *);
m->m_len += hlen;
m->m_data -= hlen;
DEBUG_ARG("icmp6_type = %d", icmp->icmp6_type);
switch (icmp->icmp6_type) {
case ICMP6_ECHO_REQUEST:
if (in6_equal_host(&ip->ip_dst)) {
icmp6_send_echoreply(m, slirp, ip, icmp);
} else {
/* TODO */
g_critical("external icmpv6 not supported yet");
}
break;
case ICMP6_NDP_RS:
case ICMP6_NDP_RA:
case ICMP6_NDP_NS:
case ICMP6_NDP_NA:
case ICMP6_NDP_REDIRECT:
ndp_input(m, slirp, ip, icmp);
break;
case ICMP6_UNREACH:
case ICMP6_TOOBIG:
case ICMP6_TIMXCEED:
case ICMP6_PARAMPROB:
/* XXX? report error? close socket? */
default:
break;
}
end:
m_free(m);
}

View File

@@ -0,0 +1,219 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/*
* Copyright (c) 2013
* Guillaume Subiron, Yann Bordenave, Serigne Modou Wagne.
*/
#ifndef SLIRP_IP6_ICMP_H
#define SLIRP_IP6_ICMP_H
/*
* Interface Control Message Protocol version 6 Definitions.
* Per RFC 4443, March 2006.
*
* Network Discover Protocol Definitions.
* Per RFC 4861, September 2007.
*/
struct icmp6_echo { /* Echo Messages */
uint16_t id;
uint16_t seq_num;
};
union icmp6_error_body {
uint32_t unused;
uint32_t pointer;
uint32_t mtu;
};
/*
* NDP Messages
*/
struct ndp_rs { /* Router Solicitation Message */
uint32_t reserved;
};
struct ndp_ra { /* Router Advertisement Message */
uint8_t chl; /* Cur Hop Limit */
#if G_BYTE_ORDER == G_BIG_ENDIAN
uint8_t M : 1, O : 1, reserved : 6;
#else
uint8_t reserved : 6, O : 1, M : 1;
#endif
uint16_t lifetime; /* Router Lifetime */
uint32_t reach_time; /* Reachable Time */
uint32_t retrans_time; /* Retrans Timer */
};
G_STATIC_ASSERT(sizeof(struct ndp_ra) == 12);
struct ndp_ns { /* Neighbor Solicitation Message */
uint32_t reserved;
struct in6_addr target; /* Target Address */
};
G_STATIC_ASSERT(sizeof(struct ndp_ns) == 20);
struct ndp_na { /* Neighbor Advertisement Message */
#if G_BYTE_ORDER == G_BIG_ENDIAN
uint32_t R : 1, /* Router Flag */
S : 1, /* Solicited Flag */
O : 1, /* Override Flag */
reserved_hi : 5, reserved_lo : 24;
#else
uint32_t reserved_hi : 5, O : 1, S : 1, R : 1, reserved_lo : 24;
#endif
struct in6_addr target; /* Target Address */
};
G_STATIC_ASSERT(sizeof(struct ndp_na) == 20);
struct ndp_redirect {
uint32_t reserved;
struct in6_addr target; /* Target Address */
struct in6_addr dest; /* Destination Address */
};
G_STATIC_ASSERT(sizeof(struct ndp_redirect) == 36);
/*
* Structure of an icmpv6 header.
*/
struct icmp6 {
uint8_t icmp6_type; /* type of message, see below */
uint8_t icmp6_code; /* type sub code */
uint16_t icmp6_cksum; /* ones complement cksum of struct */
union {
union icmp6_error_body error_body;
struct icmp6_echo echo;
struct ndp_rs ndp_rs;
struct ndp_ra ndp_ra;
struct ndp_ns ndp_ns;
struct ndp_na ndp_na;
struct ndp_redirect ndp_redirect;
} icmp6_body;
#define icmp6_err icmp6_body.error_body
#define icmp6_echo icmp6_body.echo
#define icmp6_nrs icmp6_body.ndp_rs
#define icmp6_nra icmp6_body.ndp_ra
#define icmp6_nns icmp6_body.ndp_ns
#define icmp6_nna icmp6_body.ndp_na
#define icmp6_redirect icmp6_body.ndp_redirect
};
G_STATIC_ASSERT(sizeof(struct icmp6) == 40);
#define ICMP6_MINLEN 4
#define ICMP6_ERROR_MINLEN 8
#define ICMP6_ECHO_MINLEN 8
#define ICMP6_NDP_RS_MINLEN 8
#define ICMP6_NDP_RA_MINLEN 16
#define ICMP6_NDP_NS_MINLEN 24
#define ICMP6_NDP_NA_MINLEN 24
#define ICMP6_NDP_REDIRECT_MINLEN 40
/*
* NDP Options
*/
struct ndpopt {
uint8_t ndpopt_type; /* Option type */
uint8_t ndpopt_len; /* /!\ In units of 8 octets */
union {
unsigned char linklayer_addr[6]; /* Source/Target Link-layer */
#define ndpopt_linklayer ndpopt_body.linklayer_addr
struct prefixinfo { /* Prefix Information */
uint8_t prefix_length;
#if G_BYTE_ORDER == G_BIG_ENDIAN
uint8_t L : 1, A : 1, reserved1 : 6;
#else
uint8_t reserved1 : 6, A : 1, L : 1;
#endif
uint32_t valid_lt; /* Valid Lifetime */
uint32_t pref_lt; /* Preferred Lifetime */
uint32_t reserved2;
struct in6_addr prefix;
} SLIRP_PACKED prefixinfo;
#define ndpopt_prefixinfo ndpopt_body.prefixinfo
struct rdnss {
uint16_t reserved;
uint32_t lifetime;
struct in6_addr addr;
} SLIRP_PACKED rdnss;
#define ndpopt_rdnss ndpopt_body.rdnss
} ndpopt_body;
} SLIRP_PACKED;
/* NDP options type */
#define NDPOPT_LINKLAYER_SOURCE 1 /* Source Link-Layer Address */
#define NDPOPT_LINKLAYER_TARGET 2 /* Target Link-Layer Address */
#define NDPOPT_PREFIX_INFO 3 /* Prefix Information */
#define NDPOPT_RDNSS 25 /* Recursive DNS Server Address */
/* NDP options size, in octets. */
#define NDPOPT_LINKLAYER_LEN 8
#define NDPOPT_PREFIXINFO_LEN 32
#define NDPOPT_RDNSS_LEN 24
/*
* Definition of type and code field values.
* Per https://www.iana.org/assignments/icmpv6-parameters/icmpv6-parameters.xml
* Last Updated 2012-11-12
*/
/* Errors */
#define ICMP6_UNREACH 1 /* Destination Unreachable */
#define ICMP6_UNREACH_NO_ROUTE 0 /* no route to dest */
#define ICMP6_UNREACH_DEST_PROHIB 1 /* com with dest prohibited */
#define ICMP6_UNREACH_SCOPE 2 /* beyond scope of src addr */
#define ICMP6_UNREACH_ADDRESS 3 /* address unreachable */
#define ICMP6_UNREACH_PORT 4 /* port unreachable */
#define ICMP6_UNREACH_SRC_FAIL 5 /* src addr failed */
#define ICMP6_UNREACH_REJECT_ROUTE 6 /* reject route to dest */
#define ICMP6_UNREACH_SRC_HDR_ERROR 7 /* error in src routing header */
#define ICMP6_TOOBIG 2 /* Packet Too Big */
#define ICMP6_TIMXCEED 3 /* Time Exceeded */
#define ICMP6_TIMXCEED_INTRANS 0 /* hop limit exceeded in transit */
#define ICMP6_TIMXCEED_REASS 1 /* ttl=0 in reass */
#define ICMP6_PARAMPROB 4 /* Parameter Problem */
#define ICMP6_PARAMPROB_HDR_FIELD 0 /* err header field */
#define ICMP6_PARAMPROB_NXTHDR_TYPE 1 /* unrecognized Next Header type */
#define ICMP6_PARAMPROB_IPV6_OPT 2 /* unrecognized IPv6 option */
/* Informational Messages */
#define ICMP6_ECHO_REQUEST 128 /* Echo Request */
#define ICMP6_ECHO_REPLY 129 /* Echo Reply */
#define ICMP6_NDP_RS 133 /* Router Solicitation (NDP) */
#define ICMP6_NDP_RA 134 /* Router Advertisement (NDP) */
#define ICMP6_NDP_NS 135 /* Neighbor Solicitation (NDP) */
#define ICMP6_NDP_NA 136 /* Neighbor Advertisement (NDP) */
#define ICMP6_NDP_REDIRECT 137 /* Redirect Message (NDP) */
/*
* Router Configuration Variables (rfc4861#section-6)
*/
#define NDP_IsRouter 1
#define NDP_AdvSendAdvertisements 1
#define NDP_MaxRtrAdvInterval 600000
#define NDP_MinRtrAdvInterval \
((NDP_MaxRtrAdvInterval >= 9) ? NDP_MaxRtrAdvInterval / 3 : \
NDP_MaxRtrAdvInterval)
#define NDP_AdvManagedFlag 0
#define NDP_AdvOtherConfigFlag 0
#define NDP_AdvLinkMTU 0
#define NDP_AdvReachableTime 0
#define NDP_AdvRetransTime 0
#define NDP_AdvCurHopLimit 64
#define NDP_AdvDefaultLifetime ((3 * NDP_MaxRtrAdvInterval) / 1000)
#define NDP_AdvValidLifetime 86400
#define NDP_AdvOnLinkFlag 1
#define NDP_AdvPrefLifetime 14400
#define NDP_AdvAutonomousFlag 1
void icmp6_init(Slirp *slirp);
void icmp6_cleanup(Slirp *slirp);
void icmp6_input(struct mbuf *);
void icmp6_send_error(struct mbuf *m, uint8_t type, uint8_t code);
void ndp_send_ra(Slirp *slirp);
void ndp_send_ns(Slirp *slirp, struct in6_addr addr);
#endif

View File

@@ -0,0 +1,85 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/*
* Copyright (c) 2013
* Guillaume Subiron, Yann Bordenave, Serigne Modou Wagne.
*/
#include "slirp.h"
#include "ip6_icmp.h"
/*
* IP initialization: fill in IP protocol switch table.
* All protocols not implemented in kernel go to raw IP protocol handler.
*/
void ip6_init(Slirp *slirp)
{
icmp6_init(slirp);
}
void ip6_cleanup(Slirp *slirp)
{
icmp6_cleanup(slirp);
}
void ip6_input(struct mbuf *m)
{
struct ip6 *ip6;
Slirp *slirp = m->slirp;
if (!slirp->in6_enabled) {
goto bad;
}
DEBUG_CALL("ip6_input");
DEBUG_ARG("m = %p", m);
DEBUG_ARG("m_len = %d", m->m_len);
if (m->m_len < sizeof(struct ip6)) {
goto bad;
}
ip6 = mtod(m, struct ip6 *);
if (ip6->ip_v != IP6VERSION) {
goto bad;
}
if (ntohs(ip6->ip_pl) + sizeof(struct ip6) > slirp->if_mtu) {
icmp6_send_error(m, ICMP6_TOOBIG, 0);
goto bad;
}
// Check if the message size is big enough to hold what's
// set in the payload length header. If not this is an invalid
// packet
if (m->m_len < ntohs(ip6->ip_pl) + sizeof(struct ip6)) {
goto bad;
}
/* check ip_ttl for a correct ICMP reply */
if (ip6->ip_hl == 0) {
icmp6_send_error(m, ICMP6_TIMXCEED, ICMP6_TIMXCEED_INTRANS);
goto bad;
}
/*
* Switch out to protocol's input routine.
*/
switch (ip6->ip_nh) {
case IPPROTO_TCP:
NTOHS(ip6->ip_pl);
tcp_input(m, sizeof(struct ip6), (struct socket *)NULL, AF_INET6);
break;
case IPPROTO_UDP:
udp6_input(m);
break;
case IPPROTO_ICMPV6:
icmp6_input(m);
break;
default:
m_free(m);
}
return;
bad:
m_free(m);
}

View File

@@ -0,0 +1,39 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/*
* Copyright (c) 2013
* Guillaume Subiron, Yann Bordenave, Serigne Modou Wagne.
*/
#include "slirp.h"
/* Number of packets queued before we start sending
* (to prevent allocing too many mbufs) */
#define IF6_THRESH 10
/*
* IPv6 output. The packet in mbuf chain m contains a IP header
*/
int ip6_output(struct socket *so, struct mbuf *m, int fast)
{
struct ip6 *ip = mtod(m, struct ip6 *);
DEBUG_CALL("ip6_output");
DEBUG_ARG("so = %p", so);
DEBUG_ARG("m = %p", m);
/* Fill IPv6 header */
ip->ip_v = IP6VERSION;
ip->ip_hl = IP6_HOP_LIMIT;
ip->ip_tc_hi = 0;
ip->ip_tc_lo = 0;
ip->ip_fl_hi = 0;
ip->ip_fl_lo = 0;
if (fast) {
if_encap(m->slirp, m);
} else {
if_output(so, m);
}
return 0;
}

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/* /*
* Copyright (c) 1982, 1986, 1988, 1993 * Copyright (c) 1982, 1986, 1988, 1993
* The Regents of the University of California. All rights reserved. * The Regents of the University of California. All rights reserved.
@@ -33,334 +34,459 @@
#include "slirp.h" #include "slirp.h"
#include "ip_icmp.h" #include "ip_icmp.h"
struct icmpstat icmpstat; #ifndef WITH_ICMP_ERROR_MSG
#define WITH_ICMP_ERROR_MSG 0
#endif
/* The message sent when emulating PING */ /* The message sent when emulating PING */
/* Be nice and tell them it's just a psuedo-ping packet */ /* Be nice and tell them it's just a pseudo-ping packet */
char icmp_ping_msg[] = "This is a psuedo-PING packet used by Slirp to emulate ICMP ECHO-REQUEST packets.\n"; static const char icmp_ping_msg[] =
"This is a pseudo-PING packet used by Slirp to emulate ICMP ECHO-REQUEST "
"packets.\n";
/* list of actions for icmp_error() on RX of an icmp message */ /* list of actions for icmp_send_error() on RX of an icmp message */
static int icmp_flush[19] = { static const int icmp_flush[19] = {
/* ECHO REPLY (0) */ 0, /* ECHO REPLY (0) */ 0,
1, 1,
1, 1,
/* DEST UNREACH (3) */ 1, /* DEST UNREACH (3) */ 1,
/* SOURCE QUENCH (4)*/ 1, /* SOURCE QUENCH (4)*/ 1,
/* REDIRECT (5) */ 1, /* REDIRECT (5) */ 1,
1, 1,
1, 1,
/* ECHO (8) */ 0, /* ECHO (8) */ 0,
/* ROUTERADVERT (9) */ 1, /* ROUTERADVERT (9) */ 1,
/* ROUTERSOLICIT (10) */ 1, /* ROUTERSOLICIT (10) */ 1,
/* TIME EXCEEDED (11) */ 1, /* TIME EXCEEDED (11) */ 1,
/* PARAMETER PROBLEM (12) */ 1, /* PARAMETER PROBLEM (12) */ 1,
/* TIMESTAMP (13) */ 0, /* TIMESTAMP (13) */ 0,
/* TIMESTAMP REPLY (14) */ 0, /* TIMESTAMP REPLY (14) */ 0,
/* INFO (15) */ 0, /* INFO (15) */ 0,
/* INFO REPLY (16) */ 0, /* INFO REPLY (16) */ 0,
/* ADDR MASK (17) */ 0, /* ADDR MASK (17) */ 0,
/* ADDR MASK REPLY (18) */ 0 /* ADDR MASK REPLY (18) */ 0
}; };
void icmp_init(Slirp *slirp)
{
slirp->icmp.so_next = slirp->icmp.so_prev = &slirp->icmp;
slirp->icmp_last_so = &slirp->icmp;
}
void icmp_cleanup(Slirp *slirp)
{
struct socket *so, *so_next;
for (so = slirp->icmp.so_next; so != &slirp->icmp; so = so_next) {
so_next = so->so_next;
icmp_detach(so);
}
}
static int icmp_send(struct socket *so, struct mbuf *m, int hlen)
{
struct ip *ip = mtod(m, struct ip *);
struct sockaddr_in addr;
so->s = slirp_socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
if (so->s == -1) {
return -1;
}
if (slirp_bind_outbound(so, AF_INET) != 0) {
// bind failed - close socket
closesocket(so->s);
so->s = -1;
return -1;
}
so->so_m = m;
so->so_faddr = ip->ip_dst;
so->so_laddr = ip->ip_src;
so->so_iptos = ip->ip_tos;
so->so_type = IPPROTO_ICMP;
so->so_state = SS_ISFCONNECTED;
so->so_expire = curtime + SO_EXPIRE;
addr.sin_family = AF_INET;
addr.sin_addr = so->so_faddr;
insque(so, &so->slirp->icmp);
if (sendto(so->s, m->m_data + hlen, m->m_len - hlen, 0,
(struct sockaddr *)&addr, sizeof(addr)) == -1) {
DEBUG_MISC("icmp_input icmp sendto tx errno = %d-%s", errno,
strerror(errno));
icmp_send_error(m, ICMP_UNREACH, ICMP_UNREACH_NET, 0, strerror(errno));
icmp_detach(so);
}
return 0;
}
void icmp_detach(struct socket *so)
{
so->slirp->cb->unregister_poll_fd(so->s, so->slirp->opaque);
closesocket(so->s);
sofree(so);
}
/* /*
* Process a received ICMP message. * Process a received ICMP message.
*/ */
void void icmp_input(struct mbuf *m, int hlen)
icmp_input(m, hlen)
struct SLIRPmbuf *m;
int hlen;
{ {
register struct icmp *icp; register struct icmp *icp;
register struct ip *ip=mtod(m, struct ip *); register struct ip *ip = mtod(m, struct ip *);
int icmplen=ip->ip_len; int icmplen = ip->ip_len;
/* int code; */ Slirp *slirp = m->slirp;
DEBUG_CALL("icmp_input");
DEBUG_ARG("m = %lx", (long )m);
DEBUG_ARG("m_len = %d", m->m_len);
icmpstat.icps_received++; DEBUG_CALL("icmp_input");
DEBUG_ARG("m = %p", m);
/* DEBUG_ARG("m_len = %d", m->m_len);
* Locate icmp structure in SLIRPmbuf, and check
* that its not corrupted and of at least minimum length.
*/
if (icmplen < ICMP_MINLEN) { /* min 8 bytes payload */
icmpstat.icps_tooshort++;
freeit:
m_freem(m);
goto end_error;
}
m->m_len -= hlen; /*
m->m_data += hlen; * Locate icmp structure in mbuf, and check
icp = mtod(m, struct icmp *); * that its not corrupted and of at least minimum length.
if (cksum(m, icmplen)) { */
icmpstat.icps_checksum++; if (icmplen < ICMP_MINLEN) { /* min 8 bytes payload */
goto freeit; freeit:
} m_free(m);
m->m_len += hlen; goto end_error;
m->m_data -= hlen; }
/* icmpstat.icps_inhist[icp->icmp_type]++; */
/* code = icp->icmp_code; */
DEBUG_ARG("icmp_type = %d", icp->icmp_type); m->m_len -= hlen;
switch (icp->icmp_type) { m->m_data += hlen;
case ICMP_ECHO: icp = mtod(m, struct icmp *);
icp->icmp_type = ICMP_ECHOREPLY; if (cksum(m, icmplen)) {
ip->ip_len += hlen; /* since ip_input subtracts this */ goto freeit;
if (ip->ip_dst.s_addr == alias_addr.s_addr) { }
icmp_reflect(m); m->m_len += hlen;
} else { m->m_data -= hlen;
struct SLIRPsocket *so;
struct sockaddr_in addr; DEBUG_ARG("icmp_type = %d", icp->icmp_type);
if ((so = socreate()) == NULL) goto freeit; switch (icp->icmp_type) {
if(udp_attach(so) == -1) { case ICMP_ECHO:
DEBUG_MISC((dfd,"icmp_input udp_attach errno = %d-%s\n", ip->ip_len += hlen; /* since ip_input subtracts this */
errno,strerror(errno))); if (ip->ip_dst.s_addr == slirp->vhost_addr.s_addr ||
sofree(so); ip->ip_dst.s_addr == slirp->vnameserver_addr.s_addr) {
m_free(m); icmp_reflect(m);
goto end_error; } else if (slirp->restricted) {
} goto freeit;
so->so_m = m; } else {
so->so_faddr = ip->ip_dst; struct socket *so;
so->so_fport = htons(7); struct sockaddr_storage addr;
so->so_laddr = ip->ip_src; so = socreate(slirp);
so->so_lport = htons(9); if (icmp_send(so, m, hlen) == 0) {
so->so_iptos = ip->ip_tos; return;
so->so_type = IPPROTO_ICMP; }
so->so_state = SS_ISFCONNECTED; if (udp_attach(so, AF_INET) == -1) {
DEBUG_MISC("icmp_input udp_attach errno = %d-%s", errno,
/* Send the packet */ strerror(errno));
addr.sin_family = AF_INET; sofree(so);
if ((so->so_faddr.s_addr & htonl(0xffffff00)) == special_addr.s_addr) { m_free(m);
/* It's an alias */ goto end_error;
switch(ntohl(so->so_faddr.s_addr) & 0xff) { }
case CTL_DNS: so->so_m = m;
addr.sin_addr = dns_addr; so->so_ffamily = AF_INET;
break; so->so_faddr = ip->ip_dst;
case CTL_ALIAS: so->so_fport = htons(7);
default: so->so_lfamily = AF_INET;
addr.sin_addr = loopback_addr; so->so_laddr = ip->ip_src;
break; so->so_lport = htons(9);
} so->so_iptos = ip->ip_tos;
} else { so->so_type = IPPROTO_ICMP;
addr.sin_addr = so->so_faddr; so->so_state = SS_ISFCONNECTED;
}
addr.sin_port = so->so_fport; /* Send the packet */
if(sendto(so->s, icmp_ping_msg, strlen(icmp_ping_msg), 0, addr = so->fhost.ss;
(struct sockaddr *)&addr, sizeof(addr)) == -1) { if (sotranslate_out(so, &addr) < 0) {
DEBUG_MISC((dfd,"icmp_input udp sendto tx errno = %d-%s\n", icmp_send_error(m, ICMP_UNREACH, ICMP_UNREACH_NET, 0,
errno,strerror(errno))); strerror(errno));
icmp_error(m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,strerror(errno)); udp_detach(so);
udp_detach(so); return;
} }
} /* if ip->ip_dst.s_addr == alias_addr.s_addr */
break; if (sendto(so->s, icmp_ping_msg, strlen(icmp_ping_msg), 0,
case ICMP_UNREACH: (struct sockaddr *)&addr, sockaddr_size(&addr)) == -1) {
/* XXX? report error? close socket? */ DEBUG_MISC("icmp_input udp sendto tx errno = %d-%s", errno,
case ICMP_TIMXCEED: strerror(errno));
case ICMP_PARAMPROB: icmp_send_error(m, ICMP_UNREACH, ICMP_UNREACH_NET, 0,
case ICMP_SOURCEQUENCH: strerror(errno));
case ICMP_TSTAMP: udp_detach(so);
case ICMP_MASKREQ: }
case ICMP_REDIRECT: } /* if ip->ip_dst.s_addr == alias_addr.s_addr */
icmpstat.icps_notsupp++; break;
m_freem(m); case ICMP_UNREACH:
break; /* XXX? report error? close socket? */
case ICMP_TIMXCEED:
default: case ICMP_PARAMPROB:
icmpstat.icps_badtype++; case ICMP_SOURCEQUENCH:
m_freem(m); case ICMP_TSTAMP:
} /* swith */ case ICMP_MASKREQ:
case ICMP_REDIRECT:
m_free(m);
break;
default:
m_free(m);
} /* swith */
end_error: end_error:
/* m is m_free()'d xor put in a socket xor or given to ip_send */ /* m is m_free()'d xor put in a socket xor or given to ip_send */
return; return;
} }
/* /*
* Send an ICMP message in response to a situation * Send an ICMP message in response to a situation
* *
* RFC 1122: 3.2.2 MUST send at least the IP header and 8 bytes of header. MAY send more (we do). * RFC 1122: 3.2.2 MUST send at least the IP header and 8 bytes of header.
* MUST NOT change this header information. *MAY send more (we do). MUST NOT change this header information. MUST NOT reply
* MUST NOT reply to a multicast/broadcast IP address. *to a multicast/broadcast IP address. MUST NOT reply to a multicast/broadcast
* MUST NOT reply to a multicast/broadcast MAC address. *MAC address. MUST reply to only the first fragment.
* MUST reply to only the first fragment.
*/ */
/* /*
* Send ICMP_UNREACH back to the source regarding msrc. * Send ICMP_UNREACH back to the source regarding msrc.
* SLIRPmbuf *msrc is used as a template, but is NOT m_free()'d. * mbuf *msrc is used as a template, but is NOT m_free()'d.
* It is reported as the bad ip packet. The header should * It is reported as the bad ip packet. The header should
* be fully correct and in host byte order. * be fully correct and in host byte order.
* ICMP fragmentation is illegal. All machines must accept 576 bytes in one * ICMP fragmentation is illegal. All machines must accept 576 bytes in one
* packet. The maximum payload is 576-20(ip hdr)-8(icmp hdr)=548 * packet. The maximum payload is 576-20(ip hdr)-8(icmp hdr)=548
*/ */
#define ICMP_MAXDATALEN (IP_MSS-28) #define ICMP_MAXDATALEN (IP_MSS - 28)
void void icmp_send_error(struct mbuf *msrc, uint8_t type, uint8_t code, int minsize,
icmp_error(struct SLIRPmbuf *msrc, u_char type, u_char code, int minsize, char *message) const char *message)
{ {
unsigned hlen, shlen, s_ip_len; unsigned hlen, shlen, s_ip_len;
register struct ip *ip; register struct ip *ip;
register struct icmp *icp; register struct icmp *icp;
register struct SLIRPmbuf *m; register struct mbuf *m;
DEBUG_CALL("icmp_error"); DEBUG_CALL("icmp_send_error");
DEBUG_ARG("msrc = %lx", (long )msrc); DEBUG_ARG("msrc = %p", msrc);
DEBUG_ARG("msrc_len = %d", msrc->m_len); DEBUG_ARG("msrc_len = %d", msrc->m_len);
if(type!=ICMP_UNREACH && type!=ICMP_TIMXCEED) goto end_error; if (type != ICMP_UNREACH && type != ICMP_TIMXCEED)
goto end_error;
/* check msrc */ /* check msrc */
if(!msrc) goto end_error; if (!msrc)
ip = mtod(msrc, struct ip *); goto end_error;
#if SLIRP_DEBUG ip = mtod(msrc, struct ip *);
{ char bufa[20], bufb[20]; if (slirp_debug & DBG_MISC) {
strcpy(bufa, inet_ntoa(ip->ip_src)); char bufa[20], bufb[20];
strcpy(bufb, inet_ntoa(ip->ip_dst)); slirp_pstrcpy(bufa, sizeof(bufa), inet_ntoa(ip->ip_src));
DEBUG_MISC((dfd, " %.16s to %.16s\n", bufa, bufb)); slirp_pstrcpy(bufb, sizeof(bufb), inet_ntoa(ip->ip_dst));
} DEBUG_MISC(" %.16s to %.16s", bufa, bufb);
#endif }
if(ip->ip_off & IP_OFFMASK) goto end_error; /* Only reply to fragment 0 */ if (ip->ip_off & IP_OFFMASK)
goto end_error; /* Only reply to fragment 0 */
shlen=ip->ip_hl << 2; /* Do not reply to source-only IPs */
s_ip_len=ip->ip_len; if ((ip->ip_src.s_addr & htonl(~(0xf << 28))) == 0) {
if(ip->ip_p == IPPROTO_ICMP) { goto end_error;
icp = (struct icmp *)((char *)ip + shlen); }
/*
* Assume any unknown ICMP type is an error. This isn't
* specified by the RFC, but think about it..
*/
if(icp->icmp_type>18 || icmp_flush[icp->icmp_type]) goto end_error;
}
/* make a copy */ shlen = ip->ip_hl << 2;
if(!(m=m_get())) goto end_error; /* get SLIRPmbuf */ s_ip_len = ip->ip_len;
{ u_int new_m_size; if (ip->ip_p == IPPROTO_ICMP) {
new_m_size=sizeof(struct ip )+ICMP_MINLEN+msrc->m_len+ICMP_MAXDATALEN; icp = (struct icmp *)((char *)ip + shlen);
if(new_m_size>m->m_size) m_inc(m, new_m_size); /*
} * Assume any unknown ICMP type is an error. This isn't
memcpy(m->m_data, msrc->m_data, msrc->m_len); * specified by the RFC, but think about it..
m->m_len = msrc->m_len; /* copy msrc to m */ */
if (icp->icmp_type > 18 || icmp_flush[icp->icmp_type])
goto end_error;
}
/* make the header of the reply packet */ /* make a copy */
ip = mtod(m, struct ip *); m = m_get(msrc->slirp);
hlen= sizeof(struct ip ); /* no options in reply */ if (!m) {
goto end_error;
/* fill in icmp */ }
m->m_data += hlen;
m->m_len -= hlen;
icp = mtod(m, struct icmp *); {
int new_m_size;
new_m_size =
sizeof(struct ip) + ICMP_MINLEN + msrc->m_len + ICMP_MAXDATALEN;
if (new_m_size > m->m_size)
m_inc(m, new_m_size);
}
memcpy(m->m_data, msrc->m_data, msrc->m_len);
m->m_len = msrc->m_len; /* copy msrc to m */
if(minsize) s_ip_len=shlen+ICMP_MINLEN; /* return header+8b only */ /* make the header of the reply packet */
else if(s_ip_len>ICMP_MAXDATALEN) /* maximum size */ ip = mtod(m, struct ip *);
s_ip_len=ICMP_MAXDATALEN; hlen = sizeof(struct ip); /* no options in reply */
m->m_len=ICMP_MINLEN+s_ip_len; /* 8 bytes ICMP header */ /* fill in icmp */
m->m_data += hlen;
m->m_len -= hlen;
/* min. size = 8+sizeof(struct ip)+8 */ icp = mtod(m, struct icmp *);
icp->icmp_type = type; if (minsize)
icp->icmp_code = code; s_ip_len = shlen + ICMP_MINLEN; /* return header+8b only */
icp->icmp_id = 0; else if (s_ip_len > ICMP_MAXDATALEN) /* maximum size */
icp->icmp_seq = 0; s_ip_len = ICMP_MAXDATALEN;
memcpy(&icp->icmp_ip, msrc->m_data, s_ip_len); /* report the ip packet */ m->m_len = ICMP_MINLEN + s_ip_len; /* 8 bytes ICMP header */
HTONS(icp->icmp_ip.ip_len);
HTONS(icp->icmp_ip.ip_id);
HTONS(icp->icmp_ip.ip_off);
#if SLIRP_DEBUG /* min. size = 8+sizeof(struct ip)+8 */
if(message) { /* DEBUG : append message to ICMP packet */
int message_len;
char *cpnt;
message_len=strlen(message);
if(message_len>ICMP_MAXDATALEN) message_len=ICMP_MAXDATALEN;
cpnt=(char *)m->m_data+m->m_len;
memcpy(cpnt, message, message_len);
m->m_len+=message_len;
}
#endif
icp->icmp_cksum = 0; icp->icmp_type = type;
icp->icmp_cksum = cksum(m, m->m_len); icp->icmp_code = code;
icp->icmp_id = 0;
icp->icmp_seq = 0;
m->m_data -= hlen; memcpy(&icp->icmp_ip, msrc->m_data, s_ip_len); /* report the ip packet */
m->m_len += hlen; HTONS(icp->icmp_ip.ip_len);
HTONS(icp->icmp_ip.ip_id);
HTONS(icp->icmp_ip.ip_off);
/* fill in ip */ if (message && WITH_ICMP_ERROR_MSG) { /* append message to ICMP packet */
ip->ip_hl = hlen >> 2; int message_len;
ip->ip_len = (u_int16_t)m->m_len; char *cpnt;
message_len = strlen(message);
ip->ip_tos=((ip->ip_tos & 0x1E) | 0xC0); /* high priority for errors */ if (message_len > ICMP_MAXDATALEN)
message_len = ICMP_MAXDATALEN;
cpnt = (char *)m->m_data + m->m_len;
memcpy(cpnt, message, message_len);
m->m_len += message_len;
}
ip->ip_ttl = MAXTTL; icp->icmp_cksum = 0;
ip->ip_p = IPPROTO_ICMP; icp->icmp_cksum = cksum(m, m->m_len);
ip->ip_dst = ip->ip_src; /* ip adresses */
ip->ip_src = alias_addr;
(void ) ip_output((struct SLIRPsocket *)NULL, m); m->m_data -= hlen;
m->m_len += hlen;
icmpstat.icps_reflect++;
/* fill in ip */
ip->ip_hl = hlen >> 2;
ip->ip_len = m->m_len;
ip->ip_tos = ((ip->ip_tos & 0x1E) | 0xC0); /* high priority for errors */
ip->ip_ttl = MAXTTL;
ip->ip_p = IPPROTO_ICMP;
ip->ip_dst = ip->ip_src; /* ip addresses */
ip->ip_src = m->slirp->vhost_addr;
(void)ip_output((struct socket *)NULL, m);
end_error: end_error:
return; return;
} }
#undef ICMP_MAXDATALEN #undef ICMP_MAXDATALEN
/* /*
* Reflect the ip packet back to the source * Reflect the ip packet back to the source
*/ */
void void icmp_reflect(struct mbuf *m)
icmp_reflect(m)
struct SLIRPmbuf *m;
{ {
register struct ip *ip = mtod(m, struct ip *); register struct ip *ip = mtod(m, struct ip *);
int hlen = ip->ip_hl << 2; int hlen = ip->ip_hl << 2;
int optlen = hlen - sizeof(struct ip ); int optlen = hlen - sizeof(struct ip);
register struct icmp *icp; register struct icmp *icp;
/*
* Send an icmp packet back to the ip level,
* after supplying a checksum.
*/
m->m_data += hlen;
m->m_len -= hlen;
icp = mtod(m, struct icmp *);
icp->icmp_cksum = 0;
icp->icmp_cksum = cksum(m, ip->ip_len - hlen);
m->m_data -= hlen;
m->m_len += hlen;
/* fill in ip */
if (optlen > 0) {
/* /*
* Strip out original options by copying rest of first * Send an icmp packet back to the ip level,
* SLIRPmbuf's data back, and adjust the IP length. * after supplying a checksum.
*/ */
memmove((SLIRPcaddr_t)(ip + 1), (SLIRPcaddr_t)ip + hlen, m->m_data += hlen;
(unsigned )(m->m_len - hlen)); m->m_len -= hlen;
hlen -= optlen; icp = mtod(m, struct icmp *);
ip->ip_hl = hlen >> 2;
ip->ip_len -= optlen;
m->m_len -= optlen;
}
ip->ip_ttl = MAXTTL; icp->icmp_type = ICMP_ECHOREPLY;
{ /* swap */ icp->icmp_cksum = 0;
struct in_addr icmp_dst; icp->icmp_cksum = cksum(m, ip->ip_len - hlen);
icmp_dst = ip->ip_dst;
ip->ip_dst = ip->ip_src;
ip->ip_src = icmp_dst;
}
(void ) ip_output((struct SLIRPsocket *)NULL, m); m->m_data -= hlen;
m->m_len += hlen;
icmpstat.icps_reflect++; /* fill in ip */
if (optlen > 0) {
/*
* Strip out original options by copying rest of first
* mbuf's data back, and adjust the IP length.
*/
memmove((char *)(ip + 1), (char *)ip + hlen,
(unsigned)(m->m_len - hlen));
hlen -= optlen;
ip->ip_hl = hlen >> 2;
ip->ip_len -= optlen;
m->m_len -= optlen;
}
ip->ip_ttl = MAXTTL;
{ /* swap */
struct in_addr icmp_dst;
icmp_dst = ip->ip_dst;
ip->ip_dst = ip->ip_src;
ip->ip_src = icmp_dst;
}
(void)ip_output((struct socket *)NULL, m);
}
void icmp_receive(struct socket *so)
{
struct mbuf *m = so->so_m;
struct ip *ip = mtod(m, struct ip *);
int hlen = ip->ip_hl << 2;
uint8_t error_code;
struct icmp *icp;
int id, len;
m->m_data += hlen;
m->m_len -= hlen;
icp = mtod(m, struct icmp *);
id = icp->icmp_id;
len = recv(so->s, icp, M_ROOM(m), 0);
/*
* The behavior of reading SOCK_DGRAM+IPPROTO_ICMP sockets is inconsistent
* between host OSes. On Linux, only the ICMP header and payload is
* included. On macOS/Darwin, the socket acts like a raw socket and
* includes the IP header as well. On other BSDs, SOCK_DGRAM+IPPROTO_ICMP
* sockets aren't supported at all, so we treat them like raw sockets. It
* isn't possible to detect this difference at runtime, so we must use an
* #ifdef to determine if we need to remove the IP header.
*/
#ifdef CONFIG_BSD
if (len >= sizeof(struct ip)) {
struct ip *inner_ip = mtod(m, struct ip *);
int inner_hlen = inner_ip->ip_hl << 2;
if (inner_hlen > len) {
len = -1;
errno = -EINVAL;
} else {
len -= inner_hlen;
memmove(icp, (unsigned char *)icp + inner_hlen, len);
}
} else {
len = -1;
errno = -EINVAL;
}
#endif
icp->icmp_id = id;
m->m_data -= hlen;
m->m_len += hlen;
if (len == -1 || len == 0) {
if (errno == ENETUNREACH) {
error_code = ICMP_UNREACH_NET;
} else {
error_code = ICMP_UNREACH_HOST;
}
DEBUG_MISC(" udp icmp rx errno = %d-%s", errno, strerror(errno));
icmp_send_error(so->so_m, ICMP_UNREACH, error_code, 0, strerror(errno));
} else {
icmp_reflect(so->so_m);
so->so_m = NULL; /* Don't m_free() it again! */
}
icmp_detach(so);
} }

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/* /*
* Copyright (c) 1982, 1986, 1993 * Copyright (c) 1982, 1986, 1993
* The Regents of the University of California. All rights reserved. * The Regents of the University of California. All rights reserved.
@@ -30,139 +31,136 @@
* ip_icmp.h,v 1.4 1995/05/30 08:09:43 rgrimes Exp * ip_icmp.h,v 1.4 1995/05/30 08:09:43 rgrimes Exp
*/ */
#ifndef _NETINET_IP_ICMP_H_ #ifndef NETINET_IP_ICMP_H
#define _NETINET_IP_ICMP_H_ #define NETINET_IP_ICMP_H
/* /*
* Interface Control Message Protocol Definitions. * Interface Control Message Protocol Definitions.
* Per RFC 792, September 1981. * Per RFC 792, September 1981.
*/ */
typedef u_int32_t n_time; typedef uint32_t n_time;
/* /*
* Structure of an icmp header. * Structure of an icmp header.
*/ */
#ifdef PRAGMA_PACK_SUPPORTED
#pragma pack(1)
#endif
struct icmp { struct icmp {
u_char icmp_type; /* type of message, see below */ uint8_t icmp_type; /* type of message, see below */
u_char icmp_code; /* type sub code */ uint8_t icmp_code; /* type sub code */
u_short icmp_cksum; /* ones complement cksum of struct */ uint16_t icmp_cksum; /* ones complement cksum of struct */
union { union {
u_char ih_pptr; /* ICMP_PARAMPROB */ uint8_t ih_pptr; /* ICMP_PARAMPROB */
struct in_addr ih_gwaddr; /* ICMP_REDIRECT */ struct in_addr ih_gwaddr; /* ICMP_REDIRECT */
struct ih_idseq { struct ih_idseq {
u_short icd_id; uint16_t icd_id;
u_short icd_seq; uint16_t icd_seq;
} ih_idseq; } ih_idseq;
int ih_void; int ih_void;
/* ICMP_UNREACH_NEEDFRAG -- Path MTU Discovery (RFC1191) */ /* ICMP_UNREACH_NEEDFRAG -- Path MTU Discovery (RFC1191) */
struct ih_pmtu { struct ih_pmtu {
u_short ipm_void; uint16_t ipm_void;
u_short ipm_nextmtu; uint16_t ipm_nextmtu;
} ih_pmtu; } ih_pmtu;
} icmp_hun; } icmp_hun;
#define icmp_pptr icmp_hun.ih_pptr #define icmp_pptr icmp_hun.ih_pptr
#define icmp_gwaddr icmp_hun.ih_gwaddr #define icmp_gwaddr icmp_hun.ih_gwaddr
#define icmp_id icmp_hun.ih_idseq.icd_id #define icmp_id icmp_hun.ih_idseq.icd_id
#define icmp_seq icmp_hun.ih_idseq.icd_seq #define icmp_seq icmp_hun.ih_idseq.icd_seq
#define icmp_void icmp_hun.ih_void #define icmp_void icmp_hun.ih_void
#define icmp_pmvoid icmp_hun.ih_pmtu.ipm_void #define icmp_pmvoid icmp_hun.ih_pmtu.ipm_void
#define icmp_nextmtu icmp_hun.ih_pmtu.ipm_nextmtu #define icmp_nextmtu icmp_hun.ih_pmtu.ipm_nextmtu
union { union {
struct id_ts { struct id_ts {
n_time its_otime; n_time its_otime;
n_time its_rtime; n_time its_rtime;
n_time its_ttime; n_time its_ttime;
} id_ts; } id_ts;
struct id_ip { struct id_ip {
struct ip idi_ip; struct ip idi_ip;
/* options and then 64 bits of data */ /* options and then 64 bits of data */
} id_ip; } id_ip;
uint32_t id_mask; uint32_t id_mask;
char id_data[1]; char id_data[1];
} icmp_dun; } icmp_dun;
#define icmp_otime icmp_dun.id_ts.its_otime #define icmp_otime icmp_dun.id_ts.its_otime
#define icmp_rtime icmp_dun.id_ts.its_rtime #define icmp_rtime icmp_dun.id_ts.its_rtime
#define icmp_ttime icmp_dun.id_ts.its_ttime #define icmp_ttime icmp_dun.id_ts.its_ttime
#define icmp_ip icmp_dun.id_ip.idi_ip #define icmp_ip icmp_dun.id_ip.idi_ip
#define icmp_mask icmp_dun.id_mask #define icmp_mask icmp_dun.id_mask
#define icmp_data icmp_dun.id_data #define icmp_data icmp_dun.id_data
} PACKED__; };
#ifdef PRAGMA_PACK_SUPPORTED
#pragma pack(0)
#endif
/* /*
* Lower bounds on packet lengths for various types. * Lower bounds on packet lengths for various types.
* For the error advice packets must first insure that the * For the error advice packets must first ensure that the
* packet is large enought to contain the returned ip header. * packet is large enough to contain the returned ip header.
* Only then can we do the check to see if 64 bits of packet * Only then can we do the check to see if 64 bits of packet
* data have been returned, since we need to check the returned * data have been returned, since we need to check the returned
* ip header length. * ip header length.
*/ */
#define ICMP_MINLEN 8 /* abs minimum */ #define ICMP_MINLEN 8 /* abs minimum */
#define ICMP_TSLEN (8 + 3 * sizeof (n_time)) /* timestamp */ #define ICMP_TSLEN (8 + 3 * sizeof(n_time)) /* timestamp */
#define ICMP_MASKLEN 12 /* address mask */ #define ICMP_MASKLEN 12 /* address mask */
#define ICMP_ADVLENMIN (8 + sizeof (struct ip) + 8) /* min */ #define ICMP_ADVLENMIN (8 + sizeof(struct ip) + 8) /* min */
#define ICMP_ADVLEN(p) (8 + ((p)->icmp_ip.ip_hl << 2) + 8) #define ICMP_ADVLEN(p) (8 + ((p)->icmp_ip.ip_hl << 2) + 8)
/* N.B.: must separately check that ip_hl >= 5 */ /* N.B.: must separately check that ip_hl >= 5 */
/* /*
* Definition of type and code field values. * Definition of type and code field values.
*/ */
#define ICMP_ECHOREPLY 0 /* echo reply */ #define ICMP_ECHOREPLY 0 /* echo reply */
#define ICMP_UNREACH 3 /* dest unreachable, codes: */ #define ICMP_UNREACH 3 /* dest unreachable, codes: */
#define ICMP_UNREACH_NET 0 /* bad net */ #define ICMP_UNREACH_NET 0 /* bad net */
#define ICMP_UNREACH_HOST 1 /* bad host */ #define ICMP_UNREACH_HOST 1 /* bad host */
#define ICMP_UNREACH_PROTOCOL 2 /* bad protocol */ #define ICMP_UNREACH_PROTOCOL 2 /* bad protocol */
#define ICMP_UNREACH_PORT 3 /* bad port */ #define ICMP_UNREACH_PORT 3 /* bad port */
#define ICMP_UNREACH_NEEDFRAG 4 /* IP_DF caused drop */ #define ICMP_UNREACH_NEEDFRAG 4 /* IP_DF caused drop */
#define ICMP_UNREACH_SRCFAIL 5 /* src route failed */ #define ICMP_UNREACH_SRCFAIL 5 /* src route failed */
#define ICMP_UNREACH_NET_UNKNOWN 6 /* unknown net */ #define ICMP_UNREACH_NET_UNKNOWN 6 /* unknown net */
#define ICMP_UNREACH_HOST_UNKNOWN 7 /* unknown host */ #define ICMP_UNREACH_HOST_UNKNOWN 7 /* unknown host */
#define ICMP_UNREACH_ISOLATED 8 /* src host isolated */ #define ICMP_UNREACH_ISOLATED 8 /* src host isolated */
#define ICMP_UNREACH_NET_PROHIB 9 /* prohibited access */ #define ICMP_UNREACH_NET_PROHIB 9 /* prohibited access */
#define ICMP_UNREACH_HOST_PROHIB 10 /* ditto */ #define ICMP_UNREACH_HOST_PROHIB 10 /* ditto */
#define ICMP_UNREACH_TOSNET 11 /* bad tos for net */ #define ICMP_UNREACH_TOSNET 11 /* bad tos for net */
#define ICMP_UNREACH_TOSHOST 12 /* bad tos for host */ #define ICMP_UNREACH_TOSHOST 12 /* bad tos for host */
#define ICMP_SOURCEQUENCH 4 /* packet lost, slow down */ #define ICMP_SOURCEQUENCH 4 /* packet lost, slow down */
#define ICMP_REDIRECT 5 /* shorter route, codes: */ #define ICMP_REDIRECT 5 /* shorter route, codes: */
#define ICMP_REDIRECT_NET 0 /* for network */ #define ICMP_REDIRECT_NET 0 /* for network */
#define ICMP_REDIRECT_HOST 1 /* for host */ #define ICMP_REDIRECT_HOST 1 /* for host */
#define ICMP_REDIRECT_TOSNET 2 /* for tos and net */ #define ICMP_REDIRECT_TOSNET 2 /* for tos and net */
#define ICMP_REDIRECT_TOSHOST 3 /* for tos and host */ #define ICMP_REDIRECT_TOSHOST 3 /* for tos and host */
#define ICMP_ECHO 8 /* echo service */ #define ICMP_ECHO 8 /* echo service */
#define ICMP_ROUTERADVERT 9 /* router advertisement */ #define ICMP_ROUTERADVERT 9 /* router advertisement */
#define ICMP_ROUTERSOLICIT 10 /* router solicitation */ #define ICMP_ROUTERSOLICIT 10 /* router solicitation */
#define ICMP_TIMXCEED 11 /* time exceeded, code: */ #define ICMP_TIMXCEED 11 /* time exceeded, code: */
#define ICMP_TIMXCEED_INTRANS 0 /* ttl==0 in transit */ #define ICMP_TIMXCEED_INTRANS 0 /* ttl==0 in transit */
#define ICMP_TIMXCEED_REASS 1 /* ttl==0 in reass */ #define ICMP_TIMXCEED_REASS 1 /* ttl==0 in reass */
#define ICMP_PARAMPROB 12 /* ip header bad */ #define ICMP_PARAMPROB 12 /* ip header bad */
#define ICMP_PARAMPROB_OPTABSENT 1 /* req. opt. absent */ #define ICMP_PARAMPROB_OPTABSENT 1 /* req. opt. absent */
#define ICMP_TSTAMP 13 /* timestamp request */ #define ICMP_TSTAMP 13 /* timestamp request */
#define ICMP_TSTAMPREPLY 14 /* timestamp reply */ #define ICMP_TSTAMPREPLY 14 /* timestamp reply */
#define ICMP_IREQ 15 /* information request */ #define ICMP_IREQ 15 /* information request */
#define ICMP_IREQREPLY 16 /* information reply */ #define ICMP_IREQREPLY 16 /* information reply */
#define ICMP_MASKREQ 17 /* address mask request */ #define ICMP_MASKREQ 17 /* address mask request */
#define ICMP_MASKREPLY 18 /* address mask reply */ #define ICMP_MASKREPLY 18 /* address mask reply */
#define ICMP_MAXTYPE 18 #define ICMP_MAXTYPE 18
#define ICMP_INFOTYPE(type) \ #define ICMP_INFOTYPE(type) \
((type) == ICMP_ECHOREPLY || (type) == ICMP_ECHO || \ ((type) == ICMP_ECHOREPLY || (type) == ICMP_ECHO || \
(type) == ICMP_ROUTERADVERT || (type) == ICMP_ROUTERSOLICIT || \ (type) == ICMP_ROUTERADVERT || (type) == ICMP_ROUTERSOLICIT || \
(type) == ICMP_TSTAMP || (type) == ICMP_TSTAMPREPLY || \ (type) == ICMP_TSTAMP || (type) == ICMP_TSTAMPREPLY || \
(type) == ICMP_IREQ || (type) == ICMP_IREQREPLY || \ (type) == ICMP_IREQ || (type) == ICMP_IREQREPLY || \
(type) == ICMP_MASKREQ || (type) == ICMP_MASKREPLY) (type) == ICMP_MASKREQ || (type) == ICMP_MASKREPLY)
void icmp_input _P((struct SLIRPmbuf *, int)); void icmp_init(Slirp *slirp);
void icmp_error _P((struct SLIRPmbuf *, u_char, u_char, int, char *)); void icmp_cleanup(Slirp *slirp);
void icmp_reflect _P((struct SLIRPmbuf *)); void icmp_input(struct mbuf *, int);
void icmp_send_error(struct mbuf *msrc, uint8_t type, uint8_t code, int minsize,
const char *message);
void icmp_reflect(struct mbuf *);
void icmp_receive(struct socket *so);
void icmp_detach(struct socket *so);
#endif #endif

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/* /*
* Copyright (c) 1982, 1986, 1988, 1993 * Copyright (c) 1982, 1986, 1988, 1993
* The Regents of the University of California. All rights reserved. * The Regents of the University of California. All rights reserved.
@@ -33,405 +34,382 @@
/* /*
* Changes and additions relating to SLiRP are * Changes and additions relating to SLiRP are
* Copyright (c) 1995 Danny Gasparovski. * Copyright (c) 1995 Danny Gasparovski.
*
* Please read the file COPYRIGHT for the
* terms and conditions of the copyright.
*/ */
#include <stdint.h>
#include "slirp.h" #include "slirp.h"
#include "ip_icmp.h" #include "ip_icmp.h"
int ip_defttl; static struct ip *ip_reass(Slirp *slirp, struct ip *ip, struct ipq *fp);
struct ipstat ipstat; static void ip_freef(Slirp *slirp, struct ipq *fp);
struct ipq ipq; static void ip_enq(register struct ipasfrag *p, register struct ipasfrag *prev);
static void ip_deq(register struct ipasfrag *p);
/* /*
* IP initialization: fill in IP protocol switch table. * IP initialization: fill in IP protocol switch table.
* All protocols not implemented in kernel go to raw IP protocol handler. * All protocols not implemented in kernel go to raw IP protocol handler.
*/ */
void void ip_init(Slirp *slirp)
ip_init()
{ {
ipq.next = ipq.prev = (ipqp_32)&ipq; slirp->ipq.ip_link.next = slirp->ipq.ip_link.prev = &slirp->ipq.ip_link;
ip_id = tt.tv_sec & 0xffff; udp_init(slirp);
udp_init(); tcp_init(slirp);
tcp_init(); icmp_init(slirp);
ip_defttl = IPDEFTTL; }
void ip_cleanup(Slirp *slirp)
{
udp_cleanup(slirp);
tcp_cleanup(slirp);
icmp_cleanup(slirp);
} }
/* /*
* Ip input routine. Checksum and byte swap header. If fragmented * Ip input routine. Checksum and byte swap header. If fragmented
* try to reassemble. Process options. Pass to next level. * try to reassemble. Process options. Pass to next level.
*/ */
void void ip_input(struct mbuf *m)
ip_input(m)
struct SLIRPmbuf *m;
{ {
register struct ip *ip; Slirp *slirp = m->slirp;
u_int hlen; register struct ip *ip;
int hlen;
DEBUG_CALL("ip_input");
DEBUG_ARG("m = %lx", (long)m);
DEBUG_ARG("m_len = %d", m->m_len);
ipstat.ips_total++; if (!slirp->in_enabled) {
goto bad;
if (m->m_len < sizeof (struct ip)) { }
ipstat.ips_toosmall++;
return;
}
ip = mtod(m, struct ip *);
if (ip->ip_v != IPVERSION) {
ipstat.ips_badvers++;
goto bad;
}
hlen = ip->ip_hl << 2; DEBUG_CALL("ip_input");
if (hlen<sizeof(struct ip ) || hlen>m->m_len) {/* min header length */ DEBUG_ARG("m = %p", m);
ipstat.ips_badhlen++; /* or packet too short */ DEBUG_ARG("m_len = %d", m->m_len);
goto bad;
}
/* keep ip header intact for ICMP reply if (m->m_len < sizeof(struct ip)) {
* ip->ip_sum = cksum(m, hlen); goto bad;
* if (ip->ip_sum) { }
*/
if(cksum(m,hlen)) {
ipstat.ips_badsum++;
goto bad;
}
/* ip = mtod(m, struct ip *);
* Convert fields to host representation.
*/
NTOHS(ip->ip_len);
if (ip->ip_len < hlen) {
ipstat.ips_badlen++;
goto bad;
}
NTOHS(ip->ip_id);
NTOHS(ip->ip_off);
/* if (ip->ip_v != IPVERSION) {
* Check that the amount of data in the buffers goto bad;
* is as at least much as the IP header would have us expect. }
* Trim SLIRPmbufs if longer than we expect.
* Drop packet if shorter than we expect.
*/
if (m->m_len < ip->ip_len) {
ipstat.ips_tooshort++;
goto bad;
}
/* Should drop packet if SLIRPmbuf too long? hmmm... */
if (m->m_len > ip->ip_len)
m_adj(m, ip->ip_len - m->m_len);
/* check ip_ttl for a correct ICMP reply */ hlen = ip->ip_hl << 2;
if(ip->ip_ttl==0 || ip->ip_ttl==1) { if (hlen < sizeof(struct ip) || hlen > m->m_len) { /* min header length */
icmp_error(m, ICMP_TIMXCEED,ICMP_TIMXCEED_INTRANS, 0,"ttl"); goto bad; /* or packet too short */
goto bad; }
}
/* /* keep ip header intact for ICMP reply
* Process options and, if not destined for us, * ip->ip_sum = cksum(m, hlen);
* ship it on. ip_dooptions returns 1 when an * if (ip->ip_sum) {
* error was detected (causing an icmp message */
* to be sent and the original packet to be freed). if (cksum(m, hlen)) {
*/ goto bad;
/* We do no IP options */ }
/* if (hlen > sizeof (struct ip) && ip_dooptions(m))
* goto next;
*/
/*
* If offset or IP_MF are set, must reassemble.
* Otherwise, nothing need be done.
* (We could look in the reassembly queue to see
* if the packet was previously fragmented,
* but it's not worth the time; just let them time out.)
*
* XXX This should fail, don't fragment yet
*/
if (ip->ip_off &~ IP_DF) {
register struct ipq *fp;
/*
* Look for queue of fragments
* of this datagram.
*/
for (fp = (struct ipq *) ipq.next; fp != &ipq;
fp = (struct ipq *) fp->next)
if (ip->ip_id == fp->ipq_id &&
ip->ip_src.s_addr == fp->ipq_src.s_addr &&
ip->ip_dst.s_addr == fp->ipq_dst.s_addr &&
ip->ip_p == fp->ipq_p)
goto found;
fp = 0;
found:
/* /*
* Adjust ip_len to not reflect header, * Convert fields to host representation.
* set ip_mff if more fragments are expected, */
* convert offset of this to bytes. NTOHS(ip->ip_len);
*/ if (ip->ip_len < hlen) {
ip->ip_len -= hlen; goto bad;
if (ip->ip_off & IP_MF) }
((struct ipasfrag *)ip)->ipf_mff |= 1; NTOHS(ip->ip_id);
else NTOHS(ip->ip_off);
((struct ipasfrag *)ip)->ipf_mff &= ~1;
ip->ip_off <<= 3; /*
* Check that the amount of data in the buffers
* is as at least much as the IP header would have us expect.
* Trim mbufs if longer than we expect.
* Drop packet if shorter than we expect.
*/
if (m->m_len < ip->ip_len) {
goto bad;
}
/* /* Should drop packet if mbuf too long? hmmm... */
* If datagram marked as having more fragments if (m->m_len > ip->ip_len)
* or if this is not the first fragment, m_adj(m, ip->ip_len - m->m_len);
* attempt reassembly; if it succeeds, proceed.
*/
if (((struct ipasfrag *)ip)->ipf_mff & 1 || ip->ip_off) {
ipstat.ips_fragments++;
ip = ip_reass((struct ipasfrag *)ip, fp);
if (ip == 0)
return;
ipstat.ips_reassembled++;
m = dtom(ip);
} else
if (fp)
ip_freef(fp);
} else /* check ip_ttl for a correct ICMP reply */
ip->ip_len -= hlen; if (ip->ip_ttl == 0) {
icmp_send_error(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS, 0, "ttl");
goto bad;
}
/* /*
* Switch out to protocol's input routine. * If offset or IP_MF are set, must reassemble.
*/ * Otherwise, nothing need be done.
ipstat.ips_delivered++; * (We could look in the reassembly queue to see
switch (ip->ip_p) { * if the packet was previously fragmented,
case IPPROTO_TCP: * but it's not worth the time; just let them time out.)
tcp_input(m, hlen, (struct SLIRPsocket *)NULL); *
break; * XXX This should fail, don't fragment yet
case IPPROTO_UDP: */
udp_input(m, hlen); if (ip->ip_off & ~IP_DF) {
break; register struct ipq *fp;
case IPPROTO_ICMP: struct qlink *l;
icmp_input(m, hlen); /*
break; * Look for queue of fragments
default: * of this datagram.
ipstat.ips_noproto++; */
m_free(m); for (l = slirp->ipq.ip_link.next; l != &slirp->ipq.ip_link;
} l = l->next) {
return; fp = container_of(l, struct ipq, ip_link);
if (ip->ip_id == fp->ipq_id &&
ip->ip_src.s_addr == fp->ipq_src.s_addr &&
ip->ip_dst.s_addr == fp->ipq_dst.s_addr &&
ip->ip_p == fp->ipq_p)
goto found;
}
fp = NULL;
found:
/*
* Adjust ip_len to not reflect header,
* set ip_mff if more fragments are expected,
* convert offset of this to bytes.
*/
ip->ip_len -= hlen;
if (ip->ip_off & IP_MF)
ip->ip_tos |= 1;
else
ip->ip_tos &= ~1;
ip->ip_off <<= 3;
/*
* If datagram marked as having more fragments
* or if this is not the first fragment,
* attempt reassembly; if it succeeds, proceed.
*/
if (ip->ip_tos & 1 || ip->ip_off) {
ip = ip_reass(slirp, ip, fp);
if (ip == NULL)
return;
m = dtom(slirp, ip);
} else if (fp)
ip_freef(slirp, fp);
} else
ip->ip_len -= hlen;
/*
* Switch out to protocol's input routine.
*/
switch (ip->ip_p) {
case IPPROTO_TCP:
tcp_input(m, hlen, (struct socket *)NULL, AF_INET);
break;
case IPPROTO_UDP:
udp_input(m, hlen);
break;
case IPPROTO_ICMP:
icmp_input(m, hlen);
break;
default:
m_free(m);
}
return;
bad: bad:
m_freem(m); m_free(m);
return;
} }
#define iptofrag(P) ((struct ipasfrag *)(((char *)(P)) - sizeof(struct qlink)))
#define fragtoip(P) ((struct ip *)(((char *)(P)) + sizeof(struct qlink)))
/* /*
* Take incoming datagram fragment and try to * Take incoming datagram fragment and try to
* reassemble it into whole datagram. If a chain for * reassemble it into whole datagram. If a chain for
* reassembly of this datagram already exists, then it * reassembly of this datagram already exists, then it
* is given as fp; otherwise have to make a chain. * is given as fp; otherwise have to make a chain.
*/ */
struct ip * static struct ip *ip_reass(Slirp *slirp, struct ip *ip, struct ipq *fp)
ip_reass(ip, fp)
register struct ipasfrag *ip;
register struct ipq *fp;
{ {
register struct SLIRPmbuf *m = dtom(ip); register struct mbuf *m = dtom(slirp, ip);
register struct ipasfrag *q; register struct ipasfrag *q;
int hlen = ip->ip_hl << 2; int hlen = ip->ip_hl << 2;
int i, next; int i, next;
DEBUG_CALL("ip_reass");
DEBUG_ARG("ip = %lx", (long)ip);
DEBUG_ARG("fp = %lx", (long)fp);
DEBUG_ARG("m = %lx", (long)m);
/* DEBUG_CALL("ip_reass");
* Presence of header sizes in SLIRPmbufs DEBUG_ARG("ip = %p", ip);
* would confuse code below. DEBUG_ARG("fp = %p", fp);
* Fragment m_data is concatenated. DEBUG_ARG("m = %p", m);
*/
m->m_data += hlen;
m->m_len -= hlen;
/* /*
* If first fragment to arrive, create a reassembly queue. * Presence of header sizes in mbufs
*/ * would confuse code below.
if (fp == 0) { * Fragment m_data is concatenated.
struct SLIRPmbuf *t; */
if ((t = m_get()) == NULL) goto dropfrag; m->m_data += hlen;
fp = mtod(t, struct ipq *); m->m_len -= hlen;
insque_32(fp, &ipq);
fp->ipq_ttl = IPFRAGTTL;
fp->ipq_p = ip->ip_p;
fp->ipq_id = ip->ip_id;
fp->ipq_next = fp->ipq_prev = (ipasfragp_32)fp;
fp->ipq_src = ((struct ip *)ip)->ip_src;
fp->ipq_dst = ((struct ip *)ip)->ip_dst;
q = (struct ipasfrag *)fp;
goto insert;
}
/*
* Find a segment which begins after this one does.
*/
for (q = (struct ipasfrag *)fp->ipq_next; q != (struct ipasfrag *)fp;
q = (struct ipasfrag *)q->ipf_next)
if (q->ip_off > ip->ip_off)
break;
/* /*
* If there is a preceding segment, it may provide some of * If first fragment to arrive, create a reassembly queue.
* our data already. If so, drop the data from the incoming */
* segment. If it provides all of our data, drop us. if (fp == NULL) {
*/ struct mbuf *t = m_get(slirp);
if (q->ipf_prev != (ipasfragp_32)fp) {
i = ((struct ipasfrag *)(q->ipf_prev))->ip_off +
((struct ipasfrag *)(q->ipf_prev))->ip_len - ip->ip_off;
if (i > 0) {
if (i >= ip->ip_len)
goto dropfrag;
m_adj(dtom(ip), i);
ip->ip_off += i;
ip->ip_len -= i;
}
}
/* if (t == NULL) {
* While we overlap succeeding segments trim them or, goto dropfrag;
* if they are completely covered, dequeue them. }
*/ fp = mtod(t, struct ipq *);
while (q != (struct ipasfrag *)fp && ip->ip_off + ip->ip_len > q->ip_off) { insque(&fp->ip_link, &slirp->ipq.ip_link);
i = (ip->ip_off + ip->ip_len) - q->ip_off; fp->ipq_ttl = IPFRAGTTL;
if (i < q->ip_len) { fp->ipq_p = ip->ip_p;
q->ip_len -= i; fp->ipq_id = ip->ip_id;
q->ip_off += i; fp->frag_link.next = fp->frag_link.prev = &fp->frag_link;
m_adj(dtom(q), i); fp->ipq_src = ip->ip_src;
break; fp->ipq_dst = ip->ip_dst;
} q = (struct ipasfrag *)fp;
q = (struct ipasfrag *) q->ipf_next; goto insert;
m_freem(dtom((struct ipasfrag *) q->ipf_prev)); }
ip_deq((struct ipasfrag *) q->ipf_prev);
} /*
* Find a segment which begins after this one does.
*/
for (q = fp->frag_link.next; q != (struct ipasfrag *)&fp->frag_link;
q = q->ipf_next)
if (q->ipf_off > ip->ip_off)
break;
/*
* If there is a preceding segment, it may provide some of
* our data already. If so, drop the data from the incoming
* segment. If it provides all of our data, drop us.
*/
if (q->ipf_prev != &fp->frag_link) {
struct ipasfrag *pq = q->ipf_prev;
i = pq->ipf_off + pq->ipf_len - ip->ip_off;
if (i > 0) {
if (i >= ip->ip_len)
goto dropfrag;
m_adj(dtom(slirp, ip), i);
ip->ip_off += i;
ip->ip_len -= i;
}
}
/*
* While we overlap succeeding segments trim them or,
* if they are completely covered, dequeue them.
*/
while (q != (struct ipasfrag *)&fp->frag_link &&
ip->ip_off + ip->ip_len > q->ipf_off) {
struct ipasfrag *prev;
i = (ip->ip_off + ip->ip_len) - q->ipf_off;
if (i < q->ipf_len) {
q->ipf_len -= i;
q->ipf_off += i;
m_adj(dtom(slirp, q), i);
break;
}
prev = q;
q = q->ipf_next;
ip_deq(prev);
m_free(dtom(slirp, prev));
}
insert: insert:
/* /*
* Stick new segment in its place; * Stick new segment in its place;
* check for complete reassembly. * check for complete reassembly.
*/ */
ip_enq(ip, (struct ipasfrag *) q->ipf_prev); ip_enq(iptofrag(ip), q->ipf_prev);
next = 0; next = 0;
for (q = (struct ipasfrag *) fp->ipq_next; q != (struct ipasfrag *)fp; for (q = fp->frag_link.next; q != (struct ipasfrag *)&fp->frag_link;
q = (struct ipasfrag *) q->ipf_next) { q = q->ipf_next) {
if (q->ip_off != next) if (q->ipf_off != next)
return (0); return NULL;
next += q->ip_len; next += q->ipf_len;
} }
if (((struct ipasfrag *)(q->ipf_prev))->ipf_mff & 1) if (((struct ipasfrag *)(q->ipf_prev))->ipf_tos & 1)
return (0); return NULL;
/* /*
* Reassembly is complete; concatenate fragments. * Reassembly is complete; concatenate fragments.
*/ */
q = (struct ipasfrag *) fp->ipq_next; q = fp->frag_link.next;
m = dtom(q); m = dtom(slirp, q);
int delta = (char *)q - (m->m_flags & M_EXT ? m->m_ext : m->m_dat);
q = (struct ipasfrag *) q->ipf_next; q = (struct ipasfrag *)q->ipf_next;
while (q != (struct ipasfrag *)fp) { while (q != (struct ipasfrag *)&fp->frag_link) {
struct SLIRPmbuf *t; struct mbuf *t = dtom(slirp, q);
t = dtom(q); q = (struct ipasfrag *)q->ipf_next;
q = (struct ipasfrag *) q->ipf_next; m_cat(m, t);
m_cat(m, t); }
}
/* /*
* Create header for new ip packet by * Create header for new ip packet by
* modifying header of first packet; * modifying header of first packet;
* dequeue and discard fragment reassembly header. * dequeue and discard fragment reassembly header.
* Make header visible. * Make header visible.
*/ */
ip = (struct ipasfrag *) fp->ipq_next; q = fp->frag_link.next;
/* /*
* If the fragments concatenated to an SLIRPmbuf that's * If the fragments concatenated to an mbuf that's bigger than the total
* bigger than the total size of the fragment, then and * size of the fragment and the mbuf was not already using an m_ext buffer,
* m_ext buffer was alloced. But fp->ipq_next points to * then an m_ext buffer was alloced. But fp->ipq_next points to the old
* the old buffer (in the SLIRPmbuf), so we must point ip * buffer (in the mbuf), so we must point ip into the new buffer.
* into the new buffer. */
*/ if (m->m_flags & M_EXT) {
if (m->m_flags & M_EXT) { q = (struct ipasfrag *)(m->m_ext + delta);
int delta; }
delta = (char *)ip - m->m_dat;
ip = (struct ipasfrag *)(m->m_ext + delta);
}
/* DEBUG_ARG("ip = %lx", (long)ip); ip = fragtoip(q);
* ip=(struct ipasfrag *)m->m_data; */ ip->ip_len = next;
ip->ip_tos &= ~1;
ip->ip_src = fp->ipq_src;
ip->ip_dst = fp->ipq_dst;
remque(&fp->ip_link);
(void)m_free(dtom(slirp, fp));
m->m_len += (ip->ip_hl << 2);
m->m_data -= (ip->ip_hl << 2);
ip->ip_len = next; return ip;
ip->ipf_mff &= ~1;
((struct ip *)ip)->ip_src = fp->ipq_src;
((struct ip *)ip)->ip_dst = fp->ipq_dst;
remque_32(fp);
(void) m_free(dtom(fp));
m = dtom(ip);
m->m_len += (ip->ip_hl << 2);
m->m_data -= (ip->ip_hl << 2);
return ((struct ip *)ip);
dropfrag: dropfrag:
ipstat.ips_fragdropped++; m_free(m);
m_freem(m); return NULL;
return (0);
} }
/* /*
* Free a fragment reassembly header and all * Free a fragment reassembly header and all
* associated datagrams. * associated datagrams.
*/ */
void static void ip_freef(Slirp *slirp, struct ipq *fp)
ip_freef(fp)
struct ipq *fp;
{ {
register struct ipasfrag *q, *p; register struct ipasfrag *q, *p;
for (q = (struct ipasfrag *) fp->ipq_next; q != (struct ipasfrag *)fp; for (q = fp->frag_link.next; q != (struct ipasfrag *)&fp->frag_link;
q = p) { q = p) {
p = (struct ipasfrag *) q->ipf_next; p = q->ipf_next;
ip_deq(q); ip_deq(q);
m_freem(dtom(q)); m_free(dtom(slirp, q));
} }
remque_32(fp); remque(&fp->ip_link);
(void) m_free(dtom(fp)); (void)m_free(dtom(slirp, fp));
} }
/* /*
* Put an ip fragment on a reassembly chain. * Put an ip fragment on a reassembly chain.
* Like insque, but pointers in middle of structure. * Like insque, but pointers in middle of structure.
*/ */
void static void ip_enq(register struct ipasfrag *p, register struct ipasfrag *prev)
ip_enq(p, prev)
register struct ipasfrag *p, *prev;
{ {
DEBUG_CALL("ip_enq"); DEBUG_CALL("ip_enq");
DEBUG_ARG("prev = %lx", (long)prev); DEBUG_ARG("prev = %p", prev);
p->ipf_prev = (ipasfragp_32) prev; p->ipf_prev = prev;
p->ipf_next = prev->ipf_next; p->ipf_next = prev->ipf_next;
((struct ipasfrag *)(prev->ipf_next))->ipf_prev = (ipasfragp_32) p; ((struct ipasfrag *)(prev->ipf_next))->ipf_prev = p;
prev->ipf_next = (ipasfragp_32) p; prev->ipf_next = p;
} }
/* /*
* To ip_enq as remque is to insque. * To ip_enq as remque is to insque.
*/ */
void static void ip_deq(register struct ipasfrag *p)
ip_deq(p)
register struct ipasfrag *p;
{ {
((struct ipasfrag *)(p->ipf_prev))->ipf_next = p->ipf_next; ((struct ipasfrag *)(p->ipf_prev))->ipf_next = p->ipf_next;
((struct ipasfrag *)(p->ipf_next))->ipf_prev = p->ipf_prev; ((struct ipasfrag *)(p->ipf_next))->ipf_prev = p->ipf_prev;
} }
/* /*
@@ -439,234 +417,26 @@ ip_deq(p)
* if a timer expires on a reassembly * if a timer expires on a reassembly
* queue, discard it. * queue, discard it.
*/ */
void void ip_slowtimo(Slirp *slirp)
ip_slowtimo()
{ {
register struct ipq *fp; struct qlink *l;
DEBUG_CALL("ip_slowtimo");
fp = (struct ipq *) ipq.next;
if (fp == 0)
return;
while (fp != &ipq) { DEBUG_CALL("ip_slowtimo");
--fp->ipq_ttl;
fp = (struct ipq *) fp->next; l = slirp->ipq.ip_link.next;
if (((struct ipq *)(fp->prev))->ipq_ttl == 0) {
ipstat.ips_fragtimeout++; if (l == NULL)
ip_freef((struct ipq *) fp->prev); return;
}
} while (l != &slirp->ipq.ip_link) {
struct ipq *fp = container_of(l, struct ipq, ip_link);
l = l->next;
if (--fp->ipq_ttl == 0) {
ip_freef(slirp, fp);
}
}
} }
/*
* Do option processing on a datagram,
* possibly discarding it if bad options are encountered,
* or forwarding it if source-routed.
* Returns 1 if packet has been forwarded/freed,
* 0 if the packet should be processed further.
*/
#ifdef notdef
int
ip_dooptions(m)
struct SLIRPmbuf *m;
{
register struct ip *ip = mtod(m, struct ip *);
register u_char *cp;
register struct ip_timestamp *ipt;
register struct in_ifaddr *ia;
/* int opt, optlen, cnt, off, code, type = ICMP_PARAMPROB, forward = 0; */
int opt, optlen, cnt, off, code, type, forward = 0;
struct in_addr *sin, dst;
typedef u_int32_t n_time;
n_time ntime;
dst = ip->ip_dst;
cp = (u_char *)(ip + 1);
cnt = (ip->ip_hl << 2) - sizeof (struct ip);
for (; cnt > 0; cnt -= optlen, cp += optlen) {
opt = cp[IPOPT_OPTVAL];
if (opt == IPOPT_EOL)
break;
if (opt == IPOPT_NOP)
optlen = 1;
else {
optlen = cp[IPOPT_OLEN];
if (optlen <= 0 || optlen > cnt) {
code = &cp[IPOPT_OLEN] - (u_char *)ip;
goto bad;
}
}
switch (opt) {
default:
break;
/*
* Source routing with record.
* Find interface with current destination address.
* If none on this machine then drop if strictly routed,
* or do nothing if loosely routed.
* Record interface address and bring up next address
* component. If strictly routed make sure next
* address is on directly accessible net.
*/
case IPOPT_LSRR:
case IPOPT_SSRR:
if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) {
code = &cp[IPOPT_OFFSET] - (u_char *)ip;
goto bad;
}
ipaddr.sin_addr = ip->ip_dst;
ia = (struct in_ifaddr *)
ifa_ifwithaddr((struct sockaddr *)&ipaddr);
if (ia == 0) {
if (opt == IPOPT_SSRR) {
type = ICMP_UNREACH;
code = ICMP_UNREACH_SRCFAIL;
goto bad;
}
/*
* Loose routing, and not at next destination
* yet; nothing to do except forward.
*/
break;
}
off--; / * 0 origin * /
if (off > optlen - sizeof(struct in_addr)) {
/*
* End of source route. Should be for us.
*/
save_rte(cp, ip->ip_src);
break;
}
/*
* locate outgoing interface
*/
bcopy((SLIRPcaddr_t)(cp + off), (SLIRPcaddr_t)&ipaddr.sin_addr,
sizeof(ipaddr.sin_addr));
if (opt == IPOPT_SSRR) {
#define INA struct in_ifaddr *
#define SA struct sockaddr *
if ((ia = (INA)ifa_ifwithdstaddr((SA)&ipaddr)) == 0)
ia = (INA)ifa_ifwithnet((SA)&ipaddr);
} else
ia = ip_rtaddr(ipaddr.sin_addr);
if (ia == 0) {
type = ICMP_UNREACH;
code = ICMP_UNREACH_SRCFAIL;
goto bad;
}
ip->ip_dst = ipaddr.sin_addr;
bcopy((SLIRPcaddr_t)&(IA_SIN(ia)->sin_addr),
(SLIRPcaddr_t)(cp + off), sizeof(struct in_addr));
cp[IPOPT_OFFSET] += sizeof(struct in_addr);
/*
* Let ip_intr's mcast routing check handle mcast pkts
*/
forward = !IN_MULTICAST(ntohl(ip->ip_dst.s_addr));
break;
case IPOPT_RR:
if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) {
code = &cp[IPOPT_OFFSET] - (u_char *)ip;
goto bad;
}
/*
* If no space remains, ignore.
*/
off--; * 0 origin *
if (off > optlen - sizeof(struct in_addr))
break;
bcopy((SLIRPcaddr_t)(&ip->ip_dst), (SLIRPcaddr_t)&ipaddr.sin_addr,
sizeof(ipaddr.sin_addr));
/*
* locate outgoing interface; if we're the destination,
* use the incoming interface (should be same).
*/
if ((ia = (INA)ifa_ifwithaddr((SA)&ipaddr)) == 0 &&
(ia = ip_rtaddr(ipaddr.sin_addr)) == 0) {
type = ICMP_UNREACH;
code = ICMP_UNREACH_HOST;
goto bad;
}
bcopy((SLIRPcaddr_t)&(IA_SIN(ia)->sin_addr),
(SLIRPcaddr_t)(cp + off), sizeof(struct in_addr));
cp[IPOPT_OFFSET] += sizeof(struct in_addr);
break;
case IPOPT_TS:
code = cp - (u_char *)ip;
ipt = (struct ip_timestamp *)cp;
if (ipt->ipt_len < 5)
goto bad;
if (ipt->ipt_ptr > ipt->ipt_len - sizeof (int32_t)) {
if (++ipt->ipt_oflw == 0)
goto bad;
break;
}
sin = (struct in_addr *)(cp + ipt->ipt_ptr - 1);
switch (ipt->ipt_flg) {
case IPOPT_TS_TSONLY:
break;
case IPOPT_TS_TSANDADDR:
if (ipt->ipt_ptr + sizeof(n_time) +
sizeof(struct in_addr) > ipt->ipt_len)
goto bad;
ipaddr.sin_addr = dst;
ia = (INA)ifaof_ i f p foraddr((SA)&ipaddr,
m->m_pkthdr.rcvif);
if (ia == 0)
continue;
bcopy((SLIRPcaddr_t)&IA_SIN(ia)->sin_addr,
(SLIRPcaddr_t)sin, sizeof(struct in_addr));
ipt->ipt_ptr += sizeof(struct in_addr);
break;
case IPOPT_TS_PRESPEC:
if (ipt->ipt_ptr + sizeof(n_time) +
sizeof(struct in_addr) > ipt->ipt_len)
goto bad;
bcopy((SLIRPcaddr_t)sin, (SLIRPcaddr_t)&ipaddr.sin_addr,
sizeof(struct in_addr));
if (ifa_ifwithaddr((SA)&ipaddr) == 0)
continue;
ipt->ipt_ptr += sizeof(struct in_addr);
break;
default:
goto bad;
}
ntime = iptime();
bcopy((SLIRPcaddr_t)&ntime, (SLIRPcaddr_t)cp + ipt->ipt_ptr - 1,
sizeof(n_time));
ipt->ipt_ptr += sizeof(n_time);
}
}
if (forward) {
ip_forward(m, 1);
return (1);
}
}
}
return (0);
bad:
/* ip->ip_len -= ip->ip_hl << 2; XXX icmp_error adds in hdr length */
/* Not yet */
icmp_error(m, type, code, 0, 0);
ipstat.ips_badoptions++;
return (1);
}
#endif /* notdef */
/* /*
* Strip out IP options, at higher * Strip out IP options, at higher
* level protocol in the kernel. * level protocol in the kernel.
@@ -674,21 +444,18 @@ bad:
* will be moved, and return value is their length. * will be moved, and return value is their length.
* (XXX) should be deleted; last arg currently ignored. * (XXX) should be deleted; last arg currently ignored.
*/ */
void void ip_stripoptions(register struct mbuf *m, struct mbuf *mopt)
ip_stripoptions(m, mopt)
struct SLIRPmbuf *m;
struct SLIRPmbuf *mopt;
{ {
register int i; register int i;
struct ip *ip = mtod(m, struct ip *); struct ip *ip = mtod(m, struct ip *);
register SLIRPcaddr_t opts; register char *opts;
int olen; int olen;
olen = (ip->ip_hl<<2) - sizeof (struct ip); olen = (ip->ip_hl << 2) - sizeof(struct ip);
opts = (SLIRPcaddr_t)(ip + 1); opts = (char *)(ip + 1);
i = m->m_len - (sizeof (struct ip) + olen); i = m->m_len - (sizeof(struct ip) + olen);
memcpy(opts, opts + olen, (unsigned)i); memmove(opts, opts + olen, (unsigned)i);
m->m_len -= olen; m->m_len -= olen;
ip->ip_hl = sizeof(struct ip) >> 2; ip->ip_hl = sizeof(struct ip) >> 2;
} }

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/* /*
* Copyright (c) 1982, 1986, 1988, 1990, 1993 * Copyright (c) 1982, 1986, 1988, 1990, 1993
* The Regents of the University of California. All rights reserved. * The Regents of the University of California. All rights reserved.
@@ -33,170 +34,136 @@
/* /*
* Changes and additions relating to SLiRP are * Changes and additions relating to SLiRP are
* Copyright (c) 1995 Danny Gasparovski. * Copyright (c) 1995 Danny Gasparovski.
*
* Please read the file COPYRIGHT for the
* terms and conditions of the copyright.
*/ */
#include "slirp.h" #include "slirp.h"
u_int16_t ip_id; /* Number of packets queued before we start sending
* (to prevent allocing too many mbufs) */
#define IF_THRESH 10
/* /*
* IP output. The packet in SLIRPmbuf chain m contains a skeletal IP * IP output. The packet in mbuf chain m contains a skeletal IP
* header (with len, off, ttl, proto, tos, src, dst). * header (with len, off, ttl, proto, tos, src, dst).
* The SLIRPmbuf chain containing the packet will be freed. * The mbuf chain containing the packet will be freed.
* The SLIRPmbuf opt, if present, will not be freed. * The mbuf opt, if present, will not be freed.
*/ */
int int ip_output(struct socket *so, struct mbuf *m0)
ip_output(so, m0)
struct SLIRPsocket *so;
struct SLIRPmbuf *m0;
{ {
struct ip *ip; Slirp *slirp = m0->slirp;
struct SLIRPmbuf *m = m0; register struct ip *ip;
u_int hlen = sizeof(struct ip ); register struct mbuf *m = m0;
u_int len, off; register int hlen = sizeof(struct ip);
int error = 0; int len, off, error = 0;
DEBUG_CALL("ip_output"); DEBUG_CALL("ip_output");
DEBUG_ARG("so = %lx", (long)so); DEBUG_ARG("so = %p", so);
DEBUG_ARG("m0 = %lx", (long)m0); DEBUG_ARG("m0 = %p", m0);
/* We do no options */
/* if (opt) {
* m = ip_insertoptions(m, opt, &len);
* hlen = len;
* }
*/
ip = mtod(m, struct ip *);
/*
* Fill in IP header.
*/
ip->ip_v = IPVERSION;
ip->ip_off &= IP_DF;
ip->ip_id = htons(ip_id++);
ip->ip_hl = hlen >> 2;
ipstat.ips_localout++;
/* ip = mtod(m, struct ip *);
* Verify that we have any chance at all of being able to queue /*
* the packet or packet fragments * Fill in IP header.
*/ */
/* XXX Hmmm... */ ip->ip_v = IPVERSION;
/* if (if_queued > if_thresh && towrite <= 0) { ip->ip_off &= IP_DF;
* error = ENOBUFS; ip->ip_id = htons(slirp->ip_id++);
* goto bad; ip->ip_hl = hlen >> 2;
* }
*/
/*
* If small enough for interface, can just send directly.
*/
if ((u_int16_t)ip->ip_len <= if_mtu) {
ip->ip_len = htons((u_int16_t)ip->ip_len);
ip->ip_off = htons((u_int16_t)ip->ip_off);
ip->ip_sum = 0;
ip->ip_sum = cksum(m, hlen);
if_output(so, m); /*
goto done; * If small enough for interface, can just send directly.
} */
if ((uint16_t)ip->ip_len <= slirp->if_mtu) {
ip->ip_len = htons((uint16_t)ip->ip_len);
ip->ip_off = htons((uint16_t)ip->ip_off);
ip->ip_sum = 0;
ip->ip_sum = cksum(m, hlen);
/* if_output(so, m);
* Too large for interface; fragment if possible. goto done;
* Must be able to put at least 8 bytes per fragment. }
*/
if (ip->ip_off & IP_DF) { /*
error = -1; * Too large for interface; fragment if possible.
ipstat.ips_cantfrag++; * Must be able to put at least 8 bytes per fragment.
goto bad; */
} if (ip->ip_off & IP_DF) {
error = -1;
len = (if_mtu - hlen) &~ 7; /* ip databytes per packet */ goto bad;
if (len < 8) { }
error = -1;
goto bad; len = (slirp->if_mtu - hlen) & ~7; /* ip databytes per packet */
} if (len < 8) {
error = -1;
goto bad;
}
{ {
int mhlen, firstlen = len; int mhlen, firstlen = len;
struct SLIRPmbuf **mnext = &m->m_nextpkt; struct mbuf **mnext = &m->m_nextpkt;
/* /*
* Loop through length of segment after first fragment, * Loop through length of segment after first fragment,
* make new header and copy data of each part and link onto chain. * make new header and copy data of each part and link onto chain.
*/ */
m0 = m; m0 = m;
mhlen = sizeof (struct ip); mhlen = sizeof(struct ip);
for (off = hlen + len; off < ip->ip_len; off += len) { for (off = hlen + len; off < (uint16_t)ip->ip_len; off += len) {
struct ip *mhip; register struct ip *mhip;
m = m_get(); m = m_get(slirp);
if (m == 0) { if (m == NULL) {
error = -1; error = -1;
ipstat.ips_odropped++; goto sendorfree;
goto sendorfree; }
} m->m_data += IF_MAXLINKHDR;
m->m_data += if_maxlinkhdr; mhip = mtod(m, struct ip *);
mhip = mtod(m, struct ip *); *mhip = *ip;
*mhip = *ip;
/* No options */
/* if (hlen > sizeof (struct ip)) {
* mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip);
* mhip->ip_hl = mhlen >> 2;
* }
*/
m->m_len = mhlen;
mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF);
if (ip->ip_off & IP_MF)
mhip->ip_off |= IP_MF;
if (off + len >= (u_int16_t)ip->ip_len)
len = (u_int16_t)ip->ip_len - off;
else
mhip->ip_off |= IP_MF;
mhip->ip_len = htons((u_int16_t)(len + mhlen));
if (m_copy(m, m0, off, len) < 0) {
error = -1;
goto sendorfree;
}
mhip->ip_off = htons((u_int16_t)mhip->ip_off);
mhip->ip_sum = 0;
mhip->ip_sum = cksum(m, mhlen);
*mnext = m;
mnext = &m->m_nextpkt;
ipstat.ips_ofragments++;
}
/*
* Update first fragment by trimming what's been copied out
* and updating header, then send each fragment (in order).
*/
m = m0;
m_adj(m, hlen + firstlen - ip->ip_len);
ip->ip_len = htons((u_int16_t)m->m_len);
ip->ip_off = htons((u_int16_t)(ip->ip_off | IP_MF));
ip->ip_sum = 0;
ip->ip_sum = cksum(m, hlen);
sendorfree:
for (m = m0; m; m = m0) {
m0 = m->m_nextpkt;
m->m_nextpkt = 0;
if (error == 0)
if_output(so, m);
else
m_freem(m);
}
if (error == 0) m->m_len = mhlen;
ipstat.ips_fragmented++; mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF);
if (ip->ip_off & IP_MF)
mhip->ip_off |= IP_MF;
if (off + len >= (uint16_t)ip->ip_len)
len = (uint16_t)ip->ip_len - off;
else
mhip->ip_off |= IP_MF;
mhip->ip_len = htons((uint16_t)(len + mhlen));
if (m_copy(m, m0, off, len) < 0) {
error = -1;
goto sendorfree;
}
mhip->ip_off = htons((uint16_t)mhip->ip_off);
mhip->ip_sum = 0;
mhip->ip_sum = cksum(m, mhlen);
*mnext = m;
mnext = &m->m_nextpkt;
}
/*
* Update first fragment by trimming what's been copied out
* and updating header, then send each fragment (in order).
*/
m = m0;
m_adj(m, hlen + firstlen - (uint16_t)ip->ip_len);
ip->ip_len = htons((uint16_t)m->m_len);
ip->ip_off = htons((uint16_t)(ip->ip_off | IP_MF));
ip->ip_sum = 0;
ip->ip_sum = cksum(m, hlen);
sendorfree:
for (m = m0; m; m = m0) {
m0 = m->m_nextpkt;
m->m_nextpkt = NULL;
if (error == 0)
if_output(so, m);
else
m_free(m);
}
} }
done: done:
return (error); return (error);
bad: bad:
m_freem(m0); m_free(m0);
goto done; goto done;
} }

View File

@@ -0,0 +1,24 @@
/* SPDX-License-Identifier: BSD-3-Clause */
#ifndef LIBSLIRP_VERSION_H_
#define LIBSLIRP_VERSION_H_
#ifdef __cplusplus
extern "C" {
#endif
#define SLIRP_MAJOR_VERSION 4
#define SLIRP_MINOR_VERSION 3
#define SLIRP_MICRO_VERSION 1
#define SLIRP_VERSION_STRING "4.3.1-git-86Box"
#define SLIRP_CHECK_VERSION(major,minor,micro) \
(SLIRP_MAJOR_VERSION > (major) || \
(SLIRP_MAJOR_VERSION == (major) && SLIRP_MINOR_VERSION > (minor)) || \
(SLIRP_MAJOR_VERSION == (major) && SLIRP_MINOR_VERSION == (minor) && \
SLIRP_MICRO_VERSION >= (micro)))
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* LIBSLIRP_VERSION_H_ */

View File

@@ -1,41 +1,175 @@
#ifndef _LIBSLIRP_H /* SPDX-License-Identifier: BSD-3-Clause */
#define _LIBSLIRP_H #ifndef LIBSLIRP_H
#define LIBSLIRP_H
#include <stdint.h>
#include <stdbool.h>
#include <sys/types.h>
#ifdef _WIN32 #ifdef _WIN32
#include <winsock2.h> #include <winsock2.h>
int inet_aton(const char *cp, struct in_addr *ia); #include <in6addr.h>
#else #else
#include <sys/select.h> #include <netinet/in.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#endif #endif
#include "libslirp-version.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
int slirp_init(void); typedef struct Slirp Slirp;
int slirp_select_fill(int *pnfds, enum {
fd_set *readfds, fd_set *writefds, fd_set *xfds); SLIRP_POLL_IN = 1 << 0,
SLIRP_POLL_OUT = 1 << 1,
SLIRP_POLL_PRI = 1 << 2,
SLIRP_POLL_ERR = 1 << 3,
SLIRP_POLL_HUP = 1 << 4,
};
void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds); typedef ssize_t (*SlirpReadCb)(void *buf, size_t len, void *opaque);
typedef ssize_t (*SlirpWriteCb)(const void *buf, size_t len, void *opaque);
typedef void (*SlirpTimerCb)(void *opaque);
typedef int (*SlirpAddPollCb)(int fd, int events, void *opaque);
typedef int (*SlirpGetREventsCb)(int idx, void *opaque);
void slirp_input(const uint8 *pkt, int pkt_len); /*
* Callbacks from slirp
*/
typedef struct SlirpCb {
/*
* Send an ethernet frame to the guest network. The opaque
* parameter is the one given to slirp_init(). The function
* doesn't need to send all the data and may return <len (no
* buffering is done on libslirp side, so the data will be dropped
* in this case). <0 reports an IO error.
*/
SlirpWriteCb send_packet;
/* Print a message for an error due to guest misbehavior. */
void (*guest_error)(const char *msg, void *opaque);
/* Return the virtual clock value in nanoseconds */
int64_t (*clock_get_ns)(void *opaque);
/* Create a new timer with the given callback and opaque data */
void *(*timer_new)(SlirpTimerCb cb, void *cb_opaque, void *opaque);
/* Remove and free a timer */
void (*timer_free)(void *timer, void *opaque);
/* Modify a timer to expire at @expire_time */
void (*timer_mod)(void *timer, int64_t expire_time, void *opaque);
/* Register a fd for future polling */
void (*register_poll_fd)(int fd, void *opaque);
/* Unregister a fd */
void (*unregister_poll_fd)(int fd, void *opaque);
/* Kick the io-thread, to signal that new events may be processed */
void (*notify)(void *opaque);
} SlirpCb;
/* you must provide the following functions: */ #define SLIRP_CONFIG_VERSION_MIN 1
int slirp_can_output(void); #define SLIRP_CONFIG_VERSION_MAX 3
void slirp_output(const uint8 *pkt, int pkt_len);
int slirp_redir(int is_udp, int host_port, typedef struct SlirpConfig {
struct in_addr guest_addr, int guest_port); /* Version must be provided */
int slirp_add_exec(int do_pty, const char *args, int addr_low_byte, uint32_t version;
int guest_port); /*
* Fields introduced in SlirpConfig version 1 begin
*/
int restricted;
bool in_enabled;
struct in_addr vnetwork;
struct in_addr vnetmask;
struct in_addr vhost;
bool in6_enabled;
struct in6_addr vprefix_addr6;
uint8_t vprefix_len;
struct in6_addr vhost6;
const char *vhostname;
const char *tftp_server_name;
const char *tftp_path;
const char *bootfile;
struct in_addr vdhcp_start;
struct in_addr vnameserver;
struct in6_addr vnameserver6;
const char **vdnssearch;
const char *vdomainname;
/* Default: IF_MTU_DEFAULT */
size_t if_mtu;
/* Default: IF_MRU_DEFAULT */
size_t if_mru;
/* Prohibit connecting to 127.0.0.1:* */
bool disable_host_loopback;
/*
* Enable emulation code (*warning*: this code isn't safe, it is not
* recommended to enable it)
*/
bool enable_emu;
/*
* Fields introduced in SlirpConfig version 2 begin
*/
struct sockaddr_in *outbound_addr;
struct sockaddr_in6 *outbound_addr6;
/*
* Fields introduced in SlirpConfig version 3 begin
*/
bool disable_dns; /* slirp will not redirect/serve any DNS packet */
} SlirpConfig;
extern const char *tftp_prefix; Slirp *slirp_new(const SlirpConfig *cfg, const SlirpCb *callbacks,
extern char slirp_hostname[33]; void *opaque);
/* slirp_init is deprecated in favor of slirp_new */
Slirp *slirp_init(int restricted, bool in_enabled, struct in_addr vnetwork,
struct in_addr vnetmask, struct in_addr vhost,
bool in6_enabled, struct in6_addr vprefix_addr6,
uint8_t vprefix_len, struct in6_addr vhost6,
const char *vhostname, const char *tftp_server_name,
const char *tftp_path, const char *bootfile,
struct in_addr vdhcp_start, struct in_addr vnameserver,
struct in6_addr vnameserver6, const char **vdnssearch,
const char *vdomainname, const SlirpCb *callbacks,
void *opaque);
void slirp_cleanup(Slirp *slirp);
void slirp_pollfds_fill(Slirp *slirp, uint32_t *timeout,
SlirpAddPollCb add_poll, void *opaque);
void slirp_pollfds_poll(Slirp *slirp, int select_error,
SlirpGetREventsCb get_revents, void *opaque);
void slirp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len);
int slirp_add_hostfwd(Slirp *slirp, int is_udp, struct in_addr host_addr,
int host_port, struct in_addr guest_addr, int guest_port);
int slirp_remove_hostfwd(Slirp *slirp, int is_udp, struct in_addr host_addr,
int host_port);
int slirp_add_exec(Slirp *slirp, const char *cmdline,
struct in_addr *guest_addr, int guest_port);
int slirp_add_unix(Slirp *slirp, const char *unixsock,
struct in_addr *guest_addr, int guest_port);
int slirp_add_guestfwd(Slirp *slirp, SlirpWriteCb write_cb, void *opaque,
struct in_addr *guest_addr, int guest_port);
/* remove entries added by slirp_add_exec, slirp_add_unix or slirp_add_guestfwd */
int slirp_remove_guestfwd(Slirp *slirp, struct in_addr guest_addr,
int guest_port);
char *slirp_connection_info(Slirp *slirp);
void slirp_socket_recv(Slirp *slirp, struct in_addr guest_addr, int guest_port,
const uint8_t *buf, int size);
size_t slirp_socket_can_recv(Slirp *slirp, struct in_addr guest_addr,
int guest_port);
void slirp_state_save(Slirp *s, SlirpWriteCb write_cb, void *opaque);
int slirp_state_load(Slirp *s, int version_id, SlirpReadCb read_cb,
void *opaque);
int slirp_state_version(void);
const char *slirp_version_string(void);
#ifdef __cplusplus #ifdef __cplusplus
} } /* extern "C" */
#endif #endif
#endif #endif /* LIBSLIRP_H */

View File

@@ -1,54 +1,16 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/* /*
* Copyright (c) 1995 Danny Gasparovski. * Copyright (c) 1995 Danny Gasparovski.
*
* Please read the file COPYRIGHT for the
* terms and conditions of the copyright.
*/ */
#ifdef HAVE_SYS_SELECT_H #ifndef SLIRP_MAIN_H
#include <sys/select.h> #define SLIRP_MAIN_H
#endif
#define TOWRITEMAX 512 extern unsigned curtime;
extern struct timeval tt;
extern int link_up;
extern int slirp_socket;
extern int slirp_socket_unit;
extern int slirp_socket_port;
extern u_int32_t slirp_socket_addr;
extern char *slirp_socket_passwd;
extern int ctty_closed;
/*
* Get the difference in 2 times from updtim()
* Allow for wraparound times, "just in case"
* x is the greater of the 2 (current time) and y is
* what it's being compared against.
*/
#define TIME_DIFF(x,y) (x)-(y) < 0 ? ~0-(y)+(x) : (x)-(y)
extern char *slirp_tty;
extern char *exec_shell;
extern u_int curtime;
extern fd_set *global_readfds, *global_writefds, *global_xfds;
extern struct in_addr ctl_addr;
extern struct in_addr special_addr;
extern struct in_addr alias_addr;
extern struct in_addr our_addr;
extern struct in_addr loopback_addr; extern struct in_addr loopback_addr;
extern struct in_addr dns_addr; extern unsigned long loopback_mask;
extern char *username;
extern char *socket_path; int if_encap(Slirp *slirp, struct mbuf *ifm);
extern int towrite_max; ssize_t slirp_send(struct socket *so, const void *buf, size_t len, int flags);
extern int ppp_exit;
extern int so_options;
extern int tcp_keepintvl;
extern uint8_t client_ethaddr[6];
#define PROTO_SLIP 0x1
#ifdef USE_PPP
#define PROTO_PPP 0x2
#endif #endif
void if_encap(const uint8_t *ip_data, int ip_data_len);

View File

@@ -1,8 +1,6 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/* /*
* Copyright (c) 1995 Danny Gasparovski * Copyright (c) 1995 Danny Gasparovski
*
* Please read the file COPYRIGHT for the
* terms and conditions of the copyright.
*/ */
/* /*
@@ -10,209 +8,189 @@
* FreeBSD. They are fixed size, determined by the MTU, * FreeBSD. They are fixed size, determined by the MTU,
* so that one whole packet can fit. Mbuf's cannot be * so that one whole packet can fit. Mbuf's cannot be
* chained together. If there's more data than the mbuf * chained together. If there's more data than the mbuf
* could hold, an external malloced buffer is pointed to * could hold, an external g_malloced buffer is pointed to
* by m_ext (and the data pointers) and M_EXT is set in * by m_ext (and the data pointers) and M_EXT is set in
* the flags * the flags
*/ */
#include <stdlib.h>
#include "slirp.h" #include "slirp.h"
struct mbuf *mbutl; #define MBUF_THRESH 30
char *mclrefcnt;
int mbuf_alloced = 0;
struct SLIRPmbuf m_freelist, m_usedlist;
int mbuf_thresh = 30;
int mbuf_max = 0;
size_t msize;
void /*
m_init() * Find a nice value for msize
*/
#define SLIRP_MSIZE(mtu) \
(offsetof(struct mbuf, m_dat) + IF_MAXLINKHDR + TCPIPHDR_DELTA + (mtu))
void m_init(Slirp *slirp)
{ {
m_freelist.m_next = m_freelist.m_prev = &m_freelist; slirp->m_freelist.qh_link = slirp->m_freelist.qh_rlink = &slirp->m_freelist;
m_usedlist.m_next = m_usedlist.m_prev = &m_usedlist; slirp->m_usedlist.qh_link = slirp->m_usedlist.qh_rlink = &slirp->m_usedlist;
msize_init();
} }
void msize_init() void m_cleanup(Slirp *slirp)
{ {
/* struct mbuf *m, *next;
* Find a nice value for msize
* XXX if_maxlinkhdr already in mtu m = (struct mbuf *)slirp->m_usedlist.qh_link;
*/ while ((struct quehead *)m != &slirp->m_usedlist) {
msize = (if_mtu>if_mru?if_mtu:if_mru) + next = m->m_next;
if_maxlinkhdr + sizeof(struct m_hdr ) + 6; if (m->m_flags & M_EXT) {
g_free(m->m_ext);
}
g_free(m);
m = next;
}
m = (struct mbuf *)slirp->m_freelist.qh_link;
while ((struct quehead *)m != &slirp->m_freelist) {
next = m->m_next;
g_free(m);
m = next;
}
} }
/* /*
* Get an mbuf from the free list, if there are none * Get an mbuf from the free list, if there are none
* malloc one * allocate one
* *
* Because fragmentation can occur if we alloc new mbufs and * Because fragmentation can occur if we alloc new mbufs and
* free old mbufs, we mark all mbufs above mbuf_thresh as M_DOFREE, * free old mbufs, we mark all mbufs above mbuf_thresh as M_DOFREE,
* which tells m_free to actually free() it * which tells m_free to actually g_free() it
*/ */
struct SLIRPmbuf * m_get() struct mbuf *m_get(Slirp *slirp)
{ {
struct SLIRPmbuf *m; register struct mbuf *m;
int flags = 0; int flags = 0;
DEBUG_CALL("m_get"); DEBUG_CALL("m_get");
if (m_freelist.m_next == &m_freelist) { if (slirp->m_freelist.qh_link == &slirp->m_freelist) {
m = (struct SLIRPmbuf *)malloc(msize); m = g_malloc(SLIRP_MSIZE(slirp->if_mtu));
if (m == NULL) goto end_error; slirp->mbuf_alloced++;
mbuf_alloced++; if (slirp->mbuf_alloced > MBUF_THRESH)
if (mbuf_alloced > mbuf_thresh) flags = M_DOFREE;
flags = M_DOFREE; m->slirp = slirp;
if (mbuf_alloced > mbuf_max) } else {
mbuf_max = mbuf_alloced; m = (struct mbuf *)slirp->m_freelist.qh_link;
} else { remque(m);
m = m_freelist.m_next; }
remque(m);
} /* Insert it in the used list */
insque(m, &slirp->m_usedlist);
/* Insert it in the used list */ m->m_flags = (flags | M_USEDLIST);
insque(m,&m_usedlist);
m->m_flags = (flags | M_USEDLIST); /* Initialise it */
m->m_size = SLIRP_MSIZE(slirp->if_mtu) - offsetof(struct mbuf, m_dat);
/* Initialise it */ m->m_data = m->m_dat;
m->m_size = msize - sizeof(struct m_hdr); m->m_len = 0;
m->m_data = m->m_dat; m->m_nextpkt = NULL;
m->m_len = 0; m->m_prevpkt = NULL;
m->m_nextpkt = 0; m->resolution_requested = false;
m->m_prevpkt = 0; m->expiration_date = (uint64_t)-1;
end_error: DEBUG_ARG("m = %p", m);
DEBUG_ARG("m = %lx", (long )m); return m;
return m;
} }
//For some reason this fails in GDB saying tehre is no m_flags member void m_free(struct mbuf *m)
void
m_free(m)
struct SLIRPmbuf *m;
{ {
DEBUG_CALL("m_free");
DEBUG_CALL("m_free"); DEBUG_ARG("m = %p", m);
DEBUG_ARG("m = %lx", (long )m);
if(m) {
/* Remove from m_usedlist */
if (m->m_flags & M_USEDLIST)
remque(m);
if (m) {
/* Remove from m_usedlist */
if (m->m_flags & M_USEDLIST)
remque(m);
/* If it's M_EXT, free() it */
/* If it's M_EXT, free() it */ if (m->m_flags & M_EXT) {
if (m->m_flags & M_EXT) g_free(m->m_ext);
free(m->m_ext); }
/*
/* * Either free() it or put it on the free list
* Either free() it or put it on the free list */
*/ if (m->m_flags & M_DOFREE) {
if (m->m_flags & M_DOFREE) { m->slirp->mbuf_alloced--;
free(m); g_free(m);
mbuf_alloced--; } else if ((m->m_flags & M_FREELIST) == 0) {
} else if ((m->m_flags & M_FREELIST) == 0) { insque(m, &m->slirp->m_freelist);
insque(m,&m_freelist); m->m_flags = M_FREELIST; /* Clobber other flags */
m->m_flags = M_FREELIST; /* Clobber other flags */ }
} } /* if(m) */
} /* if(m) */
} }
/* /*
* Copy data from one mbuf to the end of * Copy data from one mbuf to the end of
* the other.. if result is too big for one mbuf, malloc() * the other.. if result is too big for one mbuf, allocate
* an M_EXT data segment * an M_EXT data segment
*/ */
void void m_cat(struct mbuf *m, struct mbuf *n)
m_cat(m, n)
struct SLIRPmbuf *m, *n;
{ {
/* /*
* If there's no room, realloc * If there's no room, realloc
*/ */
if (M_FREEROOM(m) < n->m_len) if (M_FREEROOM(m) < n->m_len)
m_inc(m,m->m_size+MINCSIZE); m_inc(m, m->m_len + n->m_len);
memcpy(m->m_data+m->m_len, n->m_data, n->m_len);
m->m_len += n->m_len;
m_free(n); memcpy(m->m_data + m->m_len, n->m_data, n->m_len);
m->m_len += n->m_len;
m_free(n);
} }
/* make m size bytes large */ /* make m 'size' bytes large from m_data */
void void m_inc(struct mbuf *m, int size)
m_inc(m, size)
struct SLIRPmbuf *m;
int size;
{ {
int datasize; int gapsize;
/* some compiles throw up on gotos. This one we can fake. */ /* some compilers throw up on gotos. This one we can fake. */
if(m->m_size>size) return; if (M_ROOM(m) > size) {
return;
}
if (m->m_flags & M_EXT) { if (m->m_flags & M_EXT) {
datasize = m->m_data - m->m_ext; gapsize = m->m_data - m->m_ext;
m->m_ext = (char *)realloc(m->m_ext,size); m->m_ext = g_realloc(m->m_ext, size + gapsize);
/* if (m->m_ext == NULL) } else {
* return (struct SLIRPmbuf *)NULL; gapsize = m->m_data - m->m_dat;
*/ m->m_ext = g_malloc(size + gapsize);
m->m_data = m->m_ext + datasize; memcpy(m->m_ext, m->m_dat, m->m_size);
} else { m->m_flags |= M_EXT;
char *dat; }
datasize = m->m_data - m->m_dat;
dat = (char *)malloc(size);
/* if (dat == NULL)
* return (struct SLIRPmbuf *)NULL;
*/
memcpy(dat, m->m_dat, m->m_size);
m->m_ext = dat;
m->m_data = m->m_ext + datasize;
m->m_flags |= M_EXT;
}
m->m_size = size;
m->m_data = m->m_ext + gapsize;
m->m_size = size + gapsize;
} }
void m_adj(struct mbuf *m, int len)
void
m_adj(m, len)
struct SLIRPmbuf *m;
int len;
{ {
if (m == NULL) if (m == NULL)
return; return;
if (len >= 0) { if (len >= 0) {
/* Trim from head */ /* Trim from head */
m->m_data += len; m->m_data += len;
m->m_len -= len; m->m_len -= len;
} else { } else {
/* Trim from tail */ /* Trim from tail */
len = -len; len = -len;
m->m_len -= len; m->m_len -= len;
} }
} }
/* /*
* Copy len bytes from m, starting off bytes into n * Copy len bytes from m, starting off bytes into n
*/ */
int int m_copy(struct mbuf *n, struct mbuf *m, int off, int len)
m_copy(n, m, off, len)
struct SLIRPmbuf *n, *m;
int off, len;
{ {
if (len > M_FREEROOM(n)) if (len > M_FREEROOM(n))
return -1; return -1;
memcpy((n->m_data + n->m_len), (m->m_data + off), len); memcpy((n->m_data + n->m_len), (m->m_data + off), len);
n->m_len += len; n->m_len += len;
return 0; return 0;
} }
@@ -221,28 +199,26 @@ m_copy(n, m, off, len)
* XXX This is a kludge, I should eliminate the need for it * XXX This is a kludge, I should eliminate the need for it
* Fortunately, it's not used often * Fortunately, it's not used often
*/ */
struct SLIRPmbuf * struct mbuf *dtom(Slirp *slirp, void *dat)
dtom(dat)
void *dat;
{ {
struct SLIRPmbuf *m; struct mbuf *m;
DEBUG_CALL("dtom");
DEBUG_ARG("dat = %lx", (long )dat);
/* bug corrected for M_EXT buffers */ DEBUG_CALL("dtom");
for (m = m_usedlist.m_next; m != &m_usedlist; m = m->m_next) { DEBUG_ARG("dat = %p", dat);
if (m->m_flags & M_EXT) {
if( (char *)dat>=m->m_ext && (char *)dat<(m->m_ext + m->m_size) ) /* bug corrected for M_EXT buffers */
return m; for (m = (struct mbuf *)slirp->m_usedlist.qh_link;
} else { (struct quehead *)m != &slirp->m_usedlist; m = m->m_next) {
if( (char *)dat >= m->m_dat && (char *)dat<(m->m_dat + m->m_size) ) if (m->m_flags & M_EXT) {
return m; if ((char *)dat >= m->m_ext && (char *)dat < (m->m_ext + m->m_size))
} return m;
} } else {
if ((char *)dat >= m->m_dat && (char *)dat < (m->m_dat + m->m_size))
DEBUG_ERROR((dfd, "dtom failed")); return m;
}
return (struct SLIRPmbuf *)0; }
DEBUG_ERROR("dtom failed");
return (struct mbuf *)0;
} }

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/* /*
* Copyright (c) 1982, 1986, 1988, 1993 * Copyright (c) 1982, 1986, 1988, 1993
* The Regents of the University of California. All rights reserved. * The Regents of the University of California. All rights reserved.
@@ -30,21 +31,14 @@
* mbuf.h,v 1.9 1994/11/14 13:54:20 bde Exp * mbuf.h,v 1.9 1994/11/14 13:54:20 bde Exp
*/ */
#ifndef _MBUF_H_ #ifndef MBUF_H
#define _MBUF_H_ #define MBUF_H
#define m_freem m_free
#define MINCSIZE 4096 /* Amount to increase mbuf if too small */
/* /*
* Macros for type conversion * Macros for type conversion
* mtod(m,t) - convert mbuf pointer to data pointer of correct type * mtod(m,t) - convert mbuf pointer to data pointer of correct type
* dtom(x) - convert data pointer within mbuf to mbuf pointer (XXX)
*/ */
#define mtod(m,t) ((t)(m)->m_data) #define mtod(m, t) ((t)(m)->m_data)
/* #define dtom(x) ((struct SLIRPmbuf *)((int)(x) & ~(M_SIZE-1))) */
/* XXX About mbufs for slirp: /* XXX About mbufs for slirp:
* Only one mbuf is ever used in a chain, for each "cell" of data. * Only one mbuf is ever used in a chain, for each "cell" of data.
@@ -54,90 +48,80 @@
* free the m_ext. This is inefficient memory-wise, but who cares. * free the m_ext. This is inefficient memory-wise, but who cares.
*/ */
/* XXX should union some of these! */ /*
/* header at beginning of each mbuf: */ * mbufs allow to have a gap between the start of the allocated buffer (m_ext if
struct m_hdr { * M_EXT is set, m_dat otherwise) and the in-use data:
struct SLIRPmbuf *mh_next; /* Linked list of mbufs */ *
struct SLIRPmbuf *mh_prev; * |--gapsize----->|---m_len------->
struct SLIRPmbuf *mh_nextpkt; /* Next packet in queue/record */ * |----------m_size------------------------------>
struct SLIRPmbuf *mh_prevpkt; /* Flags aren't used in the output queue */ * |----M_ROOM-------------------->
int mh_flags; /* Misc flags */ * |-M_FREEROOM-->
*
* ^ ^ ^
* m_dat/m_ext m_data end of buffer
*/
size_t mh_size; /* Size of data */ /*
struct SLIRPsocket *mh_so;
SLIRPcaddr_t mh_data; /* Location of data */
int32_t mh_len; /* Amount of data in this mbuf */
};
/*
* How much room is in the mbuf, from m_data to the end of the mbuf * How much room is in the mbuf, from m_data to the end of the mbuf
*/ */
#define M_ROOM(m) ((m->m_flags & M_EXT)? \ #define M_ROOM(m) \
(((m)->m_ext + (m)->m_size) - (m)->m_data) \ ((m->m_flags & M_EXT) ? (((m)->m_ext + (m)->m_size) - (m)->m_data) : \
: \ (((m)->m_dat + (m)->m_size) - (m)->m_data))
(((m)->m_dat + (m)->m_size) - (m)->m_data))
/* /*
* How much free room there is * How much free room there is
*/ */
#define M_FREEROOM(m) (M_ROOM(m) - (m)->m_len) #define M_FREEROOM(m) (M_ROOM(m) - (m)->m_len)
#define M_TRAILINGSPACE M_FREEROOM
struct SLIRPmbuf { struct mbuf {
struct m_hdr m_hdr; /* XXX should union some of these! */
union M_dat { /* header at beginning of each mbuf: */
char m_dat_[1]; /* ANSI don't like 0 sized arrays */ struct mbuf *m_next; /* Linked list of mbufs */
char *m_ext_; struct mbuf *m_prev;
} M_dat; struct mbuf *m_nextpkt; /* Next packet in queue/record */
struct mbuf *m_prevpkt; /* Flags aren't used in the output queue */
int m_flags; /* Misc flags */
int m_size; /* Size of mbuf, from m_dat or m_ext */
struct socket *m_so;
char *m_data; /* Current location of data */
int m_len; /* Amount of data in this mbuf, from m_data */
Slirp *slirp;
bool resolution_requested;
uint64_t expiration_date;
char *m_ext;
/* start of dynamic buffer area, must be last element */
char m_dat[];
}; };
#define m_next m_hdr.mh_next
#define m_prev m_hdr.mh_prev
#define m_nextpkt m_hdr.mh_nextpkt
#define m_prevpkt m_hdr.mh_prevpkt
#define m_flags m_hdr.mh_flags
#define m_len m_hdr.mh_len
#define m_data m_hdr.mh_data
#define m_size m_hdr.mh_size
#define m_dat M_dat.m_dat_
#define m_ext M_dat.m_ext_
#define m_so m_hdr.mh_so
#define ifq_prev m_prev #define ifq_prev m_prev
#define ifq_next m_next #define ifq_next m_next
#define ifs_prev m_prevpkt #define ifs_prev m_prevpkt
#define ifs_next m_nextpkt #define ifs_next m_nextpkt
#define ifq_so m_so #define ifq_so m_so
#define M_EXT 0x01 /* m_ext points to more (malloced) data */ #define M_EXT 0x01 /* m_ext points to more (malloced) data */
#define M_FREELIST 0x02 /* mbuf is on free list */ #define M_FREELIST 0x02 /* mbuf is on free list */
#define M_USEDLIST 0x04 /* XXX mbuf is on used list (for dtom()) */ #define M_USEDLIST 0x04 /* XXX mbuf is on used list (for dtom()) */
#define M_DOFREE 0x08 /* when m_free is called on the mbuf, free() #define M_DOFREE \
* it rather than putting it on the free list */ 0x08 /* when m_free is called on the mbuf, free() \
* it rather than putting it on the free list */
/* void m_init(Slirp *);
* Mbuf statistics. XXX void m_cleanup(Slirp *slirp);
*/ struct mbuf *m_get(Slirp *);
void m_free(struct mbuf *);
void m_cat(register struct mbuf *, register struct mbuf *);
void m_inc(struct mbuf *, int);
void m_adj(struct mbuf *, int);
int m_copy(struct mbuf *, struct mbuf *, int, int);
struct mbuf *dtom(Slirp *, void *);
struct mbstat { static inline void ifs_init(struct mbuf *ifm)
int mbs_alloced; /* Number of mbufs allocated */ {
ifm->ifs_next = ifm->ifs_prev = ifm;
}; }
extern struct mbstat mbstat;
extern int mbuf_alloced;
extern struct SLIRPmbuf m_freelist, m_usedlist;
extern int mbuf_max;
void m_init _P((void));
void msize_init _P((void));
struct SLIRPmbuf * m_get _P((void));
void m_free _P((struct SLIRPmbuf *));
void m_cat _P((register struct SLIRPmbuf *, register struct SLIRPmbuf *));
void m_inc _P((struct SLIRPmbuf *, int));
void m_adj _P((struct SLIRPmbuf *, int));
int m_copy _P((struct SLIRPmbuf *, struct SLIRPmbuf *, int, int));
struct SLIRPmbuf * dtom _P((void *));
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,34 +1,23 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/* /*
* Copyright (c) 1995 Danny Gasparovski. * Copyright (c) 1995 Danny Gasparovski.
*
* Please read the file COPYRIGHT for the
* terms and conditions of the copyright.
*/ */
#ifndef _MISC_H_ #ifndef MISC_H
#define _MISC_H_ #define MISC_H
struct ex_list { #include "libslirp.h"
int ex_pty; /* Do we want a pty? */
int ex_addr; /* The last byte of the address */ struct gfwd_list {
int ex_fport; /* Port to telnet to */ SlirpWriteCb write_cb;
char *ex_exec; /* Command line of what to exec */ void *opaque;
struct ex_list *ex_next; struct in_addr ex_addr; /* Server address */
int ex_fport; /* Port to telnet to */
char *ex_exec; /* Command line of what to exec */
char *ex_unix; /* unix socket */
struct gfwd_list *ex_next;
}; };
extern struct ex_list *exec_list;
extern u_int curtime, time_fasttimo, last_slowtimo, detach_time, detach_wait;
extern int (*lprint_print) _P((void *, const char *, va_list));
extern char *lprint_ptr, *lprint_ptr2, **lprint_arg;
extern struct sbuf *lprint_sb;
#ifndef HAVE_STRDUP
char *strdup _P((const char *));
#endif
void do_wait _P((int));
#define EMU_NONE 0x0 #define EMU_NONE 0x0
/* TCP emulations */ /* TCP emulations */
@@ -39,49 +28,45 @@ void do_wait _P((int));
#define EMU_REALAUDIO 0x5 #define EMU_REALAUDIO 0x5
#define EMU_RLOGIN 0x6 #define EMU_RLOGIN 0x6
#define EMU_IDENT 0x7 #define EMU_IDENT 0x7
#define EMU_RSH 0x8
#define EMU_NOCONNECT 0x10 /* Don't connect */ #define EMU_NOCONNECT 0x10 /* Don't connect */
/* UDP emulations */
#define EMU_TALK 0x1
#define EMU_NTALK 0x2
#define EMU_CUSEEME 0x3
struct tos_t { struct tos_t {
u_int16_t lport; uint16_t lport;
u_int16_t fport; uint16_t fport;
u_int8_t tos; uint8_t tos;
u_int8_t emu; uint8_t emu;
}; };
struct emu_t { struct emu_t {
u_int16_t lport; uint16_t lport;
u_int16_t fport; uint16_t fport;
u_int8_t tos; uint8_t tos;
u_int8_t emu; uint8_t emu;
struct emu_t *next; struct emu_t *next;
}; };
extern struct emu_t *tcpemu; struct slirp_quehead {
struct slirp_quehead *qh_link;
struct slirp_quehead *qh_rlink;
};
extern int x_port, x_server, x_display; void slirp_insque(void *, void *);
void slirp_remque(void *);
int fork_exec(struct socket *so, const char *ex);
int open_unix(struct socket *so, const char *unixsock);
int show_x _P((char *, struct SLIRPsocket *)); struct gfwd_list *add_guestfwd(struct gfwd_list **ex_ptr, SlirpWriteCb write_cb,
void redir_x _P((u_int32_t, int, int, int)); void *opaque, struct in_addr addr, int port);
void getouraddr _P((void));
void slirp_insque _P((void *, void *)); struct gfwd_list *add_exec(struct gfwd_list **ex_ptr, const char *cmdline,
void slirp_remque _P((void *)); struct in_addr addr, int port);
int add_exec _P((struct ex_list **, int, char *, int, int));
int slirp_openpty _P((int *, int *)); struct gfwd_list *add_unix(struct gfwd_list **ex_ptr, const char *unixsock,
int fork_exec _P((struct SLIRPsocket *, char *, int)); struct in_addr addr, int port);
void snooze_hup _P((int));
void snooze _P((void)); int remove_guestfwd(struct gfwd_list **ex_ptr, struct in_addr addr, int port);
void relay _P((int));
void add_emu _P((char *)); int slirp_bind_outbound(struct socket *so, unsigned short af);
void u_sleep _P((int));
void fd_nonblock _P((int));
void fd_block _P((int));
int rsh_exec _P((struct SLIRPsocket *, struct SLIRPsocket *, char *, char *, char *));
#endif #endif

View File

@@ -0,0 +1,445 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/*
* Copyright Gavin Shan, IBM Corporation 2016.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef NCSI_PKT_H
#define NCSI_PKT_H
/* from linux/net/ncsi/ncsi-pkt.h */
#define __be32 uint32_t
#define __be16 uint16_t
struct ncsi_pkt_hdr {
unsigned char mc_id; /* Management controller ID */
unsigned char revision; /* NCSI version - 0x01 */
unsigned char reserved; /* Reserved */
unsigned char id; /* Packet sequence number */
unsigned char type; /* Packet type */
unsigned char channel; /* Network controller ID */
__be16 length; /* Payload length */
__be32 reserved1[2]; /* Reserved */
};
struct ncsi_cmd_pkt_hdr {
struct ncsi_pkt_hdr common; /* Common NCSI packet header */
};
struct ncsi_rsp_pkt_hdr {
struct ncsi_pkt_hdr common; /* Common NCSI packet header */
__be16 code; /* Response code */
__be16 reason; /* Response reason */
};
struct ncsi_aen_pkt_hdr {
struct ncsi_pkt_hdr common; /* Common NCSI packet header */
unsigned char reserved2[3]; /* Reserved */
unsigned char type; /* AEN packet type */
};
/* NCSI common command packet */
struct ncsi_cmd_pkt {
struct ncsi_cmd_pkt_hdr cmd; /* Command header */
__be32 checksum; /* Checksum */
unsigned char pad[26];
};
struct ncsi_rsp_pkt {
struct ncsi_rsp_pkt_hdr rsp; /* Response header */
__be32 checksum; /* Checksum */
unsigned char pad[22];
};
/* Select Package */
struct ncsi_cmd_sp_pkt {
struct ncsi_cmd_pkt_hdr cmd; /* Command header */
unsigned char reserved[3]; /* Reserved */
unsigned char hw_arbitration; /* HW arbitration */
__be32 checksum; /* Checksum */
unsigned char pad[22];
};
/* Disable Channel */
struct ncsi_cmd_dc_pkt {
struct ncsi_cmd_pkt_hdr cmd; /* Command header */
unsigned char reserved[3]; /* Reserved */
unsigned char ald; /* Allow link down */
__be32 checksum; /* Checksum */
unsigned char pad[22];
};
/* Reset Channel */
struct ncsi_cmd_rc_pkt {
struct ncsi_cmd_pkt_hdr cmd; /* Command header */
__be32 reserved; /* Reserved */
__be32 checksum; /* Checksum */
unsigned char pad[22];
};
/* AEN Enable */
struct ncsi_cmd_ae_pkt {
struct ncsi_cmd_pkt_hdr cmd; /* Command header */
unsigned char reserved[3]; /* Reserved */
unsigned char mc_id; /* MC ID */
__be32 mode; /* AEN working mode */
__be32 checksum; /* Checksum */
unsigned char pad[18];
};
/* Set Link */
struct ncsi_cmd_sl_pkt {
struct ncsi_cmd_pkt_hdr cmd; /* Command header */
__be32 mode; /* Link working mode */
__be32 oem_mode; /* OEM link mode */
__be32 checksum; /* Checksum */
unsigned char pad[18];
};
/* Set VLAN Filter */
struct ncsi_cmd_svf_pkt {
struct ncsi_cmd_pkt_hdr cmd; /* Command header */
__be16 reserved; /* Reserved */
__be16 vlan; /* VLAN ID */
__be16 reserved1; /* Reserved */
unsigned char index; /* VLAN table index */
unsigned char enable; /* Enable or disable */
__be32 checksum; /* Checksum */
unsigned char pad[14];
};
/* Enable VLAN */
struct ncsi_cmd_ev_pkt {
struct ncsi_cmd_pkt_hdr cmd; /* Command header */
unsigned char reserved[3]; /* Reserved */
unsigned char mode; /* VLAN filter mode */
__be32 checksum; /* Checksum */
unsigned char pad[22];
};
/* Set MAC Address */
struct ncsi_cmd_sma_pkt {
struct ncsi_cmd_pkt_hdr cmd; /* Command header */
unsigned char mac[6]; /* MAC address */
unsigned char index; /* MAC table index */
unsigned char at_e; /* Addr type and operation */
__be32 checksum; /* Checksum */
unsigned char pad[18];
};
/* Enable Broadcast Filter */
struct ncsi_cmd_ebf_pkt {
struct ncsi_cmd_pkt_hdr cmd; /* Command header */
__be32 mode; /* Filter mode */
__be32 checksum; /* Checksum */
unsigned char pad[22];
};
/* Enable Global Multicast Filter */
struct ncsi_cmd_egmf_pkt {
struct ncsi_cmd_pkt_hdr cmd; /* Command header */
__be32 mode; /* Global MC mode */
__be32 checksum; /* Checksum */
unsigned char pad[22];
};
/* Set NCSI Flow Control */
struct ncsi_cmd_snfc_pkt {
struct ncsi_cmd_pkt_hdr cmd; /* Command header */
unsigned char reserved[3]; /* Reserved */
unsigned char mode; /* Flow control mode */
__be32 checksum; /* Checksum */
unsigned char pad[22];
};
/* Get Link Status */
struct ncsi_rsp_gls_pkt {
struct ncsi_rsp_pkt_hdr rsp; /* Response header */
__be32 status; /* Link status */
__be32 other; /* Other indications */
__be32 oem_status; /* OEM link status */
__be32 checksum;
unsigned char pad[10];
};
/* Get Version ID */
struct ncsi_rsp_gvi_pkt {
struct ncsi_rsp_pkt_hdr rsp; /* Response header */
__be32 ncsi_version; /* NCSI version */
unsigned char reserved[3]; /* Reserved */
unsigned char alpha2; /* NCSI version */
unsigned char fw_name[12]; /* f/w name string */
__be32 fw_version; /* f/w version */
__be16 pci_ids[4]; /* PCI IDs */
__be32 mf_id; /* Manufacture ID */
__be32 checksum;
};
/* Get Capabilities */
struct ncsi_rsp_gc_pkt {
struct ncsi_rsp_pkt_hdr rsp; /* Response header */
__be32 cap; /* Capabilities */
__be32 bc_cap; /* Broadcast cap */
__be32 mc_cap; /* Multicast cap */
__be32 buf_cap; /* Buffering cap */
__be32 aen_cap; /* AEN cap */
unsigned char vlan_cnt; /* VLAN filter count */
unsigned char mixed_cnt; /* Mix filter count */
unsigned char mc_cnt; /* MC filter count */
unsigned char uc_cnt; /* UC filter count */
unsigned char reserved[2]; /* Reserved */
unsigned char vlan_mode; /* VLAN mode */
unsigned char channel_cnt; /* Channel count */
__be32 checksum; /* Checksum */
};
/* Get Parameters */
struct ncsi_rsp_gp_pkt {
struct ncsi_rsp_pkt_hdr rsp; /* Response header */
unsigned char mac_cnt; /* Number of MAC addr */
unsigned char reserved[2]; /* Reserved */
unsigned char mac_enable; /* MAC addr enable flags */
unsigned char vlan_cnt; /* VLAN tag count */
unsigned char reserved1; /* Reserved */
__be16 vlan_enable; /* VLAN tag enable flags */
__be32 link_mode; /* Link setting */
__be32 bc_mode; /* BC filter mode */
__be32 valid_modes; /* Valid mode parameters */
unsigned char vlan_mode; /* VLAN mode */
unsigned char fc_mode; /* Flow control mode */
unsigned char reserved2[2]; /* Reserved */
__be32 aen_mode; /* AEN mode */
unsigned char mac[6]; /* Supported MAC addr */
__be16 vlan; /* Supported VLAN tags */
__be32 checksum; /* Checksum */
};
/* Get Controller Packet Statistics */
struct ncsi_rsp_gcps_pkt {
struct ncsi_rsp_pkt_hdr rsp; /* Response header */
__be32 cnt_hi; /* Counter cleared */
__be32 cnt_lo; /* Counter cleared */
__be32 rx_bytes; /* Rx bytes */
__be32 tx_bytes; /* Tx bytes */
__be32 rx_uc_pkts; /* Rx UC packets */
__be32 rx_mc_pkts; /* Rx MC packets */
__be32 rx_bc_pkts; /* Rx BC packets */
__be32 tx_uc_pkts; /* Tx UC packets */
__be32 tx_mc_pkts; /* Tx MC packets */
__be32 tx_bc_pkts; /* Tx BC packets */
__be32 fcs_err; /* FCS errors */
__be32 align_err; /* Alignment errors */
__be32 false_carrier; /* False carrier detection */
__be32 runt_pkts; /* Rx runt packets */
__be32 jabber_pkts; /* Rx jabber packets */
__be32 rx_pause_xon; /* Rx pause XON frames */
__be32 rx_pause_xoff; /* Rx XOFF frames */
__be32 tx_pause_xon; /* Tx XON frames */
__be32 tx_pause_xoff; /* Tx XOFF frames */
__be32 tx_s_collision; /* Single collision frames */
__be32 tx_m_collision; /* Multiple collision frames */
__be32 l_collision; /* Late collision frames */
__be32 e_collision; /* Excessive collision frames */
__be32 rx_ctl_frames; /* Rx control frames */
__be32 rx_64_frames; /* Rx 64-bytes frames */
__be32 rx_127_frames; /* Rx 65-127 bytes frames */
__be32 rx_255_frames; /* Rx 128-255 bytes frames */
__be32 rx_511_frames; /* Rx 256-511 bytes frames */
__be32 rx_1023_frames; /* Rx 512-1023 bytes frames */
__be32 rx_1522_frames; /* Rx 1024-1522 bytes frames */
__be32 rx_9022_frames; /* Rx 1523-9022 bytes frames */
__be32 tx_64_frames; /* Tx 64-bytes frames */
__be32 tx_127_frames; /* Tx 65-127 bytes frames */
__be32 tx_255_frames; /* Tx 128-255 bytes frames */
__be32 tx_511_frames; /* Tx 256-511 bytes frames */
__be32 tx_1023_frames; /* Tx 512-1023 bytes frames */
__be32 tx_1522_frames; /* Tx 1024-1522 bytes frames */
__be32 tx_9022_frames; /* Tx 1523-9022 bytes frames */
__be32 rx_valid_bytes; /* Rx valid bytes */
__be32 rx_runt_pkts; /* Rx error runt packets */
__be32 rx_jabber_pkts; /* Rx error jabber packets */
__be32 checksum; /* Checksum */
};
/* Get NCSI Statistics */
struct ncsi_rsp_gns_pkt {
struct ncsi_rsp_pkt_hdr rsp; /* Response header */
__be32 rx_cmds; /* Rx NCSI commands */
__be32 dropped_cmds; /* Dropped commands */
__be32 cmd_type_errs; /* Command type errors */
__be32 cmd_csum_errs; /* Command checksum errors */
__be32 rx_pkts; /* Rx NCSI packets */
__be32 tx_pkts; /* Tx NCSI packets */
__be32 tx_aen_pkts; /* Tx AEN packets */
__be32 checksum; /* Checksum */
};
/* Get NCSI Pass-through Statistics */
struct ncsi_rsp_gnpts_pkt {
struct ncsi_rsp_pkt_hdr rsp; /* Response header */
__be32 tx_pkts; /* Tx packets */
__be32 tx_dropped; /* Tx dropped packets */
__be32 tx_channel_err; /* Tx channel errors */
__be32 tx_us_err; /* Tx undersize errors */
__be32 rx_pkts; /* Rx packets */
__be32 rx_dropped; /* Rx dropped packets */
__be32 rx_channel_err; /* Rx channel errors */
__be32 rx_us_err; /* Rx undersize errors */
__be32 rx_os_err; /* Rx oversize errors */
__be32 checksum; /* Checksum */
};
/* Get package status */
struct ncsi_rsp_gps_pkt {
struct ncsi_rsp_pkt_hdr rsp; /* Response header */
__be32 status; /* Hardware arbitration status */
__be32 checksum;
};
/* Get package UUID */
struct ncsi_rsp_gpuuid_pkt {
struct ncsi_rsp_pkt_hdr rsp; /* Response header */
unsigned char uuid[16]; /* UUID */
__be32 checksum;
};
/* AEN: Link State Change */
struct ncsi_aen_lsc_pkt {
struct ncsi_aen_pkt_hdr aen; /* AEN header */
__be32 status; /* Link status */
__be32 oem_status; /* OEM link status */
__be32 checksum; /* Checksum */
unsigned char pad[14];
};
/* AEN: Configuration Required */
struct ncsi_aen_cr_pkt {
struct ncsi_aen_pkt_hdr aen; /* AEN header */
__be32 checksum; /* Checksum */
unsigned char pad[22];
};
/* AEN: Host Network Controller Driver Status Change */
struct ncsi_aen_hncdsc_pkt {
struct ncsi_aen_pkt_hdr aen; /* AEN header */
__be32 status; /* Status */
__be32 checksum; /* Checksum */
unsigned char pad[18];
};
/* NCSI packet revision */
#define NCSI_PKT_REVISION 0x01
/* NCSI packet commands */
#define NCSI_PKT_CMD_CIS 0x00 /* Clear Initial State */
#define NCSI_PKT_CMD_SP 0x01 /* Select Package */
#define NCSI_PKT_CMD_DP 0x02 /* Deselect Package */
#define NCSI_PKT_CMD_EC 0x03 /* Enable Channel */
#define NCSI_PKT_CMD_DC 0x04 /* Disable Channel */
#define NCSI_PKT_CMD_RC 0x05 /* Reset Channel */
#define NCSI_PKT_CMD_ECNT 0x06 /* Enable Channel Network Tx */
#define NCSI_PKT_CMD_DCNT 0x07 /* Disable Channel Network Tx */
#define NCSI_PKT_CMD_AE 0x08 /* AEN Enable */
#define NCSI_PKT_CMD_SL 0x09 /* Set Link */
#define NCSI_PKT_CMD_GLS 0x0a /* Get Link */
#define NCSI_PKT_CMD_SVF 0x0b /* Set VLAN Filter */
#define NCSI_PKT_CMD_EV 0x0c /* Enable VLAN */
#define NCSI_PKT_CMD_DV 0x0d /* Disable VLAN */
#define NCSI_PKT_CMD_SMA 0x0e /* Set MAC address */
#define NCSI_PKT_CMD_EBF 0x10 /* Enable Broadcast Filter */
#define NCSI_PKT_CMD_DBF 0x11 /* Disable Broadcast Filter */
#define NCSI_PKT_CMD_EGMF 0x12 /* Enable Global Multicast Filter */
#define NCSI_PKT_CMD_DGMF 0x13 /* Disable Global Multicast Filter */
#define NCSI_PKT_CMD_SNFC 0x14 /* Set NCSI Flow Control */
#define NCSI_PKT_CMD_GVI 0x15 /* Get Version ID */
#define NCSI_PKT_CMD_GC 0x16 /* Get Capabilities */
#define NCSI_PKT_CMD_GP 0x17 /* Get Parameters */
#define NCSI_PKT_CMD_GCPS 0x18 /* Get Controller Packet Statistics */
#define NCSI_PKT_CMD_GNS 0x19 /* Get NCSI Statistics */
#define NCSI_PKT_CMD_GNPTS 0x1a /* Get NCSI Pass-throu Statistics */
#define NCSI_PKT_CMD_GPS 0x1b /* Get package status */
#define NCSI_PKT_CMD_OEM 0x50 /* OEM */
#define NCSI_PKT_CMD_PLDM 0x51 /* PLDM request over NCSI over RBT */
#define NCSI_PKT_CMD_GPUUID 0x52 /* Get package UUID */
/* NCSI packet responses */
#define NCSI_PKT_RSP_CIS (NCSI_PKT_CMD_CIS + 0x80)
#define NCSI_PKT_RSP_SP (NCSI_PKT_CMD_SP + 0x80)
#define NCSI_PKT_RSP_DP (NCSI_PKT_CMD_DP + 0x80)
#define NCSI_PKT_RSP_EC (NCSI_PKT_CMD_EC + 0x80)
#define NCSI_PKT_RSP_DC (NCSI_PKT_CMD_DC + 0x80)
#define NCSI_PKT_RSP_RC (NCSI_PKT_CMD_RC + 0x80)
#define NCSI_PKT_RSP_ECNT (NCSI_PKT_CMD_ECNT + 0x80)
#define NCSI_PKT_RSP_DCNT (NCSI_PKT_CMD_DCNT + 0x80)
#define NCSI_PKT_RSP_AE (NCSI_PKT_CMD_AE + 0x80)
#define NCSI_PKT_RSP_SL (NCSI_PKT_CMD_SL + 0x80)
#define NCSI_PKT_RSP_GLS (NCSI_PKT_CMD_GLS + 0x80)
#define NCSI_PKT_RSP_SVF (NCSI_PKT_CMD_SVF + 0x80)
#define NCSI_PKT_RSP_EV (NCSI_PKT_CMD_EV + 0x80)
#define NCSI_PKT_RSP_DV (NCSI_PKT_CMD_DV + 0x80)
#define NCSI_PKT_RSP_SMA (NCSI_PKT_CMD_SMA + 0x80)
#define NCSI_PKT_RSP_EBF (NCSI_PKT_CMD_EBF + 0x80)
#define NCSI_PKT_RSP_DBF (NCSI_PKT_CMD_DBF + 0x80)
#define NCSI_PKT_RSP_EGMF (NCSI_PKT_CMD_EGMF + 0x80)
#define NCSI_PKT_RSP_DGMF (NCSI_PKT_CMD_DGMF + 0x80)
#define NCSI_PKT_RSP_SNFC (NCSI_PKT_CMD_SNFC + 0x80)
#define NCSI_PKT_RSP_GVI (NCSI_PKT_CMD_GVI + 0x80)
#define NCSI_PKT_RSP_GC (NCSI_PKT_CMD_GC + 0x80)
#define NCSI_PKT_RSP_GP (NCSI_PKT_CMD_GP + 0x80)
#define NCSI_PKT_RSP_GCPS (NCSI_PKT_CMD_GCPS + 0x80)
#define NCSI_PKT_RSP_GNS (NCSI_PKT_CMD_GNS + 0x80)
#define NCSI_PKT_RSP_GNPTS (NCSI_PKT_CMD_GNPTS + 0x80)
#define NCSI_PKT_RSP_GPS (NCSI_PKT_CMD_GPS + 0x80)
#define NCSI_PKT_RSP_OEM (NCSI_PKT_CMD_OEM + 0x80)
#define NCSI_PKT_RSP_PLDM (NCSI_PKT_CMD_PLDM + 0x80)
#define NCSI_PKT_RSP_GPUUID (NCSI_PKT_CMD_GPUUID + 0x80)
/* NCSI response code/reason */
#define NCSI_PKT_RSP_C_COMPLETED 0x0000 /* Command Completed */
#define NCSI_PKT_RSP_C_FAILED 0x0001 /* Command Failed */
#define NCSI_PKT_RSP_C_UNAVAILABLE 0x0002 /* Command Unavailable */
#define NCSI_PKT_RSP_C_UNSUPPORTED 0x0003 /* Command Unsupported */
#define NCSI_PKT_RSP_R_NO_ERROR 0x0000 /* No Error */
#define NCSI_PKT_RSP_R_INTERFACE 0x0001 /* Interface not ready */
#define NCSI_PKT_RSP_R_PARAM 0x0002 /* Invalid Parameter */
#define NCSI_PKT_RSP_R_CHANNEL 0x0003 /* Channel not Ready */
#define NCSI_PKT_RSP_R_PACKAGE 0x0004 /* Package not Ready */
#define NCSI_PKT_RSP_R_LENGTH 0x0005 /* Invalid payload length */
#define NCSI_PKT_RSP_R_UNKNOWN 0x7fff /* Command type unsupported */
/* NCSI AEN packet type */
#define NCSI_PKT_AEN 0xFF /* AEN Packet */
#define NCSI_PKT_AEN_LSC 0x00 /* Link status change */
#define NCSI_PKT_AEN_CR 0x01 /* Configuration required */
#define NCSI_PKT_AEN_HNCDSC 0x02 /* HNC driver status change */
#endif /* NCSI_PKT_H */

193
src/network/slirp/ncsi.c Normal file
View File

@@ -0,0 +1,193 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/*
* NC-SI (Network Controller Sideband Interface) "echo" model
*
* Copyright (C) 2016-2018 IBM Corp.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "slirp.h"
#include "ncsi-pkt.h"
static uint32_t ncsi_calculate_checksum(uint16_t *data, int len)
{
uint32_t checksum = 0;
int i;
/*
* 32-bit unsigned sum of the NC-SI packet header and NC-SI packet
* payload interpreted as a series of 16-bit unsigned integer values.
*/
for (i = 0; i < len / 2; i++) {
checksum += htons(data[i]);
}
checksum = (~checksum + 1);
return checksum;
}
/* Get Capabilities */
static int ncsi_rsp_handler_gc(struct ncsi_rsp_pkt_hdr *rnh)
{
struct ncsi_rsp_gc_pkt *rsp = (struct ncsi_rsp_gc_pkt *)rnh;
rsp->cap = htonl(~0);
rsp->bc_cap = htonl(~0);
rsp->mc_cap = htonl(~0);
rsp->buf_cap = htonl(~0);
rsp->aen_cap = htonl(~0);
rsp->vlan_mode = 0xff;
rsp->uc_cnt = 2;
return 0;
}
/* Get Link status */
static int ncsi_rsp_handler_gls(struct ncsi_rsp_pkt_hdr *rnh)
{
struct ncsi_rsp_gls_pkt *rsp = (struct ncsi_rsp_gls_pkt *)rnh;
rsp->status = htonl(0x1);
return 0;
}
/* Get Parameters */
static int ncsi_rsp_handler_gp(struct ncsi_rsp_pkt_hdr *rnh)
{
struct ncsi_rsp_gp_pkt *rsp = (struct ncsi_rsp_gp_pkt *)rnh;
/* no MAC address filters or VLAN filters on the channel */
rsp->mac_cnt = 0;
rsp->mac_enable = 0;
rsp->vlan_cnt = 0;
rsp->vlan_enable = 0;
return 0;
}
static const struct ncsi_rsp_handler {
unsigned char type;
int payload;
int (*handler)(struct ncsi_rsp_pkt_hdr *rnh);
} ncsi_rsp_handlers[] = { { NCSI_PKT_RSP_CIS, 4, NULL },
{ NCSI_PKT_RSP_SP, 4, NULL },
{ NCSI_PKT_RSP_DP, 4, NULL },
{ NCSI_PKT_RSP_EC, 4, NULL },
{ NCSI_PKT_RSP_DC, 4, NULL },
{ NCSI_PKT_RSP_RC, 4, NULL },
{ NCSI_PKT_RSP_ECNT, 4, NULL },
{ NCSI_PKT_RSP_DCNT, 4, NULL },
{ NCSI_PKT_RSP_AE, 4, NULL },
{ NCSI_PKT_RSP_SL, 4, NULL },
{ NCSI_PKT_RSP_GLS, 16, ncsi_rsp_handler_gls },
{ NCSI_PKT_RSP_SVF, 4, NULL },
{ NCSI_PKT_RSP_EV, 4, NULL },
{ NCSI_PKT_RSP_DV, 4, NULL },
{ NCSI_PKT_RSP_SMA, 4, NULL },
{ NCSI_PKT_RSP_EBF, 4, NULL },
{ NCSI_PKT_RSP_DBF, 4, NULL },
{ NCSI_PKT_RSP_EGMF, 4, NULL },
{ NCSI_PKT_RSP_DGMF, 4, NULL },
{ NCSI_PKT_RSP_SNFC, 4, NULL },
{ NCSI_PKT_RSP_GVI, 40, NULL },
{ NCSI_PKT_RSP_GC, 32, ncsi_rsp_handler_gc },
{ NCSI_PKT_RSP_GP, 40, ncsi_rsp_handler_gp },
{ NCSI_PKT_RSP_GCPS, 172, NULL },
{ NCSI_PKT_RSP_GNS, 172, NULL },
{ NCSI_PKT_RSP_GNPTS, 172, NULL },
{ NCSI_PKT_RSP_GPS, 8, NULL },
{ NCSI_PKT_RSP_OEM, 0, NULL },
{ NCSI_PKT_RSP_PLDM, 0, NULL },
{ NCSI_PKT_RSP_GPUUID, 20, NULL } };
/*
* packet format : ncsi header + payload + checksum
*/
#define NCSI_MAX_PAYLOAD 172
#define NCSI_MAX_LEN (sizeof(struct ncsi_pkt_hdr) + NCSI_MAX_PAYLOAD + 4)
void ncsi_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
{
const struct ncsi_pkt_hdr *nh =
(const struct ncsi_pkt_hdr *)(pkt + ETH_HLEN);
uint8_t ncsi_reply[ETH_HLEN + NCSI_MAX_LEN];
struct ethhdr *reh = (struct ethhdr *)ncsi_reply;
struct ncsi_rsp_pkt_hdr *rnh =
(struct ncsi_rsp_pkt_hdr *)(ncsi_reply + ETH_HLEN);
const struct ncsi_rsp_handler *handler = NULL;
int i;
int ncsi_rsp_len = sizeof(*nh);
uint32_t checksum;
uint32_t *pchecksum;
memset(ncsi_reply, 0, sizeof(ncsi_reply));
memset(reh->h_dest, 0xff, ETH_ALEN);
memset(reh->h_source, 0xff, ETH_ALEN);
reh->h_proto = htons(ETH_P_NCSI);
for (i = 0; i < G_N_ELEMENTS(ncsi_rsp_handlers); i++) {
if (ncsi_rsp_handlers[i].type == nh->type + 0x80) {
handler = &ncsi_rsp_handlers[i];
break;
}
}
rnh->common.mc_id = nh->mc_id;
rnh->common.revision = NCSI_PKT_REVISION;
rnh->common.id = nh->id;
rnh->common.type = nh->type + 0x80;
rnh->common.channel = nh->channel;
if (handler) {
rnh->common.length = htons(handler->payload);
rnh->code = htons(NCSI_PKT_RSP_C_COMPLETED);
rnh->reason = htons(NCSI_PKT_RSP_R_NO_ERROR);
if (handler->handler) {
/* TODO: handle errors */
handler->handler(rnh);
}
ncsi_rsp_len += handler->payload;
} else {
rnh->common.length = 0;
rnh->code = htons(NCSI_PKT_RSP_C_UNAVAILABLE);
rnh->reason = htons(NCSI_PKT_RSP_R_UNKNOWN);
}
/* Add the optional checksum at the end of the frame. */
checksum = ncsi_calculate_checksum((uint16_t *)rnh, ncsi_rsp_len);
pchecksum = (uint32_t *)((void *)rnh + ncsi_rsp_len);
*pchecksum = htonl(checksum);
ncsi_rsp_len += 4;
slirp_send_packet_all(slirp, ncsi_reply, ETH_HLEN + ncsi_rsp_len);
}

View File

@@ -0,0 +1,87 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/*
* Copyright (c) 2013
* Guillaume Subiron, Yann Bordenave, Serigne Modou Wagne.
*/
#include "slirp.h"
void ndp_table_add(Slirp *slirp, struct in6_addr ip_addr,
uint8_t ethaddr[ETH_ALEN])
{
char addrstr[INET6_ADDRSTRLEN];
NdpTable *ndp_table = &slirp->ndp_table;
int i;
inet_ntop(AF_INET6, &(ip_addr), addrstr, INET6_ADDRSTRLEN);
DEBUG_CALL("ndp_table_add");
DEBUG_ARG("ip = %s", addrstr);
DEBUG_ARG("hw addr = %02x:%02x:%02x:%02x:%02x:%02x", ethaddr[0], ethaddr[1],
ethaddr[2], ethaddr[3], ethaddr[4], ethaddr[5]);
if (IN6_IS_ADDR_MULTICAST(&ip_addr) || in6_zero(&ip_addr)) {
/* Do not register multicast or unspecified addresses */
DEBUG_CALL(" abort: do not register multicast or unspecified address");
return;
}
/* Search for an entry */
for (i = 0; i < NDP_TABLE_SIZE; i++) {
if (in6_equal(&ndp_table->table[i].ip_addr, &ip_addr)) {
DEBUG_CALL(" already in table: update the entry");
/* Update the entry */
memcpy(ndp_table->table[i].eth_addr, ethaddr, ETH_ALEN);
return;
}
}
/* No entry found, create a new one */
DEBUG_CALL(" create new entry");
ndp_table->table[ndp_table->next_victim].ip_addr = ip_addr;
memcpy(ndp_table->table[ndp_table->next_victim].eth_addr, ethaddr,
ETH_ALEN);
ndp_table->next_victim = (ndp_table->next_victim + 1) % NDP_TABLE_SIZE;
}
bool ndp_table_search(Slirp *slirp, struct in6_addr ip_addr,
uint8_t out_ethaddr[ETH_ALEN])
{
char addrstr[INET6_ADDRSTRLEN];
NdpTable *ndp_table = &slirp->ndp_table;
int i;
inet_ntop(AF_INET6, &(ip_addr), addrstr, INET6_ADDRSTRLEN);
DEBUG_CALL("ndp_table_search");
DEBUG_ARG("ip = %s", addrstr);
assert(!in6_zero(&ip_addr));
/* Multicast address: fec0::abcd:efgh/8 -> 33:33:ab:cd:ef:gh */
if (IN6_IS_ADDR_MULTICAST(&ip_addr)) {
out_ethaddr[0] = 0x33;
out_ethaddr[1] = 0x33;
out_ethaddr[2] = ip_addr.s6_addr[12];
out_ethaddr[3] = ip_addr.s6_addr[13];
out_ethaddr[4] = ip_addr.s6_addr[14];
out_ethaddr[5] = ip_addr.s6_addr[15];
DEBUG_ARG("multicast addr = %02x:%02x:%02x:%02x:%02x:%02x",
out_ethaddr[0], out_ethaddr[1], out_ethaddr[2],
out_ethaddr[3], out_ethaddr[4], out_ethaddr[5]);
return 1;
}
for (i = 0; i < NDP_TABLE_SIZE; i++) {
if (in6_equal(&ndp_table->table[i].ip_addr, &ip_addr)) {
memcpy(out_ethaddr, ndp_table->table[i].eth_addr, ETH_ALEN);
DEBUG_ARG("found hw addr = %02x:%02x:%02x:%02x:%02x:%02x",
out_ethaddr[0], out_ethaddr[1], out_ethaddr[2],
out_ethaddr[3], out_ethaddr[4], out_ethaddr[5]);
return 1;
}
}
DEBUG_CALL(" ip not found in table");
return 0;
}

View File

@@ -1,116 +0,0 @@
/*
* File: queue.c
* Author: Robert I. Pitts <rip@cs.bu.edu>
* Last Modified: March 9, 2000
* Topic: Queue - Array Implementation
* ----------------------------------------------------------------
*/
#include <stdio.h>
#include <stdlib.h>
#include "queue.h"
/*
* Constants
* ---------
* MAX_QUEUE_SIZE = Largest number of items queue can hold.
*/
#define MAX_QUEUE_SIZE 100
/*
* struct queueCDT gives the implementation of a queue.
* It holds the information that we need for each queue.
*/
typedef struct queueCDT {
queueElementT contents[MAX_QUEUE_SIZE];
int front;
int count;
} queueCDT;
queueADT QueueCreate(void)
{
queueADT queue;
queue = (queueADT)malloc(sizeof(queueCDT));
if (queue == NULL) {
fprintf(stderr, "Insufficient Memory for new Queue.\n");
exit(ERROR_MEMORY); /* Exit program, returning error code. */
}
queue->front = 0;
queue->count = 0;
return queue;
}
void QueueDestroy(queueADT queue)
{
free(queue);
}
void QueueEnter(queueADT queue, queueElementT element)
{
int newElementIndex;
if (queue->count >= MAX_QUEUE_SIZE) {
// fprintf(stderr, "QueueEnter on Full Queue.\n");
// exit(ERROR_QUEUE); /* Exit program, returning error code. */
return;
}
/*
* Calculate index at which to put
* next element.
*/
newElementIndex = (queue->front + queue->count)
% MAX_QUEUE_SIZE;
queue->contents[newElementIndex] = element;
//printf("element %d, pointer to %d, [%s]\n",newElementIndex,element,element);
queue->count++;
}
int QueuePeek(queueADT queue)
{
return queue->count;
}
queueElementT QueueDelete(queueADT queue)
{
queueElementT oldElement;
if (queue->count <= 0) {
//fprintf(stderr, "QueueDelete on Empty Queue.\n");
//exit(ERROR_QUEUE); /* Exit program, returning error code. */
return NULL;
}
/* Save the element so we can return it. */
oldElement = queue->contents[queue->front];
/*
* Advance the index of the front,
* making sure it wraps around the
* array properly.
*/
queue->front++;
queue->front %= MAX_QUEUE_SIZE;
//printf("dequing @%d [%s]\n",oldElement,oldElement);
queue->count--;
return oldElement;
}
int QueueIsEmpty(queueADT queue)
{
return queue->count <= 0;
}
int QueueIsFull(queueADT queue)
{
return queue->count >= MAX_QUEUE_SIZE;
}

View File

@@ -1,101 +0,0 @@
/*
* File: queue.h
* Author: Robert I. Pitts <rip@cs.bu.edu>
* Last Modified: March 9, 2000
* Topic: Queue - Array Implementation
* ----------------------------------------------------------------
*/
#ifndef _QUEUE_H
#define _QUEUE_H
/*
* Constants
* ---------
* ERROR_* These signal error conditions in queue functions
* and are used as exit codes for the program.
*/
#define ERROR_QUEUE 2
#define ERROR_MEMORY 3
/*
* Type: queueElementT
* -------------------
* This is the type of objects held in the queue.
*/
/*typedef char queueElementT;
typedef unsigned char *queueElementT;
*/
struct queuepacket{
int len;
unsigned char data[2000];
};
typedef struct queuepacket *queueElementT;
/*
* Type: queueADT
* --------------
* The actual implementation of a queue is completely
* hidden. Client will work with queueADT which is a
* pointer to underlying queueCDT.
*/
/*
* NOTE: need word struct below so that the compiler
* knows at least that a queueCDT will be some sort
* of struct.
*/
typedef struct queueCDT *queueADT;
/*
* Function: QueueCreate
* Usage: queue = QueueCreate();
* -------------------------
* A new empty queue is created and returned.
*/
queueADT QueueCreate(void);
/* Function: QueueDestroy
* Usage: QueueDestroy(queue);
* -----------------------
* This function frees all memory associated with
* the queue. "queue" may not be used again unless
* queue = QueueCreate() is called first.
*/
void QueueDestroy(queueADT queue);
/*
* Functions: QueueEnter, QueueDelete
* Usage: QueueEnter(queue, element);
* element = QueueDelete(queue);
* --------------------------------------------
* These are the fundamental queue operations that enter
* elements in and delete elements from the queue. A call
* to QueueDelete() on an empty queue or to QueueEnter()
* on a full queue is an error. Make use of QueueIsFull()
* and QueueIsEmpty() (see below) to avoid these errors.
*/
void QueueEnter(queueADT queue, queueElementT element);
queueElementT QueueDelete(queueADT queue);
/*
* Functions: QueueIsEmpty, QueueIsFull
* Usage: if (QueueIsEmpty(queue)) ...
* -----------------------------------
* These return a true/false value based on whether
* the queue is empty or full, respectively.
*/
int QueueIsEmpty(queueADT queue);
int QueueIsFull(queueADT queue);
int QueuePeek(queueADT queue);
#endif /* not defined _QUEUE_H */

View File

@@ -1,69 +1,42 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/* /*
* Copyright (c) 1995 Danny Gasparovski. * Copyright (c) 1995 Danny Gasparovski.
*
* Please read the file COPYRIGHT for the
* terms and conditions of the copyright.
*/ */
#include <stdlib.h>
#include "slirp.h" #include "slirp.h"
/* Done as a macro in socket.h */ static void sbappendsb(struct sbuf *sb, struct mbuf *m);
/* int
* sbspace(struct sockbuff *sb)
* {
* return SB_DATALEN - sb->sb_cc;
* }
*/
void void sbfree(struct sbuf *sb)
sbfree(sb)
struct sbuf *sb;
{ {
free(sb->sb_data); g_free(sb->sb_data);
} }
void bool sbdrop(struct sbuf *sb, size_t num)
sbdrop(sb, num)
struct sbuf *sb;
int num;
{ {
/* int limit = sb->sb_datalen / 2;
* We can only drop how much we have
* This should never succeed g_warn_if_fail(num <= sb->sb_cc);
*/ if (num > sb->sb_cc)
if(num > sb->sb_cc) num = sb->sb_cc;
num = sb->sb_cc;
sb->sb_cc -= num; sb->sb_cc -= num;
sb->sb_rptr += num; sb->sb_rptr += num;
if(sb->sb_rptr >= sb->sb_data + sb->sb_datalen) if (sb->sb_rptr >= sb->sb_data + sb->sb_datalen)
sb->sb_rptr -= sb->sb_datalen; sb->sb_rptr -= sb->sb_datalen;
if (sb->sb_cc < limit && sb->sb_cc + num >= limit) {
return true;
}
return false;
} }
void void sbreserve(struct sbuf *sb, size_t size)
sbreserve(sb, size)
struct sbuf *sb;
int size;
{ {
if (sb->sb_data) { sb->sb_wptr = sb->sb_rptr = sb->sb_data = g_realloc(sb->sb_data, size);
/* Already alloced, realloc if necessary */ sb->sb_cc = 0;
if (sb->sb_datalen != size) { sb->sb_datalen = size;
sb->sb_wptr = sb->sb_rptr = sb->sb_data = (char *)realloc(sb->sb_data, size);
sb->sb_cc = 0;
if (sb->sb_wptr)
sb->sb_datalen = size;
else
sb->sb_datalen = 0;
}
} else {
sb->sb_wptr = sb->sb_rptr = sb->sb_data = (char *)malloc(size);
sb->sb_cc = 0;
if (sb->sb_wptr)
sb->sb_datalen = size;
else
sb->sb_datalen = 0;
}
} }
/* /*
@@ -72,100 +45,97 @@ sbreserve(sb, size)
* this prevents an unnecessary copy of the data * this prevents an unnecessary copy of the data
* (the socket is non-blocking, so we won't hang) * (the socket is non-blocking, so we won't hang)
*/ */
void void sbappend(struct socket *so, struct mbuf *m)
sbappend(so, m)
struct SLIRPsocket *so;
struct SLIRPmbuf *m;
{ {
int ret = 0; int ret = 0;
DEBUG_CALL("sbappend"); DEBUG_CALL("sbappend");
DEBUG_ARG("so = %lx", (long)so); DEBUG_ARG("so = %p", so);
DEBUG_ARG("m = %lx", (long)m); DEBUG_ARG("m = %p", m);
DEBUG_ARG("m->m_len = %d", m->m_len); DEBUG_ARG("m->m_len = %d", m->m_len);
/* Shouldn't happen, but... e.g. foreign host closes connection */ /* Shouldn't happen, but... e.g. foreign host closes connection */
if (m->m_len <= 0) { if (m->m_len <= 0) {
m_free(m); m_free(m);
return; return;
} }
/* /*
* If there is urgent data, call sosendoob * If there is urgent data, call sosendoob
* if not all was sent, sowrite will take care of the rest * if not all was sent, sowrite will take care of the rest
* (The rest of this function is just an optimisation) * (The rest of this function is just an optimisation)
*/ */
if (so->so_urgc) { if (so->so_urgc) {
sbappendsb(&so->so_rcv, m); sbappendsb(&so->so_rcv, m);
m_free(m); m_free(m);
sosendoob(so); (void)sosendoob(so);
return; return;
} }
/* /*
* We only write if there's nothing in the buffer, * We only write if there's nothing in the buffer,
* ottherwise it'll arrive out of order, and hence corrupt * ottherwise it'll arrive out of order, and hence corrupt
*/ */
if (!so->so_rcv.sb_cc) if (!so->so_rcv.sb_cc)
ret = send(so->s, m->m_data, m->m_len, 0); ret = slirp_send(so, m->m_data, m->m_len, 0);
if (ret <= 0) { if (ret <= 0) {
/* /*
* Nothing was written * Nothing was written
* It's possible that the socket has closed, but * It's possible that the socket has closed, but
* we don't need to check because if it has closed, * we don't need to check because if it has closed,
* it will be detected in the normal way by soread() * it will be detected in the normal way by soread()
*/ */
sbappendsb(&so->so_rcv, m); sbappendsb(&so->so_rcv, m);
} else if (ret != m->m_len) { } else if (ret != m->m_len) {
/* /*
* Something was written, but not everything.. * Something was written, but not everything..
* sbappendsb the rest * sbappendsb the rest
*/ */
m->m_len -= ret; m->m_len -= ret;
m->m_data += ret; m->m_data += ret;
sbappendsb(&so->so_rcv, m); sbappendsb(&so->so_rcv, m);
} /* else */ } /* else */
/* Whatever happened, we free the SLIRPmbuf */ /* Whatever happened, we free the mbuf */
m_free(m); m_free(m);
} }
/* /*
* Copy the data from m into sb * Copy the data from m into sb
* The caller is responsible to make sure there's enough room * The caller is responsible to make sure there's enough room
*/ */
void static void sbappendsb(struct sbuf *sb, struct mbuf *m)
sbappendsb(sb, m)
struct sbuf *sb;
struct SLIRPmbuf *m;
{ {
int len, n, nn; int len, n, nn;
len = m->m_len;
if (sb->sb_wptr < sb->sb_rptr) { len = m->m_len;
n = sb->sb_rptr - sb->sb_wptr;
if (n > len) n = len;
memcpy(sb->sb_wptr, m->m_data, n);
} else {
/* Do the right edge first */
n = sb->sb_data + sb->sb_datalen - sb->sb_wptr;
if (n > len) n = len;
memcpy(sb->sb_wptr, m->m_data, n);
len -= n;
if (len) {
/* Now the left edge */
nn = sb->sb_rptr - sb->sb_data;
if (nn > len) nn = len;
memcpy(sb->sb_data,m->m_data+n,nn);
n += nn;
}
}
sb->sb_cc += n; if (sb->sb_wptr < sb->sb_rptr) {
sb->sb_wptr += n; n = sb->sb_rptr - sb->sb_wptr;
if (sb->sb_wptr >= sb->sb_data + sb->sb_datalen) if (n > len)
sb->sb_wptr -= sb->sb_datalen; n = len;
memcpy(sb->sb_wptr, m->m_data, n);
} else {
/* Do the right edge first */
n = sb->sb_data + sb->sb_datalen - sb->sb_wptr;
if (n > len)
n = len;
memcpy(sb->sb_wptr, m->m_data, n);
len -= n;
if (len) {
/* Now the left edge */
nn = sb->sb_rptr - sb->sb_data;
if (nn > len)
nn = len;
memcpy(sb->sb_data, m->m_data + n, nn);
n += nn;
}
}
sb->sb_cc += n;
sb->sb_wptr += n;
if (sb->sb_wptr >= sb->sb_data + sb->sb_datalen)
sb->sb_wptr -= sb->sb_datalen;
} }
/* /*
@@ -173,30 +143,26 @@ sbappendsb(sb, m)
* Don't update the sbuf rptr, this will be * Don't update the sbuf rptr, this will be
* done in sbdrop when the data is acked * done in sbdrop when the data is acked
*/ */
void void sbcopy(struct sbuf *sb, size_t off, size_t len, char *to)
sbcopy(sb, off, len, to)
struct sbuf *sb;
int off;
int len;
char *to;
{ {
char *from; char *from;
from = sb->sb_rptr + off;
if (from >= sb->sb_data + sb->sb_datalen)
from -= sb->sb_datalen;
if (from < sb->sb_wptr) { g_assert(len + off <= sb->sb_cc);
if (len > sb->sb_cc) len = sb->sb_cc;
memcpy(to,from,len); from = sb->sb_rptr + off;
} else { if (from >= sb->sb_data + sb->sb_datalen)
/* re-use off */ from -= sb->sb_datalen;
off = (sb->sb_data + sb->sb_datalen) - from;
if (off > len) off = len; if (from < sb->sb_wptr) {
memcpy(to,from,off); memcpy(to, from, len);
len -= off; } else {
if (len) /* re-use off */
memcpy(to+off,sb->sb_data,len); off = (sb->sb_data + sb->sb_datalen) - from;
} if (off > len)
off = len;
memcpy(to, from, off);
len -= off;
if (len)
memcpy(to + off, sb->sb_data, len);
}
} }

View File

@@ -1,31 +1,27 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/* /*
* Copyright (c) 1995 Danny Gasparovski. * Copyright (c) 1995 Danny Gasparovski.
*
* Please read the file COPYRIGHT for the
* terms and conditions of the copyright.
*/ */
#ifndef _SBUF_H_ #ifndef SBUF_H
#define _SBUF_H_ #define SBUF_H
#define sbflush(sb) sbdrop((sb),(sb)->sb_cc)
#define sbspace(sb) ((sb)->sb_datalen - (sb)->sb_cc) #define sbspace(sb) ((sb)->sb_datalen - (sb)->sb_cc)
struct sbuf { struct sbuf {
u_int sb_cc; /* actual chars in buffer */ uint32_t sb_cc; /* actual chars in buffer */
u_int sb_datalen; /* Length of data */ uint32_t sb_datalen; /* Length of data */
char *sb_wptr; /* write pointer. points to where the next char *sb_wptr; /* write pointer. points to where the next
* bytes should be written in the sbuf */ * bytes should be written in the sbuf */
char *sb_rptr; /* read pointer. points to where the next char *sb_rptr; /* read pointer. points to where the next
* byte should be read from the sbuf */ * byte should be read from the sbuf */
char *sb_data; /* Actual data */ char *sb_data; /* Actual data */
}; };
void sbfree _P((struct sbuf *)); void sbfree(struct sbuf *sb);
void sbdrop _P((struct sbuf *, int)); bool sbdrop(struct sbuf *sb, size_t len);
void sbreserve _P((struct sbuf *, int)); void sbreserve(struct sbuf *sb, size_t size);
void sbappend _P((struct SLIRPsocket *, struct SLIRPmbuf *)); void sbappend(struct socket *sb, struct mbuf *mb);
void sbappendsb _P((struct sbuf *, struct SLIRPmbuf *)); void sbcopy(struct sbuf *sb, size_t off, size_t len, char *p);
void sbcopy _P((struct sbuf *, int, int, char *));
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,441 +1,285 @@
#ifndef __COMMON_H__ /* SPDX-License-Identifier: BSD-3-Clause */
#define __COMMON_H__ #ifndef SLIRP_H
#define SLIRP_H
#define SLIRP_VERSION "Cockatrice special"
#define CONFIG_QEMU
#ifndef CONFIG_QEMU
#include "version.h"
#endif
#include "config.h"
#include "slirp_config.h"
#ifdef _WIN32 #ifdef _WIN32
#ifdef __GNUC__ /* MINGW? */
# include <inttypes.h> /* as defined in sdkddkver.h */
typedef uint8_t u_int8_t; #ifndef _WIN32_WINNT
typedef uint16_t u_int16_t; #define _WIN32_WINNT 0x0600 /* Vista */
typedef uint32_t u_int32_t; #endif
typedef uint64_t u_int64_t; /* reduces the number of implicitly included headers */
typedef char *SLIRPcaddr_t; #ifndef WIN32_LEAN_AND_MEAN
typedef int socklen_t; #define WIN32_LEAN_AND_MEAN
typedef unsigned long ioctlsockopt_t; #endif
#include <winsock2.h>
#include <windows.h>
#include <ws2tcpip.h>
#include <sys/timeb.h>
#include <iphlpapi.h>
#else #else
typedef unsigned char u_int8_t; #if !defined(__HAIKU__)
typedef char int8_t; #define O_BINARY 0
typedef unsigned char uint8_t;
typedef unsigned short u_int16_t;
typedef unsigned short uint16_t;
typedef short int16_t;
typedef unsigned int u_int32_t;
typedef unsigned int uint32_t;
typedef int int32_t;
typedef unsigned __int64 u_int64_t;
typedef char *SLIRPcaddr_t;
typedef int socklen_t;
typedef unsigned long ioctlsockopt_t;
#endif
# include <winsock2.h> /* needs to be on top otherwise, it'll pull in winsock1 */
# include <windows.h>
# include <sys/timeb.h>
# include <iphlpapi.h>
# define USE_FIONBIO 1
#ifndef EWOULDBLOCK
# define EWOULDBLOCK WSAEWOULDBLOCK
#endif
#ifndef EINPROGRESS
# define EINPROGRESS WSAEINPROGRESS
#endif
#ifndef ENOTCONN
# define ENOTCONN WSAENOTCONN
#endif
#ifndef EHOSTUNREACH
# define EHOSTUNREACH WSAEHOSTUNREACH
#endif
#ifndef ENETUNREACH
# define ENETUNREACH WSAENETUNREACH
#endif
#ifndef ECONNREFUSED
# define ECONNREFUSED WSAECONNREFUSED
#endif
/* Basilisk II Router defines those */
# define udp_read_completion slirp_udp_read_completion
# define write_udp slirp_write_udp
# define init_udp slirp_init_udp
# define final_udp slirp_final_udp
#else
# include <inttypes.h>
# define HAVE_STDINT_H
# define HAVE_STDLIB_H
# define HAVE_STRING_H
# define HAVE_UNISTD_H
# define HAVE_INET_ATON
typedef uint8_t u_int8_t;
typedef uint16_t u_int16_t;
typedef uint32_t u_int32_t;
typedef uint64_t u_int64_t;
typedef char *SLIRPcaddr_t;
typedef int ioctlsockopt_t;
# define ioctlsocket ioctl
# define closesocket(s) close(s)
# define O_BINARY 0
#endif
#include <sys/types.h>
#ifdef HAVE_SYS_BITYPES_H
# include <sys/bitypes.h>
#endif
#ifdef HAVE_STDINT_H
# include <stdint.h>
#endif
#ifndef _MSC_VER
#include <sys/time.h>
#else
#include <time.h>
#endif
#ifdef NEED_TYPEDEFS
typedef char int8_t;
typedef unsigned char u_int8_t;
# if SIZEOF_SHORT == 2
typedef short int16_t;
typedef unsigned short u_int16_t;
# else
# if SIZEOF_INT == 2
typedef int int16_t;
typedef unsigned int u_int16_t;
# else
#error Cannot find a type with sizeof() == 2
# endif
# endif
# if SIZEOF_SHORT == 4
typedef short int32_t;
typedef unsigned short u_int32_t;
# else
# if SIZEOF_INT == 4
typedef int int32_t;
typedef unsigned int u_int32_t;
# else
#error Cannot find a type with sizeof() == 4
# endif
# endif
#endif /* NEED_TYPEDEFS */
/* Basilisk II types glue */
typedef u_int8_t uint8;
typedef u_int16_t uint16;
typedef u_int32_t uint32;
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#ifdef HAVE_STDLIB_H
# include <stdlib.h>
#endif
#include <stdio.h>
#include <errno.h>
#ifndef HAVE_MEMMOVE
#define memmove(x, y, z) bcopy(y, x, z)
#endif
#if TIME_WITH_SYS_TIME
# include <sys/time.h>
# include <time.h>
#else
# if HAVE_SYS_TIME_H
# include <sys/time.h>
# else
# include <time.h>
# endif
#endif
#ifdef HAVE_STRING_H
# include <string.h>
#else
#ifndef _MSC_VER
# include <strings.h>
#else
#include <string.h>
#endif #endif
#endif #endif
#ifndef _WIN32 #ifndef _WIN32
#include <sys/uio.h> #include <sys/uio.h>
#endif
#ifndef _P
#ifndef NO_PROTOTYPES
# define _P(x) x
#else
# define _P(x) ()
#endif
#endif
#ifndef _WIN32
#include <netinet/in.h> #include <netinet/in.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#endif
#ifdef GETTIMEOFDAY_ONE_ARG
#define gettimeofday(x, y) gettimeofday(x)
#endif
/* Systems lacking strdup() definition in <string.h>. */
#if defined(ultrix)
char *strdup _P((const char *));
#endif
/* Systems lacking malloc() definition in <stdlib.h>. */
#if defined(ultrix) || defined(hcx)
void *malloc _P((size_t arg));
void free _P((void *ptr));
#endif
#ifndef HAVE_INET_ATON
int inet_aton _P((const char *cp, struct in_addr *ia));
#endif
#include <fcntl.h>
#ifndef NO_UNIX_SOCKETS
#include <sys/un.h>
#endif
#include <signal.h>
#ifdef HAVE_SYS_SIGNAL_H
# include <sys/signal.h>
#endif
#ifndef _WIN32
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/ioctl.h>
#endif #endif
#if defined(HAVE_SYS_IOCTL_H) #ifdef __APPLE__
# include <sys/ioctl.h> #include <sys/filio.h>
#endif #endif
#ifdef HAVE_SYS_SELECT_H
# include <sys/select.h>
#endif
#ifdef HAVE_SYS_WAIT_H
# include <sys/wait.h>
#endif
#ifdef HAVE_SYS_FILIO_H
# include <sys/filio.h>
#endif
#ifdef USE_PPP
#include <ppp/slirppp.h>
#endif
#ifdef __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
#include <sys/stat.h>
/* Avoid conflicting with the libc insque() and remque(), which /* Avoid conflicting with the libc insque() and remque(), which
have different prototypes. */ have different prototypes. */
#define insque slirp_insque #define insque slirp_insque
#define remque slirp_remque #define remque slirp_remque
#define quehead slirp_quehead
#ifdef HAVE_SYS_STROPTS_H
#include <sys/stropts.h>
#endif
#include "debug.h" #include "debug.h"
#include "util.h"
#if defined __GNUC__ #include "libslirp.h"
#define PACKED__ __attribute__ ((packed))
#elif defined __sgi
#define PRAGMA_PACK_SUPPORTED 1
#define PACK_END 0
#define PACKED__
#elif _MSC_VER
#define PACKED__
#else
#error "Packed attribute or pragma shall be supported"
#endif
#if defined(_MSC_VER)
#pragma pack(push, 1)
#endif
#include "ip.h" #include "ip.h"
#include "ip6.h"
#include "tcp.h" #include "tcp.h"
#include "tcp_timer.h" #include "tcp_timer.h"
#include "tcp_var.h" #include "tcp_var.h"
#include "tcpip.h" #include "tcpip.h"
#include "udp.h" #include "udp.h"
#include "icmp_var.h" #include "ip_icmp.h"
#include "ip6_icmp.h"
#include "mbuf.h" #include "mbuf.h"
#include "sbuf.h" #include "sbuf.h"
#include "socket.h" #include "socket.h"
#include "if.h" #include "if.h"
#include "main.h" #include "main.h"
#include "misc.h" #include "misc.h"
#include "ctl.h"
#ifdef USE_PPP
#include "ppp/pppd.h"
#include "ppp/ppp.h"
#endif
#include "bootp.h" #include "bootp.h"
#include "tftp.h" #include "tftp.h"
#include "libslirp.h"
extern struct ttys *ttys_unit[MAX_INTERFACES]; #define ARPOP_REQUEST 1 /* ARP request */
#define ARPOP_REPLY 2 /* ARP reply */
#ifndef NULL struct ethhdr {
#define NULL (void *)0 unsigned char h_dest[ETH_ALEN]; /* destination eth addr */
#endif unsigned char h_source[ETH_ALEN]; /* source ether addr */
unsigned short h_proto; /* packet type ID field */
};
#ifndef FULL_BOLT struct slirp_arphdr {
void if_start _P((void)); unsigned short ar_hrd; /* format of hardware address */
#else unsigned short ar_pro; /* format of protocol address */
void if_start _P((struct ttys *)); unsigned char ar_hln; /* length of hardware address */
#endif unsigned char ar_pln; /* length of protocol address */
unsigned short ar_op; /* ARP opcode (command) */
#ifdef BAD_SPRINTF /*
# define vsprintf vsprintf_len * Ethernet looks like this : This bit is variable sized however...
# define sprintf sprintf_len */
extern int vsprintf_len _P((char *, const char *, va_list)); unsigned char ar_sha[ETH_ALEN]; /* sender hardware address */
extern int sprintf_len _P((char *, const char *, ...)); uint32_t ar_sip; /* sender IP address */
#endif unsigned char ar_tha[ETH_ALEN]; /* target hardware address */
uint32_t ar_tip; /* target IP address */
} SLIRP_PACKED;
#ifdef DECLARE_SPRINTF #define ARP_TABLE_SIZE 16
# ifndef BAD_SPRINTF
extern int vsprintf _P((char *, const char *, va_list));
# endif
extern int vfprintf _P((FILE *, const char *, va_list));
#endif
#ifndef HAVE_STRERROR typedef struct ArpTable {
#ifndef _MSC_VER struct slirp_arphdr table[ARP_TABLE_SIZE];
extern char *strerror _P((int error)); int next_victim;
#define HAVE_STRERROR } ArpTable;
#endif
#endif
#ifndef HAVE_INDEX void arp_table_add(Slirp *slirp, uint32_t ip_addr,
char *index _P((const char *, int)); const uint8_t ethaddr[ETH_ALEN]);
#endif
#ifndef HAVE_GETHOSTID bool arp_table_search(Slirp *slirp, uint32_t ip_addr,
long gethostid _P((void)); uint8_t out_ethaddr[ETH_ALEN]);
#endif
void lprint _P((const char *, ...)); struct ndpentry {
unsigned char eth_addr[ETH_ALEN]; /* sender hardware address */
struct in6_addr ip_addr; /* sender IP address */
};
extern int do_echo; #define NDP_TABLE_SIZE 16
#ifdef _MSC_VER typedef struct NdpTable {
#define __inline struct ndpentry table[NDP_TABLE_SIZE];
#endif int next_victim;
} NdpTable;
#if SIZEOF_CHAR_P == 4 void ndp_table_add(Slirp *slirp, struct in6_addr ip_addr,
# define insque_32 insque uint8_t ethaddr[ETH_ALEN]);
# define remque_32 remque bool ndp_table_search(Slirp *slirp, struct in6_addr ip_addr,
#else uint8_t out_ethaddr[ETH_ALEN]);
# ifdef NEED_QUE32_INLINE
extern __inline void insque_32 _P((void *, void *)); struct Slirp {
extern __inline void remque_32 _P((void *)); unsigned time_fasttimo;
# else unsigned last_slowtimo;
extern void insque_32 _P((void *, void *)); bool do_slowtimo;
extern void remque_32 _P((void *));
# endif bool in_enabled, in6_enabled;
#endif
/* virtual network configuration */
struct in_addr vnetwork_addr;
struct in_addr vnetwork_mask;
struct in_addr vhost_addr;
struct in6_addr vprefix_addr6;
uint8_t vprefix_len;
struct in6_addr vhost_addr6;
struct in_addr vdhcp_startaddr;
struct in_addr vnameserver_addr;
struct in6_addr vnameserver_addr6;
struct in_addr client_ipaddr;
char client_hostname[33];
int restricted;
struct gfwd_list *guestfwd_list;
int if_mtu;
int if_mru;
bool disable_host_loopback;
/* mbuf states */
struct quehead m_freelist;
struct quehead m_usedlist;
int mbuf_alloced;
/* if states */
struct quehead if_fastq; /* fast queue (for interactive data) */
struct quehead if_batchq; /* queue for non-interactive data */
bool if_start_busy; /* avoid if_start recursion */
/* ip states */
struct ipq ipq; /* ip reass. queue */
uint16_t ip_id; /* ip packet ctr, for ids */
/* bootp/dhcp states */
BOOTPClient bootp_clients[NB_BOOTP_CLIENTS];
char *bootp_filename;
size_t vdnssearch_len;
uint8_t *vdnssearch;
char *vdomainname;
/* tcp states */
struct socket tcb;
struct socket *tcp_last_so;
tcp_seq tcp_iss; /* tcp initial send seq # */
uint32_t tcp_now; /* for RFC 1323 timestamps */
/* udp states */
struct socket udb;
struct socket *udp_last_so;
/* icmp states */
struct socket icmp;
struct socket *icmp_last_so;
/* tftp states */
char *tftp_prefix;
struct tftp_session tftp_sessions[TFTP_SESSIONS_MAX];
char *tftp_server_name;
ArpTable arp_table;
NdpTable ndp_table;
GRand *grand;
void *ra_timer;
bool enable_emu;
const SlirpCb *cb;
void *opaque;
struct sockaddr_in *outbound_addr;
struct sockaddr_in6 *outbound_addr6;
bool disable_dns; /* slirp will not redirect/serve any DNS packet */
};
void if_start(Slirp *);
int get_dns_addr(struct in_addr *pdns_addr);
int get_dns6_addr(struct in6_addr *pdns6_addr, uint32_t *scope_id);
/* ncsi.c */
void ncsi_input(Slirp *slirp, const uint8_t *pkt, int pkt_len);
#ifndef _WIN32 #ifndef _WIN32
#include <netdb.h> #include <netdb.h>
#endif #endif
#define DEFAULT_BAUD 115200
extern bool slirp_do_keepalive;
#define TCP_MAXIDLE (TCPTV_KEEPCNT * TCPTV_KEEPINTVL)
/* dnssearch.c */
int translate_dnssearch(Slirp *s, const char **names);
/* cksum.c */ /* cksum.c */
int cksum(struct SLIRPmbuf *m, int len); int cksum(struct mbuf *m, int len);
int ip6_cksum(struct mbuf *m);
/* if.c */ /* if.c */
void if_init _P((void)); void if_init(Slirp *);
void if_output _P((struct SLIRPsocket *, struct SLIRPmbuf *)); void if_output(struct socket *, struct mbuf *);
/* ip_input.c */ /* ip_input.c */
void ip_init _P((void)); void ip_init(Slirp *);
void ip_input _P((struct SLIRPmbuf *)); void ip_cleanup(Slirp *);
struct ip * ip_reass _P((register struct ipasfrag *, register struct ipq *)); void ip_input(struct mbuf *);
void ip_freef _P((struct ipq *)); void ip_slowtimo(Slirp *);
void ip_enq _P((register struct ipasfrag *, register struct ipasfrag *)); void ip_stripoptions(register struct mbuf *, struct mbuf *);
void ip_deq _P((register struct ipasfrag *));
void ip_slowtimo _P((void));
void ip_stripoptions _P((register struct SLIRPmbuf *, struct SLIRPmbuf *));
/* ip_output.c */ /* ip_output.c */
int ip_output _P((struct SLIRPsocket *, struct SLIRPmbuf *)); int ip_output(struct socket *, struct mbuf *);
/* ip6_input.c */
void ip6_init(Slirp *);
void ip6_cleanup(Slirp *);
void ip6_input(struct mbuf *);
/* ip6_output */
int ip6_output(struct socket *, struct mbuf *, int fast);
/* tcp_input.c */ /* tcp_input.c */
int tcp_reass _P((register struct tcpcb *, register struct tcpiphdr *, struct SLIRPmbuf *)); void tcp_input(register struct mbuf *, int, struct socket *, unsigned short af);
void tcp_input _P((register struct SLIRPmbuf *, int, struct SLIRPsocket *)); int tcp_mss(register struct tcpcb *, unsigned);
void tcp_dooptions _P((struct tcpcb *, u_char *, int, struct tcpiphdr *));
void tcp_xmit_timer _P((register struct tcpcb *, int));
int tcp_mss _P((register struct tcpcb *, u_int));
/* tcp_output.c */ /* tcp_output.c */
int tcp_output _P((register struct tcpcb *)); int tcp_output(register struct tcpcb *);
void tcp_setpersist _P((register struct tcpcb *)); void tcp_setpersist(register struct tcpcb *);
/* tcp_subr.c */ /* tcp_subr.c */
void tcp_init _P((void)); void tcp_init(Slirp *);
void tcp_template _P((struct tcpcb *)); void tcp_cleanup(Slirp *);
void tcp_respond _P((struct tcpcb *, register struct tcpiphdr *, register struct SLIRPmbuf *, tcp_seq, tcp_seq, int)); void tcp_template(struct tcpcb *);
struct tcpcb * tcp_newtcpcb _P((struct SLIRPsocket *)); void tcp_respond(struct tcpcb *, register struct tcpiphdr *,
struct tcpcb * tcp_close _P((register struct tcpcb *)); register struct mbuf *, tcp_seq, tcp_seq, int, unsigned short);
void tcp_drain _P((void)); struct tcpcb *tcp_newtcpcb(struct socket *);
void tcp_sockclosed _P((struct tcpcb *)); struct tcpcb *tcp_close(register struct tcpcb *);
int tcp_fconnect _P((struct SLIRPsocket *)); void tcp_sockclosed(struct tcpcb *);
void tcp_connect _P((struct SLIRPsocket *)); int tcp_fconnect(struct socket *, unsigned short af);
int tcp_attach _P((struct SLIRPsocket *)); void tcp_connect(struct socket *);
u_int8_t tcp_tos _P((struct SLIRPsocket *)); void tcp_attach(struct socket *);
int tcp_emu _P((struct SLIRPsocket *, struct SLIRPmbuf *)); uint8_t tcp_tos(struct socket *);
int tcp_ctl _P((struct SLIRPsocket *)); int tcp_emu(struct socket *, struct mbuf *);
int tcp_ctl(struct socket *);
struct tcpcb *tcp_drop(struct tcpcb *tp, int err); struct tcpcb *tcp_drop(struct tcpcb *tp, int err);
struct socket *slirp_find_ctl_socket(Slirp *slirp, struct in_addr guest_addr,
int guest_port);
#if defined(_MSC_VER) void slirp_send_packet_all(Slirp *slirp, const void *buf, size_t len);
#pragma pack(pop)
#endif
#ifdef USE_PPP
#define MIN_MRU MINMRU
#define MAX_MRU MAXMRU
#else
#define MIN_MRU 128
#define MAX_MRU 16384
#endif
#ifndef _WIN32
#define min(x,y) ((x) < (y) ? (x) : (y))
#define max(x,y) ((x) > (y) ? (x) : (y))
#endif
#ifdef _WIN32
#undef errno
#define errno (WSAGetLastError())
#endif
#define PROBE_CONN
#endif #endif

View File

@@ -1,135 +0,0 @@
/*
* User definable configuration options
*/
/* Undefine if you don't want talk emulation */
#undef EMULATE_TALK
/* Define if you want the connection to be probed */
/* XXX Not working yet, so ignore this for now */
#undef PROBE_CONN
/* Define to 1 if you want KEEPALIVE timers */
#define DO_KEEPALIVE 0
/* Define to MAX interfaces you expect to use at once */
/* MAX_INTERFACES determines the max. TOTAL number of interfaces (SLIP and PPP) */
/* MAX_PPP_INTERFACES determines max. number of PPP interfaces */
#define MAX_INTERFACES 1
#define MAX_PPP_INTERFACES 1
/* Define if you want slirp's socket in /tmp */
/* XXXXXX Do this in ./configure */
#undef USE_TMPSOCKET
/* Define if you want slirp to use cfsetXspeed() on the terminal */
#undef DO_CFSETSPEED
/* Define this if you want slirp to write to the tty as fast as it can */
/* This should only be set if you are using load-balancing, slirp does a */
/* pretty good job on single modems already, and seting this will make */
/* interactive sessions less responsive */
/* XXXXX Talk about having fast modem as unit 0 */
#undef FULL_BOLT
/*
* Define if you want slirp to use less CPU
* You will notice a small lag in interactive sessions, but it's not that bad
* Things like Netscape/ftp/etc. are completely unaffected
* This is mainly for sysadmins who have many slirp users
*/
#undef USE_LOWCPU
/* Define this if your compiler doesn't like prototypes */
#ifndef __STDC__
#define NO_PROTOTYPES
#endif
/*********************************************************/
/*
* Autoconf defined configuration options
* You shouldn't need to touch any of these
*/
/* Ignore this */
#undef DUMMY_PPP
/* XXX: Define according to how time.h should be included */
#undef TIME_WITH_SYS_TIME
#define TIME_WITH_SYS_TIME 0
#undef HAVE_SYS_TIME_H
/* Define if your sprintf returns char * instead of int */
#undef BAD_SPRINTF
/* Define if you have readv */
#undef HAVE_READV
/* Define if iovec needs to be declared */
#undef DECLARE_IOVEC
#ifdef _WIN32
#define DECLARE_IOVEC
#endif
/* Define if a declaration of sprintf/fprintf is needed */
#undef DECLARE_SPRINTF
/* Define if you have sys/stropts.h */
#undef HAVE_SYS_STROPTS_H
/* Define if your compiler doesn't like prototypes */
#undef NO_PROTOTYPES
/* Define if you don't have u_int32_t etc. typedef'd */
#undef NEED_TYPEDEFS
#ifdef __sun__
#define NEED_TYPEDEFS
#endif
/* Define to sizeof(char *) */
#define SIZEOF_CHAR_P SIZEOF_VOID_P
/* Define if you have random() */
#undef HAVE_RANDOM
/* Define if you have srandom() */
#undef HAVE_SRANDOM
/* Define if you have setenv */
#undef HAVE_SETENV
/* Define if you have index() */
#undef HAVE_INDEX
/* Define if you have bcmp() */
#undef HAVE_BCMP
/* Define if you have drand48 */
#undef HAVE_DRAND48
/* Define if you have memmove */
#define HAVE_MEMMOVE
/* Define if you have gethostid */
#undef HAVE_GETHOSTID
/* Define if you DON'T have unix-domain sockets */
#undef NO_UNIX_SOCKETS
#ifdef _WIN32
#define NO_UNIX_SOCKETS
#endif
/* Define if gettimeofday only takes one argument */
#undef GETTIMEOFDAY_ONE_ARG
/* Define if you have revoke() */
#undef HAVE_REVOKE
/* Define if you have the sysv method of opening pty's (/dev/ptmx, etc.) */
#undef HAVE_GRANTPT
/* Define if you have fchmod */
#undef HAVE_FCHMOD
/* Define if you have <sys/type32.h> */
#undef HAVE_SYS_TYPES32_H

File diff suppressed because it is too large Load Diff

View File

@@ -1,14 +1,12 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/* /*
* Copyright (c) 1995 Danny Gasparovski. * Copyright (c) 1995 Danny Gasparovski.
*
* Please read the file COPYRIGHT for the
* terms and conditions of the copyright.
*/ */
/* MINE */ #ifndef SLIRP_SOCKET_H
#define SLIRP_SOCKET_H
#ifndef _SLIRP_SOCKET_H_ #include "misc.h"
#define _SLIRP_SOCKET_H_
#define SO_EXPIRE 240000 #define SO_EXPIRE 240000
#define SO_EXPIREFAST 10000 #define SO_EXPIREFAST 10000
@@ -17,40 +15,59 @@
* Our socket structure * Our socket structure
*/ */
struct SLIRPsocket { union slirp_sockaddr {
struct SLIRPsocket *so_next,*so_prev; /* For a linked list of sockets */ struct sockaddr_storage ss;
struct sockaddr_in sin;
struct sockaddr_in6 sin6;
};
int s; /* The actual socket */ struct socket {
struct socket *so_next, *so_prev; /* For a linked list of sockets */
/* XXX union these with not-yet-used sbuf params */ int s; /* The actual socket */
struct SLIRPmbuf *so_m; /* Pointer to the original SYN packet, struct gfwd_list *guestfwd;
* for non-blocking connect()'s, and
* PING reply's */ int pollfds_idx; /* GPollFD GArray index */
struct tcpiphdr *so_ti; /* Pointer to the original ti within
* so_mconn, for non-blocking connections */ Slirp *slirp; /* managing slirp instance */
int so_urgc;
struct in_addr so_faddr; /* foreign host table entry */ /* XXX union these with not-yet-used sbuf params */
struct in_addr so_laddr; /* local host table entry */ struct mbuf *so_m; /* Pointer to the original SYN packet,
u_int16_t so_fport; /* foreign port */ * for non-blocking connect()'s, and
u_int16_t so_lport; /* local port */ * PING reply's */
struct tcpiphdr *so_ti; /* Pointer to the original ti within
u_int8_t so_iptos; /* Type of service */ * so_mconn, for non-blocking connections */
u_int8_t so_emu; /* Is the socket emulated? */ uint32_t so_urgc;
union slirp_sockaddr fhost; /* Foreign host */
u_char so_type; /* Type of socket, UDP or TCP */ #define so_faddr fhost.sin.sin_addr
int so_state; /* internal state flags SS_*, below */ #define so_fport fhost.sin.sin_port
#define so_faddr6 fhost.sin6.sin6_addr
struct tcpcb *so_tcpcb; /* pointer to TCP protocol control block */ #define so_fport6 fhost.sin6.sin6_port
u_int so_expire; /* When the socket will expire */ #define so_ffamily fhost.ss.ss_family
int so_queued; /* Number of packets queued from this socket */ union slirp_sockaddr lhost; /* Local host */
int so_nqueued; /* Number of packets queued in a row #define so_laddr lhost.sin.sin_addr
* Used to determine when to "downgrade" a session #define so_lport lhost.sin.sin_port
* from fastq to batchq */ #define so_laddr6 lhost.sin6.sin6_addr
#define so_lport6 lhost.sin6.sin6_port
struct sbuf so_rcv; /* Receive buffer */ #define so_lfamily lhost.ss.ss_family
struct sbuf so_snd; /* Send buffer */
void * extra; /* Extra pointer */ uint8_t so_iptos; /* Type of service */
uint8_t so_emu; /* Is the socket emulated? */
uint8_t so_type; /* Type of socket, UDP or TCP */
int32_t so_state; /* internal state flags SS_*, below */
struct tcpcb *so_tcpcb; /* pointer to TCP protocol control block */
unsigned so_expire; /* When the socket will expire */
int so_queued; /* Number of packets queued from this socket */
int so_nqueued; /* Number of packets queued in a row
* Used to determine when to "downgrade" a session
* from fastq to batchq */
struct sbuf so_rcv; /* Receive buffer */
struct sbuf so_snd; /* Send buffer */
}; };
@@ -58,47 +75,90 @@ struct SLIRPsocket {
* Socket state bits. (peer means the host on the Internet, * Socket state bits. (peer means the host on the Internet,
* local host means the host on the other end of the modem) * local host means the host on the other end of the modem)
*/ */
#define SS_NOFDREF 0x001 /* No fd reference */ #define SS_NOFDREF 0x001 /* No fd reference */
#define SS_ISFCONNECTING 0x002 /* Socket is connecting to peer (non-blocking connect()'s) */ #define SS_ISFCONNECTING \
#define SS_ISFCONNECTED 0x004 /* Socket is connected to peer */ 0x002 /* Socket is connecting to peer (non-blocking connect()'s) */
#define SS_FCANTRCVMORE 0x008 /* Socket can't receive more from peer (for half-closes) */ #define SS_ISFCONNECTED 0x004 /* Socket is connected to peer */
#define SS_FCANTSENDMORE 0x010 /* Socket can't send more to peer (for half-closes) */ #define SS_FCANTRCVMORE \
/* #define SS_ISFDISCONNECTED 0x020*/ /* Socket has disconnected from peer, in 2MSL state */ 0x008 /* Socket can't receive more from peer (for half-closes) */
#define SS_FWDRAIN 0x040 /* We received a FIN, drain data and set SS_FCANTSENDMORE */ #define SS_FCANTSENDMORE \
0x010 /* Socket can't send more to peer (for half-closes) */
#define SS_FWDRAIN \
0x040 /* We received a FIN, drain data and set SS_FCANTSENDMORE */
#define SS_CTL 0x080 #define SS_CTL 0x080
#define SS_FACCEPTCONN 0x100 /* Socket is accepting connections from a host on the internet */ #define SS_FACCEPTCONN \
#define SS_FACCEPTONCE 0x200 /* If set, the SS_FACCEPTCONN socket will die after one accept */ 0x100 /* Socket is accepting connections from a host on the internet */
#define SS_FACCEPTONCE \
0x200 /* If set, the SS_FACCEPTCONN socket will die after one accept */
extern struct SLIRPsocket tcb; #define SS_PERSISTENT_MASK 0xf000 /* Unremovable state bits */
#define SS_HOSTFWD 0x1000 /* Socket describes host->guest forwarding */
#define SS_INCOMING \
0x2000 /* Connection was initiated by a host on the internet */
static inline int sockaddr_equal(struct sockaddr_storage *a,
struct sockaddr_storage *b)
{
if (a->ss_family != b->ss_family) {
return 0;
}
switch (a->ss_family) {
case AF_INET: {
struct sockaddr_in *a4 = (struct sockaddr_in *)a;
struct sockaddr_in *b4 = (struct sockaddr_in *)b;
return a4->sin_addr.s_addr == b4->sin_addr.s_addr &&
a4->sin_port == b4->sin_port;
}
case AF_INET6: {
struct sockaddr_in6 *a6 = (struct sockaddr_in6 *)a;
struct sockaddr_in6 *b6 = (struct sockaddr_in6 *)b;
return (in6_equal(&a6->sin6_addr, &b6->sin6_addr) &&
a6->sin6_port == b6->sin6_port);
}
default:
g_assert_not_reached();
}
return 0;
}
static inline socklen_t sockaddr_size(struct sockaddr_storage *a)
{
switch (a->ss_family) {
case AF_INET:
return sizeof(struct sockaddr_in);
case AF_INET6:
return sizeof(struct sockaddr_in6);
default:
g_assert_not_reached();
}
}
struct socket *solookup(struct socket **, struct socket *,
struct sockaddr_storage *, struct sockaddr_storage *);
struct socket *socreate(Slirp *);
void sofree(struct socket *);
int soread(struct socket *);
int sorecvoob(struct socket *);
int sosendoob(struct socket *);
int sowrite(struct socket *);
void sorecvfrom(struct socket *);
int sosendto(struct socket *, struct mbuf *);
struct socket *tcp_listen(Slirp *, uint32_t, unsigned, uint32_t, unsigned, int);
void soisfconnecting(register struct socket *);
void soisfconnected(register struct socket *);
void sofwdrain(struct socket *);
struct iovec; /* For win32 */
size_t sopreprbuf(struct socket *so, struct iovec *iov, int *np);
int soreadbuf(struct socket *so, const char *buf, int size);
int sotranslate_out(struct socket *, struct sockaddr_storage *);
void sotranslate_in(struct socket *, struct sockaddr_storage *);
void sotranslate_accept(struct socket *);
void sodrop(struct socket *, int num);
#if defined(DECLARE_IOVEC) && !defined(HAVE_READV) #endif /* SLIRP_SOCKET_H */
struct iovec {
char *iov_base;
size_t iov_len;
};
#endif
void so_init _P((void));
struct SLIRPsocket * solookup _P((struct SLIRPsocket *, struct in_addr, u_int, struct in_addr, u_int));
struct SLIRPsocket * socreate _P((void));
void sofree _P((struct SLIRPsocket *));
int soread _P((struct SLIRPsocket *));
void sorecvoob _P((struct SLIRPsocket *));
int sosendoob _P((struct SLIRPsocket *));
int sowrite _P((struct SLIRPsocket *));
void sorecvfrom _P((struct SLIRPsocket *));
int sosendto _P((struct SLIRPsocket *, struct SLIRPmbuf *));
struct SLIRPsocket * solisten _P((u_int, u_int32_t, u_int, int));
void sorwakeup _P((struct SLIRPsocket *));
void sowwakeup _P((struct SLIRPsocket *));
void soisfconnecting _P((register struct SLIRPsocket *));
void soisfconnected _P((register struct SLIRPsocket *));
void sofcantrcvmore _P((struct SLIRPsocket *));
void sofcantsendmore _P((struct SLIRPsocket *));
void soisfdisconnected _P((struct SLIRPsocket *));
void sofwdrain _P((struct SLIRPsocket *));
#endif /* _SOCKET_H_ */

379
src/network/slirp/state.c Normal file
View File

@@ -0,0 +1,379 @@
/* SPDX-License-Identifier: MIT */
/*
* libslirp
*
* Copyright (c) 2004-2008 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "slirp.h"
#include "vmstate.h"
#include "stream.h"
static int slirp_tcp_post_load(void *opaque, int version)
{
tcp_template((struct tcpcb *)opaque);
return 0;
}
static const VMStateDescription vmstate_slirp_tcp = {
.name = "slirp-tcp",
.version_id = 0,
.post_load = slirp_tcp_post_load,
.fields = (VMStateField[]){ VMSTATE_INT16(t_state, struct tcpcb),
VMSTATE_INT16_ARRAY(t_timer, struct tcpcb,
TCPT_NTIMERS),
VMSTATE_INT16(t_rxtshift, struct tcpcb),
VMSTATE_INT16(t_rxtcur, struct tcpcb),
VMSTATE_INT16(t_dupacks, struct tcpcb),
VMSTATE_UINT16(t_maxseg, struct tcpcb),
VMSTATE_UINT8(t_force, struct tcpcb),
VMSTATE_UINT16(t_flags, struct tcpcb),
VMSTATE_UINT32(snd_una, struct tcpcb),
VMSTATE_UINT32(snd_nxt, struct tcpcb),
VMSTATE_UINT32(snd_up, struct tcpcb),
VMSTATE_UINT32(snd_wl1, struct tcpcb),
VMSTATE_UINT32(snd_wl2, struct tcpcb),
VMSTATE_UINT32(iss, struct tcpcb),
VMSTATE_UINT32(snd_wnd, struct tcpcb),
VMSTATE_UINT32(rcv_wnd, struct tcpcb),
VMSTATE_UINT32(rcv_nxt, struct tcpcb),
VMSTATE_UINT32(rcv_up, struct tcpcb),
VMSTATE_UINT32(irs, struct tcpcb),
VMSTATE_UINT32(rcv_adv, struct tcpcb),
VMSTATE_UINT32(snd_max, struct tcpcb),
VMSTATE_UINT32(snd_cwnd, struct tcpcb),
VMSTATE_UINT32(snd_ssthresh, struct tcpcb),
VMSTATE_INT16(t_idle, struct tcpcb),
VMSTATE_INT16(t_rtt, struct tcpcb),
VMSTATE_UINT32(t_rtseq, struct tcpcb),
VMSTATE_INT16(t_srtt, struct tcpcb),
VMSTATE_INT16(t_rttvar, struct tcpcb),
VMSTATE_UINT16(t_rttmin, struct tcpcb),
VMSTATE_UINT32(max_sndwnd, struct tcpcb),
VMSTATE_UINT8(t_oobflags, struct tcpcb),
VMSTATE_UINT8(t_iobc, struct tcpcb),
VMSTATE_INT16(t_softerror, struct tcpcb),
VMSTATE_UINT8(snd_scale, struct tcpcb),
VMSTATE_UINT8(rcv_scale, struct tcpcb),
VMSTATE_UINT8(request_r_scale, struct tcpcb),
VMSTATE_UINT8(requested_s_scale, struct tcpcb),
VMSTATE_UINT32(ts_recent, struct tcpcb),
VMSTATE_UINT32(ts_recent_age, struct tcpcb),
VMSTATE_UINT32(last_ack_sent, struct tcpcb),
VMSTATE_END_OF_LIST() }
};
/* The sbuf has a pair of pointers that are migrated as offsets;
* we calculate the offsets and restore the pointers using
* pre_save/post_load on a tmp structure.
*/
struct sbuf_tmp {
struct sbuf *parent;
uint32_t roff, woff;
};
static int sbuf_tmp_pre_save(void *opaque)
{
struct sbuf_tmp *tmp = opaque;
tmp->woff = tmp->parent->sb_wptr - tmp->parent->sb_data;
tmp->roff = tmp->parent->sb_rptr - tmp->parent->sb_data;
return 0;
}
static int sbuf_tmp_post_load(void *opaque, int version)
{
struct sbuf_tmp *tmp = opaque;
uint32_t requested_len = tmp->parent->sb_datalen;
/* Allocate the buffer space used by the field after the tmp */
sbreserve(tmp->parent, tmp->parent->sb_datalen);
if (tmp->woff >= requested_len || tmp->roff >= requested_len) {
g_critical("invalid sbuf offsets r/w=%u/%u len=%u", tmp->roff,
tmp->woff, requested_len);
return -EINVAL;
}
tmp->parent->sb_wptr = tmp->parent->sb_data + tmp->woff;
tmp->parent->sb_rptr = tmp->parent->sb_data + tmp->roff;
return 0;
}
static const VMStateDescription vmstate_slirp_sbuf_tmp = {
.name = "slirp-sbuf-tmp",
.post_load = sbuf_tmp_post_load,
.pre_save = sbuf_tmp_pre_save,
.version_id = 0,
.fields = (VMStateField[]){ VMSTATE_UINT32(woff, struct sbuf_tmp),
VMSTATE_UINT32(roff, struct sbuf_tmp),
VMSTATE_END_OF_LIST() }
};
static const VMStateDescription vmstate_slirp_sbuf = {
.name = "slirp-sbuf",
.version_id = 0,
.fields = (VMStateField[]){ VMSTATE_UINT32(sb_cc, struct sbuf),
VMSTATE_UINT32(sb_datalen, struct sbuf),
VMSTATE_WITH_TMP(struct sbuf, struct sbuf_tmp,
vmstate_slirp_sbuf_tmp),
VMSTATE_VBUFFER_UINT32(sb_data, struct sbuf, 0,
NULL, sb_datalen),
VMSTATE_END_OF_LIST() }
};
static bool slirp_older_than_v4(void *opaque, int version_id)
{
return version_id < 4;
}
static bool slirp_family_inet(void *opaque, int version_id)
{
union slirp_sockaddr *ssa = (union slirp_sockaddr *)opaque;
return ssa->ss.ss_family == AF_INET;
}
static int slirp_socket_pre_load(void *opaque)
{
struct socket *so = opaque;
tcp_attach(so);
/* Older versions don't load these fields */
so->so_ffamily = AF_INET;
so->so_lfamily = AF_INET;
return 0;
}
#ifndef _WIN32
#define VMSTATE_SIN4_ADDR(f, s, t) VMSTATE_UINT32_TEST(f, s, t)
#else
/* Win uses u_long rather than uint32_t - but it's still 32bits long */
#define VMSTATE_SIN4_ADDR(f, s, t) \
VMSTATE_SINGLE_TEST(f, s, t, 0, slirp_vmstate_info_uint32, u_long)
#endif
/* The OS provided ss_family field isn't that portable; it's size
* and type varies (16/8 bit, signed, unsigned)
* and the values it contains aren't fully portable.
*/
typedef struct SS_FamilyTmpStruct {
union slirp_sockaddr *parent;
uint16_t portable_family;
} SS_FamilyTmpStruct;
#define SS_FAMILY_MIG_IPV4 2 /* Linux, BSD, Win... */
#define SS_FAMILY_MIG_IPV6 10 /* Linux */
#define SS_FAMILY_MIG_OTHER 0xffff
static int ss_family_pre_save(void *opaque)
{
SS_FamilyTmpStruct *tss = opaque;
tss->portable_family = SS_FAMILY_MIG_OTHER;
if (tss->parent->ss.ss_family == AF_INET) {
tss->portable_family = SS_FAMILY_MIG_IPV4;
} else if (tss->parent->ss.ss_family == AF_INET6) {
tss->portable_family = SS_FAMILY_MIG_IPV6;
}
return 0;
}
static int ss_family_post_load(void *opaque, int version_id)
{
SS_FamilyTmpStruct *tss = opaque;
switch (tss->portable_family) {
case SS_FAMILY_MIG_IPV4:
tss->parent->ss.ss_family = AF_INET;
break;
case SS_FAMILY_MIG_IPV6:
case 23: /* compatibility: AF_INET6 from mingw */
case 28: /* compatibility: AF_INET6 from FreeBSD sys/socket.h */
tss->parent->ss.ss_family = AF_INET6;
break;
default:
g_critical("invalid ss_family type %x", tss->portable_family);
return -EINVAL;
}
return 0;
}
static const VMStateDescription vmstate_slirp_ss_family = {
.name = "slirp-socket-addr/ss_family",
.pre_save = ss_family_pre_save,
.post_load = ss_family_post_load,
.fields =
(VMStateField[]){ VMSTATE_UINT16(portable_family, SS_FamilyTmpStruct),
VMSTATE_END_OF_LIST() }
};
static const VMStateDescription vmstate_slirp_socket_addr = {
.name = "slirp-socket-addr",
.version_id = 4,
.fields =
(VMStateField[]){
VMSTATE_WITH_TMP(union slirp_sockaddr, SS_FamilyTmpStruct,
vmstate_slirp_ss_family),
VMSTATE_SIN4_ADDR(sin.sin_addr.s_addr, union slirp_sockaddr,
slirp_family_inet),
VMSTATE_UINT16_TEST(sin.sin_port, union slirp_sockaddr,
slirp_family_inet),
#if 0
/* Untested: Needs checking by someone with IPv6 test */
VMSTATE_BUFFER_TEST(sin6.sin6_addr, union slirp_sockaddr,
slirp_family_inet6),
VMSTATE_UINT16_TEST(sin6.sin6_port, union slirp_sockaddr,
slirp_family_inet6),
VMSTATE_UINT32_TEST(sin6.sin6_flowinfo, union slirp_sockaddr,
slirp_family_inet6),
VMSTATE_UINT32_TEST(sin6.sin6_scope_id, union slirp_sockaddr,
slirp_family_inet6),
#endif
VMSTATE_END_OF_LIST() }
};
static const VMStateDescription vmstate_slirp_socket = {
.name = "slirp-socket",
.version_id = 4,
.pre_load = slirp_socket_pre_load,
.fields =
(VMStateField[]){
VMSTATE_UINT32(so_urgc, struct socket),
/* Pre-v4 versions */
VMSTATE_SIN4_ADDR(so_faddr.s_addr, struct socket,
slirp_older_than_v4),
VMSTATE_SIN4_ADDR(so_laddr.s_addr, struct socket,
slirp_older_than_v4),
VMSTATE_UINT16_TEST(so_fport, struct socket, slirp_older_than_v4),
VMSTATE_UINT16_TEST(so_lport, struct socket, slirp_older_than_v4),
/* v4 and newer */
VMSTATE_STRUCT(fhost, struct socket, 4, vmstate_slirp_socket_addr,
union slirp_sockaddr),
VMSTATE_STRUCT(lhost, struct socket, 4, vmstate_slirp_socket_addr,
union slirp_sockaddr),
VMSTATE_UINT8(so_iptos, struct socket),
VMSTATE_UINT8(so_emu, struct socket),
VMSTATE_UINT8(so_type, struct socket),
VMSTATE_INT32(so_state, struct socket),
VMSTATE_STRUCT(so_rcv, struct socket, 0, vmstate_slirp_sbuf,
struct sbuf),
VMSTATE_STRUCT(so_snd, struct socket, 0, vmstate_slirp_sbuf,
struct sbuf),
VMSTATE_STRUCT_POINTER(so_tcpcb, struct socket, vmstate_slirp_tcp,
struct tcpcb),
VMSTATE_END_OF_LIST() }
};
static const VMStateDescription vmstate_slirp_bootp_client = {
.name = "slirp_bootpclient",
.fields = (VMStateField[]){ VMSTATE_UINT16(allocated, BOOTPClient),
VMSTATE_BUFFER(macaddr, BOOTPClient),
VMSTATE_END_OF_LIST() }
};
static const VMStateDescription vmstate_slirp = {
.name = "slirp",
.version_id = 4,
.fields = (VMStateField[]){ VMSTATE_UINT16_V(ip_id, Slirp, 2),
VMSTATE_STRUCT_ARRAY(
bootp_clients, Slirp, NB_BOOTP_CLIENTS, 3,
vmstate_slirp_bootp_client, BOOTPClient),
VMSTATE_END_OF_LIST() }
};
void slirp_state_save(Slirp *slirp, SlirpWriteCb write_cb, void *opaque)
{
struct gfwd_list *ex_ptr;
SlirpOStream f = {
.write_cb = write_cb,
.opaque = opaque,
};
for (ex_ptr = slirp->guestfwd_list; ex_ptr; ex_ptr = ex_ptr->ex_next)
if (ex_ptr->write_cb) {
struct socket *so;
so = slirp_find_ctl_socket(slirp, ex_ptr->ex_addr,
ntohs(ex_ptr->ex_fport));
if (!so) {
continue;
}
slirp_ostream_write_u8(&f, 42);
slirp_vmstate_save_state(&f, &vmstate_slirp_socket, so);
}
slirp_ostream_write_u8(&f, 0);
slirp_vmstate_save_state(&f, &vmstate_slirp, slirp);
}
int slirp_state_load(Slirp *slirp, int version_id, SlirpReadCb read_cb,
void *opaque)
{
struct gfwd_list *ex_ptr;
SlirpIStream f = {
.read_cb = read_cb,
.opaque = opaque,
};
while (slirp_istream_read_u8(&f)) {
int ret;
struct socket *so = socreate(slirp);
ret =
slirp_vmstate_load_state(&f, &vmstate_slirp_socket, so, version_id);
if (ret < 0) {
return ret;
}
if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) !=
slirp->vnetwork_addr.s_addr) {
return -EINVAL;
}
for (ex_ptr = slirp->guestfwd_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
if (ex_ptr->write_cb &&
so->so_faddr.s_addr == ex_ptr->ex_addr.s_addr &&
so->so_fport == ex_ptr->ex_fport) {
break;
}
}
if (!ex_ptr) {
return -EINVAL;
}
so->guestfwd = ex_ptr;
}
return slirp_vmstate_load_state(&f, &vmstate_slirp, slirp, version_id);
}
int slirp_state_version(void)
{
return 4;
}

120
src/network/slirp/stream.c Normal file
View File

@@ -0,0 +1,120 @@
/* SPDX-License-Identifier: MIT */
/*
* libslirp io streams
*
* Copyright (c) 2018 Red Hat, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "stream.h"
#include <tinyglib.h>
bool slirp_istream_read(SlirpIStream *f, void *buf, size_t size)
{
return f->read_cb(buf, size, f->opaque) == size;
}
bool slirp_ostream_write(SlirpOStream *f, const void *buf, size_t size)
{
return f->write_cb(buf, size, f->opaque) == size;
}
uint8_t slirp_istream_read_u8(SlirpIStream *f)
{
uint8_t b;
if (slirp_istream_read(f, &b, sizeof(b))) {
return b;
}
return 0;
}
bool slirp_ostream_write_u8(SlirpOStream *f, uint8_t b)
{
return slirp_ostream_write(f, &b, sizeof(b));
}
uint16_t slirp_istream_read_u16(SlirpIStream *f)
{
uint16_t b;
if (slirp_istream_read(f, &b, sizeof(b))) {
return GUINT16_FROM_BE(b);
}
return 0;
}
bool slirp_ostream_write_u16(SlirpOStream *f, uint16_t b)
{
b = GUINT16_TO_BE(b);
return slirp_ostream_write(f, &b, sizeof(b));
}
uint32_t slirp_istream_read_u32(SlirpIStream *f)
{
uint32_t b;
if (slirp_istream_read(f, &b, sizeof(b))) {
return GUINT32_FROM_BE(b);
}
return 0;
}
bool slirp_ostream_write_u32(SlirpOStream *f, uint32_t b)
{
b = GUINT32_TO_BE(b);
return slirp_ostream_write(f, &b, sizeof(b));
}
int16_t slirp_istream_read_i16(SlirpIStream *f)
{
int16_t b;
if (slirp_istream_read(f, &b, sizeof(b))) {
return GINT16_FROM_BE(b);
}
return 0;
}
bool slirp_ostream_write_i16(SlirpOStream *f, int16_t b)
{
b = GINT16_TO_BE(b);
return slirp_ostream_write(f, &b, sizeof(b));
}
int32_t slirp_istream_read_i32(SlirpIStream *f)
{
int32_t b;
if (slirp_istream_read(f, &b, sizeof(b))) {
return GINT32_FROM_BE(b);
}
return 0;
}
bool slirp_ostream_write_i32(SlirpOStream *f, int32_t b)
{
b = GINT32_TO_BE(b);
return slirp_ostream_write(f, &b, sizeof(b));
}

View File

@@ -0,0 +1,35 @@
/* SPDX-License-Identifier: BSD-3-Clause */
#ifndef STREAM_H_
#define STREAM_H_
#include "libslirp.h"
typedef struct SlirpIStream {
SlirpReadCb read_cb;
void *opaque;
} SlirpIStream;
typedef struct SlirpOStream {
SlirpWriteCb write_cb;
void *opaque;
} SlirpOStream;
bool slirp_istream_read(SlirpIStream *f, void *buf, size_t size);
bool slirp_ostream_write(SlirpOStream *f, const void *buf, size_t size);
uint8_t slirp_istream_read_u8(SlirpIStream *f);
bool slirp_ostream_write_u8(SlirpOStream *f, uint8_t b);
uint16_t slirp_istream_read_u16(SlirpIStream *f);
bool slirp_ostream_write_u16(SlirpOStream *f, uint16_t b);
uint32_t slirp_istream_read_u32(SlirpIStream *f);
bool slirp_ostream_write_u32(SlirpOStream *f, uint32_t b);
int16_t slirp_istream_read_i16(SlirpIStream *f);
bool slirp_ostream_write_i16(SlirpOStream *f, int16_t b);
int32_t slirp_istream_read_i32(SlirpIStream *f);
bool slirp_ostream_write_i32(SlirpOStream *f, int32_t b);
#endif /* STREAM_H_ */

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/* /*
* Copyright (c) 1982, 1986, 1993 * Copyright (c) 1982, 1986, 1993
* The Regents of the University of California. All rights reserved. * The Regents of the University of California. All rights reserved.
@@ -30,92 +31,81 @@
* tcp.h,v 1.3 1994/08/21 05:27:34 paul Exp * tcp.h,v 1.3 1994/08/21 05:27:34 paul Exp
*/ */
#ifndef _TCP_H_ #ifndef TCP_H
#define _TCP_H_ #define TCP_H
#if defined(__amd64__) || defined(__aarch64__) #include <tinyglib.h>
typedef uintptr_t tcp_seq;
#else
typedef u_int32_t tcp_seq;
#endif
#define PR_SLOWHZ 2 /* 2 slow timeouts per second (approx) */ typedef uint32_t tcp_seq;
#define PR_FASTHZ 5 /* 5 fast timeouts per second (not important) */
extern int tcp_rcvspace; #define PR_SLOWHZ 2 /* 2 slow timeouts per second (approx) */
extern int tcp_sndspace; #define PR_FASTHZ 5 /* 5 fast timeouts per second (not important) */
extern struct SLIRPsocket *tcp_last_so;
#define TCP_SNDSPACE 8192 #define TCP_SNDSPACE 1024 * 128
#define TCP_RCVSPACE 8192 #define TCP_RCVSPACE 1024 * 128
#define TCP_MAXSEG_MAX 32768
/* /*
* TCP header. * TCP header.
* Per RFC 793, September, 1981. * Per RFC 793, September, 1981.
*/ */
#ifdef PRAGMA_PACK_SUPPORTED #define tcphdr slirp_tcphdr
#pragma pack(1)
#endif
struct tcphdr { struct tcphdr {
u_int16_t th_sport; /* source port */ uint16_t th_sport; /* source port */
u_int16_t th_dport; /* destination port */ uint16_t th_dport; /* destination port */
tcp_seq th_seq; /* sequence number */ tcp_seq th_seq; /* sequence number */
tcp_seq th_ack; /* acknowledgement number */ tcp_seq th_ack; /* acknowledgement number */
#ifdef WORDS_BIGENDIAN #if G_BYTE_ORDER == G_BIG_ENDIAN
u_char th_off:4, /* data offset */ uint8_t th_off : 4, /* data offset */
th_x2:4; /* (unused) */ th_x2 : 4; /* (unused) */
#else #else
u_char th_x2:4, /* (unused) */ uint8_t th_x2 : 4, /* (unused) */
th_off:4; /* data offset */ th_off : 4; /* data offset */
#endif
u_int8_t th_flags;
#define TH_FIN 0x01
#define TH_SYN 0x02
#define TH_RST 0x04
#define TH_PUSH 0x08
#define TH_ACK 0x10
#define TH_URG 0x20
u_int16_t th_win; /* window */
u_int16_t th_sum; /* checksum */
u_int16_t th_urp; /* urgent pointer */
} PACKED__;
#ifdef PRAGMA_PACK_SUPPORTED
#pragma pack(PACK_END)
#endif #endif
uint8_t th_flags;
uint16_t th_win; /* window */
uint16_t th_sum; /* checksum */
uint16_t th_urp; /* urgent pointer */
};
#include "tcp_var.h" #include "tcp_var.h"
#define TCPOPT_EOL 0 #ifndef TH_FIN
#define TCPOPT_NOP 1 #define TH_FIN 0x01
#define TCPOPT_MAXSEG 2 #define TH_SYN 0x02
#define TCPOLEN_MAXSEG 4 #define TH_RST 0x04
#define TCPOPT_WINDOW 3 #define TH_PUSH 0x08
#define TCPOLEN_WINDOW 3 #define TH_ACK 0x10
#define TCPOPT_SACK_PERMITTED 4 /* Experimental */ #define TH_URG 0x20
#define TCPOLEN_SACK_PERMITTED 2 #endif
#define TCPOPT_SACK 5 /* Experimental */
#define TCPOPT_TIMESTAMP 8
#define TCPOLEN_TIMESTAMP 10
#define TCPOLEN_TSTAMP_APPA (TCPOLEN_TIMESTAMP+2) /* appendix A */
#define TCPOPT_TSTAMP_HDR \ #ifndef TCPOPT_EOL
(TCPOPT_NOP<<24|TCPOPT_NOP<<16|TCPOPT_TIMESTAMP<<8|TCPOLEN_TIMESTAMP) #define TCPOPT_EOL 0
#define TCPOPT_NOP 1
#define TCPOPT_MAXSEG 2
#define TCPOPT_WINDOW 3
#define TCPOPT_SACK_PERMITTED 4 /* Experimental */
#define TCPOPT_SACK 5 /* Experimental */
#define TCPOPT_TIMESTAMP 8
/* #define TCPOPT_TSTAMP_HDR \
* Default maximum segment size for TCP. (TCPOPT_NOP << 24 | TCPOPT_NOP << 16 | TCPOPT_TIMESTAMP << 8 | \
* With an IP MSS of 576, this is 536, TCPOLEN_TIMESTAMP)
* but 512 is probably more convenient. #endif
* This should be defined as MIN(512, IP_MSS - sizeof (struct tcpiphdr)).
*
* We make this 1460 because we only care about Ethernet in the qemu context.
*/
#define TCP_MSS 1460
#define TCP_MAXWIN 65535 /* largest value for (unscaled) window */ #ifndef TCPOLEN_MAXSEG
#define TCPOLEN_MAXSEG 4
#define TCPOLEN_WINDOW 3
#define TCPOLEN_SACK_PERMITTED 2
#define TCPOLEN_TIMESTAMP 10
#define TCPOLEN_TSTAMP_APPA (TCPOLEN_TIMESTAMP + 2) /* appendix A */
#endif
#define TCP_MAX_WINSHIFT 14 /* maximum window shift */ #undef TCP_MAXWIN
#define TCP_MAXWIN 65535 /* largest value for (unscaled) window */
#undef TCP_MAX_WINSHIFT
#define TCP_MAX_WINSHIFT 14 /* maximum window shift */
/* /*
* User-settable options (used with setsockopt). * User-settable options (used with setsockopt).
@@ -125,61 +115,55 @@ struct tcphdr {
* so we undefine them. * so we undefine them.
*/ */
#undef TCP_NODELAY #undef TCP_NODELAY
#define TCP_NODELAY 0x01 /* don't delay send to coalesce packets */ #define TCP_NODELAY 0x01 /* don't delay send to coalesce packets */
#undef TCP_MAXSEG #undef TCP_MAXSEG
/* #define TCP_MAXSEG 0x02 */ /* set maximum segment size */
/* /*
* TCP FSM state definitions. * TCP FSM state definitions.
* Per RFC793, September, 1981. * Per RFC793, September, 1981.
*/ */
#define TCP_NSTATES 11 #define TCP_NSTATES 11
#define TCPS_CLOSED 0 /* closed */ #define TCPS_CLOSED 0 /* closed */
#define TCPS_LISTEN 1 /* listening for connection */ #define TCPS_LISTEN 1 /* listening for connection */
#define TCPS_SYN_SENT 2 /* active, have sent syn */ #define TCPS_SYN_SENT 2 /* active, have sent syn */
#define TCPS_SYN_RECEIVED 3 /* have send and received syn */ #define TCPS_SYN_RECEIVED 3 /* have send and received syn */
/* states < TCPS_ESTABLISHED are those where connections not established */ /* states < TCPS_ESTABLISHED are those where connections not established */
#define TCPS_ESTABLISHED 4 /* established */ #define TCPS_ESTABLISHED 4 /* established */
#define TCPS_CLOSE_WAIT 5 /* rcvd fin, waiting for close */ #define TCPS_CLOSE_WAIT 5 /* rcvd fin, waiting for close */
/* states > TCPS_CLOSE_WAIT are those where user has closed */ /* states > TCPS_CLOSE_WAIT are those where user has closed */
#define TCPS_FIN_WAIT_1 6 /* have closed, sent fin */ #define TCPS_FIN_WAIT_1 6 /* have closed, sent fin */
#define TCPS_CLOSING 7 /* closed xchd FIN; await FIN ACK */ #define TCPS_CLOSING 7 /* closed xchd FIN; await FIN ACK */
#define TCPS_LAST_ACK 8 /* had fin and close; await FIN ACK */ #define TCPS_LAST_ACK 8 /* had fin and close; await FIN ACK */
/* states > TCPS_CLOSE_WAIT && < TCPS_FIN_WAIT_2 await ACK of FIN */ /* states > TCPS_CLOSE_WAIT && < TCPS_FIN_WAIT_2 await ACK of FIN */
#define TCPS_FIN_WAIT_2 9 /* have closed, fin is acked */ #define TCPS_FIN_WAIT_2 9 /* have closed, fin is acked */
#define TCPS_TIME_WAIT 10 /* in 2*msl quiet wait after close */ #define TCPS_TIME_WAIT 10 /* in 2*msl quiet wait after close */
#define TCPS_HAVERCVDSYN(s) ((s) >= TCPS_SYN_RECEIVED) #define TCPS_HAVERCVDSYN(s) ((s) >= TCPS_SYN_RECEIVED)
#define TCPS_HAVEESTABLISHED(s) ((s) >= TCPS_ESTABLISHED) #define TCPS_HAVEESTABLISHED(s) ((s) >= TCPS_ESTABLISHED)
#define TCPS_HAVERCVDFIN(s) ((s) >= TCPS_TIME_WAIT) #define TCPS_HAVERCVDFIN(s) ((s) >= TCPS_TIME_WAIT)
/* /*
* TCP sequence numbers are 32 bit integers operated * TCP sequence numbers are 32 bit integers operated
* on with modular arithmetic. These macros can be * on with modular arithmetic. These macros can be
* used to compare such integers. * used to compare such integers.
*/ */
#define SEQ_LT(a,b) ((int)((a)-(b)) < 0) #define SEQ_LT(a, b) ((int)((a) - (b)) < 0)
#define SEQ_LEQ(a,b) ((int)((a)-(b)) <= 0) #define SEQ_LEQ(a, b) ((int)((a) - (b)) <= 0)
#define SEQ_GT(a,b) ((int)((a)-(b)) > 0) #define SEQ_GT(a, b) ((int)((a) - (b)) > 0)
#define SEQ_GEQ(a,b) ((int)((a)-(b)) >= 0) #define SEQ_GEQ(a, b) ((int)((a) - (b)) >= 0)
/* /*
* Macros to initialize tcp sequence numbers for * Macros to initialize tcp sequence numbers for
* send and receive from initial send and receive * send and receive from initial send and receive
* sequence numbers. * sequence numbers.
*/ */
#define tcp_rcvseqinit(tp) \ #define tcp_rcvseqinit(tp) (tp)->rcv_adv = (tp)->rcv_nxt = (tp)->irs + 1
(tp)->rcv_adv = (tp)->rcv_nxt = (tp)->irs + 1
#define tcp_sendseqinit(tp) \ #define tcp_sendseqinit(tp) \
(tp)->snd_una = (tp)->snd_nxt = (tp)->snd_max = (tp)->snd_up = (tp)->iss (tp)->snd_una = (tp)->snd_nxt = (tp)->snd_max = (tp)->snd_up = (tp)->iss
#define TCP_ISSINCR (125*1024) /* increment for tcp_iss each second */ #define TCP_ISSINCR (125 * 1024) /* increment for tcp_iss each second */
extern tcp_seq tcp_iss; /* tcp initial send seq # */
extern char *tcpstates[];
#endif #endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/* /*
* Copyright (c) 1982, 1986, 1988, 1990, 1993 * Copyright (c) 1982, 1986, 1988, 1990, 1993
* The Regents of the University of California. All rights reserved. * The Regents of the University of California. All rights reserved.
@@ -32,35 +33,27 @@
#include "slirp.h" #include "slirp.h"
int tcp_keepidle = TCPTV_KEEP_IDLE; static struct tcpcb *tcp_timers(register struct tcpcb *tp, int timer);
int tcp_keepintvl = TCPTV_KEEPINTVL;
int tcp_maxidle;
int so_options = DO_KEEPALIVE;
struct tcpstat tcpstat; /* tcp statistics */
u_int32_t tcp_now; /* for RFC 1323 timestamps */
/* /*
* Fast timeout routine for processing delayed acks * Fast timeout routine for processing delayed acks
*/ */
void void tcp_fasttimo(Slirp *slirp)
tcp_fasttimo()
{ {
register struct SLIRPsocket *so; register struct socket *so;
register struct tcpcb *tp; register struct tcpcb *tp;
DEBUG_CALL("tcp_fasttimo"); DEBUG_CALL("tcp_fasttimo");
so = tcb.so_next; so = slirp->tcb.so_next;
if (so) if (so)
for (; so != &tcb; so = so->so_next) for (; so != &slirp->tcb; so = so->so_next)
if ((tp = (struct tcpcb *)so->so_tcpcb) && if ((tp = (struct tcpcb *)so->so_tcpcb) &&
(tp->t_flags & TF_DELACK)) { (tp->t_flags & TF_DELACK)) {
tp->t_flags &= ~TF_DELACK; tp->t_flags &= ~TF_DELACK;
tp->t_flags |= TF_ACKNOW; tp->t_flags |= TF_ACKNOW;
tcpstat.tcps_delack++; (void)tcp_output(tp);
(void) tcp_output(tp); }
}
} }
/* /*
@@ -68,255 +61,226 @@ tcp_fasttimo()
* Updates the timers in all active tcb's and * Updates the timers in all active tcb's and
* causes finite state machine actions if timers expire. * causes finite state machine actions if timers expire.
*/ */
void void tcp_slowtimo(Slirp *slirp)
tcp_slowtimo()
{ {
register struct SLIRPsocket *ip, *ipnxt; register struct socket *ip, *ipnxt;
register struct tcpcb *tp; register struct tcpcb *tp;
register int i; register int i;
DEBUG_CALL("tcp_slowtimo"); DEBUG_CALL("tcp_slowtimo");
tcp_maxidle = TCPTV_KEEPCNT * tcp_keepintvl; /*
/* * Search through tcb's and update active timers.
* Search through tcb's and update active timers. */
*/ ip = slirp->tcb.so_next;
ip = tcb.so_next; if (ip == NULL) {
if (ip == 0) return;
return; }
for (; ip != &tcb; ip = ipnxt) { for (; ip != &slirp->tcb; ip = ipnxt) {
ipnxt = ip->so_next; ipnxt = ip->so_next;
tp = sototcpcb(ip); tp = sototcpcb(ip);
if (tp == 0) if (tp == NULL) {
continue; continue;
for (i = 0; i < TCPT_NTIMERS; i++) { }
if (tp->t_timer[i] && --tp->t_timer[i] == 0) { for (i = 0; i < TCPT_NTIMERS; i++) {
tcp_timers(tp,i); if (tp->t_timer[i] && --tp->t_timer[i] == 0) {
if (ipnxt->so_prev != ip) tcp_timers(tp, i);
goto tpgone; if (ipnxt->so_prev != ip)
} goto tpgone;
} }
tp->t_idle++; }
if (tp->t_rtt) tp->t_idle++;
tp->t_rtt++; if (tp->t_rtt)
tpgone: tp->t_rtt++;
; tpgone:;
} }
tcp_iss += TCP_ISSINCR/PR_SLOWHZ; /* increment iss */ slirp->tcp_iss += TCP_ISSINCR / PR_SLOWHZ; /* increment iss */
#ifdef TCP_COMPAT_42 slirp->tcp_now++; /* for timestamps */
if ((int)tcp_iss < 0)
tcp_iss = 0; /* XXX */
#endif
tcp_now++; /* for timestamps */
} }
/* /*
* Cancel all timers for TCP tp. * Cancel all timers for TCP tp.
*/ */
void void tcp_canceltimers(struct tcpcb *tp)
tcp_canceltimers(tp)
struct tcpcb *tp;
{ {
register int i; register int i;
for (i = 0; i < TCPT_NTIMERS; i++) for (i = 0; i < TCPT_NTIMERS; i++)
tp->t_timer[i] = 0; tp->t_timer[i] = 0;
} }
int tcp_backoff[TCP_MAXRXTSHIFT + 1] = const int tcp_backoff[TCP_MAXRXTSHIFT + 1] = { 1, 2, 4, 8, 16, 32, 64,
{ 1, 2, 4, 8, 16, 32, 64, 64, 64, 64, 64, 64, 64 }; 64, 64, 64, 64, 64, 64 };
/* /*
* TCP timer processing. * TCP timer processing.
*/ */
struct tcpcb * static struct tcpcb *tcp_timers(register struct tcpcb *tp, int timer)
tcp_timers(tp, timer)
struct tcpcb *tp;
int timer;
{ {
int rexmt; register int rexmt;
DEBUG_CALL("tcp_timers");
switch (timer) {
/* DEBUG_CALL("tcp_timers");
* 2 MSL timeout in shutdown went off. If we're closed but
* still waiting for peer to close and connection has been idle
* too long, or if 2MSL time is up from TIME_WAIT, delete connection
* control block. Otherwise, check again in a bit.
*/
case TCPT_2MSL:
if (tp->t_state != TCPS_TIME_WAIT &&
tp->t_idle <= tcp_maxidle)
tp->t_timer[TCPT_2MSL] = tcp_keepintvl;
else
tp = tcp_close(tp);
break;
/* switch (timer) {
* Retransmission timer went off. Message has not /*
* been acked within retransmit interval. Back off * 2 MSL timeout in shutdown went off. If we're closed but
* to a longer retransmit interval and retransmit one segment. * still waiting for peer to close and connection has been idle
*/ * too long, or if 2MSL time is up from TIME_WAIT, delete connection
case TCPT_REXMT: * control block. Otherwise, check again in a bit.
*/
/* case TCPT_2MSL:
* XXXXX If a packet has timed out, then remove all the queued if (tp->t_state != TCPS_TIME_WAIT && tp->t_idle <= TCP_MAXIDLE)
* packets for that session. tp->t_timer[TCPT_2MSL] = TCPTV_KEEPINTVL;
*/ else
tp = tcp_close(tp);
if (++tp->t_rxtshift > TCP_MAXRXTSHIFT) { break;
/*
* This is a hack to suit our terminal server here at the uni of canberra
* since they have trouble with zeroes... It usually lets them through
* unharmed, but under some conditions, it'll eat the zeros. If we
* keep retransmitting it, it'll keep eating the zeroes, so we keep
* retransmitting, and eventually the connection dies...
* (this only happens on incoming data)
*
* So, if we were gonna drop the connection from too many retransmits,
* don't... instead halve the t_maxseg, which might break up the NULLs and
* let them through
*
* *sigh*
*/
tp->t_maxseg >>= 1;
if (tp->t_maxseg < 32) {
/*
* We tried our best, now the connection must die!
*/
tp->t_rxtshift = TCP_MAXRXTSHIFT;
tcpstat.tcps_timeoutdrop++;
tp = tcp_drop(tp, tp->t_softerror);
/* tp->t_softerror : ETIMEDOUT); */ /* XXX */
return (tp); /* XXX */
}
/*
* Set rxtshift to 6, which is still at the maximum
* backoff time
*/
tp->t_rxtshift = 6;
}
tcpstat.tcps_rexmttimeo++;
rexmt = TCP_REXMTVAL(tp) * tcp_backoff[tp->t_rxtshift];
TCPT_RANGESET(tp->t_rxtcur, rexmt,
(short)tp->t_rttmin, TCPTV_REXMTMAX); /* XXX */
tp->t_timer[TCPT_REXMT] = tp->t_rxtcur;
/*
* If losing, let the lower level know and try for
* a better route. Also, if we backed off this far,
* our srtt estimate is probably bogus. Clobber it
* so we'll take the next rtt measurement as our srtt;
* move the current srtt into rttvar to keep the current
* retransmit times until then.
*/
if (tp->t_rxtshift > TCP_MAXRXTSHIFT / 4) {
/* in_losing(tp->t_inpcb); */
tp->t_rttvar += (tp->t_srtt >> TCP_RTT_SHIFT);
tp->t_srtt = 0;
}
tp->snd_nxt = tp->snd_una;
/*
* If timing a segment in this window, stop the timer.
*/
tp->t_rtt = 0;
/*
* Close the congestion window down to one segment
* (we'll open it by one segment for each ack we get).
* Since we probably have a window's worth of unacked
* data accumulated, this "slow start" keeps us from
* dumping all that data as back-to-back packets (which
* might overwhelm an intermediate gateway).
*
* There are two phases to the opening: Initially we
* open by one mss on each ack. This makes the window
* size increase exponentially with time. If the
* window is larger than the path can handle, this
* exponential growth results in dropped packet(s)
* almost immediately. To get more time between
* drops but still "push" the network to take advantage
* of improving conditions, we switch from exponential
* to linear window opening at some threshold size.
* For a threshold, we use half the current window
* size, truncated to a multiple of the mss.
*
* (the minimum cwnd that will give us exponential
* growth is 2 mss. We don't allow the threshold
* to go below this.)
*/
{
u_int win = min(tp->snd_wnd, tp->snd_cwnd) / 2 / tp->t_maxseg;
if (win < 2)
win = 2;
tp->snd_cwnd = tp->t_maxseg;
tp->snd_ssthresh = win * tp->t_maxseg;
tp->t_dupacks = 0;
}
(void) tcp_output(tp);
break;
/* /*
* Persistence timer into zero window. * Retransmission timer went off. Message has not
* Force a byte to be output, if possible. * been acked within retransmit interval. Back off
*/ * to a longer retransmit interval and retransmit one segment.
case TCPT_PERSIST: */
tcpstat.tcps_persisttimeo++; case TCPT_REXMT:
tcp_setpersist(tp);
tp->t_force = 1;
(void) tcp_output(tp);
tp->t_force = 0;
break;
/* /*
* Keep-alive timer went off; send something * XXXXX If a packet has timed out, then remove all the queued
* or drop connection if idle for too long. * packets for that session.
*/ */
case TCPT_KEEP:
tcpstat.tcps_keeptimeo++;
if (tp->t_state < TCPS_ESTABLISHED)
goto dropit;
/* if (tp->t_socket->so_options & SO_KEEPALIVE && */ if (++tp->t_rxtshift > TCP_MAXRXTSHIFT) {
if ((so_options) && tp->t_state <= TCPS_CLOSE_WAIT) { /*
if (tp->t_idle >= tcp_keepidle + tcp_maxidle) * This is a hack to suit our terminal server here at the uni of
goto dropit; * canberra since they have trouble with zeroes... It usually lets
/* * them through unharmed, but under some conditions, it'll eat the
* Send a packet designed to force a response * zeros. If we keep retransmitting it, it'll keep eating the
* if the peer is up and reachable: * zeroes, so we keep retransmitting, and eventually the connection
* either an ACK if the connection is still alive, * dies... (this only happens on incoming data)
* or an RST if the peer has closed the connection *
* due to timeout or reboot. * So, if we were gonna drop the connection from too many
* Using sequence number tp->snd_una-1 * retransmits, don't... instead halve the t_maxseg, which might
* causes the transmitted zero-length segment * break up the NULLs and let them through
* to lie outside the receive window; *
* by the protocol spec, this requires the * *sigh*
* correspondent TCP to respond. */
*/
tcpstat.tcps_keepprobe++;
#ifdef TCP_COMPAT_42
/*
* The keepalive packet must have nonzero length
* to get a 4.2 host to respond.
*/
tcp_respond(tp, &tp->t_template, (struct SLIRPmbuf *)NULL,
tp->rcv_nxt - 1, tp->snd_una - 1, 0);
#else
tcp_respond(tp, &tp->t_template, (struct SLIRPmbuf *)NULL,
tp->rcv_nxt, tp->snd_una - 1, 0);
#endif
tp->t_timer[TCPT_KEEP] = tcp_keepintvl;
} else
tp->t_timer[TCPT_KEEP] = tcp_keepidle;
break;
dropit: tp->t_maxseg >>= 1;
tcpstat.tcps_keepdrops++; if (tp->t_maxseg < 32) {
tp = tcp_drop(tp, 0); /* ETIMEDOUT); */ /*
break; * We tried our best, now the connection must die!
} */
tp->t_rxtshift = TCP_MAXRXTSHIFT;
tp = tcp_drop(tp, tp->t_softerror);
/* tp->t_softerror : ETIMEDOUT); */ /* XXX */
return (tp); /* XXX */
}
return (tp); /*
* Set rxtshift to 6, which is still at the maximum
* backoff time
*/
tp->t_rxtshift = 6;
}
rexmt = TCP_REXMTVAL(tp) * tcp_backoff[tp->t_rxtshift];
TCPT_RANGESET(tp->t_rxtcur, rexmt, (short)tp->t_rttmin,
TCPTV_REXMTMAX); /* XXX */
tp->t_timer[TCPT_REXMT] = tp->t_rxtcur;
/*
* If losing, let the lower level know and try for
* a better route. Also, if we backed off this far,
* our srtt estimate is probably bogus. Clobber it
* so we'll take the next rtt measurement as our srtt;
* move the current srtt into rttvar to keep the current
* retransmit times until then.
*/
if (tp->t_rxtshift > TCP_MAXRXTSHIFT / 4) {
tp->t_rttvar += (tp->t_srtt >> TCP_RTT_SHIFT);
tp->t_srtt = 0;
}
tp->snd_nxt = tp->snd_una;
/*
* If timing a segment in this window, stop the timer.
*/
tp->t_rtt = 0;
/*
* Close the congestion window down to one segment
* (we'll open it by one segment for each ack we get).
* Since we probably have a window's worth of unacked
* data accumulated, this "slow start" keeps us from
* dumping all that data as back-to-back packets (which
* might overwhelm an intermediate gateway).
*
* There are two phases to the opening: Initially we
* open by one mss on each ack. This makes the window
* size increase exponentially with time. If the
* window is larger than the path can handle, this
* exponential growth results in dropped packet(s)
* almost immediately. To get more time between
* drops but still "push" the network to take advantage
* of improving conditions, we switch from exponential
* to linear window opening at some threshold size.
* For a threshold, we use half the current window
* size, truncated to a multiple of the mss.
*
* (the minimum cwnd that will give us exponential
* growth is 2 mss. We don't allow the threshold
* to go below this.)
*/
{
unsigned win = MIN(tp->snd_wnd, tp->snd_cwnd) / 2 / tp->t_maxseg;
if (win < 2)
win = 2;
tp->snd_cwnd = tp->t_maxseg;
tp->snd_ssthresh = win * tp->t_maxseg;
tp->t_dupacks = 0;
}
(void)tcp_output(tp);
break;
/*
* Persistence timer into zero window.
* Force a byte to be output, if possible.
*/
case TCPT_PERSIST:
tcp_setpersist(tp);
tp->t_force = 1;
(void)tcp_output(tp);
tp->t_force = 0;
break;
/*
* Keep-alive timer went off; send something
* or drop connection if idle for too long.
*/
case TCPT_KEEP:
if (tp->t_state < TCPS_ESTABLISHED)
goto dropit;
if (slirp_do_keepalive && tp->t_state <= TCPS_CLOSE_WAIT) {
if (tp->t_idle >= TCPTV_KEEP_IDLE + TCP_MAXIDLE)
goto dropit;
/*
* Send a packet designed to force a response
* if the peer is up and reachable:
* either an ACK if the connection is still alive,
* or an RST if the peer has closed the connection
* due to timeout or reboot.
* Using sequence number tp->snd_una-1
* causes the transmitted zero-length segment
* to lie outside the receive window;
* by the protocol spec, this requires the
* correspondent TCP to respond.
*/
tcp_respond(tp, &tp->t_template, (struct mbuf *)NULL, tp->rcv_nxt,
tp->snd_una - 1, 0, tp->t_socket->so_ffamily);
tp->t_timer[TCPT_KEEP] = TCPTV_KEEPINTVL;
} else
tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_IDLE;
break;
dropit:
tp = tcp_drop(tp, 0);
break;
}
return (tp);
} }

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/* /*
* Copyright (c) 1982, 1986, 1993 * Copyright (c) 1982, 1986, 1993
* The Regents of the University of California. All rights reserved. * The Regents of the University of California. All rights reserved.
@@ -30,19 +31,19 @@
* tcp_timer.h,v 1.4 1994/08/21 05:27:38 paul Exp * tcp_timer.h,v 1.4 1994/08/21 05:27:38 paul Exp
*/ */
#ifndef _TCP_TIMER_H_ #ifndef TCP_TIMER_H
#define _TCP_TIMER_H_ #define TCP_TIMER_H
/* /*
* Definitions of the TCP timers. These timers are counted * Definitions of the TCP timers. These timers are counted
* down PR_SLOWHZ times a second. * down PR_SLOWHZ times a second.
*/ */
#define TCPT_NTIMERS 4 #define TCPT_NTIMERS 4
#define TCPT_REXMT 0 /* retransmit */ #define TCPT_REXMT 0 /* retransmit */
#define TCPT_PERSIST 1 /* retransmit persistence */ #define TCPT_PERSIST 1 /* retransmit persistence */
#define TCPT_KEEP 2 /* keep alive */ #define TCPT_KEEP 2 /* keep alive */
#define TCPT_2MSL 3 /* 2*msl quiet time timer */ #define TCPT_2MSL 3 /* 2*msl quiet time timer */
/* /*
* The TCPT_REXMT timer is used to force retransmissions. * The TCPT_REXMT timer is used to force retransmissions.
@@ -83,56 +84,47 @@
/* /*
* Time constants. * Time constants.
*/ */
#define TCPTV_MSL ( 5*PR_SLOWHZ) /* max seg lifetime (hah!) */ #define TCPTV_MSL (5 * PR_SLOWHZ) /* max seg lifetime (hah!) */
#define TCPTV_SRTTBASE 0 /* base roundtrip time; #define TCPTV_SRTTBASE \
if 0, no idea yet */ 0 /* base roundtrip time; \
#define TCPTV_SRTTDFLT ( 3*PR_SLOWHZ) /* assumed RTT if no info */ if 0, no idea yet */
#define TCPTV_SRTTDFLT (3 * PR_SLOWHZ) /* assumed RTT if no info */
#define TCPTV_PERSMIN ( 5*PR_SLOWHZ) /* retransmit persistence */ #define TCPTV_PERSMIN (5 * PR_SLOWHZ) /* retransmit persistence */
#define TCPTV_PERSMAX ( 60*PR_SLOWHZ) /* maximum persist interval */ #define TCPTV_PERSMAX (60 * PR_SLOWHZ) /* maximum persist interval */
#define TCPTV_KEEP_INIT ( 75*PR_SLOWHZ) /* initial connect keep alive */ #define TCPTV_KEEP_INIT (75 * PR_SLOWHZ) /* initial connect keep alive */
#define TCPTV_KEEP_IDLE (120*60*PR_SLOWHZ) /* dflt time before probing */ #define TCPTV_KEEP_IDLE (120 * 60 * PR_SLOWHZ) /* dflt time before probing */
#define TCPTV_KEEPINTVL ( 75*PR_SLOWHZ) /* default probe interval */ #define TCPTV_KEEPINTVL (75 * PR_SLOWHZ) /* default probe interval */
#define TCPTV_KEEPCNT 8 /* max probes before drop */ #define TCPTV_KEEPCNT 8 /* max probes before drop */
#define TCPTV_MIN ( 1*PR_SLOWHZ) /* minimum allowable value */ #define TCPTV_MIN (1 * PR_SLOWHZ) /* minimum allowable value */
/* #define TCPTV_REXMTMAX ( 64*PR_SLOWHZ) */ /* max allowable REXMT value */ #define TCPTV_REXMTMAX (12 * PR_SLOWHZ) /* max allowable REXMT value */
#define TCPTV_REXMTMAX ( 12*PR_SLOWHZ) /* max allowable REXMT value */
#define TCP_LINGERTIME 120 /* linger at most 2 minutes */ #define TCP_LINGERTIME 120 /* linger at most 2 minutes */
#define TCP_MAXRXTSHIFT 12 /* maximum retransmits */ #define TCP_MAXRXTSHIFT 12 /* maximum retransmits */
#ifdef TCPTIMERS
char *tcptimers[] =
{ "REXMT", "PERSIST", "KEEP", "2MSL" };
#endif
/* /*
* Force a time value to be in a certain range. * Force a time value to be in a certain range.
*/ */
#define TCPT_RANGESET(tv, value, tvmin, tvmax) { \ #define TCPT_RANGESET(tv, value, tvmin, tvmax) \
(tv) = (value); \ { \
if ((tv) < (tvmin)) \ (tv) = (value); \
(tv) = (tvmin); \ if ((tv) < (tvmin)) \
else if ((tv) > (tvmax)) \ (tv) = (tvmin); \
(tv) = (tvmax); \ else if ((tv) > (tvmax)) \
} (tv) = (tvmax); \
}
extern int tcp_keepidle; /* time before keepalive probes begin */ extern const int tcp_backoff[];
extern int tcp_keepintvl; /* time between keepalive probes */
extern int tcp_maxidle; /* time to drop after starting probes */
extern int tcp_ttl; /* time to live for TCP segs */
extern int tcp_backoff[];
struct tcpcb; struct tcpcb;
void tcp_fasttimo _P((void)); void tcp_fasttimo(Slirp *);
void tcp_slowtimo _P((void)); void tcp_slowtimo(Slirp *);
void tcp_canceltimers _P((struct tcpcb *)); void tcp_canceltimers(struct tcpcb *);
struct tcpcb * tcp_timers _P((register struct tcpcb *, int));
#endif #endif

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/* /*
* Copyright (c) 1982, 1986, 1993, 1994 * Copyright (c) 1982, 1986, 1993, 1994
* The Regents of the University of California. All rights reserved. * The Regents of the University of California. All rights reserved.
@@ -30,115 +31,103 @@
* tcp_var.h,v 1.3 1994/08/21 05:27:39 paul Exp * tcp_var.h,v 1.3 1994/08/21 05:27:39 paul Exp
*/ */
#ifndef _TCP_VAR_H_ #ifndef TCP_VAR_H
#define _TCP_VAR_H_ #define TCP_VAR_H
#include "tcpip.h" #include "tcpip.h"
#include "tcp_timer.h" #include "tcp_timer.h"
#if defined(__amd64__) || defined(__aarch64__)
typedef uintptr_t tcpiphdrp_32;
#else
#if SIZEOF_CHAR_P == 4
typedef struct tcpiphdr *tcpiphdrp_32;
#else
typedef u_int32_t tcpiphdrp_32;
#endif
#endif
/* /*
* Tcp control block, one per tcp; fields: * Tcp control block, one per tcp; fields:
*/ */
struct tcpcb { struct tcpcb {
tcpiphdrp_32 seg_next; /* sequencing queue */ struct tcpiphdr *seg_next; /* sequencing queue */
tcpiphdrp_32 seg_prev; struct tcpiphdr *seg_prev;
short t_state; /* state of this connection */ short t_state; /* state of this connection */
short t_timer[TCPT_NTIMERS]; /* tcp timers */ short t_timer[TCPT_NTIMERS]; /* tcp timers */
short t_rxtshift; /* log(2) of rexmt exp. backoff */ short t_rxtshift; /* log(2) of rexmt exp. backoff */
short t_rxtcur; /* current retransmit value */ short t_rxtcur; /* current retransmit value */
short t_dupacks; /* consecutive dup acks recd */ short t_dupacks; /* consecutive dup acks recd */
u_short t_maxseg; /* maximum segment size */ uint16_t t_maxseg; /* maximum segment size */
char t_force; /* 1 if forcing out a byte */ uint8_t t_force; /* 1 if forcing out a byte */
u_short t_flags; uint16_t t_flags;
#define TF_ACKNOW 0x0001 /* ack peer immediately */ #define TF_ACKNOW 0x0001 /* ack peer immediately */
#define TF_DELACK 0x0002 /* ack, but try to delay it */ #define TF_DELACK 0x0002 /* ack, but try to delay it */
#define TF_NODELAY 0x0004 /* don't delay packets to coalesce */ #define TF_NODELAY 0x0004 /* don't delay packets to coalesce */
#define TF_NOOPT 0x0008 /* don't use tcp options */ #define TF_NOOPT 0x0008 /* don't use tcp options */
#define TF_SENTFIN 0x0010 /* have sent FIN */ #define TF_SENTFIN 0x0010 /* have sent FIN */
#define TF_REQ_SCALE 0x0020 /* have/will request window scaling */ #define TF_REQ_SCALE 0x0020 /* have/will request window scaling */
#define TF_RCVD_SCALE 0x0040 /* other side has requested scaling */ #define TF_RCVD_SCALE 0x0040 /* other side has requested scaling */
#define TF_REQ_TSTMP 0x0080 /* have/will request timestamps */ #define TF_REQ_TSTMP 0x0080 /* have/will request timestamps */
#define TF_RCVD_TSTMP 0x0100 /* a timestamp was received in SYN */ #define TF_RCVD_TSTMP 0x0100 /* a timestamp was received in SYN */
#define TF_SACK_PERMIT 0x0200 /* other side said I could SACK */ #define TF_SACK_PERMIT 0x0200 /* other side said I could SACK */
/* Make it static for now */ struct tcpiphdr t_template; /* static skeletal packet for xmit */
/* struct tcpiphdr *t_template; / * skeletal packet for transmit */
struct tcpiphdr t_template;
struct SLIRPsocket *t_socket; /* back pointer to socket */ struct socket *t_socket; /* back pointer to socket */
/* /*
* The following fields are used as in the protocol specification. * The following fields are used as in the protocol specification.
* See RFC783, Dec. 1981, page 21. * See RFC783, Dec. 1981, page 21.
*/ */
/* send sequence variables */ /* send sequence variables */
tcp_seq snd_una; /* send unacknowledged */ tcp_seq snd_una; /* send unacknowledged */
tcp_seq snd_nxt; /* send next */ tcp_seq snd_nxt; /* send next */
tcp_seq snd_up; /* send urgent pointer */ tcp_seq snd_up; /* send urgent pointer */
tcp_seq snd_wl1; /* window update seg seq number */ tcp_seq snd_wl1; /* window update seg seq number */
tcp_seq snd_wl2; /* window update seg ack number */ tcp_seq snd_wl2; /* window update seg ack number */
tcp_seq iss; /* initial send sequence number */ tcp_seq iss; /* initial send sequence number */
u_int32_t snd_wnd; /* send window */ uint32_t snd_wnd; /* send window */
/* receive sequence variables */ /* receive sequence variables */
u_int32_t rcv_wnd; /* receive window */ uint32_t rcv_wnd; /* receive window */
tcp_seq rcv_nxt; /* receive next */ tcp_seq rcv_nxt; /* receive next */
tcp_seq rcv_up; /* receive urgent pointer */ tcp_seq rcv_up; /* receive urgent pointer */
tcp_seq irs; /* initial receive sequence number */ tcp_seq irs; /* initial receive sequence number */
/* /*
* Additional variables for this implementation. * Additional variables for this implementation.
*/ */
/* receive variables */ /* receive variables */
tcp_seq rcv_adv; /* advertised window */ tcp_seq rcv_adv; /* advertised window */
/* retransmit variables */ /* retransmit variables */
tcp_seq snd_max; /* highest sequence number sent; tcp_seq snd_max; /* highest sequence number sent;
* used to recognize retransmits * used to recognize retransmits
*/ */
/* congestion control (for slow start, source quench, retransmit after loss) */ /* congestion control (for slow start, source quench, retransmit after loss)
u_int32_t snd_cwnd; /* congestion-controlled window */ */
u_int32_t snd_ssthresh; /* snd_cwnd size threshold for uint32_t snd_cwnd; /* congestion-controlled window */
* for slow start exponential to uint32_t snd_ssthresh; /* snd_cwnd size threshold for
* linear switch * for slow start exponential to
*/ * linear switch
/* */
* transmit timing stuff. See below for scale of srtt and rttvar. /*
* "Variance" is actually smoothed difference. * transmit timing stuff. See below for scale of srtt and rttvar.
*/ * "Variance" is actually smoothed difference.
short t_idle; /* inactivity time */ */
short t_rtt; /* round trip time */ short t_idle; /* inactivity time */
tcp_seq t_rtseq; /* sequence number being timed */ short t_rtt; /* round trip time */
short t_srtt; /* smoothed round-trip time */ tcp_seq t_rtseq; /* sequence number being timed */
short t_rttvar; /* variance in round-trip time */ short t_srtt; /* smoothed round-trip time */
u_short t_rttmin; /* minimum rtt allowed */ short t_rttvar; /* variance in round-trip time */
u_int32_t max_sndwnd; /* largest window peer has offered */ uint16_t t_rttmin; /* minimum rtt allowed */
uint32_t max_sndwnd; /* largest window peer has offered */
/* out-of-band data */ /* out-of-band data */
char t_oobflags; /* have some */ uint8_t t_oobflags; /* have some */
char t_iobc; /* input character */ uint8_t t_iobc; /* input character */
#define TCPOOB_HAVEDATA 0x01 #define TCPOOB_HAVEDATA 0x01
#define TCPOOB_HADDATA 0x02 #define TCPOOB_HADDATA 0x02
short t_softerror; /* possible error not yet reported */ short t_softerror; /* possible error not yet reported */
/* RFC 1323 variables */
u_char snd_scale; /* window scaling for send window */
u_char rcv_scale; /* window scaling for recv window */
u_char request_r_scale; /* pending window scaling */
u_char requested_s_scale;
u_int32_t ts_recent; /* timestamp echo data */
u_int32_t ts_recent_age; /* when last updated */
tcp_seq last_ack_sent;
/* RFC 1323 variables */
uint8_t snd_scale; /* window scaling for send window */
uint8_t rcv_scale; /* window scaling for recv window */
uint8_t request_r_scale; /* pending window scaling */
uint8_t requested_s_scale;
uint32_t ts_recent; /* timestamp echo data */
uint32_t ts_recent_age; /* when last updated */
tcp_seq last_ack_sent;
}; };
#define sototcpcb(so) ((so)->so_tcpcb) #define sototcpcb(so) ((so)->so_tcpcb)
/* /*
* The smoothed round-trip time and estimated variance * The smoothed round-trip time and estimated variance
@@ -149,10 +138,10 @@ struct tcpcb {
* and thus an "ALPHA" of 0.875. rttvar has 2 bits to the right of the * and thus an "ALPHA" of 0.875. rttvar has 2 bits to the right of the
* binary point, and is smoothed with an ALPHA of 0.75. * binary point, and is smoothed with an ALPHA of 0.75.
*/ */
#define TCP_RTT_SCALE 8 /* multiplier for srtt; 3 bits frac. */ #define TCP_RTT_SCALE 8 /* multiplier for srtt; 3 bits frac. */
#define TCP_RTT_SHIFT 3 /* shift for srtt; 3 bits frac. */ #define TCP_RTT_SHIFT 3 /* shift for srtt; 3 bits frac. */
#define TCP_RTTVAR_SCALE 4 /* multiplier for rttvar; 2 bits */ #define TCP_RTTVAR_SCALE 4 /* multiplier for rttvar; 2 bits */
#define TCP_RTTVAR_SHIFT 2 /* multiplier for rttvar; 2 bits */ #define TCP_RTTVAR_SHIFT 2 /* multiplier for rttvar; 2 bits */
/* /*
* The initial retransmission should happen at rtt + 4 * rttvar. * The initial retransmission should happen at rtt + 4 * rttvar.
@@ -167,90 +156,6 @@ struct tcpcb {
* This macro assumes that the value of TCP_RTTVAR_SCALE * This macro assumes that the value of TCP_RTTVAR_SCALE
* is the same as the multiplier for rttvar. * is the same as the multiplier for rttvar.
*/ */
#define TCP_REXMTVAL(tp) \ #define TCP_REXMTVAL(tp) (((tp)->t_srtt >> TCP_RTT_SHIFT) + (tp)->t_rttvar)
(((tp)->t_srtt >> TCP_RTT_SHIFT) + (tp)->t_rttvar)
/* XXX
* We want to avoid doing m_pullup on incoming packets but that
* means avoiding dtom on the tcp reassembly code. That in turn means
* keeping an mbuf pointer in the reassembly queue (since we might
* have a cluster). As a quick hack, the source & destination
* port numbers (which are no longer needed once we've located the
* tcpcb) are overlayed with an mbuf pointer.
*/
#if defined(__amd64__) || defined(__aarch64__)
typedef uintptr_t mbufp_32;
#else
#if SIZEOF_CHAR_P == 4
typedef struct SLIRPmbuf *mbufp_32;
#else
typedef u_int32_t mbufp_32;
#endif
#endif
#define REASS_MBUF(ti) (*(mbufp_32 *)&((ti)->ti_t))
/*
* TCP statistics.
* Many of these should be kept per connection,
* but that's inconvenient at the moment.
*/
struct tcpstat {
u_long tcps_connattempt; /* connections initiated */
u_long tcps_accepts; /* connections accepted */
u_long tcps_connects; /* connections established */
u_long tcps_drops; /* connections dropped */
u_long tcps_conndrops; /* embryonic connections dropped */
u_long tcps_closed; /* conn. closed (includes drops) */
u_long tcps_segstimed; /* segs where we tried to get rtt */
u_long tcps_rttupdated; /* times we succeeded */
u_long tcps_delack; /* delayed acks sent */
u_long tcps_timeoutdrop; /* conn. dropped in rxmt timeout */
u_long tcps_rexmttimeo; /* retransmit timeouts */
u_long tcps_persisttimeo; /* persist timeouts */
u_long tcps_keeptimeo; /* keepalive timeouts */
u_long tcps_keepprobe; /* keepalive probes sent */
u_long tcps_keepdrops; /* connections dropped in keepalive */
u_long tcps_sndtotal; /* total packets sent */
u_long tcps_sndpack; /* data packets sent */
u_long tcps_sndbyte; /* data bytes sent */
u_long tcps_sndrexmitpack; /* data packets retransmitted */
u_long tcps_sndrexmitbyte; /* data bytes retransmitted */
u_long tcps_sndacks; /* ack-only packets sent */
u_long tcps_sndprobe; /* window probes sent */
u_long tcps_sndurg; /* packets sent with URG only */
u_long tcps_sndwinup; /* window update-only packets sent */
u_long tcps_sndctrl; /* control (SYN|FIN|RST) packets sent */
u_long tcps_rcvtotal; /* total packets received */
u_long tcps_rcvpack; /* packets received in sequence */
u_long tcps_rcvbyte; /* bytes received in sequence */
u_long tcps_rcvbadsum; /* packets received with ccksum errs */
u_long tcps_rcvbadoff; /* packets received with bad offset */
/* u_long tcps_rcvshort; */ /* packets received too short */
u_long tcps_rcvduppack; /* duplicate-only packets received */
u_long tcps_rcvdupbyte; /* duplicate-only bytes received */
u_long tcps_rcvpartduppack; /* packets with some duplicate data */
u_long tcps_rcvpartdupbyte; /* dup. bytes in part-dup. packets */
u_long tcps_rcvoopack; /* out-of-order packets received */
u_long tcps_rcvoobyte; /* out-of-order bytes received */
u_long tcps_rcvpackafterwin; /* packets with data after window */
u_long tcps_rcvbyteafterwin; /* bytes rcvd after window */
u_long tcps_rcvafterclose; /* packets rcvd after "close" */
u_long tcps_rcvwinprobe; /* rcvd window probe packets */
u_long tcps_rcvdupack; /* rcvd duplicate acks */
u_long tcps_rcvacktoomuch; /* rcvd acks for unsent data */
u_long tcps_rcvackpack; /* rcvd ack packets */
u_long tcps_rcvackbyte; /* bytes acked by rcvd acks */
u_long tcps_rcvwinupd; /* rcvd window update packets */
/* u_long tcps_pawsdrop; */ /* segments dropped due to PAWS */
u_long tcps_predack; /* times hdr predict ok for acks */
u_long tcps_preddat; /* times hdr predict ok for data pkts */
u_long tcps_socachemiss; /* tcp_last_so misses */
u_long tcps_didnuttin; /* Times tcp_output didn't do anything XXX */
};
extern struct tcpstat tcpstat; /* tcp statistics */
extern u_int32_t tcp_now; /* for RFC 1323 timestamps */
#endif #endif

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/* /*
* Copyright (c) 1982, 1986, 1993 * Copyright (c) 1982, 1986, 1993
* The Regents of the University of California. All rights reserved. * The Regents of the University of California. All rights reserved.
@@ -30,41 +31,74 @@
* tcpip.h,v 1.3 1994/08/21 05:27:40 paul Exp * tcpip.h,v 1.3 1994/08/21 05:27:40 paul Exp
*/ */
#ifndef _TCPIP_H_ #ifndef TCPIP_H
#define _TCPIP_H_ #define TCPIP_H
/* /*
* Tcp+ip header, after ip options removed. * Tcp+ip header, after ip options removed.
*/ */
struct tcpiphdr { struct tcpiphdr {
struct ipovly ti_i; /* overlaid ip structure */ struct mbuf_ptr ih_mbuf; /* backpointer to mbuf */
struct tcphdr ti_t; /* tcp header */ union {
struct {
struct in_addr ih_src; /* source internet address */
struct in_addr ih_dst; /* destination internet address */
uint8_t ih_x1; /* (unused) */
uint8_t ih_pr; /* protocol */
} ti_i4;
struct {
struct in6_addr ih_src;
struct in6_addr ih_dst;
uint8_t ih_x1;
uint8_t ih_nh;
} ti_i6;
} ti;
uint16_t ti_x0;
uint16_t ti_len; /* protocol length */
struct tcphdr ti_t; /* tcp header */
}; };
#define ti_next ti_i.ih_next #define ti_mbuf ih_mbuf.mptr
#define ti_prev ti_i.ih_prev #define ti_pr ti.ti_i4.ih_pr
#define ti_x1 ti_i.ih_x1 #define ti_src ti.ti_i4.ih_src
#define ti_pr ti_i.ih_pr #define ti_dst ti.ti_i4.ih_dst
#define ti_len ti_i.ih_len #define ti_src6 ti.ti_i6.ih_src
#define ti_src ti_i.ih_src #define ti_dst6 ti.ti_i6.ih_dst
#define ti_dst ti_i.ih_dst #define ti_nh6 ti.ti_i6.ih_nh
#define ti_sport ti_t.th_sport #define ti_sport ti_t.th_sport
#define ti_dport ti_t.th_dport #define ti_dport ti_t.th_dport
#define ti_seq ti_t.th_seq #define ti_seq ti_t.th_seq
#define ti_ack ti_t.th_ack #define ti_ack ti_t.th_ack
#define ti_x2 ti_t.th_x2 #define ti_x2 ti_t.th_x2
#define ti_off ti_t.th_off #define ti_off ti_t.th_off
#define ti_flags ti_t.th_flags #define ti_flags ti_t.th_flags
#define ti_win ti_t.th_win #define ti_win ti_t.th_win
#define ti_sum ti_t.th_sum #define ti_sum ti_t.th_sum
#define ti_urp ti_t.th_urp #define ti_urp ti_t.th_urp
#define tcpiphdr2qlink(T) \
((struct qlink *)(((char *)(T)) - sizeof(struct qlink)))
#define qlink2tcpiphdr(Q) \
((struct tcpiphdr *)(((char *)(Q)) + sizeof(struct qlink)))
#define tcpiphdr_next(T) qlink2tcpiphdr(tcpiphdr2qlink(T)->next)
#define tcpiphdr_prev(T) qlink2tcpiphdr(tcpiphdr2qlink(T)->prev)
#define tcpfrag_list_first(T) qlink2tcpiphdr((T)->seg_next)
#define tcpfrag_list_end(F, T) (tcpiphdr2qlink(F) == (struct qlink *)(T))
#define tcpfrag_list_empty(T) ((T)->seg_next == (struct tcpiphdr *)(T))
/* This is the difference between the size of a tcpiphdr structure, and the
* size of actual ip+tcp headers, rounded up since we need to align data. */
#define TCPIPHDR_DELTA \
(MAX(0, (sizeof(struct tcpiphdr) - sizeof(struct ip) - \
sizeof(struct tcphdr) + 3) & \
~3))
/* /*
* Just a clean way to get to the first byte * Just a clean way to get to the first byte
* of the packet * of the packet
*/ */
struct tcpiphdr_2 { struct tcpiphdr_2 {
struct tcpiphdr dummy; struct tcpiphdr dummy;
char first_char; char first_char;
}; };
#endif #endif

View File

@@ -1,8 +1,9 @@
/* SPDX-License-Identifier: MIT */
/* /*
* tftp.c - a simple, read-only tftp server for qemu * tftp.c - a simple, read-only tftp server for qemu
* *
* Copyright (c) 2004 Magnus Damm <damm@opensource.se> * Copyright (c) 2004 Magnus Damm <damm@opensource.se>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights * in the Software without restriction, including without limitation the rights
@@ -23,310 +24,441 @@
*/ */
#include "slirp.h" #include "slirp.h"
#include "../ibm.h"
struct tftp_session { #include <sys/types.h>
int in_use; #include <sys/stat.h>
char filename[TFTP_FILENAME_MAX]; #include <fcntl.h>
struct in_addr client_ip;
u_int16_t client_port;
int timestamp;
};
struct tftp_session tftp_sessions[TFTP_SESSIONS_MAX]; static inline int tftp_session_in_use(struct tftp_session *spt)
{
return (spt->slirp != NULL);
}
const char *tftp_prefix; static inline void tftp_session_update(struct tftp_session *spt)
static void tftp_session_update(struct tftp_session *spt)
{ {
spt->timestamp = curtime; spt->timestamp = curtime;
spt->in_use = 1;
} }
static void tftp_session_terminate(struct tftp_session *spt) static void tftp_session_terminate(struct tftp_session *spt)
{ {
spt->in_use = 0; if (spt->fd >= 0) {
} close(spt->fd);
spt->fd = -1;
static int tftp_session_allocate(struct tftp_t *tp)
{
struct tftp_session *spt;
int k;
for (k = 0; k < TFTP_SESSIONS_MAX; k++) {
spt = &tftp_sessions[k];
if (!spt->in_use)
goto found;
/* sessions time out after 5 inactive seconds */
if ((int)(curtime - spt->timestamp) > 5000)
goto found;
}
return -1;
found:
memset(spt, 0, sizeof(*spt));
memcpy(&spt->client_ip, &tp->ip.ip_src, sizeof(spt->client_ip));
spt->client_port = tp->udp.uh_sport;
tftp_session_update(spt);
return k;
}
static int tftp_session_find(struct tftp_t *tp)
{
struct tftp_session *spt;
int k;
for (k = 0; k < TFTP_SESSIONS_MAX; k++) {
spt = &tftp_sessions[k];
if (spt->in_use) {
if (!memcmp(&spt->client_ip, &tp->ip.ip_src, sizeof(spt->client_ip))) {
if (spt->client_port == tp->udp.uh_sport) {
return k;
}
}
} }
} g_free(spt->filename);
spt->slirp = NULL;
return -1;
} }
static int tftp_read_data(struct tftp_session *spt, u_int16_t block_nr, static int tftp_session_allocate(Slirp *slirp, struct sockaddr_storage *srcsas,
u_int8_t *buf, int len) struct tftp_t *tp)
{ {
int fd; struct tftp_session *spt;
int bytes_read = 0; int k;
char file_path[sizeof(pcempath) + 5 + sizeof(spt->filename)]; for (k = 0; k < TFTP_SESSIONS_MAX; k++) {
strcpy(file_path, pcempath); spt = &slirp->tftp_sessions[k];
strcat(file_path, "tftp/");
strcat(file_path, spt->filename);
fd = open(file_path, O_RDONLY | O_BINARY); if (!tftp_session_in_use(spt))
goto found;
if (fd < 0) { /* sessions time out after 5 inactive seconds */
return -1; if ((int)(curtime - spt->timestamp) > 5000) {
} tftp_session_terminate(spt);
goto found;
if (len) { }
lseek(fd, block_nr * 512, SEEK_SET); }
bytes_read = read(fd, buf, len);
}
close(fd);
return bytes_read;
}
static int tftp_send_error(struct tftp_session *spt,
u_int16_t errorcode, const char *msg,
struct tftp_t *recv_tp)
{
struct sockaddr_in saddr, daddr;
struct SLIRPmbuf *m;
struct tftp_t *tp;
int nobytes;
m = m_get();
if (!m) {
return -1;
}
memset(m->m_data, 0, m->m_size);
m->m_data += if_maxlinkhdr;
tp = (void *)m->m_data;
m->m_data += sizeof(struct udpiphdr);
tp->tp_op = htons(TFTP_ERROR);
tp->x.tp_error.tp_error_code = htons(errorcode);
strncpy((char *)tp->x.tp_error.tp_msg, msg, sizeof(tp->x.tp_error.tp_msg));
tp->x.tp_error.tp_msg[sizeof(tp->x.tp_error.tp_msg)-1] = 0;
saddr.sin_addr = recv_tp->ip.ip_dst;
saddr.sin_port = recv_tp->udp.uh_dport;
daddr.sin_addr = spt->client_ip;
daddr.sin_port = spt->client_port;
nobytes = 2;
m->m_len = sizeof(struct tftp_t) - 514 + 3 + strlen(msg) -
sizeof(struct ip) - sizeof(struct udphdr);
udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
tftp_session_terminate(spt);
return 0;
}
static int tftp_send_data(struct tftp_session *spt,
u_int16_t block_nr,
struct tftp_t *recv_tp)
{
struct sockaddr_in saddr, daddr;
struct SLIRPmbuf *m;
struct tftp_t *tp;
int nobytes;
if (block_nr < 1) {
return -1;
}
m = m_get();
if (!m) {
return -1;
}
memset(m->m_data, 0, m->m_size);
m->m_data += if_maxlinkhdr;
tp = (void *)m->m_data;
m->m_data += sizeof(struct udpiphdr);
tp->tp_op = htons(TFTP_DATA);
tp->x.tp_data.tp_block_nr = htons(block_nr);
saddr.sin_addr = recv_tp->ip.ip_dst;
saddr.sin_port = recv_tp->udp.uh_dport;
daddr.sin_addr = spt->client_ip;
daddr.sin_port = spt->client_port;
nobytes = tftp_read_data(spt, block_nr - 1, tp->x.tp_data.tp_buf, 512);
if (nobytes < 0) {
m_free(m);
/* send "file not found" error back */
tftp_send_error(spt, 1, "File not found", tp);
return -1; return -1;
}
m->m_len = sizeof(struct tftp_t) - (512 - nobytes) - found:
sizeof(struct ip) - sizeof(struct udphdr); memset(spt, 0, sizeof(*spt));
memcpy(&spt->client_addr, srcsas, sockaddr_size(srcsas));
spt->fd = -1;
spt->block_size = 512;
spt->client_port = tp->udp.uh_sport;
spt->slirp = slirp;
udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
if (nobytes == 512) {
tftp_session_update(spt); tftp_session_update(spt);
}
else { return k;
}
static int tftp_session_find(Slirp *slirp, struct sockaddr_storage *srcsas,
struct tftp_t *tp)
{
struct tftp_session *spt;
int k;
for (k = 0; k < TFTP_SESSIONS_MAX; k++) {
spt = &slirp->tftp_sessions[k];
if (tftp_session_in_use(spt)) {
if (sockaddr_equal(&spt->client_addr, srcsas)) {
if (spt->client_port == tp->udp.uh_sport) {
return k;
}
}
}
}
return -1;
}
static int tftp_read_data(struct tftp_session *spt, uint32_t block_nr,
uint8_t *buf, int len)
{
int bytes_read = 0;
if (spt->fd < 0) {
spt->fd = open(spt->filename, O_RDONLY | O_BINARY);
}
if (spt->fd < 0) {
return -1;
}
if (len) {
if (lseek(spt->fd, block_nr * spt->block_size, SEEK_SET) == (off_t)-1) {
return -1;
}
bytes_read = read(spt->fd, buf, len);
}
return bytes_read;
}
static struct tftp_t *tftp_prep_mbuf_data(struct tftp_session *spt,
struct mbuf *m)
{
struct tftp_t *tp;
memset(m->m_data, 0, m->m_size);
m->m_data += IF_MAXLINKHDR;
if (spt->client_addr.ss_family == AF_INET6) {
m->m_data += sizeof(struct ip6);
} else {
m->m_data += sizeof(struct ip);
}
tp = (void *)m->m_data;
m->m_data += sizeof(struct udphdr);
return tp;
}
static void tftp_udp_output(struct tftp_session *spt, struct mbuf *m,
struct tftp_t *recv_tp)
{
if (spt->client_addr.ss_family == AF_INET6) {
struct sockaddr_in6 sa6, da6;
sa6.sin6_addr = spt->slirp->vhost_addr6;
sa6.sin6_port = recv_tp->udp.uh_dport;
da6.sin6_addr = ((struct sockaddr_in6 *)&spt->client_addr)->sin6_addr;
da6.sin6_port = spt->client_port;
udp6_output(NULL, m, &sa6, &da6);
} else {
struct sockaddr_in sa4, da4;
sa4.sin_addr = spt->slirp->vhost_addr;
sa4.sin_port = recv_tp->udp.uh_dport;
da4.sin_addr = ((struct sockaddr_in *)&spt->client_addr)->sin_addr;
da4.sin_port = spt->client_port;
udp_output(NULL, m, &sa4, &da4, IPTOS_LOWDELAY);
}
}
static int tftp_send_oack(struct tftp_session *spt, const char *keys[],
uint32_t values[], int nb, struct tftp_t *recv_tp)
{
struct mbuf *m;
struct tftp_t *tp;
int i, n = 0;
m = m_get(spt->slirp);
if (!m)
return -1;
tp = tftp_prep_mbuf_data(spt, m);
tp->tp_op = htons(TFTP_OACK);
for (i = 0; i < nb; i++) {
n += slirp_fmt0(tp->x.tp_buf + n, sizeof(tp->x.tp_buf) - n, "%s", keys[i]);
n += slirp_fmt0(tp->x.tp_buf + n, sizeof(tp->x.tp_buf) - n, "%u", values[i]);
}
m->m_len = G_SIZEOF_MEMBER(struct tftp_t, tp_op) + n;
tftp_udp_output(spt, m, recv_tp);
return 0;
}
static void tftp_send_error(struct tftp_session *spt, uint16_t errorcode,
const char *msg, struct tftp_t *recv_tp)
{
struct mbuf *m;
struct tftp_t *tp;
DEBUG_TFTP("tftp error msg: %s", msg);
m = m_get(spt->slirp);
if (!m) {
goto out;
}
tp = tftp_prep_mbuf_data(spt, m);
tp->tp_op = htons(TFTP_ERROR);
tp->x.tp_error.tp_error_code = htons(errorcode);
slirp_pstrcpy((char *)tp->x.tp_error.tp_msg, sizeof(tp->x.tp_error.tp_msg),
msg);
m->m_len = sizeof(struct tftp_t) - (TFTP_BLOCKSIZE_MAX + 2) + 3 +
strlen(msg) - sizeof(struct udphdr);
tftp_udp_output(spt, m, recv_tp);
out:
tftp_session_terminate(spt); tftp_session_terminate(spt);
}
return 0;
} }
static void tftp_handle_rrq(struct tftp_t *tp, int pktlen) static void tftp_send_next_block(struct tftp_session *spt,
struct tftp_t *recv_tp)
{ {
struct tftp_session *spt; struct mbuf *m;
int s, k, n; struct tftp_t *tp;
u_int8_t *src, *dst; int nobytes;
s = tftp_session_allocate(tp); m = m_get(spt->slirp);
if (s < 0) { if (!m) {
return; return;
}
spt = &tftp_sessions[s];
src = tp->x.tp_buf;
dst = (u_int8_t *)spt->filename;
n = pktlen - ((uint8_t *)&tp->x.tp_buf[0] - (uint8_t *)tp);
/* get name */
for (k = 0; k < n; k++) {
if (k < TFTP_FILENAME_MAX) {
dst[k] = src[k];
} }
else {
return; tp = tftp_prep_mbuf_data(spt, m);
tp->tp_op = htons(TFTP_DATA);
tp->x.tp_data.tp_block_nr = htons((spt->block_nr + 1) & 0xffff);
nobytes = tftp_read_data(spt, spt->block_nr, tp->x.tp_data.tp_buf,
spt->block_size);
if (nobytes < 0) {
m_free(m);
/* send "file not found" error back */
tftp_send_error(spt, 1, "File not found", tp);
return;
} }
if (src[k] == '\0') { m->m_len = sizeof(struct tftp_t) - (TFTP_BLOCKSIZE_MAX - nobytes) -
break; sizeof(struct udphdr);
tftp_udp_output(spt, m, recv_tp);
if (nobytes == spt->block_size) {
tftp_session_update(spt);
} else {
tftp_session_terminate(spt);
} }
}
if (k >= n) {
return;
}
k++;
/* check mode */
if ((n - k) < 6) {
return;
}
if (memcmp(&src[k], "octet\0", 6) != 0) {
tftp_send_error(spt, 4, "Unsupported transfer mode", tp);
return;
}
pclog("tftp request: %s\n", spt->filename); spt->block_nr++;
/* do sanity checks on the filename */
if (strstr(spt->filename, "../") || strstr(spt->filename, "..\\")) {
tftp_send_error(spt, 2, "Access violation", tp);
return;
}
/* check if the file exists */
if (tftp_read_data(spt, 0, (u_int8_t *)spt->filename, 0) < 0) {
tftp_send_error(spt, 1, "File not found", tp);
return;
}
tftp_send_data(spt, 1, tp);
} }
static void tftp_handle_ack(struct tftp_t *tp, int pktlen) static void tftp_handle_rrq(Slirp *slirp, struct sockaddr_storage *srcsas,
struct tftp_t *tp, int pktlen)
{ {
int s; struct tftp_session *spt;
int s, k;
size_t prefix_len;
char *req_fname;
const char *option_name[2];
uint32_t option_value[2];
int nb_options = 0;
s = tftp_session_find(tp); /* check if a session already exists and if so terminate it */
s = tftp_session_find(slirp, srcsas, tp);
if (s >= 0) {
tftp_session_terminate(&slirp->tftp_sessions[s]);
}
if (s < 0) { s = tftp_session_allocate(slirp, srcsas, tp);
return;
}
if (tftp_send_data(&tftp_sessions[s], if (s < 0) {
ntohs(tp->x.tp_data.tp_block_nr) + 1, return;
tp) < 0) { }
return;
} spt = &slirp->tftp_sessions[s];
/* unspecified prefix means service disabled */
if (!slirp->tftp_prefix) {
tftp_send_error(spt, 2, "Access violation", tp);
return;
}
/* skip header fields */
k = 0;
pktlen -= offsetof(struct tftp_t, x.tp_buf);
/* prepend tftp_prefix */
prefix_len = strlen(slirp->tftp_prefix);
spt->filename = g_malloc(prefix_len + TFTP_FILENAME_MAX + 2);
memcpy(spt->filename, slirp->tftp_prefix, prefix_len);
spt->filename[prefix_len] = '/';
/* get name */
req_fname = spt->filename + prefix_len + 1;
while (1) {
if (k >= TFTP_FILENAME_MAX || k >= pktlen) {
tftp_send_error(spt, 2, "Access violation", tp);
return;
}
req_fname[k] = tp->x.tp_buf[k];
if (req_fname[k++] == '\0') {
break;
}
}
DEBUG_TFTP("tftp rrq file: %s", req_fname);
/* check mode */
if ((pktlen - k) < 6) {
tftp_send_error(spt, 2, "Access violation", tp);
return;
}
if (strcasecmp(&tp->x.tp_buf[k], "octet") != 0) {
tftp_send_error(spt, 4, "Unsupported transfer mode", tp);
return;
}
k += 6; /* skipping octet */
/* do sanity checks on the filename */
if (
#ifdef G_OS_WIN32
strstr(req_fname, "..\\") ||
req_fname[strlen(req_fname) - 1] == '\\' ||
#endif
strstr(req_fname, "../") ||
req_fname[strlen(req_fname) - 1] == '/') {
tftp_send_error(spt, 2, "Access violation", tp);
return;
}
/* check if the file exists */
if (tftp_read_data(spt, 0, NULL, 0) < 0) {
tftp_send_error(spt, 1, "File not found", tp);
return;
}
if (tp->x.tp_buf[pktlen - 1] != 0) {
tftp_send_error(spt, 2, "Access violation", tp);
return;
}
while (k < pktlen && nb_options < G_N_ELEMENTS(option_name)) {
const char *key, *value;
key = &tp->x.tp_buf[k];
k += strlen(key) + 1;
if (k >= pktlen) {
tftp_send_error(spt, 2, "Access violation", tp);
return;
}
value = &tp->x.tp_buf[k];
k += strlen(value) + 1;
if (strcasecmp(key, "tsize") == 0) {
int tsize = atoi(value);
struct stat stat_p;
if (tsize == 0) {
if (stat(spt->filename, &stat_p) == 0)
tsize = stat_p.st_size;
else {
tftp_send_error(spt, 1, "File not found", tp);
return;
}
}
option_name[nb_options] = "tsize";
option_value[nb_options] = tsize;
nb_options++;
} else if (strcasecmp(key, "blksize") == 0) {
int blksize = atoi(value);
/* Accept blksize up to our maximum size */
if (blksize > 0) {
spt->block_size = MIN(blksize, TFTP_BLOCKSIZE_MAX);
option_name[nb_options] = "blksize";
option_value[nb_options] = spt->block_size;
nb_options++;
}
}
}
if (nb_options > 0) {
assert(nb_options <= G_N_ELEMENTS(option_name));
tftp_send_oack(spt, option_name, option_value, nb_options, tp);
return;
}
spt->block_nr = 0;
tftp_send_next_block(spt, tp);
} }
void tftp_input(struct SLIRPmbuf *m) static void tftp_handle_ack(Slirp *slirp, struct sockaddr_storage *srcsas,
struct tftp_t *tp, int pktlen)
{ {
struct tftp_t *tp = (struct tftp_t *)m->m_data; int s;
switch(ntohs(tp->tp_op)) { s = tftp_session_find(slirp, srcsas, tp);
case TFTP_RRQ:
tftp_handle_rrq(tp, m->m_len);
break;
case TFTP_ACK: if (s < 0) {
tftp_handle_ack(tp, m->m_len); return;
break; }
}
tftp_send_next_block(&slirp->tftp_sessions[s], tp);
}
static void tftp_handle_error(Slirp *slirp, struct sockaddr_storage *srcsas,
struct tftp_t *tp, int pktlen)
{
int s;
s = tftp_session_find(slirp, srcsas, tp);
if (s < 0) {
return;
}
tftp_session_terminate(&slirp->tftp_sessions[s]);
}
void tftp_input(struct sockaddr_storage *srcsas, struct mbuf *m)
{
struct tftp_t *tp = (struct tftp_t *)m->m_data;
switch (ntohs(tp->tp_op)) {
case TFTP_RRQ:
tftp_handle_rrq(m->slirp, srcsas, tp, m->m_len);
break;
case TFTP_ACK:
tftp_handle_ack(m->slirp, srcsas, tp, m->m_len);
break;
case TFTP_ERROR:
tftp_handle_error(m->slirp, srcsas, tp, m->m_len);
break;
}
} }

View File

@@ -1,40 +1,54 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/* tftp defines */ /* tftp defines */
#define TFTP_SESSIONS_MAX 3 #ifndef SLIRP_TFTP_H
#define SLIRP_TFTP_H
#define TFTP_SERVER 69 #include "util.h"
#define TFTP_RRQ 1 #define TFTP_SESSIONS_MAX 20
#define TFTP_WRQ 2
#define TFTP_DATA 3 #define TFTP_SERVER 69
#define TFTP_ACK 4
#define TFTP_ERROR 5 #define TFTP_RRQ 1
#define TFTP_WRQ 2
#define TFTP_DATA 3
#define TFTP_ACK 4
#define TFTP_ERROR 5
#define TFTP_OACK 6
#define TFTP_FILENAME_MAX 512 #define TFTP_FILENAME_MAX 512
#define TFTP_BLOCKSIZE_MAX 1428
#ifdef PRAGMA_PACK_SUPPORTED
#pragma pack(1)
#endif
struct tftp_t { struct tftp_t {
struct ip ip; struct udphdr udp;
struct udphdr udp; uint16_t tp_op;
u_int16_t tp_op; union {
union { struct {
struct { uint16_t tp_block_nr;
u_int16_t tp_block_nr; uint8_t tp_buf[TFTP_BLOCKSIZE_MAX];
u_int8_t tp_buf[512]; } tp_data;
} tp_data; struct {
struct { uint16_t tp_error_code;
u_int16_t tp_error_code; uint8_t tp_msg[TFTP_BLOCKSIZE_MAX];
u_int8_t tp_msg[512]; } tp_error;
} tp_error; char tp_buf[TFTP_BLOCKSIZE_MAX + 2];
u_int8_t tp_buf[512 + 2]; } x;
} x; } SLIRP_PACKED;
} PACKED__;
struct tftp_session {
Slirp *slirp;
char *filename;
int fd;
uint16_t block_size;
struct sockaddr_storage client_addr;
uint16_t client_port;
uint32_t block_nr;
int timestamp;
};
void tftp_input(struct sockaddr_storage *srcsas, struct mbuf *m);
#ifdef PRAGMA_PACK_SUPPORTED
#pragma pack(PACK_END)
#endif #endif
void tftp_input(struct SLIRPmbuf *m);

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/* /*
* Copyright (c) 1982, 1986, 1988, 1990, 1993 * Copyright (c) 1982, 1986, 1988, 1990, 1993
* The Regents of the University of California. All rights reserved. * The Regents of the University of California. All rights reserved.
@@ -33,649 +34,332 @@
/* /*
* Changes and additions relating to SLiRP * Changes and additions relating to SLiRP
* Copyright (c) 1995 Danny Gasparovski. * Copyright (c) 1995 Danny Gasparovski.
* *
* Please read the file COPYRIGHT for the * Please read the file COPYRIGHT for the
* terms and conditions of the copyright. * terms and conditions of the copyright.
*/ */
#include <stdlib.h>
#ifndef _WIN32
# include <unistd.h>
#endif
#include "slirp.h" #include "slirp.h"
#include "ip_icmp.h" #include "ip_icmp.h"
struct udpstat udpstat; static uint8_t udp_tos(struct socket *so);
struct SLIRPsocket udb; void udp_init(Slirp *slirp)
/*
* UDP protocol implementation.
* Per RFC 768, August, 1980.
*/
#ifndef COMPAT_42
int udpcksum = 1;
#else
int udpcksum = 0; /* XXX */
#endif
struct SLIRPsocket *udp_last_so = &udb;
void
udp_init()
{ {
udb.so_next = udb.so_prev = &udb; slirp->udb.so_next = slirp->udb.so_prev = &slirp->udb;
slirp->udp_last_so = &slirp->udb;
} }
/* m->m_data points at ip packet header
* m->m_len length ip packet void udp_cleanup(Slirp *slirp)
{
struct socket *so, *so_next;
for (so = slirp->udb.so_next; so != &slirp->udb; so = so_next) {
so_next = so->so_next;
udp_detach(slirp->udb.so_next);
}
}
/* m->m_data points at ip packet header
* m->m_len length ip packet
* ip->ip_len length data (IPDU) * ip->ip_len length data (IPDU)
*/ */
void void udp_input(register struct mbuf *m, int iphlen)
udp_input(m, iphlen)
struct SLIRPmbuf *m;
int iphlen;
{ {
struct ip *ip; Slirp *slirp = m->slirp;
struct udphdr *uh; register struct ip *ip;
/* struct SLIRPmbuf *opts = 0;*/ register struct udphdr *uh;
int len; int len;
struct ip save_ip; struct ip save_ip;
struct SLIRPsocket *so; struct socket *so;
struct sockaddr_storage lhost;
DEBUG_CALL("udp_input"); struct sockaddr_in *lhost4;
DEBUG_ARG("m = %lx", (long)m);
DEBUG_ARG("iphlen = %d", iphlen);
udpstat.udps_ipackets++;
/* DEBUG_CALL("udp_input");
* Strip IP options, if any; should skip this, DEBUG_ARG("m = %p", m);
* make available to user, and use on returned packets, DEBUG_ARG("iphlen = %d", iphlen);
* but we don't yet have a way to check the checksum
* with options still present.
*/
if(iphlen > sizeof(struct ip)) {
ip_stripoptions(m, (struct SLIRPmbuf *)0);
iphlen = sizeof(struct ip);
}
/*
* Get IP and UDP header together in first SLIRPmbuf.
*/
ip = mtod(m, struct ip *);
uh = (struct udphdr *)((SLIRPcaddr_t)ip + iphlen);
/*
* Make SLIRPmbuf data length reflect UDP length.
* If not enough data to reflect UDP length, drop.
*/
len = ntohs((u_int16_t)uh->uh_ulen);
if (ip->ip_len != len) {
if (len > ip->ip_len) {
udpstat.udps_badlen++;
goto bad;
}
m_adj(m, len - ip->ip_len);
ip->ip_len = len;
}
/*
* Save a copy of the IP header in case we want restore it
* for sending an ICMP error message in response.
*/
save_ip = *ip;
save_ip.ip_len+= iphlen; /* tcp_input subtracts this */
/*
* Checksum extended UDP header and data.
*/
if (udpcksum && uh->uh_sum) {
((struct ipovly *)ip)->ih_next = 0;
((struct ipovly *)ip)->ih_prev = 0;
((struct ipovly *)ip)->ih_x1 = 0;
((struct ipovly *)ip)->ih_len = uh->uh_ulen;
/* keep uh_sum for ICMP reply
* uh->uh_sum = cksum(m, len + sizeof (struct ip));
* if (uh->uh_sum) {
*/
if(cksum(m, len + sizeof(struct ip))) {
udpstat.udps_badsum++;
goto bad;
}
}
/*
* handle DHCP/BOOTP
*/
if (ntohs(uh->uh_dport) == BOOTP_SERVER) {
bootp_input(m);
goto bad;
}
#ifdef NEED_TFTP
/*
* handle TFTP
*/
if (ntohs(uh->uh_dport) == TFTP_SERVER) {
tftp_input(m);
goto bad;
}
#endif
/*
* Locate pcb for datagram.
*/
so = udp_last_so;
if (so->so_lport != uh->uh_sport ||
so->so_laddr.s_addr != ip->ip_src.s_addr) {
struct SLIRPsocket *tmp;
for (tmp = udb.so_next; tmp != &udb; tmp = tmp->so_next) {
if (tmp->so_lport == uh->uh_sport &&
tmp->so_laddr.s_addr == ip->ip_src.s_addr) {
tmp->so_faddr.s_addr = ip->ip_dst.s_addr;
tmp->so_fport = uh->uh_dport;
so = tmp;
break;
}
}
if (tmp == &udb) {
so = NULL;
} else {
udpstat.udpps_pcbcachemiss++;
udp_last_so = so;
}
}
if (so == NULL) {
/*
* If there's no socket for this packet,
* create one
*/
if ((so = socreate()) == NULL) goto bad;
if(udp_attach(so) == -1) {
DEBUG_MISC((dfd," udp_attach errno = %d-%s\n",
errno,strerror(errno)));
sofree(so);
goto bad;
}
/*
* Setup fields
*/
/* udp_last_so = so; */
so->so_laddr = ip->ip_src;
so->so_lport = uh->uh_sport;
if ((so->so_iptos = udp_tos(so)) == 0)
so->so_iptos = ip->ip_tos;
/*
* XXXXX Here, check if it's in udpexec_list,
* and if it is, do the fork_exec() etc.
*/
}
so->so_faddr = ip->ip_dst; /* XXX */
so->so_fport = uh->uh_dport; /* XXX */
iphlen += sizeof(struct udphdr);
m->m_len -= iphlen;
m->m_data += iphlen;
/*
* Now we sendto() the packet.
*/
if (so->so_emu)
udp_emu(so, m);
if(sosendto(so,m) == -1) {
m->m_len += iphlen;
m->m_data -= iphlen;
*ip=save_ip;
DEBUG_MISC((dfd,"udp tx errno = %d-%s\n",errno,strerror(errno)));
icmp_error(m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,strerror(errno));
}
m_free(so->so_m); /* used for ICMP if error on sorecvfrom */
/* restore the orig SLIRPmbuf packet */
m->m_len += iphlen;
m->m_data -= iphlen;
*ip=save_ip;
so->so_m=m; /* ICMP backup */
return;
bad:
m_freem(m);
/* if (opts) m_freem(opts); */
return;
}
int udp_output2(struct SLIRPsocket *so, struct SLIRPmbuf *m,
struct sockaddr_in *saddr, struct sockaddr_in *daddr,
int iptos)
{
struct udpiphdr *ui;
int error = 0;
DEBUG_CALL("udp_output");
DEBUG_ARG("so = %lx", (long)so);
DEBUG_ARG("m = %lx", (long)m);
DEBUG_ARG("saddr = %lx", (long)saddr->sin_addr.s_addr);
DEBUG_ARG("daddr = %lx", (long)daddr->sin_addr.s_addr);
/*
* Adjust for header
*/
m->m_data -= sizeof(struct udpiphdr);
m->m_len += sizeof(struct udpiphdr);
/*
* Fill in SLIRPmbuf with extended UDP header
* and addresses and length put into network format.
*/
ui = mtod(m, struct udpiphdr *);
ui->ui_next = ui->ui_prev = 0;
ui->ui_x1 = 0;
ui->ui_pr = IPPROTO_UDP;
ui->ui_len = htons(m->m_len - sizeof(struct ip)); /* + sizeof (struct udphdr)); */
/* XXXXX Check for from-one-location sockets, or from-any-location sockets */
ui->ui_src = saddr->sin_addr;
ui->ui_dst = daddr->sin_addr;
ui->ui_sport = saddr->sin_port;
ui->ui_dport = daddr->sin_port;
ui->ui_ulen = ui->ui_len;
/*
* Stuff checksum and output datagram.
*/
ui->ui_sum = 0;
if (udpcksum) {
if ((ui->ui_sum = cksum(m, /* sizeof (struct udpiphdr) + */ m->m_len)) == 0)
ui->ui_sum = 0xffff;
}
((struct ip *)ui)->ip_len = m->m_len;
((struct ip *)ui)->ip_ttl = ip_defttl;
((struct ip *)ui)->ip_tos = iptos;
udpstat.udps_opackets++;
error = ip_output(so, m);
return (error);
}
int udp_output(struct SLIRPsocket *so, struct SLIRPmbuf *m,
struct sockaddr_in *addr)
{
struct sockaddr_in saddr, daddr;
saddr = *addr;
if ((so->so_faddr.s_addr & htonl(0xffffff00)) == special_addr.s_addr) {
saddr.sin_addr.s_addr = so->so_faddr.s_addr;
if ((so->so_faddr.s_addr & htonl(0x000000ff)) == htonl(0xff))
saddr.sin_addr.s_addr = alias_addr.s_addr;
}
daddr.sin_addr = so->so_laddr;
daddr.sin_port = so->so_lport;
return udp_output2(so, m, &saddr, &daddr, so->so_iptos);
}
int
udp_attach(so)
struct SLIRPsocket *so;
{
struct sockaddr_in addr;
if((so->s = socket(AF_INET,SOCK_DGRAM,0)) != -1) {
/* /*
* Here, we bind() the socket. Although not really needed * Strip IP options, if any; should skip this,
* (sendto() on an unbound socket will bind it), it's done * make available to user, and use on returned packets,
* here so that emulation of ytalk etc. don't have to do it * but we don't yet have a way to check the checksum
* with options still present.
*/ */
memset(&addr, 0, sizeof(struct sockaddr_in)); if (iphlen > sizeof(struct ip)) {
addr.sin_family = AF_INET; ip_stripoptions(m, (struct mbuf *)0);
addr.sin_port = 0; iphlen = sizeof(struct ip);
addr.sin_addr.s_addr = INADDR_ANY;
if(bind(so->s, (struct sockaddr *)&addr, sizeof(addr))<0) {
int lasterrno=errno;
closesocket(so->s);
so->s=-1;
#ifdef _WIN32
WSASetLastError(lasterrno);
#else
errno=lasterrno;
#endif
} else {
/* success, insert in queue */
so->so_expire = curtime + SO_EXPIRE;
insque(so,&udb);
} }
}
return(so->s); /*
* Get IP and UDP header together in first mbuf.
*/
ip = mtod(m, struct ip *);
uh = (struct udphdr *)((char *)ip + iphlen);
/*
* Make mbuf data length reflect UDP length.
* If not enough data to reflect UDP length, drop.
*/
len = ntohs((uint16_t)uh->uh_ulen);
if (ip->ip_len != len) {
if (len > ip->ip_len) {
goto bad;
}
m_adj(m, len - ip->ip_len);
ip->ip_len = len;
}
/*
* Save a copy of the IP header in case we want restore it
* for sending an ICMP error message in response.
*/
save_ip = *ip;
save_ip.ip_len += iphlen; /* tcp_input subtracts this */
/*
* Checksum extended UDP header and data.
*/
if (uh->uh_sum) {
memset(&((struct ipovly *)ip)->ih_mbuf, 0, sizeof(struct mbuf_ptr));
((struct ipovly *)ip)->ih_x1 = 0;
((struct ipovly *)ip)->ih_len = uh->uh_ulen;
if (cksum(m, len + sizeof(struct ip))) {
goto bad;
}
}
lhost.ss_family = AF_INET;
lhost4 = (struct sockaddr_in *)&lhost;
lhost4->sin_addr = ip->ip_src;
lhost4->sin_port = uh->uh_sport;
/*
* handle DHCP/BOOTP
*/
if (ntohs(uh->uh_dport) == BOOTP_SERVER &&
(ip->ip_dst.s_addr == slirp->vhost_addr.s_addr ||
ip->ip_dst.s_addr == 0xffffffff)) {
bootp_input(m);
goto bad;
}
/*
* handle TFTP
*/
if (ntohs(uh->uh_dport) == TFTP_SERVER &&
ip->ip_dst.s_addr == slirp->vhost_addr.s_addr) {
m->m_data += iphlen;
m->m_len -= iphlen;
tftp_input(&lhost, m);
m->m_data -= iphlen;
m->m_len += iphlen;
goto bad;
}
if (slirp->restricted) {
goto bad;
}
/*
* Locate pcb for datagram.
*/
so = solookup(&slirp->udp_last_so, &slirp->udb, &lhost, NULL);
if (so == NULL) {
/*
* If there's no socket for this packet,
* create one
*/
so = socreate(slirp);
if (udp_attach(so, AF_INET) == -1) {
DEBUG_MISC(" udp_attach errno = %d-%s", errno, strerror(errno));
sofree(so);
goto bad;
}
/*
* Setup fields
*/
so->so_lfamily = AF_INET;
so->so_laddr = ip->ip_src;
so->so_lport = uh->uh_sport;
if ((so->so_iptos = udp_tos(so)) == 0)
so->so_iptos = ip->ip_tos;
/*
* XXXXX Here, check if it's in udpexec_list,
* and if it is, do the fork_exec() etc.
*/
}
so->so_ffamily = AF_INET;
so->so_faddr = ip->ip_dst; /* XXX */
so->so_fport = uh->uh_dport; /* XXX */
iphlen += sizeof(struct udphdr);
m->m_len -= iphlen;
m->m_data += iphlen;
/*
* Now we sendto() the packet.
*/
if (sosendto(so, m) == -1) {
m->m_len += iphlen;
m->m_data -= iphlen;
*ip = save_ip;
DEBUG_MISC("udp tx errno = %d-%s", errno, strerror(errno));
icmp_send_error(m, ICMP_UNREACH, ICMP_UNREACH_NET, 0, strerror(errno));
goto bad;
}
m_free(so->so_m); /* used for ICMP if error on sorecvfrom */
/* restore the orig mbuf packet */
m->m_len += iphlen;
m->m_data -= iphlen;
*ip = save_ip;
so->so_m = m; /* ICMP backup */
return;
bad:
m_free(m);
} }
void int udp_output(struct socket *so, struct mbuf *m, struct sockaddr_in *saddr,
udp_detach(so) struct sockaddr_in *daddr, int iptos)
struct SLIRPsocket *so;
{ {
closesocket(so->s); register struct udpiphdr *ui;
/* if (so->so_m) m_free(so->so_m); done by sofree */ int error = 0;
sofree(so); DEBUG_CALL("udp_output");
DEBUG_ARG("so = %p", so);
DEBUG_ARG("m = %p", m);
DEBUG_ARG("saddr = %s", inet_ntoa(saddr->sin_addr));
DEBUG_ARG("daddr = %s", inet_ntoa(daddr->sin_addr));
/*
* Adjust for header
*/
m->m_data -= sizeof(struct udpiphdr);
m->m_len += sizeof(struct udpiphdr);
/*
* Fill in mbuf with extended UDP header
* and addresses and length put into network format.
*/
ui = mtod(m, struct udpiphdr *);
memset(&ui->ui_i.ih_mbuf, 0, sizeof(struct mbuf_ptr));
ui->ui_x1 = 0;
ui->ui_pr = IPPROTO_UDP;
ui->ui_len = htons(m->m_len - sizeof(struct ip));
/* XXXXX Check for from-one-location sockets, or from-any-location sockets
*/
ui->ui_src = saddr->sin_addr;
ui->ui_dst = daddr->sin_addr;
ui->ui_sport = saddr->sin_port;
ui->ui_dport = daddr->sin_port;
ui->ui_ulen = ui->ui_len;
/*
* Stuff checksum and output datagram.
*/
ui->ui_sum = 0;
if ((ui->ui_sum = cksum(m, m->m_len)) == 0)
ui->ui_sum = 0xffff;
((struct ip *)ui)->ip_len = m->m_len;
((struct ip *)ui)->ip_ttl = IPDEFTTL;
((struct ip *)ui)->ip_tos = iptos;
error = ip_output(so, m);
return (error);
} }
struct tos_t udptos[] = { int udp_attach(struct socket *so, unsigned short af)
{0, 53, IPTOS_LOWDELAY, 0}, /* DNS */
{517, 517, IPTOS_LOWDELAY, EMU_TALK}, /* talk */
{518, 518, IPTOS_LOWDELAY, EMU_NTALK}, /* ntalk */
{0, 7648, IPTOS_LOWDELAY, EMU_CUSEEME}, /* Cu-Seeme */
{0, 0, 0, 0}
};
u_int8_t
udp_tos(so)
struct SLIRPsocket *so;
{ {
int i = 0; so->s = slirp_socket(af, SOCK_DGRAM, 0);
if (so->s != -1) {
while(udptos[i].tos) { if (slirp_bind_outbound(so, af) != 0) {
if ((udptos[i].fport && ntohs(so->so_fport) == udptos[i].fport) || // bind failed - close socket
(udptos[i].lport && ntohs(so->so_lport) == udptos[i].lport)) { closesocket(so->s);
so->so_emu = udptos[i].emu; so->s = -1;
return udptos[i].tos; return -1;
} }
i++; so->so_expire = curtime + SO_EXPIRE;
} insque(so, &so->slirp->udb);
}
return 0; return (so->s);
} }
#ifdef EMULATE_TALK void udp_detach(struct socket *so)
#include "talkd.h"
#endif
/*
* Here, talk/ytalk/ntalk requests must be emulated
*/
void
udp_emu(so, m)
struct SLIRPsocket *so;
struct SLIRPmbuf *m;
{ {
struct sockaddr_in addr; so->slirp->cb->unregister_poll_fd(so->s, so->slirp->opaque);
socklen_t addrlen = sizeof(addr); closesocket(so->s);
#ifdef EMULATE_TALK sofree(so);
CTL_MSG_OLD *omsg;
CTL_MSG *nmsg;
char buff[sizeof(CTL_MSG)];
u_char type;
struct talk_request {
struct talk_request *next;
struct SLIRPsocket *udp_so;
struct SLIRPsocket *tcp_so;
} *req;
static struct talk_request *req_tbl = 0;
#endif
struct cu_header {
uint16_t d_family; // destination family
uint16_t d_port; // destination port
uint32_t d_addr; // destination address
uint16_t s_family; // source family
uint16_t s_port; // source port
uint32_t so_addr; // source address
uint32_t seqn; // sequence number
uint16_t message; // message
uint16_t data_type; // data type
uint16_t pkt_len; // packet length
} *cu_head;
switch(so->so_emu) {
#ifdef EMULATE_TALK
case EMU_TALK:
case EMU_NTALK:
/*
* Talk emulation. We always change the ctl_addr to get
* some answers from the daemon. When an ANNOUNCE comes,
* we send LEAVE_INVITE to the local daemons. Also when a
* DELETE comes, we send copies to the local daemons.
*/
if (getsockname(so->s, (struct sockaddr *)&addr, &addrlen) < 0)
return;
#define IS_OLD (so->so_emu == EMU_TALK)
#define COPY_MSG(dest, src) { dest->type = src->type; \
dest->id_num = src->id_num; \
dest->pid = src->pid; \
dest->addr = src->addr; \
dest->ctl_addr = src->ctl_addr; \
memcpy(&dest->l_name, &src->l_name, NAME_SIZE_OLD); \
memcpy(&dest->r_name, &src->r_name, NAME_SIZE_OLD); \
memcpy(&dest->r_tty, &src->r_tty, TTY_SIZE); }
#define OTOSIN(ptr, field) ((struct sockaddr_in *)&ptr->field)
/* old_sockaddr to sockaddr_in */
if (IS_OLD) { /* old talk */
omsg = mtod(m, CTL_MSG_OLD*);
nmsg = (CTL_MSG *) buff;
type = omsg->type;
OTOSIN(omsg, ctl_addr)->sin_port = addr.sin_port;
OTOSIN(omsg, ctl_addr)->sin_addr = our_addr;
strncpy(omsg->l_name, getlogin(), NAME_SIZE_OLD);
} else { /* new talk */
omsg = (CTL_MSG_OLD *) buff;
nmsg = mtod(m, CTL_MSG *);
type = nmsg->type;
OTOSIN(nmsg, ctl_addr)->sin_port = addr.sin_port;
OTOSIN(nmsg, ctl_addr)->sin_addr = our_addr;
strncpy(nmsg->l_name, getlogin(), NAME_SIZE_OLD);
}
if (type == LOOK_UP)
return; /* for LOOK_UP this is enough */
if (IS_OLD) { /* make a copy of the message */
COPY_MSG(nmsg, omsg);
nmsg->vers = 1;
nmsg->answer = 0;
} else
COPY_MSG(omsg, nmsg);
/*
* If if is an ANNOUNCE message, we go through the
* request table to see if a tcp port has already
* been redirected for this socket. If not, we solisten()
* a new socket and add this entry to the table.
* The port number of the tcp socket and our IP
* are put to the addr field of the message structures.
* Then a LEAVE_INVITE is sent to both local daemon
* ports, 517 and 518. This is why we have two copies
* of the message, one in old talk and one in new talk
* format.
*/
if (type == ANNOUNCE) {
int s;
u_short temp_port;
for(req = req_tbl; req; req = req->next)
if (so == req->udp_so)
break; /* found it */
if (!req) { /* no entry for so, create new */
req = (struct talk_request *)
malloc(sizeof(struct talk_request));
req->udp_so = so;
req->tcp_so = solisten(0,
OTOSIN(omsg, addr)->sin_addr.s_addr,
OTOSIN(omsg, addr)->sin_port,
SS_FACCEPTONCE);
req->next = req_tbl;
req_tbl = req;
}
/* replace port number in addr field */
addrlen = sizeof(addr);
getsockname(req->tcp_so->s,
(struct sockaddr *) &addr,
&addrlen);
OTOSIN(omsg, addr)->sin_port = addr.sin_port;
OTOSIN(omsg, addr)->sin_addr = our_addr;
OTOSIN(nmsg, addr)->sin_port = addr.sin_port;
OTOSIN(nmsg, addr)->sin_addr = our_addr;
/* send LEAVE_INVITEs */
temp_port = OTOSIN(omsg, ctl_addr)->sin_port;
OTOSIN(omsg, ctl_addr)->sin_port = 0;
OTOSIN(nmsg, ctl_addr)->sin_port = 0;
omsg->type = nmsg->type = LEAVE_INVITE;
s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
addr.sin_addr = our_addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(517);
sendto(s, (char *)omsg, sizeof(*omsg), 0,
(struct sockaddr *)&addr, sizeof(addr));
addr.sin_port = htons(518);
sendto(s, (char *)nmsg, sizeof(*nmsg), 0,
(struct sockaddr *) &addr, sizeof(addr));
closesocket(s) ;
omsg->type = nmsg->type = ANNOUNCE;
OTOSIN(omsg, ctl_addr)->sin_port = temp_port;
OTOSIN(nmsg, ctl_addr)->sin_port = temp_port;
}
/*
* If it is a DELETE message, we send a copy to the
* local daemons. Then we delete the entry corresponding
* to our socket from the request table.
*/
if (type == DELETE) {
struct talk_request *temp_req, *req_next;
int s;
u_short temp_port;
temp_port = OTOSIN(omsg, ctl_addr)->sin_port;
OTOSIN(omsg, ctl_addr)->sin_port = 0;
OTOSIN(nmsg, ctl_addr)->sin_port = 0;
s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
addr.sin_addr = our_addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(517);
sendto(s, (char *)omsg, sizeof(*omsg), 0,
(struct sockaddr *)&addr, sizeof(addr));
addr.sin_port = htons(518);
sendto(s, (char *)nmsg, sizeof(*nmsg), 0,
(struct sockaddr *)&addr, sizeof(addr));
closesocket(s);
OTOSIN(omsg, ctl_addr)->sin_port = temp_port;
OTOSIN(nmsg, ctl_addr)->sin_port = temp_port;
/* delete table entry */
if (so == req_tbl->udp_so) {
temp_req = req_tbl;
req_tbl = req_tbl->next;
free(temp_req);
} else {
temp_req = req_tbl;
for(req = req_tbl->next; req; req = req_next) {
req_next = req->next;
if (so == req->udp_so) {
temp_req->next = req_next;
free(req);
break;
} else {
temp_req = req;
}
}
}
}
return;
#endif
case EMU_CUSEEME:
/*
* Cu-SeeMe emulation.
* Hopefully the packet is more that 16 bytes long. We don't
* do any other tests, just replace the address and port
* fields.
*/
if (m->m_len >= sizeof (*cu_head)) {
if (getsockname(so->s, (struct sockaddr *)&addr, &addrlen) < 0)
return;
cu_head = mtod(m, struct cu_header *);
cu_head->s_port = addr.sin_port;
cu_head->so_addr = our_addr.s_addr;
}
return;
}
} }
struct SLIRPsocket * static const struct tos_t udptos[] = { { 0, 53, IPTOS_LOWDELAY, 0 }, /* DNS */
udp_listen(port, laddr, lport, flags) { 0, 0, 0, 0 } };
u_int port;
u_int32_t laddr; static uint8_t udp_tos(struct socket *so)
u_int lport;
int flags;
{ {
struct sockaddr_in addr; int i = 0;
struct SLIRPsocket *so;
socklen_t addrlen = sizeof(struct sockaddr_in);
int opt = 1;
if ((so = socreate()) == NULL) {
free(so);
return NULL;
}
so->s = socket(AF_INET,SOCK_DGRAM,0);
so->so_expire = curtime + SO_EXPIRE;
insque(so,&udb);
memset(&addr, 0, sizeof(struct sockaddr_in)); while (udptos[i].tos) {
addr.sin_family = AF_INET; if ((udptos[i].fport && ntohs(so->so_fport) == udptos[i].fport) ||
addr.sin_addr.s_addr = INADDR_ANY; (udptos[i].lport && ntohs(so->so_lport) == udptos[i].lport)) {
addr.sin_port = port; if (so->slirp->enable_emu)
so->so_emu = udptos[i].emu;
return udptos[i].tos;
}
i++;
}
if (bind(so->s,(struct sockaddr *)&addr, addrlen) < 0) { return 0;
udp_detach(so); }
return NULL;
} struct socket *udp_listen(Slirp *slirp, uint32_t haddr, unsigned hport,
setsockopt(so->s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int)); uint32_t laddr, unsigned lport, int flags)
/* setsockopt(so->s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int)); */ {
/* TODO: IPv6 */
getsockname(so->s,(struct sockaddr *)&addr,&addrlen); struct sockaddr_in addr;
so->so_fport = addr.sin_port; struct socket *so;
if (addr.sin_addr.s_addr == 0 || addr.sin_addr.s_addr == loopback_addr.s_addr) socklen_t addrlen = sizeof(struct sockaddr_in);
so->so_faddr = alias_addr;
else memset(&addr, 0, sizeof(addr));
so->so_faddr = addr.sin_addr; so = socreate(slirp);
so->s = slirp_socket(AF_INET, SOCK_DGRAM, 0);
so->so_lport = lport; if (so->s < 0) {
so->so_laddr.s_addr = laddr; sofree(so);
if (flags != SS_FACCEPTONCE) return NULL;
so->so_expire = 0; }
so->so_expire = curtime + SO_EXPIRE;
so->so_state = SS_ISFCONNECTED; insque(so, &slirp->udb);
return so; addr.sin_family = AF_INET;
addr.sin_addr.s_addr = haddr;
addr.sin_port = hport;
if (bind(so->s, (struct sockaddr *)&addr, addrlen) < 0) {
udp_detach(so);
return NULL;
}
slirp_socket_set_fast_reuse(so->s);
getsockname(so->s, (struct sockaddr *)&addr, &addrlen);
so->fhost.sin = addr;
sotranslate_accept(so);
so->so_lfamily = AF_INET;
so->so_lport = lport;
so->so_laddr.s_addr = laddr;
if (flags != SS_FACCEPTONCE)
so->so_expire = 0;
so->so_state &= SS_PERSISTENT_MASK;
so->so_state |= SS_ISFCONNECTED | flags;
return so;
} }

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/* /*
* Copyright (c) 1982, 1986, 1993 * Copyright (c) 1982, 1986, 1993
* The Regents of the University of California. All rights reserved. * The Regents of the University of California. All rights reserved.
@@ -30,85 +31,60 @@
* udp.h,v 1.3 1994/08/21 05:27:41 paul Exp * udp.h,v 1.3 1994/08/21 05:27:41 paul Exp
*/ */
#ifndef _UDP_H_ #ifndef UDP_H
#define _UDP_H_ #define UDP_H
#define UDP_TTL 0x60 #define UDP_TTL 0x60
#define UDP_UDPDATALEN 16192 #define UDP_UDPDATALEN 16192
extern struct SLIRPsocket *udp_last_so;
/* /*
* Udp protocol header. * Udp protocol header.
* Per RFC 768, September, 1981. * Per RFC 768, September, 1981.
*/ */
#ifdef PRAGMA_PACK_SUPPORTED
#pragma pack(1)
#endif
struct udphdr { struct udphdr {
u_int16_t uh_sport; /* source port */ uint16_t uh_sport; /* source port */
u_int16_t uh_dport; /* destination port */ uint16_t uh_dport; /* destination port */
int16_t uh_ulen; /* udp length */ int16_t uh_ulen; /* udp length */
u_int16_t uh_sum; /* udp checksum */ uint16_t uh_sum; /* udp checksum */
} PACKED__; };
#ifdef PRAGMA_PACK_SUPPORTED
#pragma pack(PACK_END)
#endif
/* /*
* UDP kernel structures and variables. * UDP kernel structures and variables.
*/ */
struct udpiphdr { struct udpiphdr {
struct ipovly ui_i; /* overlaid ip structure */ struct ipovly ui_i; /* overlaid ip structure */
struct udphdr ui_u; /* udp header */ struct udphdr ui_u; /* udp header */
};
#define ui_next ui_i.ih_next
#define ui_prev ui_i.ih_prev
#define ui_x1 ui_i.ih_x1
#define ui_pr ui_i.ih_pr
#define ui_len ui_i.ih_len
#define ui_src ui_i.ih_src
#define ui_dst ui_i.ih_dst
#define ui_sport ui_u.uh_sport
#define ui_dport ui_u.uh_dport
#define ui_ulen ui_u.uh_ulen
#define ui_sum ui_u.uh_sum
struct udpstat {
/* input statistics: */
u_long udps_ipackets; /* total input packets */
u_long udps_hdrops; /* packet shorter than header */
u_long udps_badsum; /* checksum error */
u_long udps_badlen; /* data length larger than packet */
u_long udps_noport; /* no socket on port */
u_long udps_noportbcast; /* of above, arrived as broadcast */
u_long udps_fullsock; /* not delivered, input socket full */
u_long udpps_pcbcachemiss; /* input packets missing pcb cache */
/* output statistics: */
u_long udps_opackets; /* total output packets */
}; };
#define ui_mbuf ui_i.ih_mbuf.mptr
#define ui_x1 ui_i.ih_x1
#define ui_pr ui_i.ih_pr
#define ui_len ui_i.ih_len
#define ui_src ui_i.ih_src
#define ui_dst ui_i.ih_dst
#define ui_sport ui_u.uh_sport
#define ui_dport ui_u.uh_dport
#define ui_ulen ui_u.uh_ulen
#define ui_sum ui_u.uh_sum
/* /*
* Names for UDP sysctl objects * Names for UDP sysctl objects
*/ */
#define UDPCTL_CHECKSUM 1 /* checksum UDP packets */ #define UDPCTL_CHECKSUM 1 /* checksum UDP packets */
#define UDPCTL_MAXID 2 #define UDPCTL_MAXID 2
extern struct udpstat udpstat; struct mbuf;
extern struct SLIRPsocket udb;
struct SLIRPmbuf; void udp_init(Slirp *);
void udp_cleanup(Slirp *);
void udp_input(register struct mbuf *, int);
int udp_attach(struct socket *, unsigned short af);
void udp_detach(struct socket *);
struct socket *udp_listen(Slirp *, uint32_t, unsigned, uint32_t, unsigned, int);
int udp_output(struct socket *so, struct mbuf *m, struct sockaddr_in *saddr,
struct sockaddr_in *daddr, int iptos);
void udp6_input(register struct mbuf *);
int udp6_output(struct socket *so, struct mbuf *m, struct sockaddr_in6 *saddr,
struct sockaddr_in6 *daddr);
void udp_init _P((void));
void udp_input _P((register struct SLIRPmbuf *, int));
int udp_output _P((struct SLIRPsocket *, struct SLIRPmbuf *, struct sockaddr_in *));
int udp_attach _P((struct SLIRPsocket *));
void udp_detach _P((struct SLIRPsocket *));
u_int8_t udp_tos _P((struct SLIRPsocket *));
void udp_emu _P((struct SLIRPsocket *, struct SLIRPmbuf *));
struct SLIRPsocket * udp_listen _P((u_int, u_int32_t, u_int, int));
int udp_output2(struct SLIRPsocket *so, struct SLIRPmbuf *m,
struct sockaddr_in *saddr, struct sockaddr_in *daddr,
int iptos);
#endif #endif

173
src/network/slirp/udp6.c Normal file
View File

@@ -0,0 +1,173 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/*
* Copyright (c) 2013
* Guillaume Subiron
*/
#include "slirp.h"
#include "udp.h"
#include "dhcpv6.h"
void udp6_input(struct mbuf *m)
{
Slirp *slirp = m->slirp;
struct ip6 *ip, save_ip;
struct udphdr *uh;
int iphlen = sizeof(struct ip6);
int len;
struct socket *so;
struct sockaddr_in6 lhost;
DEBUG_CALL("udp6_input");
DEBUG_ARG("m = %p", m);
if (slirp->restricted) {
goto bad;
}
ip = mtod(m, struct ip6 *);
m->m_len -= iphlen;
m->m_data += iphlen;
uh = mtod(m, struct udphdr *);
m->m_len += iphlen;
m->m_data -= iphlen;
if (ip6_cksum(m)) {
goto bad;
}
len = ntohs((uint16_t)uh->uh_ulen);
/*
* Make mbuf data length reflect UDP length.
* If not enough data to reflect UDP length, drop.
*/
if (ntohs(ip->ip_pl) != len) {
if (len > ntohs(ip->ip_pl)) {
goto bad;
}
m_adj(m, len - ntohs(ip->ip_pl));
ip->ip_pl = htons(len);
}
/*
* Save a copy of the IP header in case we want restore it
* for sending an ICMP error message in response.
*/
save_ip = *ip;
/* Locate pcb for datagram. */
lhost.sin6_family = AF_INET6;
lhost.sin6_addr = ip->ip_src;
lhost.sin6_port = uh->uh_sport;
/* handle DHCPv6 */
if (ntohs(uh->uh_dport) == DHCPV6_SERVER_PORT &&
(in6_equal(&ip->ip_dst, &slirp->vhost_addr6) ||
in6_dhcp_multicast(&ip->ip_dst))) {
m->m_data += iphlen;
m->m_len -= iphlen;
dhcpv6_input(&lhost, m);
m->m_data -= iphlen;
m->m_len += iphlen;
goto bad;
}
/* handle TFTP */
if (ntohs(uh->uh_dport) == TFTP_SERVER &&
!memcmp(ip->ip_dst.s6_addr, slirp->vhost_addr6.s6_addr, 16)) {
m->m_data += iphlen;
m->m_len -= iphlen;
tftp_input((struct sockaddr_storage *)&lhost, m);
m->m_data -= iphlen;
m->m_len += iphlen;
goto bad;
}
so = solookup(&slirp->udp_last_so, &slirp->udb,
(struct sockaddr_storage *)&lhost, NULL);
if (so == NULL) {
/* If there's no socket for this packet, create one. */
so = socreate(slirp);
if (udp_attach(so, AF_INET6) == -1) {
DEBUG_MISC(" udp6_attach errno = %d-%s", errno, strerror(errno));
sofree(so);
goto bad;
}
/* Setup fields */
so->so_lfamily = AF_INET6;
so->so_laddr6 = ip->ip_src;
so->so_lport6 = uh->uh_sport;
}
so->so_ffamily = AF_INET6;
so->so_faddr6 = ip->ip_dst; /* XXX */
so->so_fport6 = uh->uh_dport; /* XXX */
iphlen += sizeof(struct udphdr);
m->m_len -= iphlen;
m->m_data += iphlen;
/*
* Now we sendto() the packet.
*/
if (sosendto(so, m) == -1) {
m->m_len += iphlen;
m->m_data -= iphlen;
*ip = save_ip;
DEBUG_MISC("udp tx errno = %d-%s", errno, strerror(errno));
icmp6_send_error(m, ICMP6_UNREACH, ICMP6_UNREACH_NO_ROUTE);
goto bad;
}
m_free(so->so_m); /* used for ICMP if error on sorecvfrom */
/* restore the orig mbuf packet */
m->m_len += iphlen;
m->m_data -= iphlen;
*ip = save_ip;
so->so_m = m;
return;
bad:
m_free(m);
}
int udp6_output(struct socket *so, struct mbuf *m, struct sockaddr_in6 *saddr,
struct sockaddr_in6 *daddr)
{
struct ip6 *ip;
struct udphdr *uh;
DEBUG_CALL("udp6_output");
DEBUG_ARG("so = %p", so);
DEBUG_ARG("m = %p", m);
/* adjust for header */
m->m_data -= sizeof(struct udphdr);
m->m_len += sizeof(struct udphdr);
uh = mtod(m, struct udphdr *);
m->m_data -= sizeof(struct ip6);
m->m_len += sizeof(struct ip6);
ip = mtod(m, struct ip6 *);
/* Build IP header */
ip->ip_pl = htons(m->m_len - sizeof(struct ip6));
ip->ip_nh = IPPROTO_UDP;
ip->ip_src = saddr->sin6_addr;
ip->ip_dst = daddr->sin6_addr;
/* Build UDP header */
uh->uh_sport = saddr->sin6_port;
uh->uh_dport = daddr->sin6_port;
uh->uh_ulen = ip->ip_pl;
uh->uh_sum = 0;
uh->uh_sum = ip6_cksum(m);
if (uh->uh_sum == 0) {
uh->uh_sum = 0xffff;
}
return ip6_output(so, m, 0);
}

428
src/network/slirp/util.c Normal file
View File

@@ -0,0 +1,428 @@
/* SPDX-License-Identifier: MIT */
/*
* util.c (mostly based on QEMU os-win32.c)
*
* Copyright (c) 2003-2008 Fabrice Bellard
* Copyright (c) 2010-2016 Red Hat, Inc.
*
* QEMU library functions for win32 which are shared between QEMU and
* the QEMU tools.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "util.h"
#include <tinyglib.h>
#include <fcntl.h>
#include <stdint.h>
#if defined(_WIN32)
int slirp_inet_aton(const char *cp, struct in_addr *ia)
{
uint32_t addr = inet_addr(cp);
if (addr == 0xffffffff) {
return 0;
}
ia->s_addr = addr;
return 1;
}
#endif
void slirp_set_nonblock(int fd)
{
#ifndef _WIN32
int f;
f = fcntl(fd, F_GETFL);
assert(f != -1);
f = fcntl(fd, F_SETFL, f | O_NONBLOCK);
assert(f != -1);
#else
unsigned long opt = 1;
ioctlsocket(fd, FIONBIO, &opt);
#endif
}
static void slirp_set_cloexec(int fd)
{
#ifndef _WIN32
int f;
f = fcntl(fd, F_GETFD);
assert(f != -1);
f = fcntl(fd, F_SETFD, f | FD_CLOEXEC);
assert(f != -1);
#endif
}
/*
* Opens a socket with FD_CLOEXEC set
*/
int slirp_socket(int domain, int type, int protocol)
{
int ret;
#ifdef SOCK_CLOEXEC
ret = socket(domain, type | SOCK_CLOEXEC, protocol);
if (ret != -1 || errno != EINVAL) {
return ret;
}
#endif
ret = socket(domain, type, protocol);
if (ret >= 0) {
slirp_set_cloexec(ret);
}
return ret;
}
#ifdef _WIN32
static int socket_error(void)
{
switch (WSAGetLastError()) {
case 0:
return 0;
case WSAEINTR:
return EINTR;
case WSAEINVAL:
return EINVAL;
case WSA_INVALID_HANDLE:
return EBADF;
case WSA_NOT_ENOUGH_MEMORY:
return ENOMEM;
case WSA_INVALID_PARAMETER:
return EINVAL;
case WSAENAMETOOLONG:
return ENAMETOOLONG;
case WSAENOTEMPTY:
return ENOTEMPTY;
case WSAEWOULDBLOCK:
/* not using EWOULDBLOCK as we don't want code to have
* to check both EWOULDBLOCK and EAGAIN */
return EAGAIN;
case WSAEINPROGRESS:
return EINPROGRESS;
case WSAEALREADY:
return EALREADY;
case WSAENOTSOCK:
return ENOTSOCK;
case WSAEDESTADDRREQ:
return EDESTADDRREQ;
case WSAEMSGSIZE:
return EMSGSIZE;
case WSAEPROTOTYPE:
return EPROTOTYPE;
case WSAENOPROTOOPT:
return ENOPROTOOPT;
case WSAEPROTONOSUPPORT:
return EPROTONOSUPPORT;
case WSAEOPNOTSUPP:
return EOPNOTSUPP;
case WSAEAFNOSUPPORT:
return EAFNOSUPPORT;
case WSAEADDRINUSE:
return EADDRINUSE;
case WSAEADDRNOTAVAIL:
return EADDRNOTAVAIL;
case WSAENETDOWN:
return ENETDOWN;
case WSAENETUNREACH:
return ENETUNREACH;
case WSAENETRESET:
return ENETRESET;
case WSAECONNABORTED:
return ECONNABORTED;
case WSAECONNRESET:
return ECONNRESET;
case WSAENOBUFS:
return ENOBUFS;
case WSAEISCONN:
return EISCONN;
case WSAENOTCONN:
return ENOTCONN;
case WSAETIMEDOUT:
return ETIMEDOUT;
case WSAECONNREFUSED:
return ECONNREFUSED;
case WSAELOOP:
return ELOOP;
case WSAEHOSTUNREACH:
return EHOSTUNREACH;
default:
return EIO;
}
}
#undef ioctlsocket
int slirp_ioctlsocket_wrap(int fd, int req, void *val)
{
int ret;
ret = ioctlsocket(fd, req, val);
if (ret < 0) {
errno = socket_error();
}
return ret;
}
#undef closesocket
int slirp_closesocket_wrap(int fd)
{
int ret;
ret = closesocket(fd);
if (ret < 0) {
errno = socket_error();
}
return ret;
}
#undef connect
int slirp_connect_wrap(int sockfd, const struct sockaddr *addr, int addrlen)
{
int ret;
ret = connect(sockfd, addr, addrlen);
if (ret < 0) {
errno = socket_error();
}
return ret;
}
#undef listen
int slirp_listen_wrap(int sockfd, int backlog)
{
int ret;
ret = listen(sockfd, backlog);
if (ret < 0) {
errno = socket_error();
}
return ret;
}
#undef bind
int slirp_bind_wrap(int sockfd, const struct sockaddr *addr, int addrlen)
{
int ret;
ret = bind(sockfd, addr, addrlen);
if (ret < 0) {
errno = socket_error();
}
return ret;
}
#undef socket
int slirp_socket_wrap(int domain, int type, int protocol)
{
int ret;
ret = socket(domain, type, protocol);
if (ret < 0) {
errno = socket_error();
}
return ret;
}
#undef accept
int slirp_accept_wrap(int sockfd, struct sockaddr *addr, int *addrlen)
{
int ret;
ret = accept(sockfd, addr, addrlen);
if (ret < 0) {
errno = socket_error();
}
return ret;
}
#undef shutdown
int slirp_shutdown_wrap(int sockfd, int how)
{
int ret;
ret = shutdown(sockfd, how);
if (ret < 0) {
errno = socket_error();
}
return ret;
}
#undef getsockopt
int slirp_getsockopt_wrap(int sockfd, int level, int optname, void *optval,
int *optlen)
{
int ret;
ret = getsockopt(sockfd, level, optname, optval, optlen);
if (ret < 0) {
errno = socket_error();
}
return ret;
}
#undef setsockopt
int slirp_setsockopt_wrap(int sockfd, int level, int optname,
const void *optval, int optlen)
{
int ret;
ret = setsockopt(sockfd, level, optname, optval, optlen);
if (ret < 0) {
errno = socket_error();
}
return ret;
}
#undef getpeername
int slirp_getpeername_wrap(int sockfd, struct sockaddr *addr, int *addrlen)
{
int ret;
ret = getpeername(sockfd, addr, addrlen);
if (ret < 0) {
errno = socket_error();
}
return ret;
}
#undef getsockname
int slirp_getsockname_wrap(int sockfd, struct sockaddr *addr, int *addrlen)
{
int ret;
ret = getsockname(sockfd, addr, addrlen);
if (ret < 0) {
errno = socket_error();
}
return ret;
}
#undef send
ssize_t slirp_send_wrap(int sockfd, const void *buf, size_t len, int flags)
{
int ret;
ret = send(sockfd, buf, len, flags);
if (ret < 0) {
errno = socket_error();
}
return ret;
}
#undef sendto
ssize_t slirp_sendto_wrap(int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *addr, int addrlen)
{
int ret;
ret = sendto(sockfd, buf, len, flags, addr, addrlen);
if (ret < 0) {
errno = socket_error();
}
return ret;
}
#undef recv
ssize_t slirp_recv_wrap(int sockfd, void *buf, size_t len, int flags)
{
int ret;
ret = recv(sockfd, buf, len, flags);
if (ret < 0) {
errno = socket_error();
}
return ret;
}
#undef recvfrom
ssize_t slirp_recvfrom_wrap(int sockfd, void *buf, size_t len, int flags,
struct sockaddr *addr, int *addrlen)
{
int ret;
ret = recvfrom(sockfd, buf, len, flags, addr, addrlen);
if (ret < 0) {
errno = socket_error();
}
return ret;
}
#endif /* WIN32 */
void slirp_pstrcpy(char *buf, int buf_size, const char *str)
{
int c;
char *q = buf;
if (buf_size <= 0)
return;
for (;;) {
c = *str++;
if (c == 0 || q >= buf + buf_size - 1)
break;
*q++ = c;
}
*q = '\0';
}
static int slirp_vsnprintf(char *str, size_t size,
const char *format, va_list args)
{
int rv = g_vsnprintf(str, size, format, args);
if (rv < 0) {
g_error("g_vsnprintf() failed: %s", g_strerror(errno));
}
return rv;
}
/*
* A snprintf()-like function that:
* - returns the number of bytes written (excluding optional \0-ending)
* - dies on error
* - warn on truncation
*/
int slirp_fmt(char *str, size_t size, const char *format, ...)
{
va_list args;
int rv;
va_start(args, format);
rv = slirp_vsnprintf(str, size, format, args);
va_end(args);
if (rv >= size) {
g_critical("slirp_fmt() truncation");
}
return MIN(rv, size);
}
/*
* A snprintf()-like function that:
* - always \0-end (unless size == 0)
* - returns the number of bytes actually written, including \0 ending
* - dies on error
* - warn on truncation
*/
int slirp_fmt0(char *str, size_t size, const char *format, ...)
{
va_list args;
int rv;
va_start(args, format);
rv = slirp_vsnprintf(str, size, format, args);
va_end(args);
if (rv >= size) {
g_critical("slirp_fmt0() truncation");
if (size > 0)
str[size - 1] = '\0';
rv = size;
} else {
rv += 1; /* include \0 */
}
return rv;
}

189
src/network/slirp/util.h Normal file
View File

@@ -0,0 +1,189 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright (c) 2003-2008 Fabrice Bellard
* Copyright (c) 2010-2019 Red Hat, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef UTIL_H_
#define UTIL_H_
#include <tinyglib.h>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <inttypes.h>
#ifdef _WIN32
#include <winsock2.h>
#include <windows.h>
#else
#include <sys/socket.h>
#include <netinet/tcp.h>
#include <netinet/in.h>
#endif
#if defined(_WIN32) && (defined(__x86_64__) || defined(__i386__))
#define SLIRP_PACKED __attribute__((gcc_struct, packed))
#else
#define SLIRP_PACKED __attribute__((packed))
#endif
#ifndef DIV_ROUND_UP
#define DIV_ROUND_UP(n, d) (((n) + (d)-1) / (d))
#endif
#ifndef container_of
#define container_of(ptr, type, member) \
__extension__({ \
void *__mptr = (void *)(ptr); \
((type *)(__mptr - offsetof(type, member))); \
})
#endif
#ifndef G_SIZEOF_MEMBER
#define G_SIZEOF_MEMBER(type, member) sizeof(((type *)0)->member)
#endif
#if defined(_WIN32) /* CONFIG_IOVEC */
#if !defined(IOV_MAX) /* XXX: to avoid duplicate with QEMU osdep.h */
struct iovec {
void *iov_base;
size_t iov_len;
};
#endif
#else
#include <sys/uio.h>
#endif
#define stringify(s) tostring(s)
#define tostring(s) #s
#define SCALE_MS 1000000
#define ETH_ALEN 6
#define ETH_HLEN 14
#define ETH_P_IP (0x0800) /* Internet Protocol packet */
#define ETH_P_ARP (0x0806) /* Address Resolution packet */
#define ETH_P_IPV6 (0x86dd)
#define ETH_P_VLAN (0x8100)
#define ETH_P_DVLAN (0x88a8)
#define ETH_P_NCSI (0x88f8)
#define ETH_P_UNKNOWN (0xffff)
/* FIXME: remove me when made standalone */
#ifdef _WIN32
#undef accept
#undef bind
#undef closesocket
#undef connect
#undef getpeername
#undef getsockname
#undef getsockopt
#undef ioctlsocket
#undef listen
#undef recv
#undef recvfrom
#undef send
#undef sendto
#undef setsockopt
#undef shutdown
#undef socket
#endif
#ifdef _WIN32
#define connect slirp_connect_wrap
int slirp_connect_wrap(int fd, const struct sockaddr *addr, int addrlen);
#define listen slirp_listen_wrap
int slirp_listen_wrap(int fd, int backlog);
#define bind slirp_bind_wrap
int slirp_bind_wrap(int fd, const struct sockaddr *addr, int addrlen);
#define socket slirp_socket_wrap
int slirp_socket_wrap(int domain, int type, int protocol);
#define accept slirp_accept_wrap
int slirp_accept_wrap(int fd, struct sockaddr *addr, int *addrlen);
#define shutdown slirp_shutdown_wrap
int slirp_shutdown_wrap(int fd, int how);
#define getpeername slirp_getpeername_wrap
int slirp_getpeername_wrap(int fd, struct sockaddr *addr, int *addrlen);
#define getsockname slirp_getsockname_wrap
int slirp_getsockname_wrap(int fd, struct sockaddr *addr, int *addrlen);
#define send slirp_send_wrap
ssize_t slirp_send_wrap(int fd, const void *buf, size_t len, int flags);
#define sendto slirp_sendto_wrap
ssize_t slirp_sendto_wrap(int fd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, int addrlen);
#define recv slirp_recv_wrap
ssize_t slirp_recv_wrap(int fd, void *buf, size_t len, int flags);
#define recvfrom slirp_recvfrom_wrap
ssize_t slirp_recvfrom_wrap(int fd, void *buf, size_t len, int flags,
struct sockaddr *src_addr, int *addrlen);
#define closesocket slirp_closesocket_wrap
int slirp_closesocket_wrap(int fd);
#define ioctlsocket slirp_ioctlsocket_wrap
int slirp_ioctlsocket_wrap(int fd, int req, void *val);
#define getsockopt slirp_getsockopt_wrap
int slirp_getsockopt_wrap(int sockfd, int level, int optname, void *optval,
int *optlen);
#define setsockopt slirp_setsockopt_wrap
int slirp_setsockopt_wrap(int sockfd, int level, int optname,
const void *optval, int optlen);
#define inet_aton slirp_inet_aton
int slirp_inet_aton(const char *cp, struct in_addr *ia);
#else
#define closesocket(s) close(s)
#define ioctlsocket(s, r, v) ioctl(s, r, v)
#endif
int slirp_socket(int domain, int type, int protocol);
void slirp_set_nonblock(int fd);
static inline int slirp_socket_set_nodelay(int fd)
{
int v = 1;
return setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &v, sizeof(v));
}
static inline int slirp_socket_set_fast_reuse(int fd)
{
#ifndef _WIN32
int v = 1;
return setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &v, sizeof(v));
#else
/* Enabling the reuse of an endpoint that was used by a socket still in
* TIME_WAIT state is usually performed by setting SO_REUSEADDR. On Windows
* fast reuse is the default and SO_REUSEADDR does strange things. So we
* don't have to do anything here. More info can be found at:
* http://msdn.microsoft.com/en-us/library/windows/desktop/ms740621.aspx */
return 0;
#endif
}
void slirp_pstrcpy(char *buf, int buf_size, const char *str);
int slirp_fmt(char *str, size_t size, const char *format, ...) G_GNUC_PRINTF(3, 4);
int slirp_fmt0(char *str, size_t size, const char *format, ...) G_GNUC_PRINTF(3, 4);
#endif

View File

@@ -0,0 +1,8 @@
/* SPDX-License-Identifier: BSD-3-Clause */
#include "libslirp.h"
const char *
slirp_version_string(void)
{
return SLIRP_VERSION_STRING;
}

444
src/network/slirp/vmstate.c Normal file
View File

@@ -0,0 +1,444 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/*
* VMState interpreter
*
* Copyright (c) 2009-2018 Red Hat Inc
*
* Authors:
* Juan Quintela <quintela@redhat.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <assert.h>
#include <errno.h>
#include <string.h>
#include <tinyglib.h>
#include "stream.h"
#include "vmstate.h"
static int get_nullptr(SlirpIStream *f, void *pv, size_t size,
const VMStateField *field)
{
if (slirp_istream_read_u8(f) == VMS_NULLPTR_MARKER) {
return 0;
}
g_warning("vmstate: get_nullptr expected VMS_NULLPTR_MARKER");
return -EINVAL;
}
static int put_nullptr(SlirpOStream *f, void *pv, size_t size,
const VMStateField *field)
{
if (pv == NULL) {
slirp_ostream_write_u8(f, VMS_NULLPTR_MARKER);
return 0;
}
g_warning("vmstate: put_nullptr must be called with pv == NULL");
return -EINVAL;
}
const VMStateInfo slirp_vmstate_info_nullptr = {
.name = "uint64",
.get = get_nullptr,
.put = put_nullptr,
};
/* 8 bit unsigned int */
static int get_uint8(SlirpIStream *f, void *pv, size_t size,
const VMStateField *field)
{
uint8_t *v = pv;
*v = slirp_istream_read_u8(f);
return 0;
}
static int put_uint8(SlirpOStream *f, void *pv, size_t size,
const VMStateField *field)
{
uint8_t *v = pv;
slirp_ostream_write_u8(f, *v);
return 0;
}
const VMStateInfo slirp_vmstate_info_uint8 = {
.name = "uint8",
.get = get_uint8,
.put = put_uint8,
};
/* 16 bit unsigned int */
static int get_uint16(SlirpIStream *f, void *pv, size_t size,
const VMStateField *field)
{
uint16_t *v = pv;
*v = slirp_istream_read_u16(f);
return 0;
}
static int put_uint16(SlirpOStream *f, void *pv, size_t size,
const VMStateField *field)
{
uint16_t *v = pv;
slirp_ostream_write_u16(f, *v);
return 0;
}
const VMStateInfo slirp_vmstate_info_uint16 = {
.name = "uint16",
.get = get_uint16,
.put = put_uint16,
};
/* 32 bit unsigned int */
static int get_uint32(SlirpIStream *f, void *pv, size_t size,
const VMStateField *field)
{
uint32_t *v = pv;
*v = slirp_istream_read_u32(f);
return 0;
}
static int put_uint32(SlirpOStream *f, void *pv, size_t size,
const VMStateField *field)
{
uint32_t *v = pv;
slirp_ostream_write_u32(f, *v);
return 0;
}
const VMStateInfo slirp_vmstate_info_uint32 = {
.name = "uint32",
.get = get_uint32,
.put = put_uint32,
};
/* 16 bit int */
static int get_int16(SlirpIStream *f, void *pv, size_t size,
const VMStateField *field)
{
int16_t *v = pv;
*v = slirp_istream_read_i16(f);
return 0;
}
static int put_int16(SlirpOStream *f, void *pv, size_t size,
const VMStateField *field)
{
int16_t *v = pv;
slirp_ostream_write_i16(f, *v);
return 0;
}
const VMStateInfo slirp_vmstate_info_int16 = {
.name = "int16",
.get = get_int16,
.put = put_int16,
};
/* 32 bit int */
static int get_int32(SlirpIStream *f, void *pv, size_t size,
const VMStateField *field)
{
int32_t *v = pv;
*v = slirp_istream_read_i32(f);
return 0;
}
static int put_int32(SlirpOStream *f, void *pv, size_t size,
const VMStateField *field)
{
int32_t *v = pv;
slirp_ostream_write_i32(f, *v);
return 0;
}
const VMStateInfo slirp_vmstate_info_int32 = {
.name = "int32",
.get = get_int32,
.put = put_int32,
};
/* vmstate_info_tmp, see VMSTATE_WITH_TMP, the idea is that we allocate
* a temporary buffer and the pre_load/pre_save methods in the child vmsd
* copy stuff from the parent into the child and do calculations to fill
* in fields that don't really exist in the parent but need to be in the
* stream.
*/
static int get_tmp(SlirpIStream *f, void *pv, size_t size,
const VMStateField *field)
{
int ret;
const VMStateDescription *vmsd = field->vmsd;
int version_id = field->version_id;
void *tmp = g_malloc(size);
/* Writes the parent field which is at the start of the tmp */
*(void **)tmp = pv;
ret = slirp_vmstate_load_state(f, vmsd, tmp, version_id);
g_free(tmp);
return ret;
}
static int put_tmp(SlirpOStream *f, void *pv, size_t size,
const VMStateField *field)
{
const VMStateDescription *vmsd = field->vmsd;
void *tmp = g_malloc(size);
int ret;
/* Writes the parent field which is at the start of the tmp */
*(void **)tmp = pv;
ret = slirp_vmstate_save_state(f, vmsd, tmp);
g_free(tmp);
return ret;
}
const VMStateInfo slirp_vmstate_info_tmp = {
.name = "tmp",
.get = get_tmp,
.put = put_tmp,
};
/* uint8_t buffers */
static int get_buffer(SlirpIStream *f, void *pv, size_t size,
const VMStateField *field)
{
slirp_istream_read(f, pv, size);
return 0;
}
static int put_buffer(SlirpOStream *f, void *pv, size_t size,
const VMStateField *field)
{
slirp_ostream_write(f, pv, size);
return 0;
}
const VMStateInfo slirp_vmstate_info_buffer = {
.name = "buffer",
.get = get_buffer,
.put = put_buffer,
};
static int vmstate_n_elems(void *opaque, const VMStateField *field)
{
int n_elems = 1;
if (field->flags & VMS_ARRAY) {
n_elems = field->num;
} else if (field->flags & VMS_VARRAY_INT32) {
n_elems = *(int32_t *)(opaque + field->num_offset);
} else if (field->flags & VMS_VARRAY_UINT32) {
n_elems = *(uint32_t *)(opaque + field->num_offset);
} else if (field->flags & VMS_VARRAY_UINT16) {
n_elems = *(uint16_t *)(opaque + field->num_offset);
} else if (field->flags & VMS_VARRAY_UINT8) {
n_elems = *(uint8_t *)(opaque + field->num_offset);
}
if (field->flags & VMS_MULTIPLY_ELEMENTS) {
n_elems *= field->num;
}
return n_elems;
}
static int vmstate_size(void *opaque, const VMStateField *field)
{
int size = field->size;
if (field->flags & VMS_VBUFFER) {
size = *(int32_t *)(opaque + field->size_offset);
if (field->flags & VMS_MULTIPLY) {
size *= field->size;
}
}
return size;
}
static int vmstate_save_state_v(SlirpOStream *f, const VMStateDescription *vmsd,
void *opaque, int version_id)
{
int ret = 0;
const VMStateField *field = vmsd->fields;
if (vmsd->pre_save) {
ret = vmsd->pre_save(opaque);
if (ret) {
g_warning("pre-save failed: %s", vmsd->name);
return ret;
}
}
while (field->name) {
if ((field->field_exists && field->field_exists(opaque, version_id)) ||
(!field->field_exists && field->version_id <= version_id)) {
void *first_elem = opaque + field->offset;
int i, n_elems = vmstate_n_elems(opaque, field);
int size = vmstate_size(opaque, field);
if (field->flags & VMS_POINTER) {
first_elem = *(void **)first_elem;
assert(first_elem || !n_elems || !size);
}
for (i = 0; i < n_elems; i++) {
void *curr_elem = first_elem + size * i;
if (field->flags & VMS_ARRAY_OF_POINTER) {
assert(curr_elem);
curr_elem = *(void **)curr_elem;
}
if (!curr_elem && size) {
/* if null pointer write placeholder and do not follow */
assert(field->flags & VMS_ARRAY_OF_POINTER);
ret = slirp_vmstate_info_nullptr.put(f, curr_elem, size,
NULL);
} else if (field->flags & VMS_STRUCT) {
ret = slirp_vmstate_save_state(f, field->vmsd, curr_elem);
} else if (field->flags & VMS_VSTRUCT) {
ret = vmstate_save_state_v(f, field->vmsd, curr_elem,
field->struct_version_id);
} else {
ret = field->info->put(f, curr_elem, size, field);
}
if (ret) {
g_warning("Save of field %s/%s failed", vmsd->name,
field->name);
return ret;
}
}
} else {
if (field->flags & VMS_MUST_EXIST) {
g_warning("Output state validation failed: %s/%s", vmsd->name,
field->name);
assert(!(field->flags & VMS_MUST_EXIST));
}
}
field++;
}
return 0;
}
int slirp_vmstate_save_state(SlirpOStream *f, const VMStateDescription *vmsd,
void *opaque)
{
return vmstate_save_state_v(f, vmsd, opaque, vmsd->version_id);
}
static void vmstate_handle_alloc(void *ptr, VMStateField *field, void *opaque)
{
if (field->flags & VMS_POINTER && field->flags & VMS_ALLOC) {
size_t size = vmstate_size(opaque, field);
size *= vmstate_n_elems(opaque, field);
if (size) {
*(void **)ptr = g_malloc(size);
}
}
}
int slirp_vmstate_load_state(SlirpIStream *f, const VMStateDescription *vmsd,
void *opaque, int version_id)
{
VMStateField *field = vmsd->fields;
int ret = 0;
if (version_id > vmsd->version_id) {
g_warning("%s: incoming version_id %d is too new "
"for local version_id %d",
vmsd->name, version_id, vmsd->version_id);
return -EINVAL;
}
if (vmsd->pre_load) {
int ret = vmsd->pre_load(opaque);
if (ret) {
return ret;
}
}
while (field->name) {
if ((field->field_exists && field->field_exists(opaque, version_id)) ||
(!field->field_exists && field->version_id <= version_id)) {
void *first_elem = opaque + field->offset;
int i, n_elems = vmstate_n_elems(opaque, field);
int size = vmstate_size(opaque, field);
vmstate_handle_alloc(first_elem, field, opaque);
if (field->flags & VMS_POINTER) {
first_elem = *(void **)first_elem;
assert(first_elem || !n_elems || !size);
}
for (i = 0; i < n_elems; i++) {
void *curr_elem = first_elem + size * i;
if (field->flags & VMS_ARRAY_OF_POINTER) {
curr_elem = *(void **)curr_elem;
}
if (!curr_elem && size) {
/* if null pointer check placeholder and do not follow */
assert(field->flags & VMS_ARRAY_OF_POINTER);
ret = slirp_vmstate_info_nullptr.get(f, curr_elem, size,
NULL);
} else if (field->flags & VMS_STRUCT) {
ret = slirp_vmstate_load_state(f, field->vmsd, curr_elem,
field->vmsd->version_id);
} else if (field->flags & VMS_VSTRUCT) {
ret = slirp_vmstate_load_state(f, field->vmsd, curr_elem,
field->struct_version_id);
} else {
ret = field->info->get(f, curr_elem, size, field);
}
if (ret < 0) {
g_warning("Failed to load %s:%s", vmsd->name, field->name);
return ret;
}
}
} else if (field->flags & VMS_MUST_EXIST) {
g_warning("Input validation failed: %s/%s", vmsd->name,
field->name);
return -1;
}
field++;
}
if (vmsd->post_load) {
ret = vmsd->post_load(opaque, version_id);
}
return ret;
}

391
src/network/slirp/vmstate.h Normal file
View File

@@ -0,0 +1,391 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/*
* QEMU migration/snapshot declarations
*
* Copyright (c) 2009-2011 Red Hat, Inc.
*
* Original author: Juan Quintela <quintela@redhat.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef VMSTATE_H_
#define VMSTATE_H_
#include <unistd.h>
#include <stdint.h>
#include <stdbool.h>
#include "slirp.h"
#include "stream.h"
#define stringify(s) tostring(s)
#define tostring(s) #s
typedef struct VMStateInfo VMStateInfo;
typedef struct VMStateDescription VMStateDescription;
typedef struct VMStateField VMStateField;
int slirp_vmstate_save_state(SlirpOStream *f, const VMStateDescription *vmsd,
void *opaque);
int slirp_vmstate_load_state(SlirpIStream *f, const VMStateDescription *vmsd,
void *opaque, int version_id);
/* VMStateInfo allows customized migration of objects that don't fit in
* any category in VMStateFlags. Additional information is always passed
* into get and put in terms of field and vmdesc parameters. However
* these two parameters should only be used in cases when customized
* handling is needed, such as QTAILQ. For primitive data types such as
* integer, field and vmdesc parameters should be ignored inside get/put.
*/
struct VMStateInfo {
const char *name;
int (*get)(SlirpIStream *f, void *pv, size_t size,
const VMStateField *field);
int (*put)(SlirpOStream *f, void *pv, size_t size,
const VMStateField *field);
};
enum VMStateFlags {
/* Ignored */
VMS_SINGLE = 0x001,
/* The struct member at opaque + VMStateField.offset is a pointer
* to the actual field (e.g. struct a { uint8_t *b;
* }). Dereference the pointer before using it as basis for
* further pointer arithmetic (see e.g. VMS_ARRAY). Does not
* affect the meaning of VMStateField.num_offset or
* VMStateField.size_offset; see VMS_VARRAY* and VMS_VBUFFER for
* those. */
VMS_POINTER = 0x002,
/* The field is an array of fixed size. VMStateField.num contains
* the number of entries in the array. The size of each entry is
* given by VMStateField.size and / or opaque +
* VMStateField.size_offset; see VMS_VBUFFER and
* VMS_MULTIPLY. Each array entry will be processed individually
* (VMStateField.info.get()/put() if VMS_STRUCT is not set,
* recursion into VMStateField.vmsd if VMS_STRUCT is set). May not
* be combined with VMS_VARRAY*. */
VMS_ARRAY = 0x004,
/* The field is itself a struct, containing one or more
* fields. Recurse into VMStateField.vmsd. Most useful in
* combination with VMS_ARRAY / VMS_VARRAY*, recursing into each
* array entry. */
VMS_STRUCT = 0x008,
/* The field is an array of variable size. The int32_t at opaque +
* VMStateField.num_offset contains the number of entries in the
* array. See the VMS_ARRAY description regarding array handling
* in general. May not be combined with VMS_ARRAY or any other
* VMS_VARRAY*. */
VMS_VARRAY_INT32 = 0x010,
/* Ignored */
VMS_BUFFER = 0x020,
/* The field is a (fixed-size or variable-size) array of pointers
* (e.g. struct a { uint8_t *b[]; }). Dereference each array entry
* before using it. Note: Does not imply any one of VMS_ARRAY /
* VMS_VARRAY*; these need to be set explicitly. */
VMS_ARRAY_OF_POINTER = 0x040,
/* The field is an array of variable size. The uint16_t at opaque
* + VMStateField.num_offset (subject to VMS_MULTIPLY_ELEMENTS)
* contains the number of entries in the array. See the VMS_ARRAY
* description regarding array handling in general. May not be
* combined with VMS_ARRAY or any other VMS_VARRAY*. */
VMS_VARRAY_UINT16 = 0x080,
/* The size of the individual entries (a single array entry if
* VMS_ARRAY or any of VMS_VARRAY* are set, or the field itself if
* neither is set) is variable (i.e. not known at compile-time),
* but the same for all entries. Use the int32_t at opaque +
* VMStateField.size_offset (subject to VMS_MULTIPLY) to determine
* the size of each (and every) entry. */
VMS_VBUFFER = 0x100,
/* Multiply the entry size given by the int32_t at opaque +
* VMStateField.size_offset (see VMS_VBUFFER description) with
* VMStateField.size to determine the number of bytes to be
* allocated. Only valid in combination with VMS_VBUFFER. */
VMS_MULTIPLY = 0x200,
/* The field is an array of variable size. The uint8_t at opaque +
* VMStateField.num_offset (subject to VMS_MULTIPLY_ELEMENTS)
* contains the number of entries in the array. See the VMS_ARRAY
* description regarding array handling in general. May not be
* combined with VMS_ARRAY or any other VMS_VARRAY*. */
VMS_VARRAY_UINT8 = 0x400,
/* The field is an array of variable size. The uint32_t at opaque
* + VMStateField.num_offset (subject to VMS_MULTIPLY_ELEMENTS)
* contains the number of entries in the array. See the VMS_ARRAY
* description regarding array handling in general. May not be
* combined with VMS_ARRAY or any other VMS_VARRAY*. */
VMS_VARRAY_UINT32 = 0x800,
/* Fail loading the serialised VM state if this field is missing
* from the input. */
VMS_MUST_EXIST = 0x1000,
/* When loading serialised VM state, allocate memory for the
* (entire) field. Only valid in combination with
* VMS_POINTER. Note: Not all combinations with other flags are
* currently supported, e.g. VMS_ALLOC|VMS_ARRAY_OF_POINTER won't
* cause the individual entries to be allocated. */
VMS_ALLOC = 0x2000,
/* Multiply the number of entries given by the integer at opaque +
* VMStateField.num_offset (see VMS_VARRAY*) with VMStateField.num
* to determine the number of entries in the array. Only valid in
* combination with one of VMS_VARRAY*. */
VMS_MULTIPLY_ELEMENTS = 0x4000,
/* A structure field that is like VMS_STRUCT, but uses
* VMStateField.struct_version_id to tell which version of the
* structure we are referencing to use. */
VMS_VSTRUCT = 0x8000,
};
struct VMStateField {
const char *name;
size_t offset;
size_t size;
size_t start;
int num;
size_t num_offset;
size_t size_offset;
const VMStateInfo *info;
enum VMStateFlags flags;
const VMStateDescription *vmsd;
int version_id;
int struct_version_id;
bool (*field_exists)(void *opaque, int version_id);
};
struct VMStateDescription {
const char *name;
int version_id;
int (*pre_load)(void *opaque);
int (*post_load)(void *opaque, int version_id);
int (*pre_save)(void *opaque);
VMStateField *fields;
};
extern const VMStateInfo slirp_vmstate_info_int16;
extern const VMStateInfo slirp_vmstate_info_int32;
extern const VMStateInfo slirp_vmstate_info_uint8;
extern const VMStateInfo slirp_vmstate_info_uint16;
extern const VMStateInfo slirp_vmstate_info_uint32;
/** Put this in the stream when migrating a null pointer.*/
#define VMS_NULLPTR_MARKER (0x30U) /* '0' */
extern const VMStateInfo slirp_vmstate_info_nullptr;
extern const VMStateInfo slirp_vmstate_info_buffer;
extern const VMStateInfo slirp_vmstate_info_tmp;
#define type_check_array(t1, t2, n) ((t1(*)[n])0 - (t2 *)0)
#define type_check_pointer(t1, t2) ((t1 **)0 - (t2 *)0)
#define typeof_field(type, field) typeof(((type *)0)->field)
#define type_check(t1, t2) ((t1 *)0 - (t2 *)0)
#define vmstate_offset_value(_state, _field, _type) \
(offsetof(_state, _field) + type_check(_type, typeof_field(_state, _field)))
#define vmstate_offset_pointer(_state, _field, _type) \
(offsetof(_state, _field) + \
type_check_pointer(_type, typeof_field(_state, _field)))
#define vmstate_offset_array(_state, _field, _type, _num) \
(offsetof(_state, _field) + \
type_check_array(_type, typeof_field(_state, _field), _num))
#define vmstate_offset_buffer(_state, _field) \
vmstate_offset_array(_state, _field, uint8_t, \
sizeof(typeof_field(_state, _field)))
/* In the macros below, if there is a _version, that means the macro's
* field will be processed only if the version being received is >=
* the _version specified. In general, if you add a new field, you
* would increment the structure's version and put that version
* number into the new field so it would only be processed with the
* new version.
*
* In particular, for VMSTATE_STRUCT() and friends the _version does
* *NOT* pick the version of the sub-structure. It works just as
* specified above. The version of the top-level structure received
* is passed down to all sub-structures. This means that the
* sub-structures must have version that are compatible with all the
* structures that use them.
*
* If you want to specify the version of the sub-structure, use
* VMSTATE_VSTRUCT(), which allows the specific sub-structure version
* to be directly specified.
*/
#define VMSTATE_SINGLE_TEST(_field, _state, _test, _version, _info, _type) \
{ \
.name = (stringify(_field)), .version_id = (_version), \
.field_exists = (_test), .size = sizeof(_type), .info = &(_info), \
.flags = VMS_SINGLE, \
.offset = vmstate_offset_value(_state, _field, _type), \
}
#define VMSTATE_ARRAY(_field, _state, _num, _version, _info, _type) \
{ \
.name = (stringify(_field)), .version_id = (_version), .num = (_num), \
.info = &(_info), .size = sizeof(_type), .flags = VMS_ARRAY, \
.offset = vmstate_offset_array(_state, _field, _type, _num), \
}
#define VMSTATE_STRUCT_TEST(_field, _state, _test, _version, _vmsd, _type) \
{ \
.name = (stringify(_field)), .version_id = (_version), \
.field_exists = (_test), .vmsd = &(_vmsd), .size = sizeof(_type), \
.flags = VMS_STRUCT, \
.offset = vmstate_offset_value(_state, _field, _type), \
}
#define VMSTATE_STRUCT_POINTER_V(_field, _state, _version, _vmsd, _type) \
{ \
.name = (stringify(_field)), .version_id = (_version), \
.vmsd = &(_vmsd), .size = sizeof(_type *), \
.flags = VMS_STRUCT | VMS_POINTER, \
.offset = vmstate_offset_pointer(_state, _field, _type), \
}
#define VMSTATE_STRUCT_ARRAY_TEST(_field, _state, _num, _test, _version, \
_vmsd, _type) \
{ \
.name = (stringify(_field)), .num = (_num), .field_exists = (_test), \
.version_id = (_version), .vmsd = &(_vmsd), .size = sizeof(_type), \
.flags = VMS_STRUCT | VMS_ARRAY, \
.offset = vmstate_offset_array(_state, _field, _type, _num), \
}
#define VMSTATE_STATIC_BUFFER(_field, _state, _version, _test, _start, _size) \
{ \
.name = (stringify(_field)), .version_id = (_version), \
.field_exists = (_test), .size = (_size - _start), \
.info = &slirp_vmstate_info_buffer, .flags = VMS_BUFFER, \
.offset = vmstate_offset_buffer(_state, _field) + _start, \
}
#define VMSTATE_VBUFFER_UINT32(_field, _state, _version, _test, _field_size) \
{ \
.name = (stringify(_field)), .version_id = (_version), \
.field_exists = (_test), \
.size_offset = vmstate_offset_value(_state, _field_size, uint32_t), \
.info = &slirp_vmstate_info_buffer, \
.flags = VMS_VBUFFER | VMS_POINTER, \
.offset = offsetof(_state, _field), \
}
#define QEMU_BUILD_BUG_ON_STRUCT(x) \
struct { \
int : (x) ? -1 : 1; \
}
#define QEMU_BUILD_BUG_ON_ZERO(x) \
(sizeof(QEMU_BUILD_BUG_ON_STRUCT(x)) - sizeof(QEMU_BUILD_BUG_ON_STRUCT(x)))
/* Allocate a temporary of type 'tmp_type', set tmp->parent to _state
* and execute the vmsd on the temporary. Note that we're working with
* the whole of _state here, not a field within it.
* We compile time check that:
* That _tmp_type contains a 'parent' member that's a pointer to the
* '_state' type
* That the pointer is right at the start of _tmp_type.
*/
#define VMSTATE_WITH_TMP(_state, _tmp_type, _vmsd) \
{ \
.name = "tmp", \
.size = sizeof(_tmp_type) + \
QEMU_BUILD_BUG_ON_ZERO(offsetof(_tmp_type, parent) != 0) + \
type_check_pointer(_state, typeof_field(_tmp_type, parent)), \
.vmsd = &(_vmsd), .info = &slirp_vmstate_info_tmp, \
}
#define VMSTATE_SINGLE(_field, _state, _version, _info, _type) \
VMSTATE_SINGLE_TEST(_field, _state, NULL, _version, _info, _type)
#define VMSTATE_STRUCT(_field, _state, _version, _vmsd, _type) \
VMSTATE_STRUCT_TEST(_field, _state, NULL, _version, _vmsd, _type)
#define VMSTATE_STRUCT_POINTER(_field, _state, _vmsd, _type) \
VMSTATE_STRUCT_POINTER_V(_field, _state, 0, _vmsd, _type)
#define VMSTATE_STRUCT_ARRAY(_field, _state, _num, _version, _vmsd, _type) \
VMSTATE_STRUCT_ARRAY_TEST(_field, _state, _num, NULL, _version, _vmsd, \
_type)
#define VMSTATE_INT16_V(_f, _s, _v) \
VMSTATE_SINGLE(_f, _s, _v, slirp_vmstate_info_int16, int16_t)
#define VMSTATE_INT32_V(_f, _s, _v) \
VMSTATE_SINGLE(_f, _s, _v, slirp_vmstate_info_int32, int32_t)
#define VMSTATE_UINT8_V(_f, _s, _v) \
VMSTATE_SINGLE(_f, _s, _v, slirp_vmstate_info_uint8, uint8_t)
#define VMSTATE_UINT16_V(_f, _s, _v) \
VMSTATE_SINGLE(_f, _s, _v, slirp_vmstate_info_uint16, uint16_t)
#define VMSTATE_UINT32_V(_f, _s, _v) \
VMSTATE_SINGLE(_f, _s, _v, slirp_vmstate_info_uint32, uint32_t)
#define VMSTATE_INT16(_f, _s) VMSTATE_INT16_V(_f, _s, 0)
#define VMSTATE_INT32(_f, _s) VMSTATE_INT32_V(_f, _s, 0)
#define VMSTATE_UINT8(_f, _s) VMSTATE_UINT8_V(_f, _s, 0)
#define VMSTATE_UINT16(_f, _s) VMSTATE_UINT16_V(_f, _s, 0)
#define VMSTATE_UINT32(_f, _s) VMSTATE_UINT32_V(_f, _s, 0)
#define VMSTATE_UINT16_TEST(_f, _s, _t) \
VMSTATE_SINGLE_TEST(_f, _s, _t, 0, slirp_vmstate_info_uint16, uint16_t)
#define VMSTATE_UINT32_TEST(_f, _s, _t) \
VMSTATE_SINGLE_TEST(_f, _s, _t, 0, slirp_vmstate_info_uint32, uint32_t)
#define VMSTATE_INT16_ARRAY_V(_f, _s, _n, _v) \
VMSTATE_ARRAY(_f, _s, _n, _v, slirp_vmstate_info_int16, int16_t)
#define VMSTATE_INT16_ARRAY(_f, _s, _n) VMSTATE_INT16_ARRAY_V(_f, _s, _n, 0)
#define VMSTATE_BUFFER_V(_f, _s, _v) \
VMSTATE_STATIC_BUFFER(_f, _s, _v, NULL, 0, sizeof(typeof_field(_s, _f)))
#define VMSTATE_BUFFER(_f, _s) VMSTATE_BUFFER_V(_f, _s, 0)
#define VMSTATE_END_OF_LIST() \
{ \
}
#endif

View File

@@ -701,9 +701,9 @@ SCSIOBJ := scsi.o scsi_device.o \
NETOBJ := network.o \ NETOBJ := network.o \
net_pcap.o \ net_pcap.o \
net_slirp.o \ net_slirp.o \
bootp.o ip_icmp.o misc.o socket.o tcp_timer.o cksum.o \ arp_table.o bootp.o cksum.o dnssearch.o if.o ip_icmp.o ip_input.o \
ip_input.o queue.o tcp_input.o debug.o ip_output.o \ ip_output.o mbuf.o misc.o sbuf.o slirp.o socket.o tcp_input.o \
sbuf.o tcp_output.o udp.o if.o mbuf.o slirp.o tcp_subr.o \ tcp_output.o tcp_subr.o tcp_timer.o udp.o util.o version.o \
net_dp8390.o \ net_dp8390.o \
net_3c503.o net_ne2000.o \ net_3c503.o net_ne2000.o \
net_pcnet.o net_wd8003.o net_pcnet.o net_wd8003.o

View File

@@ -941,6 +941,7 @@ recalc_vid_list(HWND hdlg)
int c = 0, d = 0; int c = 0, d = 0;
int found_card = 0; int found_card = 0;
WCHAR szText[512]; WCHAR szText[512];
char *s;
SendMessage(h, CB_RESETCONTENT, 0, 0); SendMessage(h, CB_RESETCONTENT, 0, 0);
SendMessage(h, CB_SETCURSEL, 0, 0); SendMessage(h, CB_SETCURSEL, 0, 0);
@@ -952,7 +953,12 @@ recalc_vid_list(HWND hdlg)
continue; continue;
} }
char *s = video_card_getname(c); if (c == VID_INTERNAL) {
s = malloc(512);
sprintf(s, "%s (%s)", video_card_getname(c), machine_getdevice(temp_machine)->name);
} else {
s = video_card_getname(c);
}
if (!s[0]) if (!s[0])
break; break;
@@ -1286,7 +1292,12 @@ win_settings_sound_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam)
continue; continue;
} }
s = sound_card_getname(c); if (c == SOUND_INTERNAL) {
s = malloc(512);
sprintf(s, "%s (%s)", sound_card_getname(c), machine_getdevice(temp_machine)->name);
} else {
s = sound_card_getname(c);
}
if (!s[0]) if (!s[0])
break; break;