File: | slirp/tcp_subr.c |
Location: | line 127, column 18 |
Description: | Dereference of null pointer |
1 | /* | ||
2 | * Copyright (c) 1982, 1986, 1988, 1990, 1993 | ||
3 | * The Regents of the University of California. All rights reserved. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions | ||
7 | * are met: | ||
8 | * 1. Redistributions of source code must retain the above copyright | ||
9 | * notice, this list of conditions and the following disclaimer. | ||
10 | * 2. Redistributions in binary form must reproduce the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer in the | ||
12 | * documentation and/or other materials provided with the distribution. | ||
13 | * 3. Neither the name of the University nor the names of its contributors | ||
14 | * may be used to endorse or promote products derived from this software | ||
15 | * without specific prior written permission. | ||
16 | * | ||
17 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | ||
18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | ||
21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||
26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||
27 | * SUCH DAMAGE. | ||
28 | * | ||
29 | * @(#)tcp_subr.c 8.1 (Berkeley) 6/10/93 | ||
30 | * tcp_subr.c,v 1.5 1994/10/08 22:39:58 phk Exp | ||
31 | */ | ||
32 | |||
33 | /* | ||
34 | * Changes and additions relating to SLiRP | ||
35 | * Copyright (c) 1995 Danny Gasparovski. | ||
36 | * | ||
37 | * Please read the file COPYRIGHT for the | ||
38 | * terms and conditions of the copyright. | ||
39 | */ | ||
40 | |||
41 | #include <slirp.h> | ||
42 | |||
43 | /* patchable/settable parameters for tcp */ | ||
44 | /* Don't do rfc1323 performance enhancements */ | ||
45 | #define TCP_DO_RFC13230 0 | ||
46 | |||
47 | /* | ||
48 | * Tcp initialization | ||
49 | */ | ||
50 | void | ||
51 | tcp_init(Slirp *slirp) | ||
52 | { | ||
53 | slirp->tcp_iss = 1; /* wrong */ | ||
54 | slirp->tcb.so_next = slirp->tcb.so_prev = &slirp->tcb; | ||
55 | slirp->tcp_last_so = &slirp->tcb; | ||
56 | } | ||
57 | |||
58 | void tcp_cleanup(Slirp *slirp) | ||
59 | { | ||
60 | while (slirp->tcb.so_next != &slirp->tcb) { | ||
61 | tcp_close(sototcpcb(slirp->tcb.so_next)((slirp->tcb.so_next)->so_tcpcb)); | ||
62 | } | ||
63 | } | ||
64 | |||
65 | /* | ||
66 | * Create template to be used to send tcp packets on a connection. | ||
67 | * Call after host entry created, fills | ||
68 | * in a skeletal tcp/ip header, minimizing the amount of work | ||
69 | * necessary when the connection is used. | ||
70 | */ | ||
71 | void | ||
72 | tcp_template(struct tcpcb *tp) | ||
73 | { | ||
74 | struct socket *so = tp->t_socket; | ||
75 | register struct tcpiphdr *n = &tp->t_template; | ||
76 | |||
77 | n->ti_mbufti_i.ih_mbuf.mptr = NULL((void*)0); | ||
78 | n->ti_x1ti_i.ih_x1 = 0; | ||
79 | n->ti_prti_i.ih_pr = IPPROTO_TCPIPPROTO_TCP; | ||
80 | n->ti_lenti_i.ih_len = htons(sizeof (struct tcpiphdr) - sizeof (struct ip)); | ||
81 | n->ti_srcti_i.ih_src = so->so_faddr; | ||
82 | n->ti_dstti_i.ih_dst = so->so_laddr; | ||
83 | n->ti_sportti_t.th_sport = so->so_fport; | ||
84 | n->ti_dportti_t.th_dport = so->so_lport; | ||
85 | |||
86 | n->ti_seqti_t.th_seq = 0; | ||
87 | n->ti_ackti_t.th_ack = 0; | ||
88 | n->ti_x2ti_t.th_x2 = 0; | ||
89 | n->ti_offti_t.th_off = 5; | ||
90 | n->ti_flagsti_t.th_flags = 0; | ||
91 | n->ti_winti_t.th_win = 0; | ||
92 | n->ti_sumti_t.th_sum = 0; | ||
93 | n->ti_urpti_t.th_urp = 0; | ||
94 | } | ||
95 | |||
96 | /* | ||
97 | * Send a single message to the TCP at address specified by | ||
98 | * the given TCP/IP header. If m == 0, then we make a copy | ||
99 | * of the tcpiphdr at ti and send directly to the addressed host. | ||
100 | * This is used to force keep alive messages out using the TCP | ||
101 | * template for a connection tp->t_template. If flags are given | ||
102 | * then we send a message back to the TCP which originated the | ||
103 | * segment ti, and discard the mbuf containing it and any other | ||
104 | * attached mbufs. | ||
105 | * | ||
106 | * In any case the ack and sequence number of the transmitted | ||
107 | * segment are as specified by the parameters. | ||
108 | */ | ||
109 | void | ||
110 | tcp_respond(struct tcpcb *tp, struct tcpiphdr *ti, struct mbuf *m, | ||
111 | tcp_seq ack, tcp_seq seq, int flags) | ||
112 | { | ||
113 | register int tlen; | ||
114 | int win = 0; | ||
115 | |||
116 | DEBUG_CALL("tcp_respond"); | ||
117 | DEBUG_ARG("tp = %lx", (long)tp); | ||
118 | DEBUG_ARG("ti = %lx", (long)ti); | ||
119 | DEBUG_ARG("m = %lx", (long)m); | ||
120 | DEBUG_ARG("ack = %u", ack); | ||
121 | DEBUG_ARG("seq = %u", seq); | ||
122 | DEBUG_ARG("flags = %x", flags); | ||
123 | |||
124 | if (tp) | ||
| |||
| |||
125 | win = sbspace(&tp->t_socket->so_rcv)((&tp->t_socket->so_rcv)->sb_datalen - (&tp-> t_socket->so_rcv)->sb_cc); | ||
126 | if (m == NULL((void*)0)) { | ||
| |||
127 | if ((m = m_get(tp->t_socket->slirp)) == NULL((void*)0)) | ||
| |||
128 | return; | ||
129 | tlen = 0; | ||
130 | m->m_datam_hdr.mh_data += IF_MAXLINKHDR(2 + 14 + 40); | ||
131 | *mtod(m, struct tcpiphdr *)((struct tcpiphdr *)(m)->m_hdr.mh_data) = *ti; | ||
132 | ti = mtod(m, struct tcpiphdr *)((struct tcpiphdr *)(m)->m_hdr.mh_data); | ||
133 | flags = TH_ACK0x10; | ||
134 | } else { | ||
135 | /* | ||
136 | * ti points into m so the next line is just making | ||
137 | * the mbuf point to ti | ||
138 | */ | ||
139 | m->m_datam_hdr.mh_data = (caddr_t)ti; | ||
140 | |||
141 | m->m_lenm_hdr.mh_len = sizeof (struct tcpiphdr); | ||
142 | tlen = 0; | ||
143 | #define xchg(a,b,type) { type t; t=a; a=b; b=t; } | ||
144 | xchg(ti->ti_dstti_i.ih_dst.s_addr, ti->ti_srcti_i.ih_src.s_addr, uint32_t); | ||
145 | xchg(ti->ti_dportti_t.th_dport, ti->ti_sportti_t.th_sport, uint16_t); | ||
146 | #undef xchg | ||
147 | } | ||
148 | ti->ti_lenti_i.ih_len = htons((u_short)(sizeof (struct tcphdrslirp_tcphdr) + tlen)); | ||
149 | tlen += sizeof (struct tcpiphdr); | ||
150 | m->m_lenm_hdr.mh_len = tlen; | ||
151 | |||
152 | ti->ti_mbufti_i.ih_mbuf.mptr = NULL((void*)0); | ||
153 | ti->ti_x1ti_i.ih_x1 = 0; | ||
154 | ti->ti_seqti_t.th_seq = htonl(seq); | ||
155 | ti->ti_ackti_t.th_ack = htonl(ack); | ||
156 | ti->ti_x2ti_t.th_x2 = 0; | ||
157 | ti->ti_offti_t.th_off = sizeof (struct tcphdrslirp_tcphdr) >> 2; | ||
158 | ti->ti_flagsti_t.th_flags = flags; | ||
159 | if (tp) | ||
160 | ti->ti_winti_t.th_win = htons((uint16_t) (win >> tp->rcv_scale)); | ||
161 | else | ||
162 | ti->ti_winti_t.th_win = htons((uint16_t)win); | ||
163 | ti->ti_urpti_t.th_urp = 0; | ||
164 | ti->ti_sumti_t.th_sum = 0; | ||
165 | ti->ti_sumti_t.th_sum = cksum(m, tlen); | ||
166 | ((struct ip *)ti)->ip_len = tlen; | ||
167 | |||
168 | if(flags & TH_RST0x04) | ||
169 | ((struct ip *)ti)->ip_ttl = MAXTTL255; | ||
170 | else | ||
171 | ((struct ip *)ti)->ip_ttl = IPDEFTTL64; | ||
172 | |||
173 | (void) ip_output((struct socket *)0, m); | ||
174 | } | ||
175 | |||
176 | /* | ||
177 | * Create a new TCP control block, making an | ||
178 | * empty reassembly queue and hooking it to the argument | ||
179 | * protocol control block. | ||
180 | */ | ||
181 | struct tcpcb * | ||
182 | tcp_newtcpcb(struct socket *so) | ||
183 | { | ||
184 | register struct tcpcb *tp; | ||
185 | |||
186 | tp = (struct tcpcb *)malloc(sizeof(*tp)); | ||
187 | if (tp == NULL((void*)0)) | ||
188 | return ((struct tcpcb *)0); | ||
189 | |||
190 | memset((char *) tp, 0, sizeof(struct tcpcb)); | ||
191 | tp->seg_next = tp->seg_prev = (struct tcpiphdr*)tp; | ||
192 | tp->t_maxseg = TCP_MSS1460; | ||
193 | |||
194 | tp->t_flags = TCP_DO_RFC13230 ? (TF_REQ_SCALE0x0020|TF_REQ_TSTMP0x0080) : 0; | ||
195 | tp->t_socket = so; | ||
196 | |||
197 | /* | ||
198 | * Init srtt to TCPTV_SRTTBASE (0), so we can tell that we have no | ||
199 | * rtt estimate. Set rttvar so that srtt + 2 * rttvar gives | ||
200 | * reasonable initial retransmit time. | ||
201 | */ | ||
202 | tp->t_srtt = TCPTV_SRTTBASE0; | ||
203 | tp->t_rttvar = TCPTV_SRTTDFLT( 3*2) << 2; | ||
204 | tp->t_rttmin = TCPTV_MIN( 1*2); | ||
205 | |||
206 | TCPT_RANGESET(tp->t_rxtcur,{ (tp->t_rxtcur) = (((0 >> 2) + (( 3*2) << 2)) >> 1); if ((tp->t_rxtcur) < (( 1*2))) (tp->t_rxtcur ) = (( 1*2)); else if ((tp->t_rxtcur) > (( 12*2))) (tp-> t_rxtcur) = (( 12*2)); } | ||
207 | ((TCPTV_SRTTBASE >> 2) + (TCPTV_SRTTDFLT << 2)) >> 1,{ (tp->t_rxtcur) = (((0 >> 2) + (( 3*2) << 2)) >> 1); if ((tp->t_rxtcur) < (( 1*2))) (tp->t_rxtcur ) = (( 1*2)); else if ((tp->t_rxtcur) > (( 12*2))) (tp-> t_rxtcur) = (( 12*2)); } | ||
208 | TCPTV_MIN, TCPTV_REXMTMAX){ (tp->t_rxtcur) = (((0 >> 2) + (( 3*2) << 2)) >> 1); if ((tp->t_rxtcur) < (( 1*2))) (tp->t_rxtcur ) = (( 1*2)); else if ((tp->t_rxtcur) > (( 12*2))) (tp-> t_rxtcur) = (( 12*2)); }; | ||
209 | |||
210 | tp->snd_cwnd = TCP_MAXWIN65535 << TCP_MAX_WINSHIFT14; | ||
211 | tp->snd_ssthresh = TCP_MAXWIN65535 << TCP_MAX_WINSHIFT14; | ||
212 | tp->t_state = TCPS_CLOSED0; | ||
213 | |||
214 | so->so_tcpcb = tp; | ||
215 | |||
216 | return (tp); | ||
217 | } | ||
218 | |||
219 | /* | ||
220 | * Drop a TCP connection, reporting | ||
221 | * the specified error. If connection is synchronized, | ||
222 | * then send a RST to peer. | ||
223 | */ | ||
224 | struct tcpcb *tcp_drop(struct tcpcb *tp, int err) | ||
225 | { | ||
226 | DEBUG_CALL("tcp_drop"); | ||
227 | DEBUG_ARG("tp = %lx", (long)tp); | ||
228 | DEBUG_ARG("errno = %d", errno); | ||
229 | |||
230 | if (TCPS_HAVERCVDSYN(tp->t_state)((tp->t_state) >= 3)) { | ||
231 | tp->t_state = TCPS_CLOSED0; | ||
232 | (void) tcp_output(tp); | ||
233 | } | ||
234 | return (tcp_close(tp)); | ||
235 | } | ||
236 | |||
237 | /* | ||
238 | * Close a TCP control block: | ||
239 | * discard all space held by the tcp | ||
240 | * discard internet protocol block | ||
241 | * wake up any sleepers | ||
242 | */ | ||
243 | struct tcpcb * | ||
244 | tcp_close(struct tcpcb *tp) | ||
245 | { | ||
246 | register struct tcpiphdr *t; | ||
247 | struct socket *so = tp->t_socket; | ||
248 | Slirp *slirp = so->slirp; | ||
249 | register struct mbuf *m; | ||
250 | |||
251 | DEBUG_CALL("tcp_close"); | ||
252 | DEBUG_ARG("tp = %lx", (long )tp); | ||
253 | |||
254 | /* free the reassembly queue, if any */ | ||
255 | t = tcpfrag_list_first(tp)((struct tcpiphdr*)(((char*)((tp)->seg_next)) + sizeof(struct qlink))); | ||
256 | while (!tcpfrag_list_end(t, tp)(((struct qlink*)(((char*)(t)) - sizeof(struct qlink))) == (struct qlink*)(tp))) { | ||
257 | t = tcpiphdr_next(t)((struct tcpiphdr*)(((char*)(((struct qlink*)(((char*)(t)) - sizeof (struct qlink)))->next)) + sizeof(struct qlink))); | ||
258 | m = tcpiphdr_prev(t)((struct tcpiphdr*)(((char*)(((struct qlink*)(((char*)(t)) - sizeof (struct qlink)))->prev)) + sizeof(struct qlink)))->ti_mbufti_i.ih_mbuf.mptr; | ||
259 | remqueslirp_remque(tcpiphdr2qlink(tcpiphdr_prev(t))((struct qlink*)(((char*)(((struct tcpiphdr*)(((char*)(((struct qlink*)(((char*)(t)) - sizeof(struct qlink)))->prev)) + sizeof (struct qlink))))) - sizeof(struct qlink)))); | ||
260 | m_free(m); | ||
261 | } | ||
262 | free(tp); | ||
263 | so->so_tcpcb = NULL((void*)0); | ||
264 | /* clobber input socket cache if we're closing the cached connection */ | ||
265 | if (so == slirp->tcp_last_so) | ||
266 | slirp->tcp_last_so = &slirp->tcb; | ||
267 | closesocket(so->s)close(so->s); | ||
268 | sbfree(&so->so_rcv); | ||
269 | sbfree(&so->so_snd); | ||
270 | sofree(so); | ||
271 | return ((struct tcpcb *)0); | ||
272 | } | ||
273 | |||
274 | /* | ||
275 | * TCP protocol interface to socket abstraction. | ||
276 | */ | ||
277 | |||
278 | /* | ||
279 | * User issued close, and wish to trail through shutdown states: | ||
280 | * if never received SYN, just forget it. If got a SYN from peer, | ||
281 | * but haven't sent FIN, then go to FIN_WAIT_1 state to send peer a FIN. | ||
282 | * If already got a FIN from peer, then almost done; go to LAST_ACK | ||
283 | * state. In all other cases, have already sent FIN to peer (e.g. | ||
284 | * after PRU_SHUTDOWN), and just have to play tedious game waiting | ||
285 | * for peer to send FIN or not respond to keep-alives, etc. | ||
286 | * We can let the user exit from the close as soon as the FIN is acked. | ||
287 | */ | ||
288 | void | ||
289 | tcp_sockclosed(struct tcpcb *tp) | ||
290 | { | ||
291 | |||
292 | DEBUG_CALL("tcp_sockclosed"); | ||
293 | DEBUG_ARG("tp = %lx", (long)tp); | ||
294 | |||
295 | switch (tp->t_state) { | ||
296 | |||
297 | case TCPS_CLOSED0: | ||
298 | case TCPS_LISTEN1: | ||
299 | case TCPS_SYN_SENT2: | ||
300 | tp->t_state = TCPS_CLOSED0; | ||
301 | tp = tcp_close(tp); | ||
302 | break; | ||
303 | |||
304 | case TCPS_SYN_RECEIVED3: | ||
305 | case TCPS_ESTABLISHED4: | ||
306 | tp->t_state = TCPS_FIN_WAIT_16; | ||
307 | break; | ||
308 | |||
309 | case TCPS_CLOSE_WAIT5: | ||
310 | tp->t_state = TCPS_LAST_ACK8; | ||
311 | break; | ||
312 | } | ||
313 | if (tp) | ||
314 | tcp_output(tp); | ||
315 | } | ||
316 | |||
317 | /* | ||
318 | * Connect to a host on the Internet | ||
319 | * Called by tcp_input | ||
320 | * Only do a connect, the tcp fields will be set in tcp_input | ||
321 | * return 0 if there's a result of the connect, | ||
322 | * else return -1 means we're still connecting | ||
323 | * The return value is almost always -1 since the socket is | ||
324 | * nonblocking. Connect returns after the SYN is sent, and does | ||
325 | * not wait for ACK+SYN. | ||
326 | */ | ||
327 | int tcp_fconnect(struct socket *so) | ||
328 | { | ||
329 | Slirp *slirp = so->slirp; | ||
330 | int ret=0; | ||
331 | |||
332 | DEBUG_CALL("tcp_fconnect"); | ||
333 | DEBUG_ARG("so = %lx", (long )so); | ||
334 | |||
335 | if( (ret = so->s = qemu_socket(AF_INET2,SOCK_STREAMSOCK_STREAM,0)) >= 0) { | ||
336 | int opt, s=so->s; | ||
337 | struct sockaddr_in addr; | ||
338 | |||
339 | socket_set_nonblock(s); | ||
340 | opt = 1; | ||
341 | setsockopt(s,SOL_SOCKET1,SO_REUSEADDR2,(char *)&opt,sizeof(opt )); | ||
342 | opt = 1; | ||
343 | setsockopt(s,SOL_SOCKET1,SO_OOBINLINE10,(char *)&opt,sizeof(opt )); | ||
344 | |||
345 | addr.sin_family = AF_INET2; | ||
346 | if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) == | ||
347 | slirp->vnetwork_addr.s_addr) { | ||
348 | /* It's an alias */ | ||
349 | if (so->so_faddr.s_addr == slirp->vnameserver_addr.s_addr) { | ||
350 | if (get_dns_addr(&addr.sin_addr) < 0) | ||
351 | addr.sin_addr = loopback_addr; | ||
352 | } else { | ||
353 | addr.sin_addr = loopback_addr; | ||
354 | } | ||
355 | } else | ||
356 | addr.sin_addr = so->so_faddr; | ||
357 | addr.sin_port = so->so_fport; | ||
358 | |||
359 | DEBUG_MISC((dfd, " connect()ing, addr.sin_port=%d, " | ||
360 | "addr.sin_addr.s_addr=%.16s\n", | ||
361 | ntohs(addr.sin_port), inet_ntoa(addr.sin_addr))); | ||
362 | /* We don't care what port we get */ | ||
363 | ret = connect(s,(struct sockaddr *)&addr,sizeof (addr)); | ||
364 | |||
365 | /* | ||
366 | * If it's not in progress, it failed, so we just return 0, | ||
367 | * without clearing SS_NOFDREF | ||
368 | */ | ||
369 | soisfconnecting(so); | ||
370 | } | ||
371 | |||
372 | return(ret); | ||
373 | } | ||
374 | |||
375 | /* | ||
376 | * Accept the socket and connect to the local-host | ||
377 | * | ||
378 | * We have a problem. The correct thing to do would be | ||
379 | * to first connect to the local-host, and only if the | ||
380 | * connection is accepted, then do an accept() here. | ||
381 | * But, a) we need to know who's trying to connect | ||
382 | * to the socket to be able to SYN the local-host, and | ||
383 | * b) we are already connected to the foreign host by | ||
384 | * the time it gets to accept(), so... We simply accept | ||
385 | * here and SYN the local-host. | ||
386 | */ | ||
387 | void | ||
388 | tcp_connect(struct socket *inso) | ||
389 | { | ||
390 | Slirp *slirp = inso->slirp; | ||
391 | struct socket *so; | ||
392 | struct sockaddr_in addr; | ||
393 | socklen_t addrlen = sizeof(struct sockaddr_in); | ||
394 | struct tcpcb *tp; | ||
395 | int s, opt; | ||
396 | |||
397 | DEBUG_CALL("tcp_connect"); | ||
398 | DEBUG_ARG("inso = %lx", (long)inso); | ||
399 | |||
400 | /* | ||
401 | * If it's an SS_ACCEPTONCE socket, no need to socreate() | ||
402 | * another socket, just use the accept() socket. | ||
403 | */ | ||
404 | if (inso->so_state & SS_FACCEPTONCE0x200) { | ||
405 | /* FACCEPTONCE already have a tcpcb */ | ||
406 | so = inso; | ||
407 | } else { | ||
408 | if ((so = socreate(slirp)) == NULL((void*)0)) { | ||
409 | /* If it failed, get rid of the pending connection */ | ||
410 | closesocket(accept(inso->s,(struct sockaddr *)&addr,&addrlen))close(accept(inso->s,(struct sockaddr *)&addr,&addrlen )); | ||
411 | return; | ||
412 | } | ||
413 | if (tcp_attach(so) < 0) { | ||
414 | free(so); /* NOT sofree */ | ||
415 | return; | ||
416 | } | ||
417 | so->so_laddr = inso->so_laddr; | ||
418 | so->so_lport = inso->so_lport; | ||
419 | } | ||
420 | |||
421 | (void) tcp_mss(sototcpcb(so)((so)->so_tcpcb), 0); | ||
422 | |||
423 | if ((s = accept(inso->s,(struct sockaddr *)&addr,&addrlen)) < 0) { | ||
424 | tcp_close(sototcpcb(so)((so)->so_tcpcb)); /* This will sofree() as well */ | ||
425 | return; | ||
426 | } | ||
427 | socket_set_nonblock(s); | ||
428 | opt = 1; | ||
429 | setsockopt(s,SOL_SOCKET1,SO_REUSEADDR2,(char *)&opt,sizeof(int)); | ||
430 | opt = 1; | ||
431 | setsockopt(s,SOL_SOCKET1,SO_OOBINLINE10,(char *)&opt,sizeof(int)); | ||
432 | opt = 1; | ||
433 | setsockopt(s,IPPROTO_TCPIPPROTO_TCP,TCP_NODELAY0x01,(char *)&opt,sizeof(int)); | ||
434 | |||
435 | so->so_fport = addr.sin_port; | ||
436 | so->so_faddr = addr.sin_addr; | ||
437 | /* Translate connections from localhost to the real hostname */ | ||
438 | if (so->so_faddr.s_addr == 0 || so->so_faddr.s_addr == loopback_addr.s_addr) | ||
439 | so->so_faddr = slirp->vhost_addr; | ||
440 | |||
441 | /* Close the accept() socket, set right state */ | ||
442 | if (inso->so_state & SS_FACCEPTONCE0x200) { | ||
443 | closesocket(so->s)close(so->s); /* If we only accept once, close the accept() socket */ | ||
444 | so->so_state = SS_NOFDREF0x001; /* Don't select it yet, even though we have an FD */ | ||
445 | /* if it's not FACCEPTONCE, it's already NOFDREF */ | ||
446 | } | ||
447 | so->s = s; | ||
448 | so->so_state |= SS_INCOMING0x2000; | ||
449 | |||
450 | so->so_iptos = tcp_tos(so); | ||
451 | tp = sototcpcb(so)((so)->so_tcpcb); | ||
452 | |||
453 | tcp_template(tp); | ||
454 | |||
455 | tp->t_state = TCPS_SYN_SENT2; | ||
456 | tp->t_timer[TCPT_KEEP2] = TCPTV_KEEP_INIT( 75*2); | ||
457 | tp->iss = slirp->tcp_iss; | ||
458 | slirp->tcp_iss += TCP_ISSINCR(125*1024)/2; | ||
459 | tcp_sendseqinit(tp)(tp)->snd_una = (tp)->snd_nxt = (tp)->snd_max = (tp) ->snd_up = (tp)->iss; | ||
460 | tcp_output(tp); | ||
461 | } | ||
462 | |||
463 | /* | ||
464 | * Attach a TCPCB to a socket. | ||
465 | */ | ||
466 | int | ||
467 | tcp_attach(struct socket *so) | ||
468 | { | ||
469 | if ((so->so_tcpcb = tcp_newtcpcb(so)) == NULL((void*)0)) | ||
470 | return -1; | ||
471 | |||
472 | insqueslirp_insque(so, &so->slirp->tcb); | ||
473 | |||
474 | return 0; | ||
475 | } | ||
476 | |||
477 | /* | ||
478 | * Set the socket's type of service field | ||
479 | */ | ||
480 | static const struct tos_t tcptos[] = { | ||
481 | {0, 20, IPTOS_THROUGHPUT0x08, 0}, /* ftp data */ | ||
482 | {21, 21, IPTOS_LOWDELAY0x10, EMU_FTP0x2}, /* ftp control */ | ||
483 | {0, 23, IPTOS_LOWDELAY0x10, 0}, /* telnet */ | ||
484 | {0, 80, IPTOS_THROUGHPUT0x08, 0}, /* WWW */ | ||
485 | {0, 513, IPTOS_LOWDELAY0x10, EMU_RLOGIN0x6|EMU_NOCONNECT0x10}, /* rlogin */ | ||
486 | {0, 514, IPTOS_LOWDELAY0x10, EMU_RSH0x8|EMU_NOCONNECT0x10}, /* shell */ | ||
487 | {0, 544, IPTOS_LOWDELAY0x10, EMU_KSH0x3}, /* kshell */ | ||
488 | {0, 543, IPTOS_LOWDELAY0x10, 0}, /* klogin */ | ||
489 | {0, 6667, IPTOS_THROUGHPUT0x08, EMU_IRC0x4}, /* IRC */ | ||
490 | {0, 6668, IPTOS_THROUGHPUT0x08, EMU_IRC0x4}, /* IRC undernet */ | ||
491 | {0, 7070, IPTOS_LOWDELAY0x10, EMU_REALAUDIO0x5 }, /* RealAudio control */ | ||
492 | {0, 113, IPTOS_LOWDELAY0x10, EMU_IDENT0x7 }, /* identd protocol */ | ||
493 | {0, 0, 0, 0} | ||
494 | }; | ||
495 | |||
496 | static struct emu_t *tcpemu = NULL((void*)0); | ||
497 | |||
498 | /* | ||
499 | * Return TOS according to the above table | ||
500 | */ | ||
501 | uint8_t | ||
502 | tcp_tos(struct socket *so) | ||
503 | { | ||
504 | int i = 0; | ||
505 | struct emu_t *emup; | ||
506 | |||
507 | while(tcptos[i].tos) { | ||
508 | if ((tcptos[i].fport && (ntohs(so->so_fport) == tcptos[i].fport)) || | ||
509 | (tcptos[i].lport && (ntohs(so->so_lport) == tcptos[i].lport))) { | ||
510 | so->so_emu = tcptos[i].emu; | ||
511 | return tcptos[i].tos; | ||
512 | } | ||
513 | i++; | ||
514 | } | ||
515 | |||
516 | /* Nope, lets see if there's a user-added one */ | ||
517 | for (emup = tcpemu; emup; emup = emup->next) { | ||
518 | if ((emup->fport && (ntohs(so->so_fport) == emup->fport)) || | ||
519 | (emup->lport && (ntohs(so->so_lport) == emup->lport))) { | ||
520 | so->so_emu = emup->emu; | ||
521 | return emup->tos; | ||
522 | } | ||
523 | } | ||
524 | |||
525 | return 0; | ||
526 | } | ||
527 | |||
528 | /* | ||
529 | * Emulate programs that try and connect to us | ||
530 | * This includes ftp (the data connection is | ||
531 | * initiated by the server) and IRC (DCC CHAT and | ||
532 | * DCC SEND) for now | ||
533 | * | ||
534 | * NOTE: It's possible to crash SLiRP by sending it | ||
535 | * unstandard strings to emulate... if this is a problem, | ||
536 | * more checks are needed here | ||
537 | * | ||
538 | * XXX Assumes the whole command came in one packet | ||
539 | * | ||
540 | * XXX Some ftp clients will have their TOS set to | ||
541 | * LOWDELAY and so Nagel will kick in. Because of this, | ||
542 | * we'll get the first letter, followed by the rest, so | ||
543 | * we simply scan for ORT instead of PORT... | ||
544 | * DCC doesn't have this problem because there's other stuff | ||
545 | * in the packet before the DCC command. | ||
546 | * | ||
547 | * Return 1 if the mbuf m is still valid and should be | ||
548 | * sbappend()ed | ||
549 | * | ||
550 | * NOTE: if you return 0 you MUST m_free() the mbuf! | ||
551 | */ | ||
552 | int | ||
553 | tcp_emu(struct socket *so, struct mbuf *m) | ||
554 | { | ||
555 | Slirp *slirp = so->slirp; | ||
556 | u_int n1, n2, n3, n4, n5, n6; | ||
557 | char buff[257]; | ||
558 | uint32_t laddr; | ||
559 | u_int lport; | ||
560 | char *bptr; | ||
561 | |||
562 | DEBUG_CALL("tcp_emu"); | ||
563 | DEBUG_ARG("so = %lx", (long)so); | ||
564 | DEBUG_ARG("m = %lx", (long)m); | ||
565 | |||
566 | switch(so->so_emu) { | ||
567 | int x, i; | ||
568 | |||
569 | case EMU_IDENT0x7: | ||
570 | /* | ||
571 | * Identification protocol as per rfc-1413 | ||
572 | */ | ||
573 | |||
574 | { | ||
575 | struct socket *tmpso; | ||
576 | struct sockaddr_in addr; | ||
577 | socklen_t addrlen = sizeof(struct sockaddr_in); | ||
578 | struct sbuf *so_rcv = &so->so_rcv; | ||
579 | |||
580 | memcpy(so_rcv->sb_wptr, m->m_datam_hdr.mh_data, m->m_lenm_hdr.mh_len); | ||
581 | so_rcv->sb_wptr += m->m_lenm_hdr.mh_len; | ||
582 | so_rcv->sb_rptr += m->m_lenm_hdr.mh_len; | ||
583 | m->m_datam_hdr.mh_data[m->m_lenm_hdr.mh_len] = 0; /* NULL terminate */ | ||
584 | if (strchr(m->m_datam_hdr.mh_data, '\r') || strchr(m->m_datam_hdr.mh_data, '\n')) { | ||
585 | if (sscanf(so_rcv->sb_data, "%u%*[ ,]%u", &n1, &n2) == 2) { | ||
586 | HTONS(n1)((n1) = htons((uint16_t)(n1))); | ||
587 | HTONS(n2)((n2) = htons((uint16_t)(n2))); | ||
588 | /* n2 is the one on our host */ | ||
589 | for (tmpso = slirp->tcb.so_next; | ||
590 | tmpso != &slirp->tcb; | ||
591 | tmpso = tmpso->so_next) { | ||
592 | if (tmpso->so_laddr.s_addr == so->so_laddr.s_addr && | ||
593 | tmpso->so_lport == n2 && | ||
594 | tmpso->so_faddr.s_addr == so->so_faddr.s_addr && | ||
595 | tmpso->so_fport == n1) { | ||
596 | if (getsockname(tmpso->s, | ||
597 | (struct sockaddr *)&addr, &addrlen) == 0) | ||
598 | n2 = ntohs(addr.sin_port); | ||
599 | break; | ||
600 | } | ||
601 | } | ||
602 | } | ||
603 | so_rcv->sb_cc = snprintf(so_rcv->sb_data, | ||
604 | so_rcv->sb_datalen, | ||
605 | "%d,%d\r\n", n1, n2); | ||
606 | so_rcv->sb_rptr = so_rcv->sb_data; | ||
607 | so_rcv->sb_wptr = so_rcv->sb_data + so_rcv->sb_cc; | ||
608 | } | ||
609 | m_free(m); | ||
610 | return 0; | ||
611 | } | ||
612 | |||
613 | case EMU_FTP0x2: /* ftp */ | ||
614 | *(m->m_datam_hdr.mh_data+m->m_lenm_hdr.mh_len) = 0; /* NUL terminate for strstr */ | ||
615 | if ((bptr = (char *)strstr(m->m_datam_hdr.mh_data, "ORT")) != NULL((void*)0)) { | ||
616 | /* | ||
617 | * Need to emulate the PORT command | ||
618 | */ | ||
619 | x = sscanf(bptr, "ORT %u,%u,%u,%u,%u,%u\r\n%256[^\177]", | ||
620 | &n1, &n2, &n3, &n4, &n5, &n6, buff); | ||
621 | if (x < 6) | ||
622 | return 1; | ||
623 | |||
624 | laddr = htonl((n1 << 24) | (n2 << 16) | (n3 << 8) | (n4)); | ||
625 | lport = htons((n5 << 8) | (n6)); | ||
626 | |||
627 | if ((so = tcp_listen(slirp, INADDR_ANY((in_addr_t) 0x00000000), 0, laddr, | ||
628 | lport, SS_FACCEPTONCE0x200)) == NULL((void*)0)) { | ||
629 | return 1; | ||
630 | } | ||
631 | n6 = ntohs(so->so_fport); | ||
632 | |||
633 | n5 = (n6 >> 8) & 0xff; | ||
634 | n6 &= 0xff; | ||
635 | |||
636 | laddr = ntohl(so->so_faddr.s_addr); | ||
637 | |||
638 | n1 = ((laddr >> 24) & 0xff); | ||
639 | n2 = ((laddr >> 16) & 0xff); | ||
640 | n3 = ((laddr >> 8) & 0xff); | ||
641 | n4 = (laddr & 0xff); | ||
642 | |||
643 | m->m_lenm_hdr.mh_len = bptr - m->m_datam_hdr.mh_data; /* Adjust length */ | ||
644 | m->m_lenm_hdr.mh_len += snprintf(bptr, m->m_hdr.mh_size - m->m_lenm_hdr.mh_len, | ||
645 | "ORT %d,%d,%d,%d,%d,%d\r\n%s", | ||
646 | n1, n2, n3, n4, n5, n6, x==7?buff:""); | ||
647 | return 1; | ||
648 | } else if ((bptr = (char *)strstr(m->m_datam_hdr.mh_data, "27 Entering")) != NULL((void*)0)) { | ||
649 | /* | ||
650 | * Need to emulate the PASV response | ||
651 | */ | ||
652 | x = sscanf(bptr, "27 Entering Passive Mode (%u,%u,%u,%u,%u,%u)\r\n%256[^\177]", | ||
653 | &n1, &n2, &n3, &n4, &n5, &n6, buff); | ||
654 | if (x < 6) | ||
655 | return 1; | ||
656 | |||
657 | laddr = htonl((n1 << 24) | (n2 << 16) | (n3 << 8) | (n4)); | ||
658 | lport = htons((n5 << 8) | (n6)); | ||
659 | |||
660 | if ((so = tcp_listen(slirp, INADDR_ANY((in_addr_t) 0x00000000), 0, laddr, | ||
661 | lport, SS_FACCEPTONCE0x200)) == NULL((void*)0)) { | ||
662 | return 1; | ||
663 | } | ||
664 | n6 = ntohs(so->so_fport); | ||
665 | |||
666 | n5 = (n6 >> 8) & 0xff; | ||
667 | n6 &= 0xff; | ||
668 | |||
669 | laddr = ntohl(so->so_faddr.s_addr); | ||
670 | |||
671 | n1 = ((laddr >> 24) & 0xff); | ||
672 | n2 = ((laddr >> 16) & 0xff); | ||
673 | n3 = ((laddr >> 8) & 0xff); | ||
674 | n4 = (laddr & 0xff); | ||
675 | |||
676 | m->m_lenm_hdr.mh_len = bptr - m->m_datam_hdr.mh_data; /* Adjust length */ | ||
677 | m->m_lenm_hdr.mh_len += snprintf(bptr, m->m_hdr.mh_size - m->m_lenm_hdr.mh_len, | ||
678 | "27 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n%s", | ||
679 | n1, n2, n3, n4, n5, n6, x==7?buff:""); | ||
680 | |||
681 | return 1; | ||
682 | } | ||
683 | |||
684 | return 1; | ||
685 | |||
686 | case EMU_KSH0x3: | ||
687 | /* | ||
688 | * The kshell (Kerberos rsh) and shell services both pass | ||
689 | * a local port port number to carry signals to the server | ||
690 | * and stderr to the client. It is passed at the beginning | ||
691 | * of the connection as a NUL-terminated decimal ASCII string. | ||
692 | */ | ||
693 | so->so_emu = 0; | ||
694 | for (lport = 0, i = 0; i < m->m_lenm_hdr.mh_len-1; ++i) { | ||
695 | if (m->m_datam_hdr.mh_data[i] < '0' || m->m_datam_hdr.mh_data[i] > '9') | ||
696 | return 1; /* invalid number */ | ||
697 | lport *= 10; | ||
698 | lport += m->m_datam_hdr.mh_data[i] - '0'; | ||
699 | } | ||
700 | if (m->m_datam_hdr.mh_data[m->m_lenm_hdr.mh_len-1] == '\0' && lport != 0 && | ||
701 | (so = tcp_listen(slirp, INADDR_ANY((in_addr_t) 0x00000000), 0, so->so_laddr.s_addr, | ||
702 | htons(lport), SS_FACCEPTONCE0x200)) != NULL((void*)0)) | ||
703 | m->m_lenm_hdr.mh_len = snprintf(m->m_datam_hdr.mh_data, m->m_hdr.mh_size, "%d", | ||
704 | ntohs(so->so_fport)) + 1; | ||
705 | return 1; | ||
706 | |||
707 | case EMU_IRC0x4: | ||
708 | /* | ||
709 | * Need to emulate DCC CHAT, DCC SEND and DCC MOVE | ||
710 | */ | ||
711 | *(m->m_datam_hdr.mh_data+m->m_lenm_hdr.mh_len) = 0; /* NULL terminate the string for strstr */ | ||
712 | if ((bptr = (char *)strstr(m->m_datam_hdr.mh_data, "DCC")) == NULL((void*)0)) | ||
713 | return 1; | ||
714 | |||
715 | /* The %256s is for the broken mIRC */ | ||
716 | if (sscanf(bptr, "DCC CHAT %256s %u %u", buff, &laddr, &lport) == 3) { | ||
717 | if ((so = tcp_listen(slirp, INADDR_ANY((in_addr_t) 0x00000000), 0, | ||
718 | htonl(laddr), htons(lport), | ||
719 | SS_FACCEPTONCE0x200)) == NULL((void*)0)) { | ||
720 | return 1; | ||
721 | } | ||
722 | m->m_lenm_hdr.mh_len = bptr - m->m_datam_hdr.mh_data; /* Adjust length */ | ||
723 | m->m_lenm_hdr.mh_len += snprintf(bptr, m->m_hdr.mh_size, | ||
724 | "DCC CHAT chat %lu %u%c\n", | ||
725 | (unsigned long)ntohl(so->so_faddr.s_addr), | ||
726 | ntohs(so->so_fport), 1); | ||
727 | } else if (sscanf(bptr, "DCC SEND %256s %u %u %u", buff, &laddr, &lport, &n1) == 4) { | ||
728 | if ((so = tcp_listen(slirp, INADDR_ANY((in_addr_t) 0x00000000), 0, | ||
729 | htonl(laddr), htons(lport), | ||
730 | SS_FACCEPTONCE0x200)) == NULL((void*)0)) { | ||
731 | return 1; | ||
732 | } | ||
733 | m->m_lenm_hdr.mh_len = bptr - m->m_datam_hdr.mh_data; /* Adjust length */ | ||
734 | m->m_lenm_hdr.mh_len += snprintf(bptr, m->m_hdr.mh_size, | ||
735 | "DCC SEND %s %lu %u %u%c\n", buff, | ||
736 | (unsigned long)ntohl(so->so_faddr.s_addr), | ||
737 | ntohs(so->so_fport), n1, 1); | ||
738 | } else if (sscanf(bptr, "DCC MOVE %256s %u %u %u", buff, &laddr, &lport, &n1) == 4) { | ||
739 | if ((so = tcp_listen(slirp, INADDR_ANY((in_addr_t) 0x00000000), 0, | ||
740 | htonl(laddr), htons(lport), | ||
741 | SS_FACCEPTONCE0x200)) == NULL((void*)0)) { | ||
742 | return 1; | ||
743 | } | ||
744 | m->m_lenm_hdr.mh_len = bptr - m->m_datam_hdr.mh_data; /* Adjust length */ | ||
745 | m->m_lenm_hdr.mh_len += snprintf(bptr, m->m_hdr.mh_size, | ||
746 | "DCC MOVE %s %lu %u %u%c\n", buff, | ||
747 | (unsigned long)ntohl(so->so_faddr.s_addr), | ||
748 | ntohs(so->so_fport), n1, 1); | ||
749 | } | ||
750 | return 1; | ||
751 | |||
752 | case EMU_REALAUDIO0x5: | ||
753 | /* | ||
754 | * RealAudio emulation - JP. We must try to parse the incoming | ||
755 | * data and try to find the two characters that contain the | ||
756 | * port number. Then we redirect an udp port and replace the | ||
757 | * number with the real port we got. | ||
758 | * | ||
759 | * The 1.0 beta versions of the player are not supported | ||
760 | * any more. | ||
761 | * | ||
762 | * A typical packet for player version 1.0 (release version): | ||
763 | * | ||
764 | * 0000:50 4E 41 00 05 | ||
765 | * 0000:00 01 00 02 1B D7 00 00 67 E6 6C DC 63 00 12 50 ........g.l.c..P | ||
766 | * 0010:4E 43 4C 49 45 4E 54 20 31 30 31 20 41 4C 50 48 NCLIENT 101 ALPH | ||
767 | * 0020:41 6C 00 00 52 00 17 72 61 66 69 6C 65 73 2F 76 Al..R..rafiles/v | ||
768 | * 0030:6F 61 2F 65 6E 67 6C 69 73 68 5F 2E 72 61 79 42 oa/english_.rayB | ||
769 | * | ||
770 | * Now the port number 0x1BD7 is found at offset 0x04 of the | ||
771 | * Now the port number 0x1BD7 is found at offset 0x04 of the | ||
772 | * second packet. This time we received five bytes first and | ||
773 | * then the rest. You never know how many bytes you get. | ||
774 | * | ||
775 | * A typical packet for player version 2.0 (beta): | ||
776 | * | ||
777 | * 0000:50 4E 41 00 06 00 02 00 00 00 01 00 02 1B C1 00 PNA............. | ||
778 | * 0010:00 67 75 78 F5 63 00 0A 57 69 6E 32 2E 30 2E 30 .gux.c..Win2.0.0 | ||
779 | * 0020:2E 35 6C 00 00 52 00 1C 72 61 66 69 6C 65 73 2F .5l..R..rafiles/ | ||
780 | * 0030:77 65 62 73 69 74 65 2F 32 30 72 65 6C 65 61 73 website/20releas | ||
781 | * 0040:65 2E 72 61 79 53 00 00 06 36 42 e.rayS...6B | ||
782 | * | ||
783 | * Port number 0x1BC1 is found at offset 0x0d. | ||
784 | * | ||
785 | * This is just a horrible switch statement. Variable ra tells | ||
786 | * us where we're going. | ||
787 | */ | ||
788 | |||
789 | bptr = m->m_datam_hdr.mh_data; | ||
790 | while (bptr < m->m_datam_hdr.mh_data + m->m_lenm_hdr.mh_len) { | ||
791 | u_short p; | ||
792 | static int ra = 0; | ||
793 | char ra_tbl[4]; | ||
794 | |||
795 | ra_tbl[0] = 0x50; | ||
796 | ra_tbl[1] = 0x4e; | ||
797 | ra_tbl[2] = 0x41; | ||
798 | ra_tbl[3] = 0; | ||
799 | |||
800 | switch (ra) { | ||
801 | case 0: | ||
802 | case 2: | ||
803 | case 3: | ||
804 | if (*bptr++ != ra_tbl[ra]) { | ||
805 | ra = 0; | ||
806 | continue; | ||
807 | } | ||
808 | break; | ||
809 | |||
810 | case 1: | ||
811 | /* | ||
812 | * We may get 0x50 several times, ignore them | ||
813 | */ | ||
814 | if (*bptr == 0x50) { | ||
815 | ra = 1; | ||
816 | bptr++; | ||
817 | continue; | ||
818 | } else if (*bptr++ != ra_tbl[ra]) { | ||
819 | ra = 0; | ||
820 | continue; | ||
821 | } | ||
822 | break; | ||
823 | |||
824 | case 4: | ||
825 | /* | ||
826 | * skip version number | ||
827 | */ | ||
828 | bptr++; | ||
829 | break; | ||
830 | |||
831 | case 5: | ||
832 | /* | ||
833 | * The difference between versions 1.0 and | ||
834 | * 2.0 is here. For future versions of | ||
835 | * the player this may need to be modified. | ||
836 | */ | ||
837 | if (*(bptr + 1) == 0x02) | ||
838 | bptr += 8; | ||
839 | else | ||
840 | bptr += 4; | ||
841 | break; | ||
842 | |||
843 | case 6: | ||
844 | /* This is the field containing the port | ||
845 | * number that RA-player is listening to. | ||
846 | */ | ||
847 | lport = (((u_char*)bptr)[0] << 8) | ||
848 | + ((u_char *)bptr)[1]; | ||
849 | if (lport < 6970) | ||
850 | lport += 256; /* don't know why */ | ||
851 | if (lport < 6970 || lport > 7170) | ||
852 | return 1; /* failed */ | ||
853 | |||
854 | /* try to get udp port between 6970 - 7170 */ | ||
855 | for (p = 6970; p < 7071; p++) { | ||
856 | if (udp_listen(slirp, INADDR_ANY((in_addr_t) 0x00000000), | ||
857 | htons(p), | ||
858 | so->so_laddr.s_addr, | ||
859 | htons(lport), | ||
860 | SS_FACCEPTONCE0x200)) { | ||
861 | break; | ||
862 | } | ||
863 | } | ||
864 | if (p == 7071) | ||
865 | p = 0; | ||
866 | *(u_char *)bptr++ = (p >> 8) & 0xff; | ||
867 | *(u_char *)bptr = p & 0xff; | ||
868 | ra = 0; | ||
869 | return 1; /* port redirected, we're done */ | ||
870 | break; | ||
871 | |||
872 | default: | ||
873 | ra = 0; | ||
874 | } | ||
875 | ra++; | ||
876 | } | ||
877 | return 1; | ||
878 | |||
879 | default: | ||
880 | /* Ooops, not emulated, won't call tcp_emu again */ | ||
881 | so->so_emu = 0; | ||
882 | return 1; | ||
883 | } | ||
884 | } | ||
885 | |||
886 | /* | ||
887 | * Do misc. config of SLiRP while its running. | ||
888 | * Return 0 if this connections is to be closed, 1 otherwise, | ||
889 | * return 2 if this is a command-line connection | ||
890 | */ | ||
891 | int tcp_ctl(struct socket *so) | ||
892 | { | ||
893 | Slirp *slirp = so->slirp; | ||
894 | struct sbuf *sb = &so->so_snd; | ||
895 | struct ex_list *ex_ptr; | ||
896 | int do_pty; | ||
897 | |||
898 | DEBUG_CALL("tcp_ctl"); | ||
899 | DEBUG_ARG("so = %lx", (long )so); | ||
900 | |||
901 | if (so->so_faddr.s_addr != slirp->vhost_addr.s_addr) { | ||
902 | /* Check if it's pty_exec */ | ||
903 | for (ex_ptr = slirp->exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) { | ||
904 | if (ex_ptr->ex_fport == so->so_fport && | ||
905 | so->so_faddr.s_addr == ex_ptr->ex_addr.s_addr) { | ||
906 | if (ex_ptr->ex_pty == 3) { | ||
907 | so->s = -1; | ||
908 | so->extra = (void *)ex_ptr->ex_exec; | ||
909 | return 1; | ||
910 | } | ||
911 | do_pty = ex_ptr->ex_pty; | ||
912 | DEBUG_MISC((dfd, " executing %s\n", ex_ptr->ex_exec)); | ||
913 | return fork_exec(so, ex_ptr->ex_exec, do_pty); | ||
914 | } | ||
915 | } | ||
916 | } | ||
917 | sb->sb_cc = | ||
918 | snprintf(sb->sb_wptr, sb->sb_datalen - (sb->sb_wptr - sb->sb_data), | ||
919 | "Error: No application configured.\r\n"); | ||
920 | sb->sb_wptr += sb->sb_cc; | ||
921 | return 0; | ||
922 | } |