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, 2 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

# Content
1 /*
2 * Copyright (c) 1982, 1986, 1988, 1990, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * @(#)tcp_subr.c 8.1 (Berkeley) 6/10/93
30 * tcp_subr.c,v 1.5 1994/10/08 22:39:58 phk Exp
31 */
32
33 /*
34 * Changes and additions relating to SLiRP
35 * Copyright (c) 1995 Danny Gasparovski.
36 *
37 * Please read the file COPYRIGHT for the
38 * terms and conditions of the copyright.
39 */
40
41 #define WANT_SYS_IOCTL_H
42 #include <stdlib.h>
43 #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 socklen_t addrlen = sizeof(struct sockaddr_in);
461 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 opt = 1;
500 setsockopt(s,IPPROTO_TCP,TCP_NODELAY,(char *)&opt,sizeof(int));
501
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 so->so_faddr = alias_addr;
507
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 socklen_t addrlen = sizeof(struct sockaddr_in);
658 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 ns->so_faddr = alias_addr;
843
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 }