ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/slirp/tcp_subr.c
Revision: 1.6
Committed: 2012-03-30T01:10:28Z (12 years, 7 months ago) by asvitkine
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 1.5: +1 -5 lines
Log Message:
Switch slirp to 3-clause BSD license. This change went in upstream to QEMU's
version of slirp (where this code comes from), with the following checkin:

commit 2f5f89963186d42a7ded253bc6cf5b32abb45cec
Author: aliguori <aliguori@c046a42c-6fe2-441c-8c8c-71466251a162>
Date:   Mon Jan 26 19:37:41 2009 +0000

    Remove the advertising clause from the slirp license

    According to the FSF, the 4-clause BSD license, which slirp is covered under,
    is not compatible with the GPL or LGPL[1].

    [1] http://www.fsf.org/licensing/licenses/index_html#GPLIncompatibleLicenses

    There are three declared copyright holders in slirp that use the 4-clause
    BSD license, the Regents of UC Berkley, Danny Gasparovski, and Kelly Price.
    Below are the appropriate permissions to remove the advertise clause from slirp
    from each party.

    Special thanks go to Richard Fontana from Red Hat for contacting all of the
    necessary authors to resolve this issue!

    Regents of UC Berkley:
    From ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change

    July 22, 1999

    To All Licensees, Distributors of Any Version of BSD:

    As you know, certain of the Berkeley Software Distribution ("BSD") source
    code files require that further distributions of products containing all or
    portions of the software, acknowledge within their advertising materials
    that such products contain software developed by UC Berkeley and its
    contributors.

    Specifically, the provision reads:

    "     * 3. All advertising materials mentioning features or use of this software
          *    must display the following acknowledgement:
          *    This product includes software developed by the University of
          *    California, Berkeley and its contributors."

    Effective immediately, licensees and distributors are no longer required to
    include the acknowledgement within advertising materials.  Accordingly, the
    foregoing paragraph of those BSD Unix files containing it is hereby deleted
    in its entirety.

    William Hoskins
    Director, Office of Technology Licensing
    University of California, Berkeley

    Danny Gasparovski:

    Subject: RE: Slirp license
    Date: Thu, 8 Jan 2009 10:51:00 +1100
    From: "Gasparovski, Daniel" <Daniel.Gasparovski@ato.gov.au>
    To: "Richard Fontana" <rfontana@redhat.com>

    Hi Richard,

    I have no objection to having Slirp code in QEMU be licensed under the
    3-clause BSD license.

    Thanks for taking the effort to consult me about this.


    Dan ...

    Kelly Price:

    Date: Thu, 8 Jan 2009 19:38:56 -0500
    From: "Kelly Price" <strredwolf@gmail.com>
    To: "Richard Fontana" <rfontana@redhat.com>
    Subject: Re: Slirp license

    Thanks for contacting me, Richard.  I'm glad you were able to find
    Dan, as I've been "keeping the light on" for Slirp.  I have no use for
    it now, and I have little time for it (now holding onto Keenspot's
    Comic Genesis and having a regular US state government position). If
    Dan would like to return to the project, I'd love to give it back to
    him.

    As for copyright, I don't own all of it.  Dan does, so I will defer to
    him.  Any of my patches I will gladly license to the 3-part BSD
    license.  My interest in re-licensing was because we didn't have ready
    info to contact Dan.  If Dan would like to port Slirp back out of
    QEMU, a lot of us 64-bit users would be grateful.

    Feel free to share this email address with Dan.  I will be glad to
    effect a transfer of the project to him and Mr. Bellard of the QEMU
    project.

    Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>


    git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6451 c046a42c-6fe2-441c-8c8c-71466251a162

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