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 if (m->m_len > so_rcv->sb_datalen
639 - (so_rcv->sb_wptr - so_rcv->sb_data)) {
640 return 1;
641 }
642
643 memcpy(so_rcv->sb_wptr, m->m_data, m->m_len);
644 so_rcv->sb_wptr += m->m_len;
645 so_rcv->sb_rptr += m->m_len;
646 m->m_data[m->m_len] = 0;
647 if (strchr(m->m_data, '\r') || strchr(m->m_data, '\n')) {
648 if (sscanf(so_rcv->sb_data, "%u%*[ ,]%u", &n1, &n2) == 2) {
649 HTONS(n1);
650 HTONS(n2);
651
652 for (tmpso = slirp->tcb.so_next;
653 tmpso != &slirp->tcb;
654 tmpso = tmpso->so_next) {
655 if (tmpso->so_laddr.s_addr == so->so_laddr.s_addr &&
656 tmpso->so_lport == n2 &&
657 tmpso->so_faddr.s_addr == so->so_faddr.s_addr &&
658 tmpso->so_fport == n1) {
659 if (getsockname(tmpso->s,
660 (struct sockaddr *)&addr, &addrlen) == 0)
661 n2 = ntohs(addr.sin_port);
662 break;
663 }
664 }
665 so_rcv->sb_cc = snprintf(so_rcv->sb_data,
666 so_rcv->sb_datalen,
667 "%d,%d\r\n", n1, n2);
668 so_rcv->sb_rptr = so_rcv->sb_data;
669 so_rcv->sb_wptr = so_rcv->sb_data + so_rcv->sb_cc;
670 }
671 }
672 m_free(m);
673 return 0;
674 }
675
676 case EMU_FTP:
677 *(m->m_data+m->m_len) = 0;
678 if ((bptr = (char *)strstr(m->m_data, "ORT")) != NULL) {
679
680
681
682 x = sscanf(bptr, "ORT %u,%u,%u,%u,%u,%u\r\n%256[^\177]",
683 &n1, &n2, &n3, &n4, &n5, &n6, buff);
684 if (x < 6)
685 return 1;
686
687 laddr = htonl((n1 << 24) | (n2 << 16) | (n3 << 8) | (n4));
688 lport = htons((n5 << 8) | (n6));
689
690 if ((so = tcp_listen(slirp, INADDR_ANY, 0, laddr,
691 lport, SS_FACCEPTONCE)) == NULL) {
692 return 1;
693 }
694 n6 = ntohs(so->so_fport);
695
696 n5 = (n6 >> 8) & 0xff;
697 n6 &= 0xff;
698
699 laddr = ntohl(so->so_faddr.s_addr);
700
701 n1 = ((laddr >> 24) & 0xff);
702 n2 = ((laddr >> 16) & 0xff);
703 n3 = ((laddr >> 8) & 0xff);
704 n4 = (laddr & 0xff);
705
706 m->m_len = bptr - m->m_data;
707 m->m_len += snprintf(bptr, m->m_size - m->m_len,
708 "ORT %d,%d,%d,%d,%d,%d\r\n%s",
709 n1, n2, n3, n4, n5, n6, x==7?buff:"");
710 return 1;
711 } else if ((bptr = (char *)strstr(m->m_data, "27 Entering")) != NULL) {
712
713
714
715 x = sscanf(bptr, "27 Entering Passive Mode (%u,%u,%u,%u,%u,%u)\r\n%256[^\177]",
716 &n1, &n2, &n3, &n4, &n5, &n6, buff);
717 if (x < 6)
718 return 1;
719
720 laddr = htonl((n1 << 24) | (n2 << 16) | (n3 << 8) | (n4));
721 lport = htons((n5 << 8) | (n6));
722
723 if ((so = tcp_listen(slirp, INADDR_ANY, 0, laddr,
724 lport, SS_FACCEPTONCE)) == NULL) {
725 return 1;
726 }
727 n6 = ntohs(so->so_fport);
728
729 n5 = (n6 >> 8) & 0xff;
730 n6 &= 0xff;
731
732 laddr = ntohl(so->so_faddr.s_addr);
733
734 n1 = ((laddr >> 24) & 0xff);
735 n2 = ((laddr >> 16) & 0xff);
736 n3 = ((laddr >> 8) & 0xff);
737 n4 = (laddr & 0xff);
738
739 m->m_len = bptr - m->m_data;
740 m->m_len += snprintf(bptr, m->m_size - m->m_len,
741 "27 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n%s",
742 n1, n2, n3, n4, n5, n6, x==7?buff:"");
743
744 return 1;
745 }
746
747 return 1;
748
749 case EMU_KSH:
750
751
752
753
754
755
756 so->so_emu = 0;
757 for (lport = 0, i = 0; i < m->m_len-1; ++i) {
758 if (m->m_data[i] < '0' || m->m_data[i] > '9')
759 return 1;
760 lport *= 10;
761 lport += m->m_data[i] - '0';
762 }
763 if (m->m_data[m->m_len-1] == '\0' && lport != 0 &&
764 (so = tcp_listen(slirp, INADDR_ANY, 0, so->so_laddr.s_addr,
765 htons(lport), SS_FACCEPTONCE)) != NULL)
766 m->m_len = snprintf(m->m_data, m->m_size, "%d",
767 ntohs(so->so_fport)) + 1;
768 return 1;
769
770 case EMU_IRC:
771
772
773
774 *(m->m_data+m->m_len) = 0;
775 if ((bptr = (char *)strstr(m->m_data, "DCC")) == NULL)
776 return 1;
777
778
779 if (sscanf(bptr, "DCC CHAT %256s %u %u", buff, &laddr, &lport) == 3) {
780 if ((so = tcp_listen(slirp, INADDR_ANY, 0,
781 htonl(laddr), htons(lport),
782 SS_FACCEPTONCE)) == NULL) {
783 return 1;
784 }
785 m->m_len = bptr - m->m_data;
786 m->m_len += snprintf(bptr, m->m_size,
787 "DCC CHAT chat %lu %u%c\n",
788 (unsigned long)ntohl(so->so_faddr.s_addr),
789 ntohs(so->so_fport), 1);
790 } else if (sscanf(bptr, "DCC SEND %256s %u %u %u", buff, &laddr, &lport, &n1) == 4) {
791 if ((so = tcp_listen(slirp, INADDR_ANY, 0,
792 htonl(laddr), htons(lport),
793 SS_FACCEPTONCE)) == NULL) {
794 return 1;
795 }
796 m->m_len = bptr - m->m_data;
797 m->m_len += snprintf(bptr, m->m_size,
798 "DCC SEND %s %lu %u %u%c\n", buff,
799 (unsigned long)ntohl(so->so_faddr.s_addr),
800 ntohs(so->so_fport), n1, 1);
801 } else if (sscanf(bptr, "DCC MOVE %256s %u %u %u", buff, &laddr, &lport, &n1) == 4) {
802 if ((so = tcp_listen(slirp, INADDR_ANY, 0,
803 htonl(laddr), htons(lport),
804 SS_FACCEPTONCE)) == NULL) {
805 return 1;
806 }
807 m->m_len = bptr - m->m_data;
808 m->m_len += snprintf(bptr, m->m_size,
809 "DCC MOVE %s %lu %u %u%c\n", buff,
810 (unsigned long)ntohl(so->so_faddr.s_addr),
811 ntohs(so->so_fport), n1, 1);
812 }
813 return 1;
814
815 case EMU_REALAUDIO:
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
848
849
850
851
852 bptr = m->m_data;
853 while (bptr < m->m_data + m->m_len) {
854 u_short p;
855 static int ra = 0;
856 char ra_tbl[4];
857
858 ra_tbl[0] = 0x50;
859 ra_tbl[1] = 0x4e;
860 ra_tbl[2] = 0x41;
861 ra_tbl[3] = 0;
862
863 switch (ra) {
864 case 0:
865 case 2:
866 case 3:
867 if (*bptr++ != ra_tbl[ra]) {
868 ra = 0;
869 continue;
870 }
871 break;
872
873 case 1:
874
875
876
877 if (*bptr == 0x50) {
878 ra = 1;
879 bptr++;
880 continue;
881 } else if (*bptr++ != ra_tbl[ra]) {
882 ra = 0;
883 continue;
884 }
885 break;
886
887 case 4:
888
889
890
891 bptr++;
892 break;
893
894 case 5:
895
896
897
898
899
900 if (*(bptr + 1) == 0x02)
901 bptr += 8;
902 else
903 bptr += 4;
904 break;
905
906 case 6:
907
908
909
910 lport = (((u_char*)bptr)[0] << 8)
911 + ((u_char *)bptr)[1];
912 if (lport < 6970)
913 lport += 256;
914 if (lport < 6970 || lport > 7170)
915 return 1;
916
917
918 for (p = 6970; p < 7071; p++) {
919 if (udp_listen(slirp, INADDR_ANY,
920 htons(p),
921 so->so_laddr.s_addr,
922 htons(lport),
923 SS_FACCEPTONCE)) {
924 break;
925 }
926 }
927 if (p == 7071)
928 p = 0;
929 *(u_char *)bptr++ = (p >> 8) & 0xff;
930 *(u_char *)bptr = p & 0xff;
931 ra = 0;
932 return 1;
933 break;
934
935 default:
936 ra = 0;
937 }
938 ra++;
939 }
940 return 1;
941
942 default:
943
944 so->so_emu = 0;
945 return 1;
946 }
947}
948
949
950
951
952
953
954int tcp_ctl(struct socket *so)
955{
956 Slirp *slirp = so->slirp;
957 struct sbuf *sb = &so->so_snd;
958 struct ex_list *ex_ptr;
959 int do_pty;
960
961 DEBUG_CALL("tcp_ctl");
962 DEBUG_ARG("so = %p", so);
963
964 if (so->so_faddr.s_addr != slirp->vhost_addr.s_addr) {
965
966 for (ex_ptr = slirp->exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
967 if (ex_ptr->ex_fport == so->so_fport &&
968 so->so_faddr.s_addr == ex_ptr->ex_addr.s_addr) {
969 if (ex_ptr->ex_pty == 3) {
970 so->s = -1;
971 so->extra = (void *)ex_ptr->ex_exec;
972 return 1;
973 }
974 do_pty = ex_ptr->ex_pty;
975 DEBUG_MISC((dfd, " executing %s\n", ex_ptr->ex_exec));
976 return fork_exec(so, ex_ptr->ex_exec, do_pty);
977 }
978 }
979 }
980 sb->sb_cc =
981 snprintf(sb->sb_wptr, sb->sb_datalen - (sb->sb_wptr - sb->sb_data),
982 "Error: No application configured.\r\n");
983 sb->sb_wptr += sb->sb_cc;
984 return 0;
985}
986