ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/slirp/tcp_subr.c
Revision: 1.2
Committed: 2005-06-30T21:25:26Z (19 years, 5 months ago) by cebix
Content type: text/plain
Branch: MAIN
CVS Tags: nigel-build-19, nigel-build-17
Changes since 1.1: +2 -2 lines
Log Message:
minor cleanups

File Contents

# User Rev Content
1 gbeauche 1.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. All advertising materials mentioning features or use of this software
14     * must display the following acknowledgement:
15     * This product includes software developed by the University of
16     * California, Berkeley and its contributors.
17     * 4. Neither the name of the University nor the names of its contributors
18     * may be used to endorse or promote products derived from this software
19     * without specific prior written permission.
20     *
21     * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22     * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23     * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24     * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25     * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26     * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27     * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30     * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31     * SUCH DAMAGE.
32     *
33     * @(#)tcp_subr.c 8.1 (Berkeley) 6/10/93
34     * tcp_subr.c,v 1.5 1994/10/08 22:39:58 phk Exp
35     */
36    
37     /*
38     * Changes and additions relating to SLiRP
39     * Copyright (c) 1995 Danny Gasparovski.
40     *
41     * Please read the file COPYRIGHT for the
42     * terms and conditions of the copyright.
43     */
44    
45     #define WANT_SYS_IOCTL_H
46     #include <slirp.h>
47    
48     /* patchable/settable parameters for tcp */
49     int tcp_mssdflt = TCP_MSS;
50     int tcp_rttdflt = TCPTV_SRTTDFLT / PR_SLOWHZ;
51     int tcp_do_rfc1323 = 0; /* Don't do rfc1323 performance enhancements */
52     int tcp_rcvspace; /* You may want to change this */
53     int tcp_sndspace; /* Keep small if you have an error prone link */
54    
55     /*
56     * Tcp initialization
57     */
58     void
59     tcp_init()
60     {
61     tcp_iss = 1; /* wrong */
62     tcb.so_next = tcb.so_prev = &tcb;
63    
64     /* tcp_rcvspace = our Window we advertise to the remote */
65     tcp_rcvspace = TCP_RCVSPACE;
66     tcp_sndspace = TCP_SNDSPACE;
67    
68     /* Make sure tcp_sndspace is at least 2*MSS */
69     if (tcp_sndspace < 2*(min(if_mtu, if_mru) - sizeof(struct tcpiphdr)))
70     tcp_sndspace = 2*(min(if_mtu, if_mru) - sizeof(struct tcpiphdr));
71     }
72    
73     /*
74     * Create template to be used to send tcp packets on a connection.
75     * Call after host entry created, fills
76     * in a skeletal tcp/ip header, minimizing the amount of work
77     * necessary when the connection is used.
78     */
79     /* struct tcpiphdr * */
80     void
81     tcp_template(tp)
82     struct tcpcb *tp;
83     {
84     struct socket *so = tp->t_socket;
85     register struct tcpiphdr *n = &tp->t_template;
86    
87     n->ti_next = n->ti_prev = 0;
88     n->ti_x1 = 0;
89     n->ti_pr = IPPROTO_TCP;
90     n->ti_len = htons(sizeof (struct tcpiphdr) - sizeof (struct ip));
91     n->ti_src = so->so_faddr;
92     n->ti_dst = so->so_laddr;
93     n->ti_sport = so->so_fport;
94     n->ti_dport = so->so_lport;
95    
96     n->ti_seq = 0;
97     n->ti_ack = 0;
98     n->ti_x2 = 0;
99     n->ti_off = 5;
100     n->ti_flags = 0;
101     n->ti_win = 0;
102     n->ti_sum = 0;
103     n->ti_urp = 0;
104     }
105    
106     /*
107     * Send a single message to the TCP at address specified by
108     * the given TCP/IP header. If m == 0, then we make a copy
109     * of the tcpiphdr at ti and send directly to the addressed host.
110     * This is used to force keep alive messages out using the TCP
111     * template for a connection tp->t_template. If flags are given
112     * then we send a message back to the TCP which originated the
113     * segment ti, and discard the mbuf containing it and any other
114     * attached mbufs.
115     *
116     * In any case the ack and sequence number of the transmitted
117     * segment are as specified by the parameters.
118     */
119     void
120     tcp_respond(tp, ti, m, ack, seq, flags)
121     struct tcpcb *tp;
122     register struct tcpiphdr *ti;
123     register struct mbuf *m;
124     tcp_seq ack, seq;
125     int flags;
126     {
127     register int tlen;
128     int win = 0;
129    
130     DEBUG_CALL("tcp_respond");
131     DEBUG_ARG("tp = %lx", (long)tp);
132     DEBUG_ARG("ti = %lx", (long)ti);
133     DEBUG_ARG("m = %lx", (long)m);
134     DEBUG_ARG("ack = %u", ack);
135     DEBUG_ARG("seq = %u", seq);
136     DEBUG_ARG("flags = %x", flags);
137    
138     if (tp)
139     win = sbspace(&tp->t_socket->so_rcv);
140     if (m == 0) {
141     if ((m = m_get()) == NULL)
142     return;
143     #ifdef TCP_COMPAT_42
144     tlen = 1;
145     #else
146     tlen = 0;
147     #endif
148     m->m_data += if_maxlinkhdr;
149     *mtod(m, struct tcpiphdr *) = *ti;
150     ti = mtod(m, struct tcpiphdr *);
151     flags = TH_ACK;
152     } else {
153     /*
154     * ti points into m so the next line is just making
155     * the mbuf point to ti
156     */
157     m->m_data = (caddr_t)ti;
158    
159     m->m_len = sizeof (struct tcpiphdr);
160     tlen = 0;
161     #define xchg(a,b,type) { type t; t=a; a=b; b=t; }
162     xchg(ti->ti_dst.s_addr, ti->ti_src.s_addr, u_int32_t);
163     xchg(ti->ti_dport, ti->ti_sport, u_int16_t);
164     #undef xchg
165     }
166     ti->ti_len = htons((u_short)(sizeof (struct tcphdr) + tlen));
167     tlen += sizeof (struct tcpiphdr);
168     m->m_len = tlen;
169    
170     ti->ti_next = ti->ti_prev = 0;
171     ti->ti_x1 = 0;
172     ti->ti_seq = htonl(seq);
173     ti->ti_ack = htonl(ack);
174     ti->ti_x2 = 0;
175     ti->ti_off = sizeof (struct tcphdr) >> 2;
176     ti->ti_flags = flags;
177     if (tp)
178     ti->ti_win = htons((u_int16_t) (win >> tp->rcv_scale));
179     else
180     ti->ti_win = htons((u_int16_t)win);
181     ti->ti_urp = 0;
182     ti->ti_sum = 0;
183     ti->ti_sum = cksum(m, tlen);
184     ((struct ip *)ti)->ip_len = tlen;
185    
186     if(flags & TH_RST)
187     ((struct ip *)ti)->ip_ttl = MAXTTL;
188     else
189     ((struct ip *)ti)->ip_ttl = ip_defttl;
190    
191     (void) ip_output((struct socket *)0, m);
192     }
193    
194     /*
195     * Create a new TCP control block, making an
196     * empty reassembly queue and hooking it to the argument
197     * protocol control block.
198     */
199     struct tcpcb *
200     tcp_newtcpcb(so)
201     struct socket *so;
202     {
203     register struct tcpcb *tp;
204    
205     tp = (struct tcpcb *)malloc(sizeof(*tp));
206     if (tp == NULL)
207     return ((struct tcpcb *)0);
208    
209     memset((char *) tp, 0, sizeof(struct tcpcb));
210     tp->seg_next = tp->seg_prev = (tcpiphdrp_32)tp;
211     tp->t_maxseg = tcp_mssdflt;
212    
213     tp->t_flags = tcp_do_rfc1323 ? (TF_REQ_SCALE|TF_REQ_TSTMP) : 0;
214     tp->t_socket = so;
215    
216     /*
217     * Init srtt to TCPTV_SRTTBASE (0), so we can tell that we have no
218     * rtt estimate. Set rttvar so that srtt + 2 * rttvar gives
219     * reasonable initial retransmit time.
220     */
221     tp->t_srtt = TCPTV_SRTTBASE;
222     tp->t_rttvar = tcp_rttdflt * PR_SLOWHZ << 2;
223     tp->t_rttmin = TCPTV_MIN;
224    
225     TCPT_RANGESET(tp->t_rxtcur,
226     ((TCPTV_SRTTBASE >> 2) + (TCPTV_SRTTDFLT << 2)) >> 1,
227     TCPTV_MIN, TCPTV_REXMTMAX);
228    
229     tp->snd_cwnd = TCP_MAXWIN << TCP_MAX_WINSHIFT;
230     tp->snd_ssthresh = TCP_MAXWIN << TCP_MAX_WINSHIFT;
231     tp->t_state = TCPS_CLOSED;
232    
233     so->so_tcpcb = tp;
234    
235     return (tp);
236     }
237    
238     /*
239     * Drop a TCP connection, reporting
240     * the specified error. If connection is synchronized,
241     * then send a RST to peer.
242     */
243     struct tcpcb *tcp_drop(struct tcpcb *tp, int err)
244     {
245     /* tcp_drop(tp, errno)
246     register struct tcpcb *tp;
247     int errno;
248     {
249     */
250    
251     DEBUG_CALL("tcp_drop");
252     DEBUG_ARG("tp = %lx", (long)tp);
253     DEBUG_ARG("errno = %d", errno);
254    
255     if (TCPS_HAVERCVDSYN(tp->t_state)) {
256     tp->t_state = TCPS_CLOSED;
257     (void) tcp_output(tp);
258     tcpstat.tcps_drops++;
259     } else
260     tcpstat.tcps_conndrops++;
261     /* if (errno == ETIMEDOUT && tp->t_softerror)
262     * errno = tp->t_softerror;
263     */
264     /* so->so_error = errno; */
265     return (tcp_close(tp));
266     }
267    
268     /*
269     * Close a TCP control block:
270     * discard all space held by the tcp
271     * discard internet protocol block
272     * wake up any sleepers
273     */
274     struct tcpcb *
275     tcp_close(tp)
276     register struct tcpcb *tp;
277     {
278     register struct tcpiphdr *t;
279     struct socket *so = tp->t_socket;
280     register struct mbuf *m;
281    
282     DEBUG_CALL("tcp_close");
283     DEBUG_ARG("tp = %lx", (long )tp);
284    
285     /* free the reassembly queue, if any */
286     t = (struct tcpiphdr *) tp->seg_next;
287     while (t != (struct tcpiphdr *)tp) {
288     t = (struct tcpiphdr *)t->ti_next;
289     m = (struct mbuf *) REASS_MBUF((struct tcpiphdr *)t->ti_prev);
290     remque_32((struct tcpiphdr *) t->ti_prev);
291     m_freem(m);
292     }
293     /* It's static */
294     /* if (tp->t_template)
295     * (void) m_free(dtom(tp->t_template));
296     */
297     /* free(tp, M_PCB); */
298     free(tp);
299     so->so_tcpcb = 0;
300     soisfdisconnected(so);
301     /* clobber input socket cache if we're closing the cached connection */
302     if (so == tcp_last_so)
303     tcp_last_so = &tcb;
304     closesocket(so->s);
305     sbfree(&so->so_rcv);
306     sbfree(&so->so_snd);
307     sofree(so);
308     tcpstat.tcps_closed++;
309     return ((struct tcpcb *)0);
310     }
311    
312     void
313     tcp_drain()
314     {
315     /* XXX */
316     }
317    
318     /*
319     * When a source quench is received, close congestion window
320     * to one segment. We will gradually open it again as we proceed.
321     */
322    
323     #ifdef notdef
324    
325     void
326     tcp_quench(i, errno)
327    
328     int errno;
329     {
330     struct tcpcb *tp = intotcpcb(inp);
331    
332     if (tp)
333     tp->snd_cwnd = tp->t_maxseg;
334     }
335    
336     #endif /* notdef */
337    
338     /*
339     * TCP protocol interface to socket abstraction.
340     */
341    
342     /*
343     * User issued close, and wish to trail through shutdown states:
344     * if never received SYN, just forget it. If got a SYN from peer,
345     * but haven't sent FIN, then go to FIN_WAIT_1 state to send peer a FIN.
346     * If already got a FIN from peer, then almost done; go to LAST_ACK
347     * state. In all other cases, have already sent FIN to peer (e.g.
348     * after PRU_SHUTDOWN), and just have to play tedious game waiting
349     * for peer to send FIN or not respond to keep-alives, etc.
350     * We can let the user exit from the close as soon as the FIN is acked.
351     */
352     void
353     tcp_sockclosed(tp)
354     struct tcpcb *tp;
355     {
356    
357     DEBUG_CALL("tcp_sockclosed");
358     DEBUG_ARG("tp = %lx", (long)tp);
359    
360     switch (tp->t_state) {
361    
362     case TCPS_CLOSED:
363     case TCPS_LISTEN:
364     case TCPS_SYN_SENT:
365     tp->t_state = TCPS_CLOSED;
366     tp = tcp_close(tp);
367     break;
368    
369     case TCPS_SYN_RECEIVED:
370     case TCPS_ESTABLISHED:
371     tp->t_state = TCPS_FIN_WAIT_1;
372     break;
373    
374     case TCPS_CLOSE_WAIT:
375     tp->t_state = TCPS_LAST_ACK;
376     break;
377     }
378     /* soisfdisconnecting(tp->t_socket); */
379     if (tp && tp->t_state >= TCPS_FIN_WAIT_2)
380     soisfdisconnected(tp->t_socket);
381     if (tp)
382     tcp_output(tp);
383     }
384    
385     /*
386     * Connect to a host on the Internet
387     * Called by tcp_input
388     * Only do a connect, the tcp fields will be set in tcp_input
389     * return 0 if there's a result of the connect,
390     * else return -1 means we're still connecting
391     * The return value is almost always -1 since the socket is
392     * nonblocking. Connect returns after the SYN is sent, and does
393     * not wait for ACK+SYN.
394     */
395     int tcp_fconnect(so)
396     struct socket *so;
397     {
398     int ret=0;
399    
400     DEBUG_CALL("tcp_fconnect");
401     DEBUG_ARG("so = %lx", (long )so);
402    
403     if( (ret=so->s=socket(AF_INET,SOCK_STREAM,0)) >= 0) {
404     int opt, s=so->s;
405     struct sockaddr_in addr;
406    
407     fd_nonblock(s);
408     opt = 1;
409     setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(opt ));
410     opt = 1;
411     setsockopt(s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(opt ));
412    
413     addr.sin_family = AF_INET;
414     if ((so->so_faddr.s_addr & htonl(0xffffff00)) == special_addr.s_addr) {
415     /* It's an alias */
416     switch(ntohl(so->so_faddr.s_addr) & 0xff) {
417     case CTL_DNS:
418     addr.sin_addr = dns_addr;
419     break;
420     case CTL_ALIAS:
421     default:
422     addr.sin_addr = loopback_addr;
423     break;
424     }
425     } else
426     addr.sin_addr = so->so_faddr;
427     addr.sin_port = so->so_fport;
428    
429     DEBUG_MISC((dfd, " connect()ing, addr.sin_port=%d, "
430     "addr.sin_addr.s_addr=%.16s\n",
431     ntohs(addr.sin_port), inet_ntoa(addr.sin_addr)));
432     /* We don't care what port we get */
433     ret = connect(s,(struct sockaddr *)&addr,sizeof (addr));
434    
435     /*
436     * If it's not in progress, it failed, so we just return 0,
437     * without clearing SS_NOFDREF
438     */
439     soisfconnecting(so);
440     }
441    
442     return(ret);
443     }
444    
445     /*
446     * Accept the socket and connect to the local-host
447     *
448     * We have a problem. The correct thing to do would be
449     * to first connect to the local-host, and only if the
450     * connection is accepted, then do an accept() here.
451     * But, a) we need to know who's trying to connect
452     * to the socket to be able to SYN the local-host, and
453     * b) we are already connected to the foreign host by
454     * the time it gets to accept(), so... We simply accept
455     * here and SYN the local-host.
456     */
457     void
458     tcp_connect(inso)
459     struct socket *inso;
460     {
461     struct socket *so;
462     struct sockaddr_in addr;
463 cebix 1.2 socklen_t addrlen = sizeof(struct sockaddr_in);
464 gbeauche 1.1 struct tcpcb *tp;
465     int s, opt;
466    
467     DEBUG_CALL("tcp_connect");
468     DEBUG_ARG("inso = %lx", (long)inso);
469    
470     /*
471     * If it's an SS_ACCEPTONCE socket, no need to socreate()
472     * another socket, just use the accept() socket.
473     */
474     if (inso->so_state & SS_FACCEPTONCE) {
475     /* FACCEPTONCE already have a tcpcb */
476     so = inso;
477     } else {
478     if ((so = socreate()) == NULL) {
479     /* If it failed, get rid of the pending connection */
480     closesocket(accept(inso->s,(struct sockaddr *)&addr,&addrlen));
481     return;
482     }
483     if (tcp_attach(so) < 0) {
484     free(so); /* NOT sofree */
485     return;
486     }
487     so->so_laddr = inso->so_laddr;
488     so->so_lport = inso->so_lport;
489     }
490    
491     (void) tcp_mss(sototcpcb(so), 0);
492    
493     if ((s = accept(inso->s,(struct sockaddr *)&addr,&addrlen)) < 0) {
494     tcp_close(sototcpcb(so)); /* This will sofree() as well */
495     return;
496     }
497     fd_nonblock(s);
498     opt = 1;
499     setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int));
500     opt = 1;
501     setsockopt(s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int));
502    
503     so->so_fport = addr.sin_port;
504     so->so_faddr = addr.sin_addr;
505     /* Translate connections from localhost to the real hostname */
506     if (so->so_faddr.s_addr == 0 || so->so_faddr.s_addr == loopback_addr.s_addr)
507     so->so_faddr = our_addr;
508    
509     /* Close the accept() socket, set right state */
510     if (inso->so_state & SS_FACCEPTONCE) {
511     closesocket(so->s); /* If we only accept once, close the accept() socket */
512     so->so_state = SS_NOFDREF; /* Don't select it yet, even though we have an FD */
513     /* if it's not FACCEPTONCE, it's already NOFDREF */
514     }
515     so->s = s;
516    
517     so->so_iptos = tcp_tos(so);
518     tp = sototcpcb(so);
519    
520     tcp_template(tp);
521    
522     /* Compute window scaling to request. */
523     /* while (tp->request_r_scale < TCP_MAX_WINSHIFT &&
524     * (TCP_MAXWIN << tp->request_r_scale) < so->so_rcv.sb_hiwat)
525     * tp->request_r_scale++;
526     */
527    
528     /* soisconnecting(so); */ /* NOFDREF used instead */
529     tcpstat.tcps_connattempt++;
530    
531     tp->t_state = TCPS_SYN_SENT;
532     tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT;
533     tp->iss = tcp_iss;
534     tcp_iss += TCP_ISSINCR/2;
535     tcp_sendseqinit(tp);
536     tcp_output(tp);
537     }
538    
539     /*
540     * Attach a TCPCB to a socket.
541     */
542     int
543     tcp_attach(so)
544     struct socket *so;
545     {
546     if ((so->so_tcpcb = tcp_newtcpcb(so)) == NULL)
547     return -1;
548    
549     insque(so, &tcb);
550    
551     return 0;
552     }
553    
554     /*
555     * Set the socket's type of service field
556     */
557     struct tos_t tcptos[] = {
558     {0, 20, IPTOS_THROUGHPUT, 0}, /* ftp data */
559     {21, 21, IPTOS_LOWDELAY, EMU_FTP}, /* ftp control */
560     {0, 23, IPTOS_LOWDELAY, 0}, /* telnet */
561     {0, 80, IPTOS_THROUGHPUT, 0}, /* WWW */
562     {0, 513, IPTOS_LOWDELAY, EMU_RLOGIN|EMU_NOCONNECT}, /* rlogin */
563     {0, 514, IPTOS_LOWDELAY, EMU_RSH|EMU_NOCONNECT}, /* shell */
564     {0, 544, IPTOS_LOWDELAY, EMU_KSH}, /* kshell */
565     {0, 543, IPTOS_LOWDELAY, 0}, /* klogin */
566     {0, 6667, IPTOS_THROUGHPUT, EMU_IRC}, /* IRC */
567     {0, 6668, IPTOS_THROUGHPUT, EMU_IRC}, /* IRC undernet */
568     {0, 7070, IPTOS_LOWDELAY, EMU_REALAUDIO }, /* RealAudio control */
569     {0, 113, IPTOS_LOWDELAY, EMU_IDENT }, /* identd protocol */
570     {0, 0, 0, 0}
571     };
572    
573     struct emu_t *tcpemu = 0;
574    
575     /*
576     * Return TOS according to the above table
577     */
578     u_int8_t
579     tcp_tos(so)
580     struct socket *so;
581     {
582     int i = 0;
583     struct emu_t *emup;
584    
585     while(tcptos[i].tos) {
586     if ((tcptos[i].fport && (ntohs(so->so_fport) == tcptos[i].fport)) ||
587     (tcptos[i].lport && (ntohs(so->so_lport) == tcptos[i].lport))) {
588     so->so_emu = tcptos[i].emu;
589     return tcptos[i].tos;
590     }
591     i++;
592     }
593    
594     /* Nope, lets see if there's a user-added one */
595     for (emup = tcpemu; emup; emup = emup->next) {
596     if ((emup->fport && (ntohs(so->so_fport) == emup->fport)) ||
597     (emup->lport && (ntohs(so->so_lport) == emup->lport))) {
598     so->so_emu = emup->emu;
599     return emup->tos;
600     }
601     }
602    
603     return 0;
604     }
605    
606     int do_echo = -1;
607    
608     /*
609     * Emulate programs that try and connect to us
610     * This includes ftp (the data connection is
611     * initiated by the server) and IRC (DCC CHAT and
612     * DCC SEND) for now
613     *
614     * NOTE: It's possible to crash SLiRP by sending it
615     * unstandard strings to emulate... if this is a problem,
616     * more checks are needed here
617     *
618     * XXX Assumes the whole command came in one packet
619     *
620     * XXX Some ftp clients will have their TOS set to
621     * LOWDELAY and so Nagel will kick in. Because of this,
622     * we'll get the first letter, followed by the rest, so
623     * we simply scan for ORT instead of PORT...
624     * DCC doesn't have this problem because there's other stuff
625     * in the packet before the DCC command.
626     *
627     * Return 1 if the mbuf m is still valid and should be
628     * sbappend()ed
629     *
630     * NOTE: if you return 0 you MUST m_free() the mbuf!
631     */
632     int
633     tcp_emu(so, m)
634     struct socket *so;
635     struct mbuf *m;
636     {
637     u_int n1, n2, n3, n4, n5, n6;
638     char buff[256];
639     u_int32_t laddr;
640     u_int lport;
641     char *bptr;
642    
643     DEBUG_CALL("tcp_emu");
644     DEBUG_ARG("so = %lx", (long)so);
645     DEBUG_ARG("m = %lx", (long)m);
646    
647     switch(so->so_emu) {
648     int x, i;
649    
650     case EMU_IDENT:
651     /*
652     * Identification protocol as per rfc-1413
653     */
654    
655     {
656     struct socket *tmpso;
657     struct sockaddr_in addr;
658 cebix 1.2 socklen_t addrlen = sizeof(struct sockaddr_in);
659 gbeauche 1.1 struct sbuf *so_rcv = &so->so_rcv;
660    
661     memcpy(so_rcv->sb_wptr, m->m_data, m->m_len);
662     so_rcv->sb_wptr += m->m_len;
663     so_rcv->sb_rptr += m->m_len;
664     m->m_data[m->m_len] = 0; /* NULL terminate */
665     if (strchr(m->m_data, '\r') || strchr(m->m_data, '\n')) {
666     if (sscanf(so_rcv->sb_data, "%d%*[ ,]%d", &n1, &n2) == 2) {
667     HTONS(n1);
668     HTONS(n2);
669     /* n2 is the one on our host */
670     for (tmpso = tcb.so_next; tmpso != &tcb; tmpso = tmpso->so_next) {
671     if (tmpso->so_laddr.s_addr == so->so_laddr.s_addr &&
672     tmpso->so_lport == n2 &&
673     tmpso->so_faddr.s_addr == so->so_faddr.s_addr &&
674     tmpso->so_fport == n1) {
675     if (getsockname(tmpso->s,
676     (struct sockaddr *)&addr, &addrlen) == 0)
677     n2 = ntohs(addr.sin_port);
678     break;
679     }
680     }
681     }
682     so_rcv->sb_cc = sprintf(so_rcv->sb_data, "%d,%d\r\n", n1, n2);
683     so_rcv->sb_rptr = so_rcv->sb_data;
684     so_rcv->sb_wptr = so_rcv->sb_data + so_rcv->sb_cc;
685     }
686     m_free(m);
687     return 0;
688     }
689    
690     #if 0
691     case EMU_RLOGIN:
692     /*
693     * Rlogin emulation
694     * First we accumulate all the initial option negotiation,
695     * then fork_exec() rlogin according to the options
696     */
697     {
698     int i, i2, n;
699     char *ptr;
700     char args[100];
701     char term[100];
702     struct sbuf *so_snd = &so->so_snd;
703     struct sbuf *so_rcv = &so->so_rcv;
704    
705     /* First check if they have a priveladged port, or too much data has arrived */
706     if (ntohs(so->so_lport) > 1023 || ntohs(so->so_lport) < 512 ||
707     (m->m_len + so_rcv->sb_wptr) > (so_rcv->sb_data + so_rcv->sb_datalen)) {
708     memcpy(so_snd->sb_wptr, "Permission denied\n", 18);
709     so_snd->sb_wptr += 18;
710     so_snd->sb_cc += 18;
711     tcp_sockclosed(sototcpcb(so));
712     m_free(m);
713     return 0;
714     }
715    
716     /* Append the current data */
717     memcpy(so_rcv->sb_wptr, m->m_data, m->m_len);
718     so_rcv->sb_wptr += m->m_len;
719     so_rcv->sb_rptr += m->m_len;
720     m_free(m);
721    
722     /*
723     * Check if we have all the initial options,
724     * and build argument list to rlogin while we're here
725     */
726     n = 0;
727     ptr = so_rcv->sb_data;
728     args[0] = 0;
729     term[0] = 0;
730     while (ptr < so_rcv->sb_wptr) {
731     if (*ptr++ == 0) {
732     n++;
733     if (n == 2) {
734     sprintf(args, "rlogin -l %s %s",
735     ptr, inet_ntoa(so->so_faddr));
736     } else if (n == 3) {
737     i2 = so_rcv->sb_wptr - ptr;
738     for (i = 0; i < i2; i++) {
739     if (ptr[i] == '/') {
740     ptr[i] = 0;
741     #ifdef HAVE_SETENV
742     sprintf(term, "%s", ptr);
743     #else
744     sprintf(term, "TERM=%s", ptr);
745     #endif
746     ptr[i] = '/';
747     break;
748     }
749     }
750     }
751     }
752     }
753    
754     if (n != 4)
755     return 0;
756    
757     /* We have it, set our term variable and fork_exec() */
758     #ifdef HAVE_SETENV
759     setenv("TERM", term, 1);
760     #else
761     putenv(term);
762     #endif
763     fork_exec(so, args, 2);
764     term[0] = 0;
765     so->so_emu = 0;
766    
767     /* And finally, send the client a 0 character */
768     so_snd->sb_wptr[0] = 0;
769     so_snd->sb_wptr++;
770     so_snd->sb_cc++;
771    
772     return 0;
773     }
774    
775     case EMU_RSH:
776     /*
777     * rsh emulation
778     * First we accumulate all the initial option negotiation,
779     * then rsh_exec() rsh according to the options
780     */
781     {
782     int n;
783     char *ptr;
784     char *user;
785     char *args;
786     struct sbuf *so_snd = &so->so_snd;
787     struct sbuf *so_rcv = &so->so_rcv;
788    
789     /* First check if they have a priveladged port, or too much data has arrived */
790     if (ntohs(so->so_lport) > 1023 || ntohs(so->so_lport) < 512 ||
791     (m->m_len + so_rcv->sb_wptr) > (so_rcv->sb_data + so_rcv->sb_datalen)) {
792     memcpy(so_snd->sb_wptr, "Permission denied\n", 18);
793     so_snd->sb_wptr += 18;
794     so_snd->sb_cc += 18;
795     tcp_sockclosed(sototcpcb(so));
796     m_free(m);
797     return 0;
798     }
799    
800     /* Append the current data */
801     memcpy(so_rcv->sb_wptr, m->m_data, m->m_len);
802     so_rcv->sb_wptr += m->m_len;
803     so_rcv->sb_rptr += m->m_len;
804     m_free(m);
805    
806     /*
807     * Check if we have all the initial options,
808     * and build argument list to rlogin while we're here
809     */
810     n = 0;
811     ptr = so_rcv->sb_data;
812     user="";
813     args="";
814     if (so->extra==NULL) {
815     struct socket *ns;
816     struct tcpcb* tp;
817     int port=atoi(ptr);
818     if (port <= 0) return 0;
819     if (port > 1023 || port < 512) {
820     memcpy(so_snd->sb_wptr, "Permission denied\n", 18);
821     so_snd->sb_wptr += 18;
822     so_snd->sb_cc += 18;
823     tcp_sockclosed(sototcpcb(so));
824     return 0;
825     }
826     if ((ns=socreate()) == NULL)
827     return 0;
828     if (tcp_attach(ns)<0) {
829     free(ns);
830     return 0;
831     }
832    
833     ns->so_laddr=so->so_laddr;
834     ns->so_lport=htons(port);
835    
836     (void) tcp_mss(sototcpcb(ns), 0);
837    
838     ns->so_faddr=so->so_faddr;
839     ns->so_fport=htons(IPPORT_RESERVED-1); /* Use a fake port. */
840    
841     if (ns->so_faddr.s_addr == 0 ||
842     ns->so_faddr.s_addr == loopback_addr.s_addr)
843     ns->so_faddr = our_addr;
844    
845     ns->so_iptos = tcp_tos(ns);
846     tp = sototcpcb(ns);
847    
848     tcp_template(tp);
849    
850     /* Compute window scaling to request. */
851     /* while (tp->request_r_scale < TCP_MAX_WINSHIFT &&
852     * (TCP_MAXWIN << tp->request_r_scale) < so->so_rcv.sb_hiwat)
853     * tp->request_r_scale++;
854     */
855    
856     /*soisfconnecting(ns);*/
857    
858     tcpstat.tcps_connattempt++;
859    
860     tp->t_state = TCPS_SYN_SENT;
861     tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT;
862     tp->iss = tcp_iss;
863     tcp_iss += TCP_ISSINCR/2;
864     tcp_sendseqinit(tp);
865     tcp_output(tp);
866     so->extra=ns;
867     }
868     while (ptr < so_rcv->sb_wptr) {
869     if (*ptr++ == 0) {
870     n++;
871     if (n == 2) {
872     user=ptr;
873     } else if (n == 3) {
874     args=ptr;
875     }
876     }
877     }
878    
879     if (n != 4)
880     return 0;
881    
882     rsh_exec(so,so->extra, user, inet_ntoa(so->so_faddr), args);
883     so->so_emu = 0;
884     so->extra=NULL;
885    
886     /* And finally, send the client a 0 character */
887     so_snd->sb_wptr[0] = 0;
888     so_snd->sb_wptr++;
889     so_snd->sb_cc++;
890    
891     return 0;
892     }
893    
894     case EMU_CTL:
895     {
896     int num;
897     struct sbuf *so_snd = &so->so_snd;
898     struct sbuf *so_rcv = &so->so_rcv;
899    
900     /*
901     * If there is binary data here, we save it in so->so_m
902     */
903     if (!so->so_m) {
904     int rxlen;
905     char *rxdata;
906     rxdata=mtod(m, char *);
907     for (rxlen=m->m_len; rxlen; rxlen--) {
908     if (*rxdata++ & 0x80) {
909     so->so_m = m;
910     return 0;
911     }
912     }
913     } /* if(so->so_m==NULL) */
914    
915     /*
916     * Append the line
917     */
918     sbappendsb(so_rcv, m);
919    
920     /* To avoid going over the edge of the buffer, we reset it */
921     if (so_snd->sb_cc == 0)
922     so_snd->sb_wptr = so_snd->sb_rptr = so_snd->sb_data;
923    
924     /*
925     * A bit of a hack:
926     * If the first packet we get here is 1 byte long, then it
927     * was done in telnet character mode, therefore we must echo
928     * the characters as they come. Otherwise, we echo nothing,
929     * because in linemode, the line is already echoed
930     * XXX two or more control connections won't work
931     */
932     if (do_echo == -1) {
933     if (m->m_len == 1) do_echo = 1;
934     else do_echo = 0;
935     }
936     if (do_echo) {
937     sbappendsb(so_snd, m);
938     m_free(m);
939     tcp_output(sototcpcb(so)); /* XXX */
940     } else
941     m_free(m);
942    
943     num = 0;
944     while (num < so->so_rcv.sb_cc) {
945     if (*(so->so_rcv.sb_rptr + num) == '\n' ||
946     *(so->so_rcv.sb_rptr + num) == '\r') {
947     int n;
948    
949     *(so_rcv->sb_rptr + num) = 0;
950     if (ctl_password && !ctl_password_ok) {
951     /* Need a password */
952     if (sscanf(so_rcv->sb_rptr, "pass %256s", buff) == 1) {
953     if (strcmp(buff, ctl_password) == 0) {
954     ctl_password_ok = 1;
955     n = sprintf(so_snd->sb_wptr,
956     "Password OK.\r\n");
957     goto do_prompt;
958     }
959     }
960     n = sprintf(so_snd->sb_wptr,
961     "Error: Password required, log on with \"pass PASSWORD\"\r\n");
962     goto do_prompt;
963     }
964     cfg_quitting = 0;
965     n = do_config(so_rcv->sb_rptr, so, PRN_SPRINTF);
966     if (!cfg_quitting) {
967     /* Register the printed data */
968     do_prompt:
969     so_snd->sb_cc += n;
970     so_snd->sb_wptr += n;
971     /* Add prompt */
972     n = sprintf(so_snd->sb_wptr, "Slirp> ");
973     so_snd->sb_cc += n;
974     so_snd->sb_wptr += n;
975     }
976     /* Drop so_rcv data */
977     so_rcv->sb_cc = 0;
978     so_rcv->sb_wptr = so_rcv->sb_rptr = so_rcv->sb_data;
979     tcp_output(sototcpcb(so)); /* Send the reply */
980     }
981     num++;
982     }
983     return 0;
984     }
985     #endif
986     case EMU_FTP: /* ftp */
987     *(m->m_data+m->m_len) = 0; /* NULL terminate for strstr */
988     if ((bptr = (char *)strstr(m->m_data, "ORT")) != NULL) {
989     /*
990     * Need to emulate the PORT command
991     */
992     x = sscanf(bptr, "ORT %d,%d,%d,%d,%d,%d\r\n%256[^\177]",
993     &n1, &n2, &n3, &n4, &n5, &n6, buff);
994     if (x < 6)
995     return 1;
996    
997     laddr = htonl((n1 << 24) | (n2 << 16) | (n3 << 8) | (n4));
998     lport = htons((n5 << 8) | (n6));
999    
1000     if ((so = solisten(0, laddr, lport, SS_FACCEPTONCE)) == NULL)
1001     return 1;
1002    
1003     n6 = ntohs(so->so_fport);
1004    
1005     n5 = (n6 >> 8) & 0xff;
1006     n6 &= 0xff;
1007    
1008     laddr = ntohl(so->so_faddr.s_addr);
1009    
1010     n1 = ((laddr >> 24) & 0xff);
1011     n2 = ((laddr >> 16) & 0xff);
1012     n3 = ((laddr >> 8) & 0xff);
1013     n4 = (laddr & 0xff);
1014    
1015     m->m_len = bptr - m->m_data; /* Adjust length */
1016     m->m_len += sprintf(bptr,"ORT %d,%d,%d,%d,%d,%d\r\n%s",
1017     n1, n2, n3, n4, n5, n6, x==7?buff:"");
1018     return 1;
1019     } else if ((bptr = (char *)strstr(m->m_data, "27 Entering")) != NULL) {
1020     /*
1021     * Need to emulate the PASV response
1022     */
1023     x = sscanf(bptr, "27 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n%256[^\177]",
1024     &n1, &n2, &n3, &n4, &n5, &n6, buff);
1025     if (x < 6)
1026     return 1;
1027    
1028     laddr = htonl((n1 << 24) | (n2 << 16) | (n3 << 8) | (n4));
1029     lport = htons((n5 << 8) | (n6));
1030    
1031     if ((so = solisten(0, laddr, lport, SS_FACCEPTONCE)) == NULL)
1032     return 1;
1033    
1034     n6 = ntohs(so->so_fport);
1035    
1036     n5 = (n6 >> 8) & 0xff;
1037     n6 &= 0xff;
1038    
1039     laddr = ntohl(so->so_faddr.s_addr);
1040    
1041     n1 = ((laddr >> 24) & 0xff);
1042     n2 = ((laddr >> 16) & 0xff);
1043     n3 = ((laddr >> 8) & 0xff);
1044     n4 = (laddr & 0xff);
1045    
1046     m->m_len = bptr - m->m_data; /* Adjust length */
1047     m->m_len += sprintf(bptr,"27 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n%s",
1048     n1, n2, n3, n4, n5, n6, x==7?buff:"");
1049    
1050     return 1;
1051     }
1052    
1053     return 1;
1054    
1055     case EMU_KSH:
1056     /*
1057     * The kshell (Kerberos rsh) and shell services both pass
1058     * a local port port number to carry signals to the server
1059     * and stderr to the client. It is passed at the beginning
1060     * of the connection as a NUL-terminated decimal ASCII string.
1061     */
1062     so->so_emu = 0;
1063     for (lport = 0, i = 0; i < m->m_len-1; ++i) {
1064     if (m->m_data[i] < '0' || m->m_data[i] > '9')
1065     return 1; /* invalid number */
1066     lport *= 10;
1067     lport += m->m_data[i] - '0';
1068     }
1069     if (m->m_data[m->m_len-1] == '\0' && lport != 0 &&
1070     (so = solisten(0, so->so_laddr.s_addr, htons(lport), SS_FACCEPTONCE)) != NULL)
1071     m->m_len = sprintf(m->m_data, "%d", ntohs(so->so_fport))+1;
1072     return 1;
1073    
1074     case EMU_IRC:
1075     /*
1076     * Need to emulate DCC CHAT, DCC SEND and DCC MOVE
1077     */
1078     *(m->m_data+m->m_len) = 0; /* NULL terminate the string for strstr */
1079     if ((bptr = (char *)strstr(m->m_data, "DCC")) == NULL)
1080     return 1;
1081    
1082     /* The %256s is for the broken mIRC */
1083     if (sscanf(bptr, "DCC CHAT %256s %u %u", buff, &laddr, &lport) == 3) {
1084     if ((so = solisten(0, htonl(laddr), htons(lport), SS_FACCEPTONCE)) == NULL)
1085     return 1;
1086    
1087     m->m_len = bptr - m->m_data; /* Adjust length */
1088     m->m_len += sprintf(bptr, "DCC CHAT chat %lu %u%c\n",
1089     (unsigned long)ntohl(so->so_faddr.s_addr),
1090     ntohs(so->so_fport), 1);
1091     } else if (sscanf(bptr, "DCC SEND %256s %u %u %u", buff, &laddr, &lport, &n1) == 4) {
1092     if ((so = solisten(0, htonl(laddr), htons(lport), SS_FACCEPTONCE)) == NULL)
1093     return 1;
1094    
1095     m->m_len = bptr - m->m_data; /* Adjust length */
1096     m->m_len += sprintf(bptr, "DCC SEND %s %lu %u %u%c\n",
1097     buff, (unsigned long)ntohl(so->so_faddr.s_addr),
1098     ntohs(so->so_fport), n1, 1);
1099     } else if (sscanf(bptr, "DCC MOVE %256s %u %u %u", buff, &laddr, &lport, &n1) == 4) {
1100     if ((so = solisten(0, htonl(laddr), htons(lport), SS_FACCEPTONCE)) == NULL)
1101     return 1;
1102    
1103     m->m_len = bptr - m->m_data; /* Adjust length */
1104     m->m_len += sprintf(bptr, "DCC MOVE %s %lu %u %u%c\n",
1105     buff, (unsigned long)ntohl(so->so_faddr.s_addr),
1106     ntohs(so->so_fport), n1, 1);
1107     }
1108     return 1;
1109    
1110     case EMU_REALAUDIO:
1111     /*
1112     * RealAudio emulation - JP. We must try to parse the incoming
1113     * data and try to find the two characters that contain the
1114     * port number. Then we redirect an udp port and replace the
1115     * number with the real port we got.
1116     *
1117     * The 1.0 beta versions of the player are not supported
1118     * any more.
1119     *
1120     * A typical packet for player version 1.0 (release version):
1121     *
1122     * 0000:50 4E 41 00 05
1123     * 0000:00 01 00 02 1B D7 00 00 67 E6 6C DC 63 00 12 50 .....×..gælÜc..P
1124     * 0010:4E 43 4C 49 45 4E 54 20 31 30 31 20 41 4C 50 48 NCLIENT 101 ALPH
1125     * 0020:41 6C 00 00 52 00 17 72 61 66 69 6C 65 73 2F 76 Al..R..rafiles/v
1126     * 0030:6F 61 2F 65 6E 67 6C 69 73 68 5F 2E 72 61 79 42 oa/english_.rayB
1127     *
1128     * Now the port number 0x1BD7 is found at offset 0x04 of the
1129     * Now the port number 0x1BD7 is found at offset 0x04 of the
1130     * second packet. This time we received five bytes first and
1131     * then the rest. You never know how many bytes you get.
1132     *
1133     * A typical packet for player version 2.0 (beta):
1134     *
1135     * 0000:50 4E 41 00 06 00 02 00 00 00 01 00 02 1B C1 00 PNA...........Á.
1136     * 0010:00 67 75 78 F5 63 00 0A 57 69 6E 32 2E 30 2E 30 .guxõc..Win2.0.0
1137     * 0020:2E 35 6C 00 00 52 00 1C 72 61 66 69 6C 65 73 2F .5l..R..rafiles/
1138     * 0030:77 65 62 73 69 74 65 2F 32 30 72 65 6C 65 61 73 website/20releas
1139     * 0040:65 2E 72 61 79 53 00 00 06 36 42 e.rayS...6B
1140     *
1141     * Port number 0x1BC1 is found at offset 0x0d.
1142     *
1143     * This is just a horrible switch statement. Variable ra tells
1144     * us where we're going.
1145     */
1146    
1147     bptr = m->m_data;
1148     while (bptr < m->m_data + m->m_len) {
1149     u_short p;
1150     static int ra = 0;
1151     char ra_tbl[4];
1152    
1153     ra_tbl[0] = 0x50;
1154     ra_tbl[1] = 0x4e;
1155     ra_tbl[2] = 0x41;
1156     ra_tbl[3] = 0;
1157    
1158     switch (ra) {
1159     case 0:
1160     case 2:
1161     case 3:
1162     if (*bptr++ != ra_tbl[ra]) {
1163     ra = 0;
1164     continue;
1165     }
1166     break;
1167    
1168     case 1:
1169     /*
1170     * We may get 0x50 several times, ignore them
1171     */
1172     if (*bptr == 0x50) {
1173     ra = 1;
1174     bptr++;
1175     continue;
1176     } else if (*bptr++ != ra_tbl[ra]) {
1177     ra = 0;
1178     continue;
1179     }
1180     break;
1181    
1182     case 4:
1183     /*
1184     * skip version number
1185     */
1186     bptr++;
1187     break;
1188    
1189     case 5:
1190     /*
1191     * The difference between versions 1.0 and
1192     * 2.0 is here. For future versions of
1193     * the player this may need to be modified.
1194     */
1195     if (*(bptr + 1) == 0x02)
1196     bptr += 8;
1197     else
1198     bptr += 4;
1199     break;
1200    
1201     case 6:
1202     /* This is the field containing the port
1203     * number that RA-player is listening to.
1204     */
1205     lport = (((u_char*)bptr)[0] << 8)
1206     + ((u_char *)bptr)[1];
1207     if (lport < 6970)
1208     lport += 256; /* don't know why */
1209     if (lport < 6970 || lport > 7170)
1210     return 1; /* failed */
1211    
1212     /* try to get udp port between 6970 - 7170 */
1213     for (p = 6970; p < 7071; p++) {
1214     if (udp_listen( htons(p),
1215     so->so_laddr.s_addr,
1216     htons(lport),
1217     SS_FACCEPTONCE)) {
1218     break;
1219     }
1220     }
1221     if (p == 7071)
1222     p = 0;
1223     *(u_char *)bptr++ = (p >> 8) & 0xff;
1224     *(u_char *)bptr++ = p & 0xff;
1225     ra = 0;
1226     return 1; /* port redirected, we're done */
1227     break;
1228    
1229     default:
1230     ra = 0;
1231     }
1232     ra++;
1233     }
1234     return 1;
1235    
1236     default:
1237     /* Ooops, not emulated, won't call tcp_emu again */
1238     so->so_emu = 0;
1239     return 1;
1240     }
1241     }
1242    
1243     /*
1244     * Do misc. config of SLiRP while its running.
1245     * Return 0 if this connections is to be closed, 1 otherwise,
1246     * return 2 if this is a command-line connection
1247     */
1248     int
1249     tcp_ctl(so)
1250     struct socket *so;
1251     {
1252     struct sbuf *sb = &so->so_snd;
1253     int command;
1254     struct ex_list *ex_ptr;
1255     int do_pty;
1256     // struct socket *tmpso;
1257    
1258     DEBUG_CALL("tcp_ctl");
1259     DEBUG_ARG("so = %lx", (long )so);
1260    
1261     #if 0
1262     /*
1263     * Check if they're authorised
1264     */
1265     if (ctl_addr.s_addr && (ctl_addr.s_addr == -1 || (so->so_laddr.s_addr != ctl_addr.s_addr))) {
1266     sb->sb_cc = sprintf(sb->sb_wptr,"Error: Permission denied.\r\n");
1267     sb->sb_wptr += sb->sb_cc;
1268     return 0;
1269     }
1270     #endif
1271     command = (ntohl(so->so_faddr.s_addr) & 0xff);
1272    
1273     switch(command) {
1274     default: /* Check for exec's */
1275    
1276     /*
1277     * Check if it's pty_exec
1278     */
1279     for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
1280     if (ex_ptr->ex_fport == so->so_fport &&
1281     command == ex_ptr->ex_addr) {
1282     do_pty = ex_ptr->ex_pty;
1283     goto do_exec;
1284     }
1285     }
1286    
1287     /*
1288     * Nothing bound..
1289     */
1290     /* tcp_fconnect(so); */
1291    
1292     /* FALLTHROUGH */
1293     case CTL_ALIAS:
1294     sb->sb_cc = sprintf(sb->sb_wptr,
1295     "Error: No application configured.\r\n");
1296     sb->sb_wptr += sb->sb_cc;
1297     return(0);
1298    
1299     do_exec:
1300     DEBUG_MISC((dfd, " executing %s \n",ex_ptr->ex_exec));
1301     return(fork_exec(so, ex_ptr->ex_exec, do_pty));
1302    
1303     #if 0
1304     case CTL_CMD:
1305     for (tmpso = tcb.so_next; tmpso != &tcb; tmpso = tmpso->so_next) {
1306     if (tmpso->so_emu == EMU_CTL &&
1307     !(tmpso->so_tcpcb?
1308     (tmpso->so_tcpcb->t_state & (TCPS_TIME_WAIT|TCPS_LAST_ACK))
1309     :0)) {
1310     /* Ooops, control connection already active */
1311     sb->sb_cc = sprintf(sb->sb_wptr,"Sorry, already connected.\r\n");
1312     sb->sb_wptr += sb->sb_cc;
1313     return 0;
1314     }
1315     }
1316     so->so_emu = EMU_CTL;
1317     ctl_password_ok = 0;
1318     sb->sb_cc = sprintf(sb->sb_wptr, "Slirp command-line ready (type \"help\" for help).\r\nSlirp> ");
1319     sb->sb_wptr += sb->sb_cc;
1320     do_echo=-1;
1321     return(2);
1322     #endif
1323     }
1324     }