summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYonit <yhalperi@redhat.com>2009-06-21 17:03:24 +0300
committerYonit <yhalperi@redhat.com>2009-06-21 17:03:24 +0300
commit0d39510a5f74043c9e44d4534f7064590d744339 (patch)
treefb568c11e3b9a637127241c0e88ce1b1dc2cc07f
parentec383e8b58b4e1e93f5bba5dce6cd1f2d0ccf116 (diff)
Export/Restore
-rw-r--r--bootp.c102
-rw-r--r--bootp.h3
-rw-r--r--ip_input.c8
-rw-r--r--mbuf.c1
-rw-r--r--net_slirp.c112
-rw-r--r--net_slirp.h20
-rw-r--r--slirp_common.h18
-rw-r--r--socket.c24
-rw-r--r--socket.h10
-rw-r--r--tcp.h2
-rw-r--r--tcp_input.c39
-rw-r--r--tcp_subr.c487
-rw-r--r--tcp_timer.c3
-rw-r--r--tcp_var.h2
-rw-r--r--tcpip.h1
15 files changed, 732 insertions, 100 deletions
diff --git a/bootp.c b/bootp.c
index bc08ae7..2619943 100644
--- a/bootp.c
+++ b/bootp.c
@@ -28,21 +28,20 @@
/* XXX: only DHCP is supported */
-#define NB_ADDR 16 // TODO: we don't need more than 1
+#define NB_ADDR 16
#define START_ADDR 15
#define START_VIRTAUL_ADDR (NB_ADDR + START_ADDR)
#define LEASE_TIME (24 * 3600)
-typedef struct {
- uint8_t allocated;
+typedef struct __attribute__((packed)) {
uint8_t macaddr[6];
} BOOTPClient;
static BOOTPClient bootp_clients[NB_ADDR];
-
-static int virtual_ips_count = 0;
+static int num_bootp_clients = 0;
+static int num_virtual_ips = 0;
const char *bootp_filename;
@@ -58,62 +57,59 @@ if (slirp_debug & DBG_CALL) { fprintf(dfd, fmt, ## args); fflush(dfd); }
static BOOTPClient *get_new_addr(struct in_addr *paddr)
{
BOOTPClient *bc;
+
+ if (num_bootp_clients == NB_ADDR) {
+ return NULL;
+ }
+
+ bc = &bootp_clients[num_bootp_clients];
+ paddr->s_addr = htonl(ntohl(special_addr.s_addr) | (num_bootp_clients + START_ADDR));
+ num_bootp_clients++;
+ return bc;
+}
+
+static BOOTPClient *find_addr(struct in_addr *paddr, const uint8_t *macaddr)
+{
+ BOOTPClient *bc;
int i;
- for(i = 0; i < NB_ADDR; i++) {
- if (!bootp_clients[i].allocated)
+ for(i = 0; i < num_bootp_clients; i++) {
+ if (!memcmp(macaddr, bootp_clients[i].macaddr, 6))
goto found;
}
return NULL;
found:
bc = &bootp_clients[i];
- bc->allocated = 1;
paddr->s_addr = htonl(ntohl(special_addr.s_addr) | (i + START_ADDR));
return bc;
}
int alloc_virtual_ip(struct in_addr *out_addr)
{
- if ((virtual_ips_count + START_VIRTAUL_ADDR) > 0xff)
+ if ((num_virtual_ips + START_VIRTAUL_ADDR) > 0xff)
return FALSE;
- out_addr->s_addr = htonl(ntohl(special_addr.s_addr) | (virtual_ips_count + START_VIRTAUL_ADDR));
- virtual_ips_count++;
+ out_addr->s_addr = htonl(ntohl(special_addr.s_addr) | (num_virtual_ips + START_VIRTAUL_ADDR));
+ num_virtual_ips++;
return TRUE;
}
void clear_virtual_ips()
{
- virtual_ips_count = 0;
+ num_virtual_ips = 0;
}
int is_virtual_ip_allocated(struct in_addr *addr)
{
+ printf("is_virtual_ip_allocated addr=%s special=%s", inet_ntoa(*addr), inet_ntoa(special_addr));
if ((addr->s_addr&htonl(0xffffff00)) == special_addr.s_addr) {
int lastbyte=(ntohl(addr->s_addr)) & 0xff;
return (((lastbyte >= START_VIRTAUL_ADDR) &&
- (lastbyte < virtual_ips_count + START_VIRTAUL_ADDR)) ||(lastbyte == CTL_ALIAS) );
+ (lastbyte < num_virtual_ips + START_VIRTAUL_ADDR)) ||(lastbyte == CTL_ALIAS) );
}
return FALSE;
}
-static BOOTPClient *find_addr(struct in_addr *paddr, const uint8_t *macaddr)
-{
- BOOTPClient *bc;
- int i;
-
- for(i = 0; i < NB_ADDR; i++) {
- if (!memcmp(macaddr, bootp_clients[i].macaddr, 6))
- goto found;
- }
- return NULL;
- found:
- bc = &bootp_clients[i];
- bc->allocated = 1;
- paddr->s_addr = htonl(ntohl(special_addr.s_addr) | (i + START_ADDR));
- return bc;
-}
-
static void dhcp_decode(const uint8_t *buf, int size,
int *pmsg_type)
{
@@ -268,10 +264,8 @@ static void bootp_reply(struct bootp_t *bp)
*q++ = 0xff;
*q++ = 0xff;
*q++ = 0x00;
-
- // TODO: removed gateway. Return it to be optional
-#if 0
- if (!slirp_restrict) {
+
+ if (!slirp_restricted) {
*q++ = RFC1533_GATEWAY;
*q++ = 4;
memcpy(q, &saddr.sin_addr, 4);
@@ -283,7 +277,6 @@ static void bootp_reply(struct bootp_t *bp)
memcpy(q, &dns_addr, 4);
q += 4;
}
-#endif
*q++ = RFC2132_LEASE_TIME;
*q++ = 4;
@@ -311,8 +304,45 @@ static void bootp_reply(struct bootp_t *bp)
void bootp_input(struct mbuf *m)
{
struct bootp_t *bp = mtod(m, struct bootp_t *);
-
+
if (bp->bp_op == BOOTP_REQUEST) {
bootp_reply(bp);
}
}
+
+typedef struct __attribute__((packed)) BootpExportData {
+ uint32_t num_virtual_ips;
+ uint32_t num_bootp_clients;
+ BOOTPClient clients[0]; // ptr to the start of the mcadder of the bootp client
+} BootpExportData;
+
+uint64_t bootp_export(void **export_data)
+{
+ int i;
+ uint64_t size = sizeof(BootpExportData) + (sizeof(BOOTPClient)*num_bootp_clients);
+ BootpExportData *ret_data = malloc(size);
+
+ ret_data->num_virtual_ips = num_virtual_ips;
+ ret_data->num_bootp_clients = num_bootp_clients;
+
+ for (i = 0; i < ret_data->num_bootp_clients ; i++) {
+ memcpy(ret_data->clients[i].macaddr, bootp_clients[i].macaddr, 6);
+ }
+
+ *export_data = ret_data;
+ return size;
+}
+
+void bootp_restore(void *export_data)
+{
+ int i;
+ BootpExportData *bootp_data = (BootpExportData *)export_data;
+
+ num_virtual_ips = bootp_data->num_virtual_ips;
+ num_bootp_clients = bootp_data->num_bootp_clients;
+
+ for (i = 0; i < num_bootp_clients; i++)
+ {
+ memcpy(bootp_clients[i].macaddr, bootp_data->clients[i].macaddr, 6);
+ }
+}
diff --git a/bootp.h b/bootp.h
index f3b1b8e..bf2a6bb 100644
--- a/bootp.h
+++ b/bootp.h
@@ -123,4 +123,7 @@ int alloc_virtual_ip(struct in_addr *out_addr);
int is_virtual_ip_allocated(struct in_addr *addr);
void clear_virtual_ips();
+uint64_t bootp_export(void **export_data);
+void bootp_restore(void *export_data);
+
#endif
diff --git a/ip_input.c b/ip_input.c
index cb56d1b..2a33906 100644
--- a/ip_input.c
+++ b/ip_input.c
@@ -70,10 +70,12 @@ static void ip_deq(register struct ipasfrag *p);
void
ip_init()
{
+ struct timeval tt;
ipq.ip_link.next = ipq.ip_link.prev = &ipq.ip_link;
- ip_id = 0;
- udp_init();
- tcp_init();
+ gettimeofday(&tt, 0);
+ ip_id = tt.tv_sec & 0xffff;
+ udp_init();
+ tcp_init();
}
/*
diff --git a/mbuf.c b/mbuf.c
index 3744cfa..5cc87c9 100644
--- a/mbuf.c
+++ b/mbuf.c
@@ -121,6 +121,7 @@ void
m_cat(m, n)
register struct mbuf *m, *n;
{
+ // TODO: bug if n->m_len > M_FREEROOM(m) + MINCSIZE
/*
* If there's no room, realloc
*/
diff --git a/net_slirp.c b/net_slirp.c
index 1a76d3f..0e7d6e4 100644
--- a/net_slirp.c
+++ b/net_slirp.c
@@ -49,12 +49,14 @@ const uint8_t special_ethaddr[6] = {
0x52, 0x54, 0x00, 0x12, 0x35, 0x00
};
+int slirp_restricted;
+
/* ARP cache for the guest IP addresses (XXX: allow many entries) */
uint8_t client_ethaddr[6]; // bootp_reply sets it or arp...
struct in_addr client_ipaddr;
-int link_up;
+int link_up = 0;
FILE *lfd;
char slirp_hostname[33];
@@ -63,6 +65,9 @@ SlirpUsrNetworkInterface *slirp_net_interface;
UserTimer *fast_timer, *slow_timer;
int fast_timer_armed, slow_timer_armed;
+
+int slirp_freezed = 0;
+
/*
u_int curtime, last_fasttimo, last_slowtimo;
static void updtime(void)
@@ -152,6 +157,10 @@ static int need_slow_timer()
static void fast_timeout(void *opaque)
{
+ if (slirp_freezed) {
+ return;
+ }
+
tcp_fasttimo();
if (if_queued)
@@ -165,6 +174,10 @@ static void fast_timeout(void *opaque)
static void slow_timeout(void *opaque)
{
+ if (slirp_freezed) {
+ return;
+ }
+
ip_slowtimo();
tcp_slowtimo();
if (need_slow_timer()) {
@@ -175,7 +188,8 @@ static void slow_timeout(void *opaque)
}
-void DLL_PUBLIC net_slirp_init(struct in_addr special_ip, SlirpUsrNetworkInterface *net_interface)
+void DLL_PUBLIC net_slirp_init(struct in_addr special_ip, int restricted,
+ SlirpUsrNetworkInterface *net_interface)
{
// debug_init("/tmp/slirp.log", DEBUG_DEFAULT);
link_up = 1;
@@ -197,6 +211,7 @@ void DLL_PUBLIC net_slirp_init(struct in_addr special_ip, SlirpUsrNetworkInterfa
special_addr.s_addr = special_ip.s_addr;
alias_addr.s_addr = special_addr.s_addr | htonl(CTL_ALIAS);
+ slirp_restricted = restricted;
slirp_net_interface = net_interface;
getouraddr();
@@ -238,7 +253,7 @@ void DLL_PUBLIC net_slirp_input(const uint8_t *pkt, int pkt_len)
ip_input(m);
break;
default:
- printf("SLIRP INPUT : UNKNOWN\n");
+ printf("SLIRP INPUT : unsupported protocol %x\n", proto);
break;
}
@@ -272,18 +287,21 @@ void DLL_PUBLIC net_slirp_socket_connect_failed_notify(SlirpSocket *sckt)
void DLL_PUBLIC net_slirp_socket_can_send_notify(SlirpSocket *sckt)
{
struct socket *so = (struct socket *)sckt;
- sotrysend(so);
+ if (socansend(so)) {
+ sowrite(so);
+ }
+
}
void DLL_PUBLIC net_slirp_socket_can_receive_notify(SlirpSocket *sckt)
{
struct socket *so = (struct socket *)sckt;
-
- // if it can't read cause a buffer is full, it will try again in sodropacked
- if (sotryrecv(so) > 0) {
- /* Output it if we read something */
- tcp_output(sototcpcb(so));
- }
+ // if we can't read cause a buffer is full, we will try again after sodropacked
+ if (socanrecv(so)) {
+ if (soread(so) > 0) {
+ tcp_output(sototcpcb(so));
+ }
+ }
}
void DLL_PUBLIC net_slirp_socket_abort(SlirpSocket *sckt)
@@ -301,3 +319,77 @@ void DLL_PUBLIC net_slirp_clear_virtual_ips()
{
clear_virtual_ips();
}
+
+
+typedef struct __attribute__((packed)) SlirpExportData {
+ uint8_t client_ethaddr[6];
+ uint8_t client_ipaddr[4];
+ uint32_t tcp_iss;
+ uint8_t bootp_data[0];
+} SlirpExportData;
+
+uint64_t DLL_PUBLIC net_slirp_state_export(void **export_state)
+{
+ void *bootp_data;
+ uint64_t bootp_size;
+ SlirpExportData *ret_data;
+ uint64_t total_size;
+
+ bootp_size = bootp_export(&bootp_data);
+ total_size = sizeof(SlirpExportData) + bootp_size;
+ ret_data = malloc(total_size);
+
+ memcpy(ret_data->client_ethaddr, client_ethaddr, 6);
+ memcpy(ret_data->client_ipaddr, &client_ipaddr.s_addr, 4);
+ ret_data->tcp_iss = tcp_iss;
+ memcpy(ret_data->bootp_data, bootp_data, bootp_size);
+ free(bootp_data);
+
+ *export_state = ret_data;
+ return total_size;
+}
+
+
+void DLL_PUBLIC net_slirp_state_restore(void *export_state)
+{
+ SlirpExportData *slirp_data = (SlirpExportData *)export_state;
+
+ bootp_restore(slirp_data->bootp_data);
+ tcp_iss = slirp_data->tcp_iss;
+ memcpy(client_ethaddr, slirp_data->client_ethaddr, 6);
+ memcpy(&client_ipaddr.s_addr, slirp_data->client_ipaddr, 4);
+ slirp_freezed = TRUE;
+
+}
+
+uint64_t DLL_PUBLIC net_slirp_tcp_socket_export(SlirpSocket *sckt, void **export_socket)
+{
+ return tcp_socket_export((struct socket *)sckt, export_socket);
+}
+
+SlirpSocket DLL_PUBLIC *net_slirp_tcp_socket_restore(void *export_socket, UserSocket *usr_socket)
+{
+ SlirpSocket *ret = tcp_socket_restore(export_socket, usr_socket);
+
+
+ return ret;
+}
+
+
+void DLL_PUBLIC net_slirp_freeze()
+{
+ slirp_freezed = TRUE;
+}
+
+
+void DLL_PUBLIC net_slirp_unfreeze()
+{
+ slirp_freezed = FALSE;
+ if (!slow_timer_armed && need_slow_timer()) {
+ slirp_net_interface->arm_timer(slirp_net_interface, slow_timer, SLOW_TIMEOUT_MS);
+ }
+
+ if (!fast_timer_armed && need_fast_timer()) {
+ slirp_net_interface->arm_timer(slirp_net_interface, fast_timer, FAST_TIMEOUT_MS);
+ }
+}
diff --git a/net_slirp.h b/net_slirp.h
index 71bdc97..e9f4258 100644
--- a/net_slirp.h
+++ b/net_slirp.h
@@ -13,7 +13,7 @@ struct SlirpUsrNetworkInterface {
int (*slirp_can_output)(SlirpUsrNetworkInterface *usr_interface);
void (*slirp_output)(SlirpUsrNetworkInterface *usr_interface, const uint8_t *pkt, int pkt_len);
int (*connect)(SlirpUsrNetworkInterface *usr_interface,
- struct in_addr src_addr, uint16_t src_port,
+ struct in_addr src_addr, uint16_t src_port,
struct in_addr dst_addr, uint16_t dst_port,
SlirpSocket *slirp_s, UserSocket **o_usr_s);
int (*send)(SlirpUsrNetworkInterface *usr_interface, UserSocket *opaque,
@@ -29,7 +29,8 @@ struct SlirpUsrNetworkInterface {
void (*arm_timer)(SlirpUsrNetworkInterface *usr_interface, UserTimer *timer, uint32_t ms);
};
-void net_slirp_init(struct in_addr special_ip, SlirpUsrNetworkInterface *net_interface);
+void net_slirp_init(struct in_addr special_ip, int restricted,
+ SlirpUsrNetworkInterface *net_interface);
void net_slirp_input(const uint8_t *pkt, int pkt_len);
// TODO: maybe we will need to change the allocation/deallocation to be for specific
@@ -44,6 +45,21 @@ void net_slirp_socket_can_send_notify(SlirpSocket *sckt);
void net_slirp_socket_can_receive_notify(SlirpSocket *sckt);
void net_slirp_socket_abort(SlirpSocket *sckt);
+/*
+ When exporting slirp, the following steps should be performed in the same order:
+ (1) net_slirp_freeze (2) net_slirp_state_export (3) for each tcp socket: net_slirp_tcp_socket_export
+ When restoring slirp: (1) net_slirp_state_restore (2) net_slirp_tcp_socket_restore (3) net_slirp_unfreeze
+*/
+
+uint64_t net_slirp_state_export(void **export_state);
+void net_slirp_state_restore(void *export_state);
+
+uint64_t net_slirp_tcp_socket_export(SlirpSocket *sckt, void **export_socket);
+SlirpSocket *net_slirp_tcp_socket_restore(void *export_socket, UserSocket *usr_socket);
+
+void net_slirp_freeze(); // deactivate timers
+void net_slirp_unfreeze(); // restore timers
+
#if 0
int slirp_redir(int is_udp, int host_port,
diff --git a/slirp_common.h b/slirp_common.h
index d35ea95..97e9852 100644
--- a/slirp_common.h
+++ b/slirp_common.h
@@ -284,14 +284,14 @@ extern struct ttys *ttys_unit[MAX_INTERFACES];
extern int link_up;
-#ifndef offsetof
-#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *) 0)->MEMBER)
-#endif
-#ifndef container_of
-#define container_of(ptr, type, member) ({ \
- const typeof(((type *) 0)->member) *__mptr = (ptr); \
- (type *) ((char *) __mptr - offsetof(type, member));})
-#endif
+#ifndef offsetof
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *) 0)->MEMBER)
+#endif
+#ifndef container_of
+#define container_of(ptr, type, member) ({ \
+ const typeof(((type *) 0)->member) *__mptr = (ptr); \
+ (type *) ((char *) __mptr - offsetof(type, member));})
+#endif
extern struct in_addr special_addr;
extern struct in_addr alias_addr;
@@ -311,6 +311,8 @@ extern const uint8_t zero_ethaddr[6];
extern const uint8_t special_ethaddr[6];
extern struct in_addr client_ipaddr;
+extern int slirp_restricted;
+
extern SlirpUsrNetworkInterface *slirp_net_interface;
#endif
diff --git a/socket.c b/socket.c
index cc027e6..046a564 100644
--- a/socket.c
+++ b/socket.c
@@ -407,24 +407,15 @@ sowrite(so)
return nn;
}
-void sotrysend (struct socket *so)
+int socansend(struct socket *so)
{
- if (so->so_state & SS_NOFDREF)
- return;
-
- if (CONN_CANFSEND(so) && so->so_rcv.sb_cc) {
- sowrite(so);
- }
+ return (!(so->so_state & SS_NOFDREF) && CONN_CANFSEND(so) && so->so_rcv.sb_cc);
}
-int sotryrecv(struct socket *so)
+
+int socanrecv(struct socket *so)
{
- int ret = 0;
- if (so->so_state & SS_NOFDREF)
- return 0;
- if (CONN_CANFRCV(so) && (so->so_snd.sb_cc < (so->so_snd.sb_datalen/2))) {
- ret = soread(so);
- }
- return ret;
+ return (!(so->so_state & SS_NOFDREF) && CONN_CANFRCV(so) &&
+ (so->so_snd.sb_cc < (so->so_snd.sb_datalen/2)));
}
void sodropacked (struct socket *so, int acked)
@@ -432,7 +423,6 @@ void sodropacked (struct socket *so, int acked)
sbdrop(&so->so_snd, acked);
}
-
#if 0 // UDP and socket listen
int soreadbuf(struct socket *so, const char *buf, int size)
{
@@ -872,3 +862,5 @@ sosbappend(so, m)
/* Whatever happened, we free the mbuf */
m_free(m);
}
+
+
diff --git a/socket.h b/socket.h
index fc392e2..f3c68b4 100644
--- a/socket.h
+++ b/socket.h
@@ -5,8 +5,6 @@
* terms and conditions of the copyright.
*/
-/* MINE */
-
#ifndef _SLIRP_SOCKET_H_
#define _SLIRP_SOCKET_H_
@@ -27,9 +25,9 @@ struct socket {
/* XXX union these with not-yet-used sbuf params */
struct mbuf *so_m; /* Pointer to the original SYN packet,
* for non-blocking connect()'s, and
- * PING reply's */
+ * PING reply's */
struct tcpiphdr *so_ti; /* Pointer to the original ti within
- * so_mconn, for non-blocking connections */
+ * 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 */
@@ -84,9 +82,9 @@ void sorecvoob _P((struct socket *));
int sosendoob _P((struct socket *));
int sowrite _P((struct socket *));
+int socanrecv(struct socket *so);
+int socansend(struct socket *so);
-void sotrysend _P((struct socket *));
-int sotryrecv _P((struct socket *));
void sodropacked _P((struct socket *, int));
void soisfconnecting _P((register struct socket *));
diff --git a/tcp.h b/tcp.h
index af4ca14..ddc0510 100644
--- a/tcp.h
+++ b/tcp.h
@@ -198,4 +198,6 @@ int tcp_emu _P((struct socket *, struct mbuf *));
int tcp_ctl _P((struct socket *));
void tcp_sockclosed _P((struct tcpcb *));
+u_int64_t tcp_socket_export(struct socket *so, void **export_socket);
+struct socket *tcp_socket_restore(void *export_socket, UserSocket *usr_socket);
#endif
diff --git a/tcp_input.c b/tcp_input.c
index f8ac7cd..d40eb8a 100644
--- a/tcp_input.c
+++ b/tcp_input.c
@@ -242,18 +242,28 @@ present:
static void
tcp_input1(register struct mbuf *m, int iphlen, struct socket *inso,
- int *drop_acked, struct socket **outso);
+ int *drop_acked_or_fconnected, struct socket **outso);
void tcp_input(m, iphlen, inso)
register struct mbuf *m;
int iphlen;
struct socket *inso;
{
- int drop_acked = 0;
+ int drop_acked_or_fconnected = 0;
+
struct socket *so = NULL;
- tcp_input1(m, iphlen, inso, &drop_acked, &so);
- if (drop_acked && so) {
- sotryrecv(so);
+ tcp_input1(m, iphlen, inso, &drop_acked_or_fconnected, &so);
+ /* tcp_input may trigger ack drop or status change to fconnected (ack after syn ack).
+ If a previous recv failed because of status, or place limit in snd buf, we should try to recv again.
+ Another use: if fin is pending, and we didn't recv it because there was also data pending for recv,
+ after the data is acked, we should recv the fin (by calling recv and getting 0) */
+ if (drop_acked_or_fconnected && so) {
+ if (socanrecv(so)) {
+ if (soread(so) > 0) {
+ /* Output it if we read something */
+ tcp_output(sototcpcb(so));
+ }
+ }
}
}
/*
@@ -262,11 +272,11 @@ void tcp_input(m, iphlen, inso)
* outso is valid only when drop_acked is true
*/
static void
-tcp_input1(m, iphlen, inso, drop_acked, outso)
+tcp_input1(m, iphlen, inso, drop_acked_or_fconnected, outso)
register struct mbuf *m;
int iphlen;
struct socket *inso;
- int *drop_acked;
+ int *drop_acked_or_fconnected;
struct socket **outso;
{
struct ip save_ip, *ip;
@@ -283,7 +293,7 @@ tcp_input1(m, iphlen, inso, drop_acked, outso)
u_long tiwin;
int ret;
/* int ts_present = 0; */
- *drop_acked = 0;
+ *drop_acked_or_fconnected = 0;
DEBUG_CALL("tcp_input");
DEBUG_ARGS((dfd," m = %8lx iphlen = %2d inso = %lx\n",
@@ -549,7 +559,7 @@ findso:
STAT(tcpstat.tcps_rcvackbyte += acked);
sodropacked(so, acked);
- *drop_acked = 1;
+ *drop_acked_or_fconnected = 1;
*outso = so;
tp->snd_una = ti->ti_ack;
@@ -788,7 +798,8 @@ findso:
STAT(tcpstat.tcps_connects++);
soisfconnected(so);
tp->t_state = TCPS_ESTABLISHED;
-
+ *drop_acked_or_fconnected = 1;
+ *outso = so;
/* Do window scaling on this connection? */
/* if ((tp->t_flags & (TF_RCVD_SCALE|TF_REQ_SCALE)) ==
* (TF_RCVD_SCALE|TF_REQ_SCALE)) {
@@ -1048,6 +1059,8 @@ trimthenstep6:
ret = tcp_ctl(so);
if (ret == 1) {
soisfconnected(so);
+ *drop_acked_or_fconnected = 1;
+ *outso = so;
so->so_state &= ~SS_CTL; /* success XXX */
} else if (ret == 2) {
so->so_state = SS_NOFDREF; /* CTL_CMD */
@@ -1057,6 +1070,8 @@ trimthenstep6:
}
} else {
soisfconnected(so);
+ *drop_acked_or_fconnected = 1;
+ *outso = so;
}
/* Do window scaling? */
@@ -1210,13 +1225,13 @@ trimthenstep6:
if (acked > so->so_snd.sb_cc) {
tp->snd_wnd -= so->so_snd.sb_cc;
sodropacked(so, (int)so->so_snd.sb_cc);
- *drop_acked = 1;
+ *drop_acked_or_fconnected = 1;
*outso = so;
ourfinisacked = 1;
} else {
sodropacked(so, acked);
- *drop_acked = 1;
+ *drop_acked_or_fconnected = 1;
*outso = so;
tp->snd_wnd -= acked;
diff --git a/tcp_subr.c b/tcp_subr.c
index 15cc2df..8a298c9 100644
--- a/tcp_subr.c
+++ b/tcp_subr.c
@@ -494,7 +494,7 @@ tcp_emu(so, m)
struct socket *so;
struct mbuf *m;
{
- printf("Error tcp_emu not supported");
+ fprintf(stderr, "Error tcp_emu not supported");
exit(-1);
}
@@ -502,6 +502,489 @@ int
tcp_ctl(so)
struct socket *so;
{
- printf("Error tcp_ctl not supported");
+ fprintf(stderr, "Error tcp_ctl not supported");
exit(-1);
}
+
+typedef struct __attribute__((packed)) TcpcbExportData {
+ int16_t state;
+ int16_t timer[TCPT_NTIMERS];
+ int16_t rxtshift;
+ int16_t rxtcur;
+ int16_t dupacks;
+ u_int16_t maxseg;
+ char force;
+ u_int16_t flags;
+
+ u_int32_t snd_una;
+ u_int32_t snd_nxt;
+ u_int32_t snd_up;
+ u_int32_t snd_wl1;
+ u_int32_t snd_wl2;
+ u_int32_t iss;
+ u_int32_t snd_wnd;
+
+ u_int32_t rcv_wnd;
+ u_int32_t rcv_nxt;
+ u_int32_t rcv_up;
+ u_int32_t irs;
+
+ u_int32_t rcv_adv;
+ u_int32_t snd_max;
+
+ u_int32_t snd_cwnd;
+ u_int32_t snd_ssthresh;
+
+ int16_t idle;
+ int16_t rtt;
+ u_int32_t rtseq;
+ int16_t srtt;
+ int16_t rttvar;
+ u_int16_t rttmin;
+ u_int32_t max_sndwnd;
+
+ char oobflags;
+ char iobc;
+
+ u_int32_t last_ack_sent;
+
+ // int16_t softerror; // always 0
+ // the current implementation of slirp doesn't support window scaling
+ // and these field are always zero
+ /* u_char snd_scale;
+ u_char rcv_scale;
+ u_char request_r_scale;
+ u_char requested_s_scale; */
+
+ // the current implementation of slirp doesn't support timestamp
+ // and these field are always zero
+ /* u_int32_t ts_recent;
+ u_int32_t ts_recent_age; */
+} TcpcbExportData;
+
+typedef struct __attribute__((packed)) TcpSocketExportData {
+ u_int32_t so_urgc;
+ u_int8_t faddr[4];
+ u_int8_t laddr[4];
+ u_int16_t fport;
+ u_int16_t lport;
+ u_int8_t iptos;
+ u_char type;
+ u_int32_t state;
+
+ int32_t syn_pack_offset; // assigned if the socket is during connections
+
+ int32_t rcv_buf_offset;
+ int32_t snd_buf_offset;
+
+ TcpcbExportData tcpcb;
+ int32_t reass_queue_offset; // offset to tcpSocketReassQueue
+ char data[0];
+} TcpSocketExportData;
+
+typedef struct __attribute__((packed)) TcpMbufExportData {
+ uint32_t size;
+ uint32_t mbuf_offset; // the tcpip header starts before the mbuf data
+ char data[0];
+} TcpMbufExportData;
+
+typedef struct __attribute__((packed)) SbufExportData {
+ uint32_t reserved;
+ uint32_t size;
+ char data[0];
+} SbufExportData;
+
+typedef struct __attribute__((packed)) ReassQueueExportData {
+ uint32_t num_packets;
+ int32_t packets[0]; // array of offsets
+} ReassQueueExportData;
+
+#define EXPORT_NULL_OFFSET -1
+
+static inline uint32_t __get_tcpip_pckt_size(struct tcpiphdr *ti)
+{
+ struct mbuf *m = dtom(ti);
+ return ((unsigned long)m->m_data - (unsigned long)ti + m->m_len);
+}
+
+static void __export_tcpip_pckt(struct tcpiphdr *ti, TcpMbufExportData *mbuf_data)
+{
+ struct mbuf *m = dtom(ti);
+ mbuf_data->size = __get_tcpip_pckt_size(ti);
+ mbuf_data->mbuf_offset = mbuf_data->size - m->m_len;
+ memcpy(mbuf_data->data, ti, mbuf_data->size);
+}
+
+static inline struct tcpiphdr *__restore_tcpip_pckt(TcpMbufExportData *exp_mbuf)
+{
+ struct mbuf *m = m_get();
+ struct tcpiphdr *ti;
+ if (!m ) {
+ return NULL;
+ }
+
+ if (M_FREEROOM(m) < (exp_mbuf->size + sizeof(struct qlink))) {
+ m_inc(m, exp_mbuf->size + sizeof(struct qlink));
+ }
+ m->m_data += sizeof(struct qlink);
+ m->m_len = exp_mbuf->size;
+
+ memcpy(m->m_data, exp_mbuf->data, exp_mbuf->size);
+ ti = mtod(m, struct tcpiphdr *);
+ ti->ti_mbuf = m;
+
+ m->m_data += exp_mbuf->mbuf_offset;
+ m->m_len -= exp_mbuf->mbuf_offset;
+
+ return ti;
+}
+
+static inline void __export_sbuf(struct sbuf *sbuf, SbufExportData *exp_sbuf)
+{
+ exp_sbuf->reserved = sbuf->sb_datalen;
+ exp_sbuf->size = sbuf->sb_cc;
+
+ sbcopy(sbuf, 0, sbuf->sb_cc, exp_sbuf->data);
+}
+
+static inline void __restore_sbuf(SbufExportData *exp_sbuf, struct sbuf *sbuf)
+{
+ sbreserve(sbuf, exp_sbuf->reserved);
+ memcpy(sbuf->sb_data, exp_sbuf->data, exp_sbuf->size);
+ sbuf->sb_cc = exp_sbuf->size;
+ sbuf->sb_rptr = sbuf->sb_data;
+
+ if (sbuf->sb_cc == sbuf->sb_datalen) {
+ sbuf->sb_wptr = sbuf->sb_data;
+ } else {
+ sbuf->sb_wptr = sbuf->sb_data + sbuf->sb_cc;
+ }
+
+
+}
+
+// returns how many bytes were written to export_data->data
+static int __tcp_socket_export_socket_data(struct socket *so, TcpSocketExportData *export_data,
+ int data_offset)
+{
+ char *data;
+ export_data->so_urgc = so->so_urgc;
+ memcpy(export_data->faddr, &so->so_faddr.s_addr, 4);
+ memcpy(export_data->laddr, &so->so_laddr.s_addr, 4);
+ export_data->fport = so->so_fport;
+ export_data->lport = so->so_lport;
+ export_data->iptos = so->so_iptos;
+ export_data->type = so->so_type;
+ export_data->state = so->so_state;
+
+ data = export_data->data + data_offset;
+ if ((so->so_state & SS_ISFCONNECTING) && so->so_ti) {
+ __export_tcpip_pckt(so->so_ti, (TcpMbufExportData *)data);
+ export_data->syn_pack_offset = data - export_data->data;
+ data += (sizeof(TcpMbufExportData) + ((TcpMbufExportData *)data)->size);
+ } else {
+ export_data->syn_pack_offset = EXPORT_NULL_OFFSET;
+ }
+
+
+ if (so->so_rcv.sb_datalen) {
+ __export_sbuf(&so->so_rcv, (SbufExportData *)data);
+ export_data->rcv_buf_offset = data - export_data->data;
+ data += (sizeof(SbufExportData) + ((SbufExportData *)data)->size);
+ } else {
+ export_data->rcv_buf_offset = EXPORT_NULL_OFFSET;
+ }
+
+ if (so->so_snd.sb_datalen) {
+ __export_sbuf(&so->so_snd, (SbufExportData *)data);
+ export_data->snd_buf_offset = data - export_data->data;
+ data += (sizeof(SbufExportData) + ((SbufExportData *)data)->size);
+ } else {
+ export_data->rcv_buf_offset = EXPORT_NULL_OFFSET;
+ }
+
+ return (data - export_data->data + data_offset);
+}
+
+
+static struct socket* __tcp_socket_restore_socket_data(TcpSocketExportData *export_data) {
+ struct socket *so = NULL;
+
+ if ((so = socreate()) == NULL) {
+ fprintf(stderr, "failed: creating socket\n");
+ goto error;
+ }
+
+ // Creates the tcpcb and adds the socket to to the tcp sockets list.
+ // Also sets the link from the tcpcp to the socket and vice versa
+ if (tcp_attach(so) < 0) {
+ fprintf(stderr, "faild: attach socket\n");
+ goto error;
+ }
+
+ so->so_urgc = export_data->so_urgc;
+ memcpy(&so->so_faddr.s_addr, export_data->faddr, 4);
+ memcpy(&so->so_laddr.s_addr, export_data->laddr, 4);
+ so->so_fport = export_data->fport;
+ so->so_lport = export_data->lport;
+ so->so_iptos = export_data->iptos;
+ so->so_type = export_data->type;
+ so->so_state = export_data->state;
+
+
+ if (export_data->syn_pack_offset != EXPORT_NULL_OFFSET) {
+ so->so_ti = __restore_tcpip_pckt((TcpMbufExportData *) (
+ export_data->data + export_data->syn_pack_offset));
+
+ if (!so->so_ti) {
+ fprintf(stderr, "failed: restoring syn packet\n");
+ goto error;
+ }
+ so->so_m = so->so_ti->ti_mbuf;
+ }
+
+ if (export_data->rcv_buf_offset != EXPORT_NULL_OFFSET) {
+ __restore_sbuf((SbufExportData *)(
+ export_data->data + export_data->rcv_buf_offset), &so->so_rcv);
+ }
+
+ if (export_data->snd_buf_offset != EXPORT_NULL_OFFSET) {
+ __restore_sbuf((SbufExportData *)(
+ export_data->data + export_data->snd_buf_offset), &so->so_snd);
+ }
+ return so;
+error:
+ if (so) {
+ if (so->so_m) {
+ m_free(so->so_m);
+ }
+ free(so);
+ }
+ return NULL;
+}
+
+static void __tcp_socket_export_tcpcb_data(struct tcpcb *tp, TcpcbExportData *export_data)
+{
+ int i;
+ export_data->state = tp->t_state;
+ for (i = 0; i < TCPT_NTIMERS; i++) {
+ export_data->timer[i] = tp->t_timer[i];
+ }
+ export_data->rxtshift = tp->t_rxtshift;
+ export_data->rxtcur = tp->t_rxtcur;
+ export_data->dupacks = tp->t_dupacks;
+ export_data->maxseg = tp->t_maxseg;
+ export_data->force = tp->t_force;
+ export_data->flags = tp->t_flags;
+
+ export_data->snd_una = tp->snd_una;
+ export_data->snd_nxt = tp->snd_nxt;
+ export_data->snd_up = tp->snd_up;
+ export_data->snd_wl1 = tp->snd_wl1;
+ export_data->snd_wl2 = tp->snd_wl2;
+ export_data->iss = tp->iss;
+ export_data->snd_wnd = tp->snd_wnd;
+
+ export_data->rcv_wnd = tp->rcv_wnd;
+ export_data->rcv_nxt = tp->rcv_nxt;
+ export_data->rcv_up = tp->rcv_up;
+ export_data->irs = tp->irs;
+
+ export_data->rcv_adv = tp->rcv_adv;
+ export_data->snd_max = tp->snd_max;
+
+ export_data->snd_cwnd = tp->snd_cwnd;
+ export_data->snd_ssthresh = tp->snd_ssthresh;
+
+ export_data->idle = tp->t_idle;
+ export_data->rtt = tp->t_rtt;
+ export_data->rtseq = tp->t_rtseq;
+ export_data->srtt = tp->t_srtt;
+ export_data->rttvar = tp->t_rttvar;
+ export_data->rttmin = tp->t_rttmin;
+ export_data->max_sndwnd = tp->max_sndwnd;
+
+ export_data->oobflags = tp->t_oobflags;
+ export_data->iobc = tp->t_iobc;
+
+ export_data->last_ack_sent = tp->last_ack_sent;
+}
+
+static void __tcp_socket_restore_tcpcb_data(TcpcbExportData *export_data, struct tcpcb *tp)
+{
+ int i;
+
+ tp->t_state = export_data->state;
+ for (i = 0; i < TCPT_NTIMERS; i++) {
+ tp->t_timer[i] = export_data->timer[i];
+ }
+ tp->t_rxtshift = export_data->rxtshift;
+ tp->t_rxtcur = export_data->rxtcur;
+ tp->t_dupacks = export_data->dupacks;
+ tp->t_maxseg = export_data->maxseg;
+ tp->t_force = export_data->force;
+ tp->t_flags = export_data->flags;
+
+ tp->snd_una = export_data->snd_una;
+ tp->snd_nxt = export_data->snd_nxt;
+ tp->snd_up = export_data->snd_up;
+ tp->snd_wl1 = export_data->snd_wl1;
+ tp->snd_wl2 = export_data->snd_wl2;
+ tp->iss = export_data->iss;
+ tp->snd_wnd = export_data->snd_wnd;
+
+ tp->rcv_wnd = export_data->rcv_wnd;
+ tp->rcv_nxt = export_data->rcv_nxt;
+ tp->rcv_up = export_data->rcv_up;
+ tp->irs = export_data->irs;
+
+ tp->rcv_adv = export_data->rcv_adv;
+ tp->snd_max = export_data->snd_max;
+
+ tp->snd_cwnd = export_data->snd_cwnd;
+ tp->snd_ssthresh = export_data->snd_ssthresh;
+
+
+ tp->t_idle = export_data->idle;
+ tp->t_rtt = export_data->rtt;
+ tp->t_rtseq = export_data->rtseq;
+ tp->t_srtt = export_data->srtt;
+ tp->t_rttvar = export_data->rttvar;
+ tp->t_rttmin = export_data->rttmin;
+ tp->max_sndwnd = export_data->max_sndwnd;
+
+ tp->t_oobflags = export_data->oobflags;
+ tp->t_iobc = export_data->iobc;
+
+ tp->last_ack_sent = export_data->last_ack_sent;
+
+ tcp_template(tp);
+}
+
+// returns how many bytes were written to export_data->data
+static int __tcp_socket_export_reass_queue(struct tcpcb *tp, int queue_size,
+ TcpSocketExportData *export_data, int data_offset)
+{
+ char *data = export_data->data + data_offset;
+ struct tcpiphdr *q;
+ ReassQueueExportData *queue_header;
+ int i;
+
+ if (!queue_size) {
+ export_data->reass_queue_offset = EXPORT_NULL_OFFSET;
+ return 0;
+ }
+
+ export_data->reass_queue_offset = data_offset;
+ queue_header = (ReassQueueExportData *)data;
+ queue_header->num_packets = queue_size;
+
+ data = (char*)(queue_header + 1) + (sizeof(int32_t)*queue_size);
+
+ for (i =0, q = tcpfrag_list_first(tp); !tcpfrag_list_end(q, tp); q = tcpiphdr_next(q), i++) {
+ __export_tcpip_pckt(q, (TcpMbufExportData *)data);
+ queue_header->packets[i] = data - export_data->data;
+
+ data += (sizeof(TcpMbufExportData) + ((TcpMbufExportData *)data)->size);
+ }
+
+ return (data - export_data->data + data_offset);
+}
+
+static int __tcp_socket_restore_reass_queue(TcpSocketExportData *export_data, struct tcpcb *tp)
+{
+ ReassQueueExportData *queue_header;
+ int i;
+ if (export_data->reass_queue_offset == EXPORT_NULL_OFFSET) {
+ return TRUE;
+ }
+
+ queue_header = (ReassQueueExportData *)(export_data->data + export_data->reass_queue_offset);
+ for (i = 0; i < queue_header->num_packets; i++) {
+ struct tcpiphdr *ti = __restore_tcpip_pckt((TcpMbufExportData *) (
+ export_data->data + queue_header->packets[i]));
+
+ if (!ti) {
+ fprintf(stderr, "failed: restoring tcpip packet\n");
+ goto error;
+ }
+ insque(tcpiphdr2qlink(ti), tcpiphdr2qlink(tcpfrag_list_last(tp)));
+ }
+
+ return TRUE;
+error:
+ while(!tcpfrag_list_empty(tp)) {
+ struct tcpiphdr *ti = tcpfrag_list_first(tp);
+ remque(tcpiphdr2qlink(ti));
+ m_free(ti->ti_mbuf);
+ }
+
+ return FALSE;
+}
+
+uint64_t tcp_socket_export(struct socket *so, void **export_socket)
+{
+ uint64_t total_size = sizeof(TcpSocketExportData);
+ struct tcpcb *tp;
+ struct tcpiphdr *q;
+ int reass_queue_size = 0;
+ TcpSocketExportData *ret;
+ int data_offset = 0;
+
+ if ((so->so_state & SS_ISFCONNECTING) && so->so_ti) {
+ total_size += sizeof(TcpMbufExportData);
+ total_size += __get_tcpip_pckt_size(so->so_ti);
+ }
+
+ if (so->so_rcv.sb_datalen) {
+ total_size += sizeof(SbufExportData);
+ total_size += so->so_rcv.sb_cc;
+ }
+
+ if (so->so_snd.sb_datalen) {
+ total_size += sizeof(SbufExportData);
+ total_size += so->so_snd.sb_cc;
+ }
+
+ tp = sototcpcb(so);
+
+ for (q = tcpfrag_list_first(tp); !tcpfrag_list_end(q, tp);
+ q = tcpiphdr_next(q)) {
+ reass_queue_size++;
+ total_size += sizeof(TcpMbufExportData);
+ total_size += __get_tcpip_pckt_size(q);
+ }
+
+ if (reass_queue_size) {
+ total_size += sizeof(ReassQueueExportData);
+ total_size += reass_queue_size*sizeof(int32_t);
+ }
+
+ ret = (TcpSocketExportData *)malloc(total_size);
+
+ data_offset += __tcp_socket_export_socket_data(so, ret, data_offset);
+ __tcp_socket_export_tcpcb_data(tp, &ret->tcpcb);
+ data_offset += __tcp_socket_export_reass_queue(tp, reass_queue_size, ret, data_offset);
+ *export_socket = ret;
+ return total_size;
+}
+
+struct socket *tcp_socket_restore(void *export_so, UserSocket *usr_so)
+{
+ TcpSocketExportData *export_data = (TcpSocketExportData *)export_so;
+ struct socket *so = __tcp_socket_restore_socket_data(export_data);
+
+ if (!so) {
+ return NULL;
+ }
+
+ __tcp_socket_restore_tcpcb_data(&export_data->tcpcb, sototcpcb(so));
+
+ if (!__tcp_socket_restore_reass_queue(export_data, sototcpcb(so))) {
+ // usr_so is still null, so tcp_close will only free resources
+ tcp_close(sototcpcb(so));
+ return NULL;
+ }
+ so->usr_so = usr_so;
+ return so;
+}
diff --git a/tcp_timer.c b/tcp_timer.c
index cb7d37f..16f0282 100644
--- a/tcp_timer.c
+++ b/tcp_timer.c
@@ -42,8 +42,6 @@
struct tcpstat tcpstat; /* tcp statistics */
#endif
-u_int32_t tcp_now; /* for RFC 1323 timestamps */
-
static struct tcpcb *tcp_timers(register struct tcpcb *tp, int timer);
/*
@@ -112,7 +110,6 @@ tpgone:
if ((int)tcp_iss < 0)
tcp_iss = 0; /* XXX */
#endif
- tcp_now++; /* for timestamps */
}
/*
diff --git a/tcp_var.h b/tcp_var.h
index 99d18fd..1789d29 100644
--- a/tcp_var.h
+++ b/tcp_var.h
@@ -229,6 +229,4 @@ struct tcpstat {
extern struct tcpstat tcpstat; /* tcp statistics */
#endif
-extern u_int32_t tcp_now; /* for RFC 1323 timestamps */
-
#endif
diff --git a/tcpip.h b/tcpip.h
index e3a31d9..c07402e 100644
--- a/tcpip.h
+++ b/tcpip.h
@@ -67,6 +67,7 @@ struct tcpiphdr {
#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_last(T) qlink2tcpiphdr((T)->seg_prev)
#define tcpfrag_list_end(F, T) (tcpiphdr2qlink(F) == (struct qlink*)(T))
#define tcpfrag_list_empty(T) ((T)->seg_next == (struct tcpiphdr*)(T))