diff options
author | Yonit <yhalperi@redhat.com> | 2009-06-21 17:03:24 +0300 |
---|---|---|
committer | Yonit <yhalperi@redhat.com> | 2009-06-21 17:03:24 +0300 |
commit | 0d39510a5f74043c9e44d4534f7064590d744339 (patch) | |
tree | fb568c11e3b9a637127241c0e88ce1b1dc2cc07f | |
parent | ec383e8b58b4e1e93f5bba5dce6cd1f2d0ccf116 (diff) |
Export/Restore
-rw-r--r-- | bootp.c | 102 | ||||
-rw-r--r-- | bootp.h | 3 | ||||
-rw-r--r-- | ip_input.c | 8 | ||||
-rw-r--r-- | mbuf.c | 1 | ||||
-rw-r--r-- | net_slirp.c | 112 | ||||
-rw-r--r-- | net_slirp.h | 20 | ||||
-rw-r--r-- | slirp_common.h | 18 | ||||
-rw-r--r-- | socket.c | 24 | ||||
-rw-r--r-- | socket.h | 10 | ||||
-rw-r--r-- | tcp.h | 2 | ||||
-rw-r--r-- | tcp_input.c | 39 | ||||
-rw-r--r-- | tcp_subr.c | 487 | ||||
-rw-r--r-- | tcp_timer.c | 3 | ||||
-rw-r--r-- | tcp_var.h | 2 | ||||
-rw-r--r-- | tcpip.h | 1 |
15 files changed, 732 insertions, 100 deletions
@@ -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); + } +} @@ -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 @@ -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(); } /* @@ -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 @@ -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); } + + @@ -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 *)); @@ -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; @@ -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 */ } /* @@ -229,6 +229,4 @@ struct tcpstat { extern struct tcpstat tcpstat; /* tcp statistics */ #endif -extern u_int32_t tcp_now; /* for RFC 1323 timestamps */ - #endif @@ -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)) |