1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41#include "qemu/osdep.h"
42#include "slirp.h"
43
44
45
46#define TCP_DO_RFC1323 0
47
48
49
50
51void
52tcp_init(Slirp *slirp)
53{
54 slirp->tcp_iss = 1;
55 slirp->tcb.so_next = slirp->tcb.so_prev = &slirp->tcb;
56 slirp->tcp_last_so = &slirp->tcb;
57}
58
59void tcp_cleanup(Slirp *slirp)
60{
61 while (slirp->tcb.so_next != &slirp->tcb) {
62 tcp_close(sototcpcb(slirp->tcb.so_next));
63 }
64}
65
66
67
68
69
70
71
72void
73tcp_template(struct tcpcb *tp)
74{
75 struct socket *so = tp->t_socket;
76 register struct tcpiphdr *n = &tp->t_template;
77
78 n->ti_mbuf = NULL;
79 memset(&n->ti, 0, sizeof(n->ti));
80 n->ti_x0 = 0;
81 switch (so->so_ffamily) {
82 case AF_INET:
83 n->ti_pr = IPPROTO_TCP;
84 n->ti_len = htons(sizeof(struct tcphdr));
85 n->ti_src = so->so_faddr;
86 n->ti_dst = so->so_laddr;
87 n->ti_sport = so->so_fport;
88 n->ti_dport = so->so_lport;
89 break;
90
91 case AF_INET6:
92 n->ti_nh6 = IPPROTO_TCP;
93 n->ti_len = htons(sizeof(struct tcphdr));
94 n->ti_src6 = so->so_faddr6;
95 n->ti_dst6 = so->so_laddr6;
96 n->ti_sport = so->so_fport6;
97 n->ti_dport = so->so_lport6;
98 break;
99
100 default:
101 g_assert_not_reached();
102 }
103
104 n->ti_seq = 0;
105 n->ti_ack = 0;
106 n->ti_x2 = 0;
107 n->ti_off = 5;
108 n->ti_flags = 0;
109 n->ti_win = 0;
110 n->ti_sum = 0;
111 n->ti_urp = 0;
112}
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127void
128tcp_respond(struct tcpcb *tp, struct tcpiphdr *ti, struct mbuf *m,
129 tcp_seq ack, tcp_seq seq, int flags, unsigned short af)
130{
131 register int tlen;
132 int win = 0;
133
134 DEBUG_CALL("tcp_respond");
135 DEBUG_ARG("tp = %p", tp);
136 DEBUG_ARG("ti = %p", ti);
137 DEBUG_ARG("m = %p", m);
138 DEBUG_ARG("ack = %u", ack);
139 DEBUG_ARG("seq = %u", seq);
140 DEBUG_ARG("flags = %x", flags);
141
142 if (tp)
143 win = sbspace(&tp->t_socket->so_rcv);
144 if (m == NULL) {
145 if (!tp || (m = m_get(tp->t_socket->slirp)) == NULL)
146 return;
147 tlen = 0;
148 m->m_data += IF_MAXLINKHDR;
149 *mtod(m, struct tcpiphdr *) = *ti;
150 ti = mtod(m, struct tcpiphdr *);
151 switch (af) {
152 case AF_INET:
153 ti->ti.ti_i4.ih_x1 = 0;
154 break;
155 case AF_INET6:
156 ti->ti.ti_i6.ih_x1 = 0;
157 break;
158 default:
159 g_assert_not_reached();
160 }
161 flags = TH_ACK;
162 } else {
163
164
165
166
167 m->m_data = (caddr_t)ti;
168
169 m->m_len = sizeof (struct tcpiphdr);
170 tlen = 0;
171#define xchg(a,b,type) { type t; t=a; a=b; b=t; }
172 switch (af) {
173 case AF_INET:
174 xchg(ti->ti_dst.s_addr, ti->ti_src.s_addr, uint32_t);
175 xchg(ti->ti_dport, ti->ti_sport, uint16_t);
176 break;
177 case AF_INET6:
178 xchg(ti->ti_dst6, ti->ti_src6, struct in6_addr);
179 xchg(ti->ti_dport, ti->ti_sport, uint16_t);
180 break;
181 default:
182 g_assert_not_reached();
183 }
184#undef xchg
185 }
186 ti->ti_len = htons((u_short)(sizeof (struct tcphdr) + tlen));
187 tlen += sizeof (struct tcpiphdr);
188 m->m_len = tlen;
189
190 ti->ti_mbuf = NULL;
191 ti->ti_x0 = 0;
192 ti->ti_seq = htonl(seq);
193 ti->ti_ack = htonl(ack);
194 ti->ti_x2 = 0;
195 ti->ti_off = sizeof (struct tcphdr) >> 2;
196 ti->ti_flags = flags;
197 if (tp)
198 ti->ti_win = htons((uint16_t) (win >> tp->rcv_scale));
199 else
200 ti->ti_win = htons((uint16_t)win);
201 ti->ti_urp = 0;
202 ti->ti_sum = 0;
203 ti->ti_sum = cksum(m, tlen);
204
205 struct tcpiphdr tcpiph_save = *(mtod(m, struct tcpiphdr *));
206 struct ip *ip;
207 struct ip6 *ip6;
208
209 switch (af) {
210 case AF_INET:
211 m->m_data += sizeof(struct tcpiphdr) - sizeof(struct tcphdr)
212 - sizeof(struct ip);
213 m->m_len -= sizeof(struct tcpiphdr) - sizeof(struct tcphdr)
214 - sizeof(struct ip);
215 ip = mtod(m, struct ip *);
216 ip->ip_len = m->m_len;
217 ip->ip_dst = tcpiph_save.ti_dst;
218 ip->ip_src = tcpiph_save.ti_src;
219 ip->ip_p = tcpiph_save.ti_pr;
220
221 if (flags & TH_RST) {
222 ip->ip_ttl = MAXTTL;
223 } else {
224 ip->ip_ttl = IPDEFTTL;
225 }
226
227 ip_output(NULL, m);
228 break;
229
230 case AF_INET6:
231 m->m_data += sizeof(struct tcpiphdr) - sizeof(struct tcphdr)
232 - sizeof(struct ip6);
233 m->m_len -= sizeof(struct tcpiphdr) - sizeof(struct tcphdr)
234 - sizeof(struct ip6);
235 ip6 = mtod(m, struct ip6 *);
236 ip6->ip_pl = tcpiph_save.ti_len;
237 ip6->ip_dst = tcpiph_save.ti_dst6;
238 ip6->ip_src = tcpiph_save.ti_src6;
239 ip6->ip_nh = tcpiph_save.ti_nh6;
240
241 ip6_output(NULL, m, 0);
242 break;
243
244 default:
245 g_assert_not_reached();
246 }
247}
248
249
250
251
252
253
254struct tcpcb *
255tcp_newtcpcb(struct socket *so)
256{
257 register struct tcpcb *tp;
258
259 tp = (struct tcpcb *)malloc(sizeof(*tp));
260 if (tp == NULL)
261 return ((struct tcpcb *)0);
262
263 memset((char *) tp, 0, sizeof(struct tcpcb));
264 tp->seg_next = tp->seg_prev = (struct tcpiphdr*)tp;
265 tp->t_maxseg = (so->so_ffamily == AF_INET) ? TCP_MSS : TCP6_MSS;
266
267 tp->t_flags = TCP_DO_RFC1323 ? (TF_REQ_SCALE|TF_REQ_TSTMP) : 0;
268 tp->t_socket = so;
269
270
271
272
273
274
275 tp->t_srtt = TCPTV_SRTTBASE;
276 tp->t_rttvar = TCPTV_SRTTDFLT << 2;
277 tp->t_rttmin = TCPTV_MIN;
278
279 TCPT_RANGESET(tp->t_rxtcur,
280 ((TCPTV_SRTTBASE >> 2) + (TCPTV_SRTTDFLT << 2)) >> 1,
281 TCPTV_MIN, TCPTV_REXMTMAX);
282
283 tp->snd_cwnd = TCP_MAXWIN << TCP_MAX_WINSHIFT;
284 tp->snd_ssthresh = TCP_MAXWIN << TCP_MAX_WINSHIFT;
285 tp->t_state = TCPS_CLOSED;
286
287 so->so_tcpcb = tp;
288
289 return (tp);
290}
291
292
293
294
295
296
297struct tcpcb *tcp_drop(struct tcpcb *tp, int err)
298{
299 DEBUG_CALL("tcp_drop");
300 DEBUG_ARG("tp = %p", tp);
301 DEBUG_ARG("errno = %d", errno);
302
303 if (TCPS_HAVERCVDSYN(tp->t_state)) {
304 tp->t_state = TCPS_CLOSED;
305 (void) tcp_output(tp);
306 }
307 return (tcp_close(tp));
308}
309
310
311
312
313
314
315
316struct tcpcb *
317tcp_close(struct tcpcb *tp)
318{
319 register struct tcpiphdr *t;
320 struct socket *so = tp->t_socket;
321 Slirp *slirp = so->slirp;
322 register struct mbuf *m;
323
324 DEBUG_CALL("tcp_close");
325 DEBUG_ARG("tp = %p", tp);
326
327
328 t = tcpfrag_list_first(tp);
329 while (!tcpfrag_list_end(t, tp)) {
330 t = tcpiphdr_next(t);
331 m = tcpiphdr_prev(t)->ti_mbuf;
332 remque(tcpiphdr2qlink(tcpiphdr_prev(t)));
333 m_free(m);
334 }
335 free(tp);
336 so->so_tcpcb = NULL;
337
338 if (so == slirp->tcp_last_so)
339 slirp->tcp_last_so = &slirp->tcb;
340 closesocket(so->s);
341 sbfree(&so->so_rcv);
342 sbfree(&so->so_snd);
343 sofree(so);
344 return ((struct tcpcb *)0);
345}
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361void
362tcp_sockclosed(struct tcpcb *tp)
363{
364
365 DEBUG_CALL("tcp_sockclosed");
366 DEBUG_ARG("tp = %p", tp);
367
368 if (!tp) {
369 return;
370 }
371
372 switch (tp->t_state) {
373
374 case TCPS_CLOSED:
375 case TCPS_LISTEN:
376 case TCPS_SYN_SENT:
377 tp->t_state = TCPS_CLOSED;
378 tp = tcp_close(tp);
379 break;
380
381 case TCPS_SYN_RECEIVED:
382 case TCPS_ESTABLISHED:
383 tp->t_state = TCPS_FIN_WAIT_1;
384 break;
385
386 case TCPS_CLOSE_WAIT:
387 tp->t_state = TCPS_LAST_ACK;
388 break;
389 }
390 tcp_output(tp);
391}
392
393
394
395
396
397
398
399
400
401
402
403int tcp_fconnect(struct socket *so, unsigned short af)
404{
405 int ret=0;
406
407 DEBUG_CALL("tcp_fconnect");
408 DEBUG_ARG("so = %p", so);
409
410 ret = so->s = qemu_socket(af, SOCK_STREAM, 0);
411 if (ret >= 0) {
412 int opt, s=so->s;
413 struct sockaddr_storage addr;
414
415 qemu_set_nonblock(s);
416 socket_set_fast_reuse(s);
417 opt = 1;
418 qemu_setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(opt));
419 opt = 1;
420 qemu_setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt));
421
422 addr = so->fhost.ss;
423 DEBUG_CALL(" connect()ing")
424 sotranslate_out(so, &addr);
425
426
427 ret = connect(s, (struct sockaddr *)&addr, sockaddr_size(&addr));
428
429
430
431
432
433 soisfconnecting(so);
434 }
435
436 return(ret);
437}
438
439
440
441
442
443
444
445
446
447
448
449
450
451void tcp_connect(struct socket *inso)
452{
453 Slirp *slirp = inso->slirp;
454 struct socket *so;
455 struct sockaddr_storage addr;
456 socklen_t addrlen = sizeof(struct sockaddr_storage);
457 struct tcpcb *tp;
458 int s, opt;
459
460 DEBUG_CALL("tcp_connect");
461 DEBUG_ARG("inso = %p", inso);
462
463
464
465
466
467 if (inso->so_state & SS_FACCEPTONCE) {
468
469 so = inso;
470 } else {
471 so = socreate(slirp);
472 if (tcp_attach(so) < 0) {
473 g_free(so);
474 return;
475 }
476 so->lhost = inso->lhost;
477 so->so_ffamily = inso->so_ffamily;
478 }
479
480 tcp_mss(sototcpcb(so), 0);
481
482 s = accept(inso->s, (struct sockaddr *)&addr, &addrlen);
483 if (s < 0) {
484 tcp_close(sototcpcb(so));
485 return;
486 }
487 qemu_set_nonblock(s);
488 socket_set_fast_reuse(s);
489 opt = 1;
490 qemu_setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(int));
491 socket_set_nodelay(s);
492
493 so->fhost.ss = addr;
494 sotranslate_accept(so);
495
496
497 if (inso->so_state & SS_FACCEPTONCE) {
498
499 closesocket(so->s);
500
501
502
503 so->so_state = SS_NOFDREF;
504 }
505 so->s = s;
506 so->so_state |= SS_INCOMING;
507
508 so->so_iptos = tcp_tos(so);
509 tp = sototcpcb(so);
510
511 tcp_template(tp);
512
513 tp->t_state = TCPS_SYN_SENT;
514 tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT;
515 tp->iss = slirp->tcp_iss;
516 slirp->tcp_iss += TCP_ISSINCR/2;
517 tcp_sendseqinit(tp);
518 tcp_output(tp);
519}
520
521
522
523
524int
525tcp_attach(struct socket *so)
526{
527 if ((so->so_tcpcb = tcp_newtcpcb(so)) == NULL)
528 return -1;
529
530 insque(so, &so->slirp->tcb);
531
532 return 0;
533}
534
535
536
537
538static const struct tos_t tcptos[] = {
539 {0, 20, IPTOS_THROUGHPUT, 0},
540 {21, 21, IPTOS_LOWDELAY, EMU_FTP},
541 {0, 23, IPTOS_LOWDELAY, 0},
542 {0, 80, IPTOS_THROUGHPUT, 0},
543 {0, 513, IPTOS_LOWDELAY, EMU_RLOGIN|EMU_NOCONNECT},
544 {0, 514, IPTOS_LOWDELAY, EMU_RSH|EMU_NOCONNECT},
545 {0, 544, IPTOS_LOWDELAY, EMU_KSH},
546 {0, 543, IPTOS_LOWDELAY, 0},
547 {0, 6667, IPTOS_THROUGHPUT, EMU_IRC},
548 {0, 6668, IPTOS_THROUGHPUT, EMU_IRC},
549 {0, 7070, IPTOS_LOWDELAY, EMU_REALAUDIO },
550 {0, 113, IPTOS_LOWDELAY, EMU_IDENT },
551 {0, 0, 0, 0}
552};
553
554static struct emu_t *tcpemu = NULL;
555
556
557
558
559uint8_t
560tcp_tos(struct socket *so)
561{
562 int i = 0;
563 struct emu_t *emup;
564
565 while(tcptos[i].tos) {
566 if ((tcptos[i].fport && (ntohs(so->so_fport) == tcptos[i].fport)) ||
567 (tcptos[i].lport && (ntohs(so->so_lport) == tcptos[i].lport))) {
568 so->so_emu = tcptos[i].emu;
569 return tcptos[i].tos;
570 }
571 i++;
572 }
573
574
575 for (emup = tcpemu; emup; emup = emup->next) {
576 if ((emup->fport && (ntohs(so->so_fport) == emup->fport)) ||
577 (emup->lport && (ntohs(so->so_lport) == emup->lport))) {
578 so->so_emu = emup->emu;
579 return emup->tos;
580 }
581 }
582
583 return 0;
584}
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610int
611tcp_emu(struct socket *so, struct mbuf *m)
612{
613 Slirp *slirp = so->slirp;
614 u_int n1, n2, n3, n4, n5, n6;
615 char buff[257];
616 uint32_t laddr;
617 u_int lport;
618 char *bptr;
619
620 DEBUG_CALL("tcp_emu");
621 DEBUG_ARG("so = %p", so);
622 DEBUG_ARG("m = %p", m);
623
624 switch(so->so_emu) {
625 int x, i;
626
627 case EMU_IDENT:
628
629
630
631
632 {
633 struct socket *tmpso;
634 struct sockaddr_in addr;
635 socklen_t addrlen = sizeof(struct sockaddr_in);
636 struct sbuf *so_rcv = &so->so_rcv;
637
638 memcpy(so_rcv->sb_wptr, m->m_data, m->m_len);
639 so_rcv->sb_wptr += m->m_len;
640 so_rcv->sb_rptr += m->m_len;
641 m->m_data[m->m_len] = 0;
642 if (strchr(m->m_data, '\r') || strchr(m->m_data, '\n')) {
643 if (sscanf(so_rcv->sb_data, "%u%*[ ,]%u", &n1, &n2) == 2) {
644 HTONS(n1);
645 HTONS(n2);
646
647 for (tmpso = slirp->tcb.so_next;
648 tmpso != &slirp->tcb;
649 tmpso = tmpso->so_next) {
650 if (tmpso->so_laddr.s_addr == so->so_laddr.s_addr &&
651 tmpso->so_lport == n2 &&
652 tmpso->so_faddr.s_addr == so->so_faddr.s_addr &&
653 tmpso->so_fport == n1) {
654 if (getsockname(tmpso->s,
655 (struct sockaddr *)&addr, &addrlen) == 0)
656 n2 = ntohs(addr.sin_port);
657 break;
658 }
659 }
660 }
661 so_rcv->sb_cc = snprintf(so_rcv->sb_data,
662 so_rcv->sb_datalen,
663 "%d,%d\r\n", n1, n2);
664 so_rcv->sb_rptr = so_rcv->sb_data;
665 so_rcv->sb_wptr = so_rcv->sb_data + so_rcv->sb_cc;
666 }
667 m_free(m);
668 return 0;
669 }
670
671 case EMU_FTP:
672 *(m->m_data+m->m_len) = 0;
673 if ((bptr = (char *)strstr(m->m_data, "ORT")) != NULL) {
674
675
676
677 x = sscanf(bptr, "ORT %u,%u,%u,%u,%u,%u\r\n%256[^\177]",
678 &n1, &n2, &n3, &n4, &n5, &n6, buff);
679 if (x < 6)
680 return 1;
681
682 laddr = htonl((n1 << 24) | (n2 << 16) | (n3 << 8) | (n4));
683 lport = htons((n5 << 8) | (n6));
684
685 if ((so = tcp_listen(slirp, INADDR_ANY, 0, laddr,
686 lport, SS_FACCEPTONCE)) == NULL) {
687 return 1;
688 }
689 n6 = ntohs(so->so_fport);
690
691 n5 = (n6 >> 8) & 0xff;
692 n6 &= 0xff;
693
694 laddr = ntohl(so->so_faddr.s_addr);
695
696 n1 = ((laddr >> 24) & 0xff);
697 n2 = ((laddr >> 16) & 0xff);
698 n3 = ((laddr >> 8) & 0xff);
699 n4 = (laddr & 0xff);
700
701 m->m_len = bptr - m->m_data;
702 m->m_len += snprintf(bptr, m->m_size - m->m_len,
703 "ORT %d,%d,%d,%d,%d,%d\r\n%s",
704 n1, n2, n3, n4, n5, n6, x==7?buff:"");
705 return 1;
706 } else if ((bptr = (char *)strstr(m->m_data, "27 Entering")) != NULL) {
707
708
709
710 x = sscanf(bptr, "27 Entering Passive Mode (%u,%u,%u,%u,%u,%u)\r\n%256[^\177]",
711 &n1, &n2, &n3, &n4, &n5, &n6, buff);
712 if (x < 6)
713 return 1;
714
715 laddr = htonl((n1 << 24) | (n2 << 16) | (n3 << 8) | (n4));
716 lport = htons((n5 << 8) | (n6));
717
718 if ((so = tcp_listen(slirp, INADDR_ANY, 0, laddr,
719 lport, SS_FACCEPTONCE)) == NULL) {
720 return 1;
721 }
722 n6 = ntohs(so->so_fport);
723
724 n5 = (n6 >> 8) & 0xff;
725 n6 &= 0xff;
726
727 laddr = ntohl(so->so_faddr.s_addr);
728
729 n1 = ((laddr >> 24) & 0xff);
730 n2 = ((laddr >> 16) & 0xff);
731 n3 = ((laddr >> 8) & 0xff);
732 n4 = (laddr & 0xff);
733
734 m->m_len = bptr - m->m_data;
735 m->m_len += snprintf(bptr, m->m_size - m->m_len,
736 "27 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n%s",
737 n1, n2, n3, n4, n5, n6, x==7?buff:"");
738
739 return 1;
740 }
741
742 return 1;
743
744 case EMU_KSH:
745
746
747
748
749
750
751 so->so_emu = 0;
752 for (lport = 0, i = 0; i < m->m_len-1; ++i) {
753 if (m->m_data[i] < '0' || m->m_data[i] > '9')
754 return 1;
755 lport *= 10;
756 lport += m->m_data[i] - '0';
757 }
758 if (m->m_data[m->m_len-1] == '\0' && lport != 0 &&
759 (so = tcp_listen(slirp, INADDR_ANY, 0, so->so_laddr.s_addr,
760 htons(lport), SS_FACCEPTONCE)) != NULL)
761 m->m_len = snprintf(m->m_data, m->m_size, "%d",
762 ntohs(so->so_fport)) + 1;
763 return 1;
764
765 case EMU_IRC:
766
767
768
769 *(m->m_data+m->m_len) = 0;
770 if ((bptr = (char *)strstr(m->m_data, "DCC")) == NULL)
771 return 1;
772
773
774 if (sscanf(bptr, "DCC CHAT %256s %u %u", buff, &laddr, &lport) == 3) {
775 if ((so = tcp_listen(slirp, INADDR_ANY, 0,
776 htonl(laddr), htons(lport),
777 SS_FACCEPTONCE)) == NULL) {
778 return 1;
779 }
780 m->m_len = bptr - m->m_data;
781 m->m_len += snprintf(bptr, m->m_size,
782 "DCC CHAT chat %lu %u%c\n",
783 (unsigned long)ntohl(so->so_faddr.s_addr),
784 ntohs(so->so_fport), 1);
785 } else if (sscanf(bptr, "DCC SEND %256s %u %u %u", buff, &laddr, &lport, &n1) == 4) {
786 if ((so = tcp_listen(slirp, INADDR_ANY, 0,
787 htonl(laddr), htons(lport),
788 SS_FACCEPTONCE)) == NULL) {
789 return 1;
790 }
791 m->m_len = bptr - m->m_data;
792 m->m_len += snprintf(bptr, m->m_size,
793 "DCC SEND %s %lu %u %u%c\n", buff,
794 (unsigned long)ntohl(so->so_faddr.s_addr),
795 ntohs(so->so_fport), n1, 1);
796 } else if (sscanf(bptr, "DCC MOVE %256s %u %u %u", buff, &laddr, &lport, &n1) == 4) {
797 if ((so = tcp_listen(slirp, INADDR_ANY, 0,
798 htonl(laddr), htons(lport),
799 SS_FACCEPTONCE)) == NULL) {
800 return 1;
801 }
802 m->m_len = bptr - m->m_data;
803 m->m_len += snprintf(bptr, m->m_size,
804 "DCC MOVE %s %lu %u %u%c\n", buff,
805 (unsigned long)ntohl(so->so_faddr.s_addr),
806 ntohs(so->so_fport), n1, 1);
807 }
808 return 1;
809
810 case EMU_REALAUDIO:
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847 bptr = m->m_data;
848 while (bptr < m->m_data + m->m_len) {
849 u_short p;
850 static int ra = 0;
851 char ra_tbl[4];
852
853 ra_tbl[0] = 0x50;
854 ra_tbl[1] = 0x4e;
855 ra_tbl[2] = 0x41;
856 ra_tbl[3] = 0;
857
858 switch (ra) {
859 case 0:
860 case 2:
861 case 3:
862 if (*bptr++ != ra_tbl[ra]) {
863 ra = 0;
864 continue;
865 }
866 break;
867
868 case 1:
869
870
871
872 if (*bptr == 0x50) {
873 ra = 1;
874 bptr++;
875 continue;
876 } else if (*bptr++ != ra_tbl[ra]) {
877 ra = 0;
878 continue;
879 }
880 break;
881
882 case 4:
883
884
885
886 bptr++;
887 break;
888
889 case 5:
890
891
892
893
894
895 if (*(bptr + 1) == 0x02)
896 bptr += 8;
897 else
898 bptr += 4;
899 break;
900
901 case 6:
902
903
904
905 lport = (((u_char*)bptr)[0] << 8)
906 + ((u_char *)bptr)[1];
907 if (lport < 6970)
908 lport += 256;
909 if (lport < 6970 || lport > 7170)
910 return 1;
911
912
913 for (p = 6970; p < 7071; p++) {
914 if (udp_listen(slirp, INADDR_ANY,
915 htons(p),
916 so->so_laddr.s_addr,
917 htons(lport),
918 SS_FACCEPTONCE)) {
919 break;
920 }
921 }
922 if (p == 7071)
923 p = 0;
924 *(u_char *)bptr++ = (p >> 8) & 0xff;
925 *(u_char *)bptr = p & 0xff;
926 ra = 0;
927 return 1;
928 break;
929
930 default:
931 ra = 0;
932 }
933 ra++;
934 }
935 return 1;
936
937 default:
938
939 so->so_emu = 0;
940 return 1;
941 }
942}
943
944
945
946
947
948
949int tcp_ctl(struct socket *so)
950{
951 Slirp *slirp = so->slirp;
952 struct sbuf *sb = &so->so_snd;
953 struct ex_list *ex_ptr;
954 int do_pty;
955
956 DEBUG_CALL("tcp_ctl");
957 DEBUG_ARG("so = %p", so);
958
959 if (so->so_faddr.s_addr != slirp->vhost_addr.s_addr) {
960
961 for (ex_ptr = slirp->exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
962 if (ex_ptr->ex_fport == so->so_fport &&
963 so->so_faddr.s_addr == ex_ptr->ex_addr.s_addr) {
964 if (ex_ptr->ex_pty == 3) {
965 so->s = -1;
966 so->extra = (void *)ex_ptr->ex_exec;
967 return 1;
968 }
969 do_pty = ex_ptr->ex_pty;
970 DEBUG_MISC((dfd, " executing %s\n", ex_ptr->ex_exec));
971 return fork_exec(so, ex_ptr->ex_exec, do_pty);
972 }
973 }
974 }
975 sb->sb_cc =
976 snprintf(sb->sb_wptr, sb->sb_datalen - (sb->sb_wptr - sb->sb_data),
977 "Error: No application configured.\r\n");
978 sb->sb_wptr += sb->sb_cc;
979 return 0;
980}
981