Revision e6d43cfb slirp/ip_icmp.c
b/slirp/ip_icmp.c | ||
---|---|---|
60 | 60 |
/* ADDR MASK REPLY (18) */ 0 |
61 | 61 |
}; |
62 | 62 |
|
63 |
void icmp_init(Slirp *slirp) |
|
64 |
{ |
|
65 |
slirp->icmp.so_next = slirp->icmp.so_prev = &slirp->icmp; |
|
66 |
slirp->icmp_last_so = &slirp->icmp; |
|
67 |
} |
|
68 |
|
|
69 |
static int icmp_send(struct socket *so, struct mbuf *m, int hlen) |
|
70 |
{ |
|
71 |
struct ip *ip = mtod(m, struct ip *); |
|
72 |
struct sockaddr_in addr; |
|
73 |
|
|
74 |
so->s = qemu_socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP); |
|
75 |
if (so->s == -1) { |
|
76 |
return -1; |
|
77 |
} |
|
78 |
|
|
79 |
so->so_m = m; |
|
80 |
so->so_faddr = ip->ip_dst; |
|
81 |
so->so_laddr = ip->ip_src; |
|
82 |
so->so_iptos = ip->ip_tos; |
|
83 |
so->so_type = IPPROTO_ICMP; |
|
84 |
so->so_state = SS_ISFCONNECTED; |
|
85 |
so->so_expire = curtime + SO_EXPIRE; |
|
86 |
|
|
87 |
addr.sin_family = AF_INET; |
|
88 |
addr.sin_addr = so->so_faddr; |
|
89 |
|
|
90 |
insque(so, &so->slirp->icmp); |
|
91 |
|
|
92 |
if (sendto(so->s, m->m_data + hlen, m->m_len - hlen, 0, |
|
93 |
(struct sockaddr *)&addr, sizeof(addr)) == -1) { |
|
94 |
DEBUG_MISC((dfd, "icmp_input icmp sendto tx errno = %d-%s\n", |
|
95 |
errno, strerror(errno))); |
|
96 |
icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_NET, 0, strerror(errno)); |
|
97 |
icmp_detach(so); |
|
98 |
} |
|
99 |
|
|
100 |
return 0; |
|
101 |
} |
|
102 |
|
|
103 |
void icmp_detach(struct socket *so) |
|
104 |
{ |
|
105 |
closesocket(so->s); |
|
106 |
sofree(so); |
|
107 |
} |
|
108 |
|
|
63 | 109 |
/* |
64 | 110 |
* Process a received ICMP message. |
65 | 111 |
*/ |
... | ... | |
97 | 143 |
DEBUG_ARG("icmp_type = %d", icp->icmp_type); |
98 | 144 |
switch (icp->icmp_type) { |
99 | 145 |
case ICMP_ECHO: |
100 |
icp->icmp_type = ICMP_ECHOREPLY; |
|
101 | 146 |
ip->ip_len += hlen; /* since ip_input subtracts this */ |
102 | 147 |
if (ip->ip_dst.s_addr == slirp->vhost_addr.s_addr) { |
103 | 148 |
icmp_reflect(m); |
... | ... | |
107 | 152 |
struct socket *so; |
108 | 153 |
struct sockaddr_in addr; |
109 | 154 |
if ((so = socreate(slirp)) == NULL) goto freeit; |
155 |
if (icmp_send(so, m, hlen) == 0) { |
|
156 |
return; |
|
157 |
} |
|
110 | 158 |
if(udp_attach(so) == -1) { |
111 | 159 |
DEBUG_MISC((dfd,"icmp_input udp_attach errno = %d-%s\n", |
112 | 160 |
errno,strerror(errno))); |
... | ... | |
321 | 369 |
m->m_len -= hlen; |
322 | 370 |
icp = mtod(m, struct icmp *); |
323 | 371 |
|
372 |
icp->icmp_type = ICMP_ECHOREPLY; |
|
324 | 373 |
icp->icmp_cksum = 0; |
325 | 374 |
icp->icmp_cksum = cksum(m, ip->ip_len - hlen); |
326 | 375 |
|
... | ... | |
351 | 400 |
|
352 | 401 |
(void ) ip_output((struct socket *)NULL, m); |
353 | 402 |
} |
403 |
|
|
404 |
void icmp_receive(struct socket *so) |
|
405 |
{ |
|
406 |
struct mbuf *m = so->so_m; |
|
407 |
struct ip *ip = mtod(m, struct ip *); |
|
408 |
int hlen = ip->ip_hl << 2; |
|
409 |
u_char error_code; |
|
410 |
struct icmp *icp; |
|
411 |
int id, len; |
|
412 |
|
|
413 |
m->m_data += hlen; |
|
414 |
m->m_len -= hlen; |
|
415 |
icp = mtod(m, struct icmp *); |
|
416 |
|
|
417 |
id = icp->icmp_id; |
|
418 |
len = recv(so->s, icp, m->m_len, 0); |
|
419 |
icp->icmp_id = id; |
|
420 |
|
|
421 |
m->m_data -= hlen; |
|
422 |
m->m_len += hlen; |
|
423 |
|
|
424 |
if (len == -1 || len == 0) { |
|
425 |
if (errno == ENETUNREACH) { |
|
426 |
error_code = ICMP_UNREACH_NET; |
|
427 |
} else { |
|
428 |
error_code = ICMP_UNREACH_HOST; |
|
429 |
} |
|
430 |
DEBUG_MISC((dfd, " udp icmp rx errno = %d-%s\n", errno, |
|
431 |
strerror(errno))); |
|
432 |
icmp_error(so->so_m, ICMP_UNREACH, error_code, 0, strerror(errno)); |
|
433 |
} else { |
|
434 |
icmp_reflect(so->so_m); |
|
435 |
so->so_m = NULL; /* Don't m_free() it again! */ |
|
436 |
} |
|
437 |
icmp_detach(so); |
|
438 |
} |
Also available in: Unified diff