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