SLiRP overhaul
This commit is contained in:
@@ -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))
|
||||||
|
|||||||
@@ -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);
|
|
||||||
@@ -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 ""
|
|
||||||
@@ -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
|
|
||||||
@@ -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"
|
|
||||||
@@ -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));
|
|
||||||
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
24
src/include/slirp/libslirp-version.h
Normal file
24
src/include/slirp/libslirp-version.h
Normal 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_ */
|
||||||
@@ -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 */
|
||||||
|
|||||||
@@ -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);
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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 */
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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_ */
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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);
|
|
||||||
@@ -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
260
src/include/tinyglib.h
Normal 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
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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.
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
qemu 0.9.0 (2007/02/05)
|
|
||||||
92
src/network/slirp/arp_table.c
Normal file
92
src/network/slirp/arp_table.c
Normal 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;
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 ""
|
|
||||||
@@ -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
|
|
||||||
@@ -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"
|
|
||||||
@@ -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
|
|
||||||
@@ -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
224
src/network/slirp/dhcpv6.c
Normal 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]);
|
||||||
|
}
|
||||||
|
}
|
||||||
68
src/network/slirp/dhcpv6.h
Normal file
68
src/network/slirp/dhcpv6.h
Normal 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
|
||||||
306
src/network/slirp/dnssearch.c
Normal file
306
src/network/slirp/dnssearch.c
Normal 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;
|
||||||
|
}
|
||||||
@@ -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
|
|
||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
214
src/network/slirp/ip6.h
Normal 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(ð[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
|
||||||
433
src/network/slirp/ip6_icmp.c
Normal file
433
src/network/slirp/ip6_icmp.c
Normal 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);
|
||||||
|
}
|
||||||
219
src/network/slirp/ip6_icmp.h
Normal file
219
src/network/slirp/ip6_icmp.h
Normal 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
|
||||||
85
src/network/slirp/ip6_input.c
Normal file
85
src/network/slirp/ip6_input.c
Normal 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);
|
||||||
|
}
|
||||||
39
src/network/slirp/ip6_output.c
Normal file
39
src/network/slirp/ip6_output.c
Normal 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;
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
24
src/network/slirp/libslirp-version.h
Normal file
24
src/network/slirp/libslirp-version.h
Normal 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_ */
|
||||||
@@ -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 */
|
||||||
|
|||||||
@@ -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);
|
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
@@ -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
|
||||||
|
|||||||
445
src/network/slirp/ncsi-pkt.h
Normal file
445
src/network/slirp/ncsi-pkt.h
Normal 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
193
src/network/slirp/ncsi.c
Normal 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);
|
||||||
|
}
|
||||||
87
src/network/slirp/ndp_table.c
Normal file
87
src/network/slirp/ndp_table.c
Normal 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;
|
||||||
|
}
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -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 */
|
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
@@ -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
|
||||||
|
|||||||
@@ -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
@@ -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
379
src/network/slirp/state.c
Normal 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
120
src/network/slirp/stream.c
Normal 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));
|
||||||
|
}
|
||||||
35
src/network/slirp/stream.h
Normal file
35
src/network/slirp/stream.h
Normal 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_ */
|
||||||
@@ -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
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
173
src/network/slirp/udp6.c
Normal 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
428
src/network/slirp/util.c
Normal 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
189
src/network/slirp/util.h
Normal 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
|
||||||
8
src/network/slirp/version.c
Normal file
8
src/network/slirp/version.c
Normal 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
444
src/network/slirp/vmstate.c
Normal 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
391
src/network/slirp/vmstate.h
Normal 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
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user