slirp: Rework internal configuration
The user mode IP stack is currently only minimally configurable /wrt to its virtual IP addresses. This is unfortunate if some guest has a fixed idea of which IP addresses to use. Therefore this patch prepares the stack for fully configurable IP addresses and masks. The user interface and default addresses remain untouched in this step, they will be enhanced in the following patch. Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
This commit is contained in:
parent
ad196a9d0c
commit
a13a4126c8
|
@ -27,8 +27,6 @@
|
||||||
|
|
||||||
#define NB_ADDR 16
|
#define NB_ADDR 16
|
||||||
|
|
||||||
#define START_ADDR 15
|
|
||||||
|
|
||||||
#define LEASE_TIME (24 * 3600)
|
#define LEASE_TIME (24 * 3600)
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -64,7 +62,7 @@ static BOOTPClient *get_new_addr(struct in_addr *paddr,
|
||||||
found:
|
found:
|
||||||
bc = &bootp_clients[i];
|
bc = &bootp_clients[i];
|
||||||
bc->allocated = 1;
|
bc->allocated = 1;
|
||||||
paddr->s_addr = htonl(ntohl(special_addr.s_addr) | (i + START_ADDR));
|
paddr->s_addr = vdhcp_startaddr.s_addr + htonl(i);
|
||||||
return bc;
|
return bc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,12 +70,12 @@ static BOOTPClient *request_addr(const struct in_addr *paddr,
|
||||||
const uint8_t *macaddr)
|
const uint8_t *macaddr)
|
||||||
{
|
{
|
||||||
uint32_t req_addr = ntohl(paddr->s_addr);
|
uint32_t req_addr = ntohl(paddr->s_addr);
|
||||||
uint32_t spec_addr = ntohl(special_addr.s_addr);
|
uint32_t dhcp_addr = ntohl(vdhcp_startaddr.s_addr);
|
||||||
BOOTPClient *bc;
|
BOOTPClient *bc;
|
||||||
|
|
||||||
if (req_addr >= (spec_addr | START_ADDR) &&
|
if (req_addr >= dhcp_addr &&
|
||||||
req_addr < (spec_addr | (NB_ADDR + START_ADDR))) {
|
req_addr < (dhcp_addr + NB_ADDR)) {
|
||||||
bc = &bootp_clients[(req_addr & 0xff) - START_ADDR];
|
bc = &bootp_clients[req_addr - dhcp_addr];
|
||||||
if (!bc->allocated || !memcmp(macaddr, bc->macaddr, 6)) {
|
if (!bc->allocated || !memcmp(macaddr, bc->macaddr, 6)) {
|
||||||
bc->allocated = 1;
|
bc->allocated = 1;
|
||||||
return bc;
|
return bc;
|
||||||
|
@ -99,7 +97,7 @@ static BOOTPClient *find_addr(struct in_addr *paddr, const uint8_t *macaddr)
|
||||||
found:
|
found:
|
||||||
bc = &bootp_clients[i];
|
bc = &bootp_clients[i];
|
||||||
bc->allocated = 1;
|
bc->allocated = 1;
|
||||||
paddr->s_addr = htonl(ntohl(special_addr.s_addr) | (i + START_ADDR));
|
paddr->s_addr = vdhcp_startaddr.s_addr + htonl(i);
|
||||||
return bc;
|
return bc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,7 +154,6 @@ static void bootp_reply(const struct bootp_t *bp)
|
||||||
struct mbuf *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;
|
|
||||||
const struct in_addr *preq_addr;
|
const struct in_addr *preq_addr;
|
||||||
int dhcp_msg_type, val;
|
int dhcp_msg_type, val;
|
||||||
uint8_t *q;
|
uint8_t *q;
|
||||||
|
@ -218,7 +215,7 @@ static void bootp_reply(const struct bootp_t *bp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
saddr.sin_addr.s_addr = htonl(ntohl(special_addr.s_addr) | CTL_ALIAS);
|
saddr.sin_addr = 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);
|
||||||
|
@ -262,10 +259,8 @@ static void bootp_reply(const struct bootp_t *bp)
|
||||||
|
|
||||||
*q++ = RFC1533_NETMASK;
|
*q++ = RFC1533_NETMASK;
|
||||||
*q++ = 4;
|
*q++ = 4;
|
||||||
*q++ = 0xff;
|
memcpy(q, &vnetwork_mask, 4);
|
||||||
*q++ = 0xff;
|
q += 4;
|
||||||
*q++ = 0xff;
|
|
||||||
*q++ = 0x00;
|
|
||||||
|
|
||||||
if (!slirp_restrict) {
|
if (!slirp_restrict) {
|
||||||
*q++ = RFC1533_GATEWAY;
|
*q++ = RFC1533_GATEWAY;
|
||||||
|
@ -275,8 +270,7 @@ static void bootp_reply(const struct bootp_t *bp)
|
||||||
|
|
||||||
*q++ = RFC1533_DNS;
|
*q++ = RFC1533_DNS;
|
||||||
*q++ = 4;
|
*q++ = 4;
|
||||||
dns_addr.s_addr = htonl(ntohl(special_addr.s_addr) | CTL_DNS);
|
memcpy(q, &vnameserver_addr, 4);
|
||||||
memcpy(q, &dns_addr, 4);
|
|
||||||
q += 4;
|
q += 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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"
|
|
|
@ -110,7 +110,7 @@ icmp_input(struct mbuf *m, int hlen)
|
||||||
case ICMP_ECHO:
|
case ICMP_ECHO:
|
||||||
icp->icmp_type = ICMP_ECHOREPLY;
|
icp->icmp_type = ICMP_ECHOREPLY;
|
||||||
ip->ip_len += hlen; /* since ip_input subtracts this */
|
ip->ip_len += hlen; /* since ip_input subtracts this */
|
||||||
if (ip->ip_dst.s_addr == alias_addr.s_addr) {
|
if (ip->ip_dst.s_addr == vhost_addr.s_addr) {
|
||||||
icmp_reflect(m);
|
icmp_reflect(m);
|
||||||
} else {
|
} else {
|
||||||
struct socket *so;
|
struct socket *so;
|
||||||
|
@ -134,16 +134,13 @@ icmp_input(struct mbuf *m, int hlen)
|
||||||
|
|
||||||
/* Send the packet */
|
/* Send the packet */
|
||||||
addr.sin_family = AF_INET;
|
addr.sin_family = AF_INET;
|
||||||
if ((so->so_faddr.s_addr & htonl(0xffffff00)) == special_addr.s_addr) {
|
if ((so->so_faddr.s_addr & vnetwork_mask.s_addr) ==
|
||||||
|
vnetwork_addr.s_addr) {
|
||||||
/* It's an alias */
|
/* It's an alias */
|
||||||
switch(ntohl(so->so_faddr.s_addr) & 0xff) {
|
if (so->so_faddr.s_addr == vnameserver_addr.s_addr) {
|
||||||
case CTL_DNS:
|
|
||||||
addr.sin_addr = dns_addr;
|
addr.sin_addr = dns_addr;
|
||||||
break;
|
} else {
|
||||||
case CTL_ALIAS:
|
|
||||||
default:
|
|
||||||
addr.sin_addr = loopback_addr;
|
addr.sin_addr = loopback_addr;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
addr.sin_addr = so->so_faddr;
|
addr.sin_addr = so->so_faddr;
|
||||||
|
@ -302,7 +299,7 @@ icmp_error(struct mbuf *msrc, u_char type, u_char code, int minsize,
|
||||||
ip->ip_ttl = MAXTTL;
|
ip->ip_ttl = MAXTTL;
|
||||||
ip->ip_p = IPPROTO_ICMP;
|
ip->ip_p = IPPROTO_ICMP;
|
||||||
ip->ip_dst = ip->ip_src; /* ip adresses */
|
ip->ip_dst = ip->ip_src; /* ip adresses */
|
||||||
ip->ip_src = alias_addr;
|
ip->ip_src = vhost_addr;
|
||||||
|
|
||||||
(void ) ip_output((struct socket *)NULL, m);
|
(void ) ip_output((struct socket *)NULL, m);
|
||||||
|
|
||||||
|
|
|
@ -134,18 +134,19 @@ ip_input(struct mbuf *m)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (slirp_restrict) {
|
if (slirp_restrict) {
|
||||||
if (memcmp(&ip->ip_dst.s_addr, &special_addr, 3)) {
|
if ((ip->ip_dst.s_addr & vnetwork_mask.s_addr) ==
|
||||||
|
vnetwork_addr.s_addr) {
|
||||||
if (ip->ip_dst.s_addr == 0xffffffff && ip->ip_p != IPPROTO_UDP)
|
if (ip->ip_dst.s_addr == 0xffffffff && ip->ip_p != IPPROTO_UDP)
|
||||||
goto bad;
|
goto bad;
|
||||||
} else {
|
} else {
|
||||||
int host = ntohl(ip->ip_dst.s_addr) & 0xff;
|
|
||||||
struct ex_list *ex_ptr;
|
struct ex_list *ex_ptr;
|
||||||
|
|
||||||
if (host == 0xff)
|
if ((ip->ip_dst.s_addr & ~vnetwork_mask.s_addr) ==
|
||||||
|
~vnetwork_mask.s_addr)
|
||||||
goto bad;
|
goto bad;
|
||||||
|
|
||||||
for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next)
|
for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next)
|
||||||
if (ex_ptr->ex_addr == host)
|
if (ex_ptr->ex_addr.s_addr == ip->ip_dst.s_addr)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (!ex_ptr)
|
if (!ex_ptr)
|
||||||
|
|
|
@ -32,9 +32,11 @@ extern char *slirp_tty;
|
||||||
extern char *exec_shell;
|
extern char *exec_shell;
|
||||||
extern u_int curtime;
|
extern u_int curtime;
|
||||||
extern fd_set *global_readfds, *global_writefds, *global_xfds;
|
extern fd_set *global_readfds, *global_writefds, *global_xfds;
|
||||||
extern struct in_addr ctl_addr;
|
extern struct in_addr vnetwork_addr;
|
||||||
extern struct in_addr special_addr;
|
extern struct in_addr vnetwork_mask;
|
||||||
extern struct in_addr alias_addr;
|
extern struct in_addr vhost_addr;
|
||||||
|
extern struct in_addr vdhcp_startaddr;
|
||||||
|
extern struct in_addr vnameserver_addr;
|
||||||
extern struct in_addr our_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 struct in_addr dns_addr;
|
||||||
|
@ -44,7 +46,6 @@ extern int towrite_max;
|
||||||
extern int ppp_exit;
|
extern int ppp_exit;
|
||||||
extern int tcp_keepintvl;
|
extern int tcp_keepintvl;
|
||||||
extern uint8_t client_ethaddr[6];
|
extern uint8_t client_ethaddr[6];
|
||||||
extern const char *slirp_special_ip;
|
|
||||||
extern int slirp_restrict;
|
extern int slirp_restrict;
|
||||||
extern char *tftp_prefix;
|
extern char *tftp_prefix;
|
||||||
extern char *bootp_filename;
|
extern char *bootp_filename;
|
||||||
|
|
|
@ -112,14 +112,15 @@ remque(void *a)
|
||||||
/* #endif */
|
/* #endif */
|
||||||
|
|
||||||
|
|
||||||
int
|
int add_exec(struct ex_list **ex_ptr, int do_pty, char *exec,
|
||||||
add_exec(struct ex_list **ex_ptr, int do_pty, char *exec, int addr, int port)
|
struct in_addr addr, int port)
|
||||||
{
|
{
|
||||||
struct ex_list *tmp_ptr;
|
struct ex_list *tmp_ptr;
|
||||||
|
|
||||||
/* First, check if the port is "bound" */
|
/* First, check if the port is "bound" */
|
||||||
for (tmp_ptr = *ex_ptr; tmp_ptr; tmp_ptr = tmp_ptr->ex_next) {
|
for (tmp_ptr = *ex_ptr; tmp_ptr; tmp_ptr = tmp_ptr->ex_next) {
|
||||||
if (port == tmp_ptr->ex_fport && addr == tmp_ptr->ex_addr)
|
if (port == tmp_ptr->ex_fport &&
|
||||||
|
addr.s_addr == tmp_ptr->ex_addr.s_addr)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
struct ex_list {
|
struct ex_list {
|
||||||
int ex_pty; /* Do we want a pty? */
|
int ex_pty; /* Do we want a pty? */
|
||||||
int ex_addr; /* The last byte of the address */
|
struct in_addr ex_addr; /* Server address */
|
||||||
int ex_fport; /* Port to telnet to */
|
int ex_fport; /* Port to telnet to */
|
||||||
const char *ex_exec; /* Command line of what to exec */
|
const char *ex_exec; /* Command line of what to exec */
|
||||||
struct ex_list *ex_next;
|
struct ex_list *ex_next;
|
||||||
|
@ -74,7 +74,7 @@ void redir_x _P((u_int32_t, int, int, int));
|
||||||
void getouraddr _P((void));
|
void getouraddr _P((void));
|
||||||
void slirp_insque _P((void *, void *));
|
void slirp_insque _P((void *, void *));
|
||||||
void slirp_remque _P((void *));
|
void slirp_remque _P((void *));
|
||||||
int add_exec _P((struct ex_list **, int, char *, int, int));
|
int add_exec _P((struct ex_list **, int, char *, struct in_addr, int));
|
||||||
int slirp_openpty _P((int *, int *));
|
int slirp_openpty _P((int *, int *));
|
||||||
int fork_exec(struct socket *so, const char *ex, int do_pty);
|
int fork_exec(struct socket *so, const char *ex, int do_pty);
|
||||||
void snooze_hup _P((int));
|
void snooze_hup _P((int));
|
||||||
|
|
122
slirp/slirp.c
122
slirp/slirp.c
|
@ -33,13 +33,16 @@ struct in_addr dns_addr;
|
||||||
/* host loopback address */
|
/* host loopback address */
|
||||||
struct in_addr loopback_addr;
|
struct in_addr loopback_addr;
|
||||||
|
|
||||||
/* address for slirp virtual addresses */
|
/* virtual network configuration */
|
||||||
struct in_addr special_addr;
|
struct in_addr vnetwork_addr;
|
||||||
/* virtual address alias for host */
|
struct in_addr vnetwork_mask;
|
||||||
struct in_addr alias_addr;
|
struct in_addr vhost_addr;
|
||||||
|
struct in_addr vdhcp_startaddr;
|
||||||
|
struct in_addr vnameserver_addr;
|
||||||
|
|
||||||
|
/* emulated hosts use the MAC addr 52:55:IP:IP:IP:IP */
|
||||||
static const uint8_t special_ethaddr[6] = {
|
static const uint8_t special_ethaddr[6] = {
|
||||||
0x52, 0x54, 0x00, 0x12, 0x35, 0x00
|
0x52, 0x55, 0x00, 0x00, 0x00, 0x00
|
||||||
};
|
};
|
||||||
|
|
||||||
/* ARP cache for the guest IP addresses (XXX: allow many entries) */
|
/* ARP cache for the guest IP addresses (XXX: allow many entries) */
|
||||||
|
@ -48,7 +51,6 @@ static struct in_addr client_ipaddr;
|
||||||
|
|
||||||
static const uint8_t zero_ethaddr[6] = { 0, 0, 0, 0, 0, 0 };
|
static const uint8_t zero_ethaddr[6] = { 0, 0, 0, 0, 0, 0 };
|
||||||
|
|
||||||
const char *slirp_special_ip = CTL_SPECIAL;
|
|
||||||
int slirp_restrict;
|
int slirp_restrict;
|
||||||
static int do_slowtimo;
|
static int do_slowtimo;
|
||||||
int link_up;
|
int link_up;
|
||||||
|
@ -176,12 +178,12 @@ void slirp_init(int restricted, const char *special_ip, const char *tftp_path,
|
||||||
{
|
{
|
||||||
// debug_init("/tmp/slirp.log", DEBUG_DEFAULT);
|
// debug_init("/tmp/slirp.log", DEBUG_DEFAULT);
|
||||||
|
|
||||||
|
struct in_addr special_addr = { .s_addr = htonl(0x0a000200) };
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
{
|
|
||||||
WSADATA Data;
|
WSADATA Data;
|
||||||
|
|
||||||
WSAStartup(MAKEWORD(2,0), &Data);
|
WSAStartup(MAKEWORD(2,0), &Data);
|
||||||
atexit(slirp_cleanup);
|
atexit(slirp_cleanup);
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
link_up = 1;
|
link_up = 1;
|
||||||
|
@ -201,9 +203,9 @@ void slirp_init(int restricted, const char *special_ip, const char *tftp_path,
|
||||||
fprintf (stderr, "Warning: No DNS servers found\n");
|
fprintf (stderr, "Warning: No DNS servers found\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (special_ip)
|
if (special_ip) {
|
||||||
slirp_special_ip = special_ip;
|
inet_aton(special_ip, &special_addr);
|
||||||
|
}
|
||||||
qemu_free(tftp_prefix);
|
qemu_free(tftp_prefix);
|
||||||
tftp_prefix = NULL;
|
tftp_prefix = NULL;
|
||||||
if (tftp_path) {
|
if (tftp_path) {
|
||||||
|
@ -215,8 +217,11 @@ void slirp_init(int restricted, const char *special_ip, const char *tftp_path,
|
||||||
bootp_filename = qemu_strdup(bootfile);
|
bootp_filename = qemu_strdup(bootfile);
|
||||||
}
|
}
|
||||||
|
|
||||||
inet_aton(slirp_special_ip, &special_addr);
|
vnetwork_addr = special_addr;
|
||||||
alias_addr.s_addr = special_addr.s_addr | htonl(CTL_ALIAS);
|
vnetwork_mask.s_addr = htonl(0xffffff00);
|
||||||
|
vhost_addr.s_addr = special_addr.s_addr | htonl(2);
|
||||||
|
vdhcp_startaddr.s_addr = special_addr.s_addr | htonl(15);
|
||||||
|
vnameserver_addr.s_addr = special_addr.s_addr | htonl(3);
|
||||||
getouraddr();
|
getouraddr();
|
||||||
register_savevm("slirp", 0, 1, slirp_state_save, slirp_state_load, NULL);
|
register_savevm("slirp", 0, 1, slirp_state_save, slirp_state_load, NULL);
|
||||||
}
|
}
|
||||||
|
@ -601,10 +606,10 @@ struct arphdr
|
||||||
* Ethernet looks like this : This bit is variable sized however...
|
* Ethernet looks like this : This bit is variable sized however...
|
||||||
*/
|
*/
|
||||||
unsigned char ar_sha[ETH_ALEN]; /* sender hardware address */
|
unsigned char ar_sha[ETH_ALEN]; /* sender hardware address */
|
||||||
unsigned char ar_sip[4]; /* sender IP address */
|
uint32_t ar_sip; /* sender IP address */
|
||||||
unsigned char ar_tha[ETH_ALEN]; /* target hardware address */
|
unsigned char ar_tha[ETH_ALEN]; /* target hardware address */
|
||||||
unsigned char ar_tip[4]; /* target IP address */
|
uint32_t ar_tip ; /* target IP address */
|
||||||
};
|
} __attribute__((packed));
|
||||||
|
|
||||||
static void arp_input(const uint8_t *pkt, int pkt_len)
|
static void arp_input(const uint8_t *pkt, int pkt_len)
|
||||||
{
|
{
|
||||||
|
@ -619,11 +624,12 @@ static void arp_input(const uint8_t *pkt, int pkt_len)
|
||||||
ar_op = ntohs(ah->ar_op);
|
ar_op = ntohs(ah->ar_op);
|
||||||
switch(ar_op) {
|
switch(ar_op) {
|
||||||
case ARPOP_REQUEST:
|
case ARPOP_REQUEST:
|
||||||
if (!memcmp(ah->ar_tip, &special_addr, 3)) {
|
if ((ah->ar_tip & vnetwork_mask.s_addr) == vnetwork_addr.s_addr) {
|
||||||
if (ah->ar_tip[3] == CTL_DNS || ah->ar_tip[3] == CTL_ALIAS)
|
if (ah->ar_tip == vnameserver_addr.s_addr ||
|
||||||
|
ah->ar_tip == vhost_addr.s_addr)
|
||||||
goto arp_ok;
|
goto arp_ok;
|
||||||
for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
|
for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
|
||||||
if (ex_ptr->ex_addr == ah->ar_tip[3])
|
if (ex_ptr->ex_addr.s_addr == ah->ar_tip)
|
||||||
goto arp_ok;
|
goto arp_ok;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
@ -633,8 +639,8 @@ static void arp_input(const uint8_t *pkt, int pkt_len)
|
||||||
|
|
||||||
/* ARP request for alias/dns mac address */
|
/* ARP request for alias/dns mac address */
|
||||||
memcpy(reh->h_dest, pkt + ETH_ALEN, ETH_ALEN);
|
memcpy(reh->h_dest, pkt + ETH_ALEN, ETH_ALEN);
|
||||||
memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 1);
|
memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 4);
|
||||||
reh->h_source[5] = ah->ar_tip[3];
|
memcpy(&reh->h_source[2], &ah->ar_tip, 4);
|
||||||
reh->h_proto = htons(ETH_P_ARP);
|
reh->h_proto = htons(ETH_P_ARP);
|
||||||
|
|
||||||
rah->ar_hrd = htons(1);
|
rah->ar_hrd = htons(1);
|
||||||
|
@ -643,16 +649,16 @@ static void arp_input(const uint8_t *pkt, int pkt_len)
|
||||||
rah->ar_pln = 4;
|
rah->ar_pln = 4;
|
||||||
rah->ar_op = htons(ARPOP_REPLY);
|
rah->ar_op = htons(ARPOP_REPLY);
|
||||||
memcpy(rah->ar_sha, reh->h_source, ETH_ALEN);
|
memcpy(rah->ar_sha, reh->h_source, ETH_ALEN);
|
||||||
memcpy(rah->ar_sip, ah->ar_tip, 4);
|
rah->ar_sip = ah->ar_tip;
|
||||||
memcpy(rah->ar_tha, ah->ar_sha, ETH_ALEN);
|
memcpy(rah->ar_tha, ah->ar_sha, ETH_ALEN);
|
||||||
memcpy(rah->ar_tip, ah->ar_sip, 4);
|
rah->ar_tip = ah->ar_sip;
|
||||||
slirp_output(arp_reply, sizeof(arp_reply));
|
slirp_output(arp_reply, sizeof(arp_reply));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ARPOP_REPLY:
|
case ARPOP_REPLY:
|
||||||
/* reply to request of client mac address ? */
|
/* reply to request of client mac address ? */
|
||||||
if (!memcmp(client_ethaddr, zero_ethaddr, ETH_ALEN) &&
|
if (!memcmp(client_ethaddr, zero_ethaddr, ETH_ALEN) &&
|
||||||
!memcmp(ah->ar_sip, &client_ipaddr.s_addr, 4)) {
|
ah->ar_sip == client_ipaddr.s_addr) {
|
||||||
memcpy(client_ethaddr, ah->ar_sha, ETH_ALEN);
|
memcpy(client_ethaddr, ah->ar_sha, ETH_ALEN);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -716,8 +722,8 @@ void if_encap(const uint8_t *ip_data, int ip_data_len)
|
||||||
in place of sending the packet and we hope that the sender
|
in place of sending the packet and we hope that the sender
|
||||||
will retry sending its packet. */
|
will retry sending its packet. */
|
||||||
memset(reh->h_dest, 0xff, ETH_ALEN);
|
memset(reh->h_dest, 0xff, ETH_ALEN);
|
||||||
memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 1);
|
memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 4);
|
||||||
reh->h_source[5] = CTL_ALIAS;
|
memcpy(&reh->h_source[2], &vhost_addr, 4);
|
||||||
reh->h_proto = htons(ETH_P_ARP);
|
reh->h_proto = htons(ETH_P_ARP);
|
||||||
rah->ar_hrd = htons(1);
|
rah->ar_hrd = htons(1);
|
||||||
rah->ar_pro = htons(ETH_P_IP);
|
rah->ar_pro = htons(ETH_P_IP);
|
||||||
|
@ -725,21 +731,21 @@ void if_encap(const uint8_t *ip_data, int ip_data_len)
|
||||||
rah->ar_pln = 4;
|
rah->ar_pln = 4;
|
||||||
rah->ar_op = htons(ARPOP_REQUEST);
|
rah->ar_op = htons(ARPOP_REQUEST);
|
||||||
/* source hw addr */
|
/* source hw addr */
|
||||||
memcpy(rah->ar_sha, special_ethaddr, ETH_ALEN - 1);
|
memcpy(rah->ar_sha, special_ethaddr, ETH_ALEN - 4);
|
||||||
rah->ar_sha[5] = CTL_ALIAS;
|
memcpy(&rah->ar_sha[2], &vhost_addr, 4);
|
||||||
/* source IP */
|
/* source IP */
|
||||||
memcpy(rah->ar_sip, &alias_addr, 4);
|
rah->ar_sip = vhost_addr.s_addr;
|
||||||
/* target hw addr (none) */
|
/* target hw addr (none) */
|
||||||
memset(rah->ar_tha, 0, ETH_ALEN);
|
memset(rah->ar_tha, 0, ETH_ALEN);
|
||||||
/* target IP */
|
/* target IP */
|
||||||
memcpy(rah->ar_tip, &iph->ip_dst, 4);
|
rah->ar_tip = iph->ip_dst.s_addr;
|
||||||
client_ipaddr = iph->ip_dst;
|
client_ipaddr = iph->ip_dst;
|
||||||
slirp_output(arp_req, sizeof(arp_req));
|
slirp_output(arp_req, sizeof(arp_req));
|
||||||
} else {
|
} else {
|
||||||
memcpy(eh->h_dest, client_ethaddr, ETH_ALEN);
|
memcpy(eh->h_dest, client_ethaddr, ETH_ALEN);
|
||||||
memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 1);
|
memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 4);
|
||||||
/* XXX: not correct */
|
/* XXX: not correct */
|
||||||
eh->h_source[5] = CTL_ALIAS;
|
memcpy(&eh->h_source[2], &vhost_addr, 4);
|
||||||
eh->h_proto = htons(ETH_P_IP);
|
eh->h_proto = htons(ETH_P_IP);
|
||||||
memcpy(buf + sizeof(struct ethhdr), ip_data, ip_data_len);
|
memcpy(buf + sizeof(struct ethhdr), ip_data, ip_data_len);
|
||||||
slirp_output(buf, ip_data_len + ETH_HLEN);
|
slirp_output(buf, ip_data_len + ETH_HLEN);
|
||||||
|
@ -772,6 +778,9 @@ int slirp_redir_rm(int is_udp, int host_port)
|
||||||
int slirp_redir(int is_udp, int host_port,
|
int slirp_redir(int is_udp, int host_port,
|
||||||
struct in_addr guest_addr, int guest_port)
|
struct in_addr guest_addr, int guest_port)
|
||||||
{
|
{
|
||||||
|
if (!guest_addr.s_addr) {
|
||||||
|
guest_addr = vdhcp_startaddr;
|
||||||
|
}
|
||||||
if (is_udp) {
|
if (is_udp) {
|
||||||
if (!udp_listen(htons(host_port), guest_addr.s_addr,
|
if (!udp_listen(htons(host_port), guest_addr.s_addr,
|
||||||
htons(guest_port), 0))
|
htons(guest_port), 0))
|
||||||
|
@ -787,8 +796,17 @@ int slirp_redir(int is_udp, int host_port,
|
||||||
int slirp_add_exec(int do_pty, const void *args, int addr_low_byte,
|
int slirp_add_exec(int do_pty, const void *args, int addr_low_byte,
|
||||||
int guest_port)
|
int guest_port)
|
||||||
{
|
{
|
||||||
return add_exec(&exec_list, do_pty, (char *)args,
|
struct in_addr guest_addr = {
|
||||||
addr_low_byte, htons(guest_port));
|
.s_addr = vnetwork_addr.s_addr | htonl(addr_low_byte)
|
||||||
|
};
|
||||||
|
|
||||||
|
if ((guest_addr.s_addr & vnetwork_mask.s_addr) != vnetwork_addr.s_addr ||
|
||||||
|
guest_addr.s_addr == vhost_addr.s_addr ||
|
||||||
|
guest_addr.s_addr == vnameserver_addr.s_addr) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return add_exec(&exec_list, do_pty, (char *)args, guest_addr,
|
||||||
|
htons(guest_port));
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t slirp_send(struct socket *so, const void *buf, size_t len, int flags)
|
ssize_t slirp_send(struct socket *so, const void *buf, size_t len, int flags)
|
||||||
|
@ -801,31 +819,32 @@ ssize_t slirp_send(struct socket *so, const void *buf, size_t len, int flags)
|
||||||
return send(so->s, buf, len, flags);
|
return send(so->s, buf, len, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct socket *slirp_find_ctl_socket(int addr_low_byte, int guest_port)
|
static struct socket *
|
||||||
|
slirp_find_ctl_socket(struct in_addr guest_addr, int guest_port)
|
||||||
{
|
{
|
||||||
struct socket *so;
|
struct socket *so;
|
||||||
|
|
||||||
for (so = tcb.so_next; so != &tcb; so = so->so_next) {
|
for (so = tcb.so_next; so != &tcb; so = so->so_next) {
|
||||||
if ((so->so_faddr.s_addr & htonl(0xffffff00)) ==
|
if (so->so_faddr.s_addr == guest_addr.s_addr &&
|
||||||
special_addr.s_addr
|
htons(so->so_fport) == guest_port) {
|
||||||
&& (ntohl(so->so_faddr.s_addr) & 0xff) ==
|
|
||||||
addr_low_byte
|
|
||||||
&& htons(so->so_fport) == guest_port)
|
|
||||||
return so;
|
return so;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t slirp_socket_can_recv(int addr_low_byte, int guest_port)
|
size_t slirp_socket_can_recv(int addr_low_byte, int guest_port)
|
||||||
{
|
{
|
||||||
|
struct in_addr guest_addr = {
|
||||||
|
.s_addr = vnetwork_addr.s_addr | htonl(addr_low_byte)
|
||||||
|
};
|
||||||
struct iovec iov[2];
|
struct iovec iov[2];
|
||||||
struct socket *so;
|
struct socket *so;
|
||||||
|
|
||||||
if (!link_up)
|
if (!link_up)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
so = slirp_find_ctl_socket(addr_low_byte, guest_port);
|
so = slirp_find_ctl_socket(guest_addr, guest_port);
|
||||||
|
|
||||||
if (!so || so->so_state & SS_NOFDREF)
|
if (!so || so->so_state & SS_NOFDREF)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -840,7 +859,10 @@ void slirp_socket_recv(int addr_low_byte, int guest_port, const uint8_t *buf,
|
||||||
int size)
|
int size)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
struct socket *so = slirp_find_ctl_socket(addr_low_byte, guest_port);
|
struct in_addr guest_addr = {
|
||||||
|
.s_addr = vnetwork_addr.s_addr | htonl(addr_low_byte)
|
||||||
|
};
|
||||||
|
struct socket *so = slirp_find_ctl_socket(guest_addr, guest_port);
|
||||||
|
|
||||||
if (!so)
|
if (!so)
|
||||||
return;
|
return;
|
||||||
|
@ -1055,15 +1077,17 @@ static int slirp_state_load(QEMUFile *f, void *opaque, int version_id)
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if ((so->so_faddr.s_addr & htonl(0xffffff00)) != special_addr.s_addr)
|
if ((so->so_faddr.s_addr & vnetwork_mask.s_addr) !=
|
||||||
|
vnetwork_addr.s_addr) {
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
}
|
||||||
for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next)
|
for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
|
||||||
if (ex_ptr->ex_pty == 3 &&
|
if (ex_ptr->ex_pty == 3 &&
|
||||||
(ntohl(so->so_faddr.s_addr) & 0xff) == ex_ptr->ex_addr &&
|
so->so_faddr.s_addr == ex_ptr->ex_addr.s_addr &&
|
||||||
so->so_fport == ex_ptr->ex_fport)
|
so->so_fport == ex_ptr->ex_fport) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (!ex_ptr)
|
if (!ex_ptr)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
|
|
@ -214,7 +214,6 @@ int inet_aton _P((const char *cp, struct in_addr *ia));
|
||||||
#include "if.h"
|
#include "if.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
#include "ctl.h"
|
|
||||||
#ifdef USE_PPP
|
#ifdef USE_PPP
|
||||||
#include "ppp/pppd.h"
|
#include "ppp/pppd.h"
|
||||||
#include "ppp/ppp.h"
|
#include "ppp/ppp.h"
|
||||||
|
|
|
@ -555,16 +555,13 @@ sosendto(struct socket *so, struct mbuf *m)
|
||||||
DEBUG_ARG("m = %lx", (long)m);
|
DEBUG_ARG("m = %lx", (long)m);
|
||||||
|
|
||||||
addr.sin_family = AF_INET;
|
addr.sin_family = AF_INET;
|
||||||
if ((so->so_faddr.s_addr & htonl(0xffffff00)) == special_addr.s_addr) {
|
if ((so->so_faddr.s_addr & vnetwork_mask.s_addr) ==
|
||||||
|
vnetwork_addr.s_addr) {
|
||||||
/* It's an alias */
|
/* It's an alias */
|
||||||
switch(ntohl(so->so_faddr.s_addr) & 0xff) {
|
if (so->so_faddr.s_addr == vnameserver_addr.s_addr) {
|
||||||
case CTL_DNS:
|
|
||||||
addr.sin_addr = dns_addr;
|
addr.sin_addr = dns_addr;
|
||||||
break;
|
} else {
|
||||||
case CTL_ALIAS:
|
|
||||||
default:
|
|
||||||
addr.sin_addr = loopback_addr;
|
addr.sin_addr = loopback_addr;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
addr.sin_addr = so->so_faddr;
|
addr.sin_addr = so->so_faddr;
|
||||||
|
@ -652,7 +649,7 @@ solisten(u_int port, u_int32_t laddr, u_int lport, int flags)
|
||||||
getsockname(s,(struct sockaddr *)&addr,&addrlen);
|
getsockname(s,(struct sockaddr *)&addr,&addrlen);
|
||||||
so->so_fport = addr.sin_port;
|
so->so_fport = addr.sin_port;
|
||||||
if (addr.sin_addr.s_addr == 0 || addr.sin_addr.s_addr == loopback_addr.s_addr)
|
if (addr.sin_addr.s_addr == 0 || addr.sin_addr.s_addr == loopback_addr.s_addr)
|
||||||
so->so_faddr = alias_addr;
|
so->so_faddr = vhost_addr;
|
||||||
else
|
else
|
||||||
so->so_faddr = addr.sin_addr;
|
so->so_faddr = addr.sin_addr;
|
||||||
|
|
||||||
|
|
|
@ -359,11 +359,12 @@ tcp_input(struct mbuf *m, int iphlen, struct socket *inso)
|
||||||
m->m_len -= sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr);
|
m->m_len -= sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr);
|
||||||
|
|
||||||
if (slirp_restrict) {
|
if (slirp_restrict) {
|
||||||
for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next)
|
for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
|
||||||
if (ex_ptr->ex_fport == ti->ti_dport &&
|
if (ex_ptr->ex_fport == ti->ti_dport &&
|
||||||
(ntohl(ti->ti_dst.s_addr) & 0xff) == ex_ptr->ex_addr)
|
ti->ti_dst.s_addr == ex_ptr->ex_addr.s_addr) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (!ex_ptr)
|
if (!ex_ptr)
|
||||||
goto drop;
|
goto drop;
|
||||||
}
|
}
|
||||||
|
@ -639,9 +640,10 @@ findso:
|
||||||
* If this is destined for the control address, then flag to
|
* If this is destined for the control address, then flag to
|
||||||
* tcp_ctl once connected, otherwise connect
|
* tcp_ctl once connected, otherwise connect
|
||||||
*/
|
*/
|
||||||
if ((so->so_faddr.s_addr&htonl(0xffffff00)) == special_addr.s_addr) {
|
if ((so->so_faddr.s_addr & vnetwork_mask.s_addr) ==
|
||||||
int lastbyte=ntohl(so->so_faddr.s_addr) & 0xff;
|
vnetwork_addr.s_addr) {
|
||||||
if (lastbyte!=CTL_ALIAS && lastbyte!=CTL_DNS) {
|
if (so->so_faddr.s_addr != vhost_addr.s_addr &&
|
||||||
|
so->so_faddr.s_addr != vnameserver_addr.s_addr) {
|
||||||
#if 0
|
#if 0
|
||||||
if(lastbyte==CTL_CMD || lastbyte==CTL_EXEC) {
|
if(lastbyte==CTL_CMD || lastbyte==CTL_EXEC) {
|
||||||
/* Command or exec adress */
|
/* Command or exec adress */
|
||||||
|
@ -652,7 +654,7 @@ findso:
|
||||||
/* May be an add exec */
|
/* May be an add exec */
|
||||||
for(ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
|
for(ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
|
||||||
if(ex_ptr->ex_fport == so->so_fport &&
|
if(ex_ptr->ex_fport == so->so_fport &&
|
||||||
lastbyte == ex_ptr->ex_addr) {
|
so->so_faddr.s_addr == ex_ptr->ex_addr.s_addr) {
|
||||||
so->so_state |= SS_CTL;
|
so->so_state |= SS_CTL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -384,16 +384,12 @@ int tcp_fconnect(struct socket *so)
|
||||||
setsockopt(s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(opt ));
|
setsockopt(s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(opt ));
|
||||||
|
|
||||||
addr.sin_family = AF_INET;
|
addr.sin_family = AF_INET;
|
||||||
if ((so->so_faddr.s_addr & htonl(0xffffff00)) == special_addr.s_addr) {
|
if ((so->so_faddr.s_addr & vnetwork_mask.s_addr) == vnetwork_addr.s_addr) {
|
||||||
/* It's an alias */
|
/* It's an alias */
|
||||||
switch(ntohl(so->so_faddr.s_addr) & 0xff) {
|
if (so->so_faddr.s_addr == vnameserver_addr.s_addr) {
|
||||||
case CTL_DNS:
|
|
||||||
addr.sin_addr = dns_addr;
|
addr.sin_addr = dns_addr;
|
||||||
break;
|
} else {
|
||||||
case CTL_ALIAS:
|
|
||||||
default:
|
|
||||||
addr.sin_addr = loopback_addr;
|
addr.sin_addr = loopback_addr;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
addr.sin_addr = so->so_faddr;
|
addr.sin_addr = so->so_faddr;
|
||||||
|
@ -478,7 +474,7 @@ tcp_connect(struct socket *inso)
|
||||||
so->so_faddr = addr.sin_addr;
|
so->so_faddr = addr.sin_addr;
|
||||||
/* Translate connections from localhost to the real hostname */
|
/* Translate connections from localhost to the real hostname */
|
||||||
if (so->so_faddr.s_addr == 0 || so->so_faddr.s_addr == loopback_addr.s_addr)
|
if (so->so_faddr.s_addr == 0 || so->so_faddr.s_addr == loopback_addr.s_addr)
|
||||||
so->so_faddr = alias_addr;
|
so->so_faddr = vhost_addr;
|
||||||
|
|
||||||
/* Close the accept() socket, set right state */
|
/* Close the accept() socket, set right state */
|
||||||
if (inso->so_state & SS_FACCEPTONCE) {
|
if (inso->so_state & SS_FACCEPTONCE) {
|
||||||
|
@ -1230,7 +1226,6 @@ do_prompt:
|
||||||
*/
|
*/
|
||||||
int tcp_ctl(struct socket *so)
|
int tcp_ctl(struct socket *so)
|
||||||
{
|
{
|
||||||
int command = (ntohl(so->so_faddr.s_addr) & 0xff);
|
|
||||||
struct sbuf *sb = &so->so_snd;
|
struct sbuf *sb = &so->so_snd;
|
||||||
struct ex_list *ex_ptr;
|
struct ex_list *ex_ptr;
|
||||||
int do_pty;
|
int do_pty;
|
||||||
|
@ -1238,11 +1233,11 @@ int tcp_ctl(struct socket *so)
|
||||||
DEBUG_CALL("tcp_ctl");
|
DEBUG_CALL("tcp_ctl");
|
||||||
DEBUG_ARG("so = %lx", (long )so);
|
DEBUG_ARG("so = %lx", (long )so);
|
||||||
|
|
||||||
if (command != CTL_ALIAS) {
|
if (so->so_faddr.s_addr != vhost_addr.s_addr) {
|
||||||
/* Check if it's pty_exec */
|
/* Check if it's pty_exec */
|
||||||
for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
|
for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
|
||||||
if (ex_ptr->ex_fport == so->so_fport &&
|
if (ex_ptr->ex_fport == so->so_fport &&
|
||||||
command == ex_ptr->ex_addr) {
|
so->so_faddr.s_addr == ex_ptr->ex_addr.s_addr) {
|
||||||
if (ex_ptr->ex_pty == 3) {
|
if (ex_ptr->ex_pty == 3) {
|
||||||
so->s = -1;
|
so->s = -1;
|
||||||
so->extra = (void *)ex_ptr->ex_exec;
|
so->extra = (void *)ex_ptr->ex_exec;
|
||||||
|
|
23
slirp/udp.c
23
slirp/udp.c
|
@ -312,12 +312,14 @@ int udp_output(struct socket *so, struct mbuf *m,
|
||||||
struct sockaddr_in saddr, daddr;
|
struct sockaddr_in saddr, daddr;
|
||||||
|
|
||||||
saddr = *addr;
|
saddr = *addr;
|
||||||
if ((so->so_faddr.s_addr & htonl(0xffffff00)) == special_addr.s_addr) {
|
if ((so->so_faddr.s_addr & vnetwork_mask.s_addr) == vnetwork_addr.s_addr) {
|
||||||
if ((so->so_faddr.s_addr & htonl(0x000000ff)) == htonl(0xff))
|
if ((so->so_faddr.s_addr & ~vnetwork_mask.s_addr) ==
|
||||||
saddr.sin_addr.s_addr = alias_addr.s_addr;
|
~vnetwork_mask.s_addr) {
|
||||||
else if (addr->sin_addr.s_addr == loopback_addr.s_addr ||
|
saddr.sin_addr = vhost_addr;
|
||||||
(ntohl(so->so_faddr.s_addr) & 0xff) != CTL_ALIAS)
|
} else if (addr->sin_addr.s_addr == loopback_addr.s_addr ||
|
||||||
saddr.sin_addr.s_addr = so->so_faddr.s_addr;
|
so->so_faddr.s_addr != vhost_addr.s_addr) {
|
||||||
|
saddr.sin_addr = so->so_faddr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
daddr.sin_addr = so->so_laddr;
|
daddr.sin_addr = so->so_laddr;
|
||||||
daddr.sin_port = so->so_lport;
|
daddr.sin_port = so->so_lport;
|
||||||
|
@ -652,11 +654,12 @@ udp_listen(u_int port, u_int32_t laddr, u_int lport, int flags)
|
||||||
|
|
||||||
getsockname(so->s,(struct sockaddr *)&addr,&addrlen);
|
getsockname(so->s,(struct sockaddr *)&addr,&addrlen);
|
||||||
so->so_fport = addr.sin_port;
|
so->so_fport = addr.sin_port;
|
||||||
if (addr.sin_addr.s_addr == 0 || addr.sin_addr.s_addr == loopback_addr.s_addr)
|
if (addr.sin_addr.s_addr == 0 ||
|
||||||
so->so_faddr = alias_addr;
|
addr.sin_addr.s_addr == loopback_addr.s_addr) {
|
||||||
else
|
so->so_faddr = vhost_addr;
|
||||||
|
} else {
|
||||||
so->so_faddr = addr.sin_addr;
|
so->so_faddr = addr.sin_addr;
|
||||||
|
}
|
||||||
so->so_lport = lport;
|
so->so_lport = lport;
|
||||||
so->so_laddr.s_addr = laddr;
|
so->so_laddr.s_addr = laddr;
|
||||||
if (flags != SS_FACCEPTONCE)
|
if (flags != SS_FACCEPTONCE)
|
||||||
|
|
Loading…
Reference in a new issue