Annotation of qemu/slirp/tcp_subr.c, revision 1.1.1.7
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: #include <slirp.h>
42:
43: /* patchable/settable parameters for tcp */
1.1.1.4 root 44: /* Don't do rfc1323 performance enhancements */
45: #define TCP_DO_RFC1323 0
1.1 root 46:
47: /*
48: * Tcp initialization
49: */
50: void
1.1.1.6 root 51: tcp_init(Slirp *slirp)
1.1 root 52: {
1.1.1.6 root 53: slirp->tcp_iss = 1; /* wrong */
54: slirp->tcb.so_next = slirp->tcb.so_prev = &slirp->tcb;
55: slirp->tcp_last_so = &slirp->tcb;
1.1 root 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: void
1.1.1.6 root 65: tcp_template(struct tcpcb *tp)
1.1 root 66: {
67: struct socket *so = tp->t_socket;
68: register struct tcpiphdr *n = &tp->t_template;
69:
1.1.1.5 root 70: n->ti_mbuf = NULL;
1.1 root 71: n->ti_x1 = 0;
72: n->ti_pr = IPPROTO_TCP;
73: n->ti_len = htons(sizeof (struct tcpiphdr) - sizeof (struct ip));
74: n->ti_src = so->so_faddr;
75: n->ti_dst = so->so_laddr;
76: n->ti_sport = so->so_fport;
77: n->ti_dport = so->so_lport;
1.1.1.4 root 78:
1.1 root 79: n->ti_seq = 0;
80: n->ti_ack = 0;
81: n->ti_x2 = 0;
82: n->ti_off = 5;
83: n->ti_flags = 0;
84: n->ti_win = 0;
85: n->ti_sum = 0;
86: n->ti_urp = 0;
87: }
88:
89: /*
90: * Send a single message to the TCP at address specified by
91: * the given TCP/IP header. If m == 0, then we make a copy
92: * of the tcpiphdr at ti and send directly to the addressed host.
93: * This is used to force keep alive messages out using the TCP
94: * template for a connection tp->t_template. If flags are given
95: * then we send a message back to the TCP which originated the
96: * segment ti, and discard the mbuf containing it and any other
97: * attached mbufs.
98: *
99: * In any case the ack and sequence number of the transmitted
100: * segment are as specified by the parameters.
101: */
102: void
1.1.1.6 root 103: tcp_respond(struct tcpcb *tp, struct tcpiphdr *ti, struct mbuf *m,
104: tcp_seq ack, tcp_seq seq, int flags)
1.1 root 105: {
106: register int tlen;
107: int win = 0;
108:
109: DEBUG_CALL("tcp_respond");
110: DEBUG_ARG("tp = %lx", (long)tp);
111: DEBUG_ARG("ti = %lx", (long)ti);
112: DEBUG_ARG("m = %lx", (long)m);
113: DEBUG_ARG("ack = %u", ack);
114: DEBUG_ARG("seq = %u", seq);
115: DEBUG_ARG("flags = %x", flags);
1.1.1.4 root 116:
1.1 root 117: if (tp)
118: win = sbspace(&tp->t_socket->so_rcv);
1.1.1.6 root 119: if (m == NULL) {
120: if ((m = m_get(tp->t_socket->slirp)) == NULL)
1.1 root 121: return;
122: tlen = 0;
1.1.1.4 root 123: m->m_data += IF_MAXLINKHDR;
1.1 root 124: *mtod(m, struct tcpiphdr *) = *ti;
125: ti = mtod(m, struct tcpiphdr *);
126: flags = TH_ACK;
127: } else {
1.1.1.4 root 128: /*
1.1 root 129: * ti points into m so the next line is just making
130: * the mbuf point to ti
131: */
132: m->m_data = (caddr_t)ti;
1.1.1.4 root 133:
1.1 root 134: m->m_len = sizeof (struct tcpiphdr);
135: tlen = 0;
136: #define xchg(a,b,type) { type t; t=a; a=b; b=t; }
137: xchg(ti->ti_dst.s_addr, ti->ti_src.s_addr, u_int32_t);
138: xchg(ti->ti_dport, ti->ti_sport, u_int16_t);
139: #undef xchg
140: }
141: ti->ti_len = htons((u_short)(sizeof (struct tcphdr) + tlen));
142: tlen += sizeof (struct tcpiphdr);
143: m->m_len = tlen;
144:
1.1.1.6 root 145: ti->ti_mbuf = NULL;
1.1 root 146: ti->ti_x1 = 0;
147: ti->ti_seq = htonl(seq);
148: ti->ti_ack = htonl(ack);
149: ti->ti_x2 = 0;
150: ti->ti_off = sizeof (struct tcphdr) >> 2;
151: ti->ti_flags = flags;
152: if (tp)
153: ti->ti_win = htons((u_int16_t) (win >> tp->rcv_scale));
154: else
155: ti->ti_win = htons((u_int16_t)win);
156: ti->ti_urp = 0;
157: ti->ti_sum = 0;
158: ti->ti_sum = cksum(m, tlen);
159: ((struct ip *)ti)->ip_len = tlen;
160:
1.1.1.4 root 161: if(flags & TH_RST)
1.1 root 162: ((struct ip *)ti)->ip_ttl = MAXTTL;
1.1.1.4 root 163: else
164: ((struct ip *)ti)->ip_ttl = IPDEFTTL;
165:
1.1 root 166: (void) ip_output((struct socket *)0, m);
167: }
168:
169: /*
170: * Create a new TCP control block, making an
171: * empty reassembly queue and hooking it to the argument
172: * protocol control block.
173: */
174: struct tcpcb *
1.1.1.6 root 175: tcp_newtcpcb(struct socket *so)
1.1 root 176: {
177: register struct tcpcb *tp;
1.1.1.4 root 178:
1.1 root 179: tp = (struct tcpcb *)malloc(sizeof(*tp));
180: if (tp == NULL)
181: return ((struct tcpcb *)0);
1.1.1.4 root 182:
1.1 root 183: memset((char *) tp, 0, sizeof(struct tcpcb));
1.1.1.5 root 184: tp->seg_next = tp->seg_prev = (struct tcpiphdr*)tp;
1.1.1.4 root 185: tp->t_maxseg = TCP_MSS;
186:
187: tp->t_flags = TCP_DO_RFC1323 ? (TF_REQ_SCALE|TF_REQ_TSTMP) : 0;
1.1 root 188: tp->t_socket = so;
1.1.1.4 root 189:
1.1 root 190: /*
191: * Init srtt to TCPTV_SRTTBASE (0), so we can tell that we have no
192: * rtt estimate. Set rttvar so that srtt + 2 * rttvar gives
193: * reasonable initial retransmit time.
194: */
195: tp->t_srtt = TCPTV_SRTTBASE;
1.1.1.4 root 196: tp->t_rttvar = TCPTV_SRTTDFLT << 2;
1.1 root 197: tp->t_rttmin = TCPTV_MIN;
198:
1.1.1.4 root 199: TCPT_RANGESET(tp->t_rxtcur,
1.1 root 200: ((TCPTV_SRTTBASE >> 2) + (TCPTV_SRTTDFLT << 2)) >> 1,
201: TCPTV_MIN, TCPTV_REXMTMAX);
202:
203: tp->snd_cwnd = TCP_MAXWIN << TCP_MAX_WINSHIFT;
204: tp->snd_ssthresh = TCP_MAXWIN << TCP_MAX_WINSHIFT;
205: tp->t_state = TCPS_CLOSED;
1.1.1.4 root 206:
1.1 root 207: so->so_tcpcb = tp;
208:
209: return (tp);
210: }
211:
212: /*
213: * Drop a TCP connection, reporting
214: * the specified error. If connection is synchronized,
215: * then send a RST to peer.
216: */
1.1.1.4 root 217: struct tcpcb *tcp_drop(struct tcpcb *tp, int err)
1.1 root 218: {
219: DEBUG_CALL("tcp_drop");
220: DEBUG_ARG("tp = %lx", (long)tp);
221: DEBUG_ARG("errno = %d", errno);
1.1.1.4 root 222:
1.1 root 223: if (TCPS_HAVERCVDSYN(tp->t_state)) {
224: tp->t_state = TCPS_CLOSED;
225: (void) tcp_output(tp);
1.1.1.6 root 226: }
1.1 root 227: return (tcp_close(tp));
228: }
229:
230: /*
231: * Close a TCP control block:
232: * discard all space held by the tcp
233: * discard internet protocol block
234: * wake up any sleepers
235: */
236: struct tcpcb *
1.1.1.6 root 237: tcp_close(struct tcpcb *tp)
1.1 root 238: {
239: register struct tcpiphdr *t;
240: struct socket *so = tp->t_socket;
1.1.1.6 root 241: Slirp *slirp = so->slirp;
1.1 root 242: register struct mbuf *m;
243:
244: DEBUG_CALL("tcp_close");
245: DEBUG_ARG("tp = %lx", (long )tp);
1.1.1.4 root 246:
1.1 root 247: /* free the reassembly queue, if any */
1.1.1.5 root 248: t = tcpfrag_list_first(tp);
249: while (!tcpfrag_list_end(t, tp)) {
250: t = tcpiphdr_next(t);
251: m = tcpiphdr_prev(t)->ti_mbuf;
252: remque(tcpiphdr2qlink(tcpiphdr_prev(t)));
1.1 root 253: m_freem(m);
254: }
255: free(tp);
1.1.1.6 root 256: so->so_tcpcb = NULL;
1.1 root 257: /* clobber input socket cache if we're closing the cached connection */
1.1.1.6 root 258: if (so == slirp->tcp_last_so)
259: slirp->tcp_last_so = &slirp->tcb;
1.1 root 260: closesocket(so->s);
261: sbfree(&so->so_rcv);
262: sbfree(&so->so_snd);
263: sofree(so);
264: return ((struct tcpcb *)0);
265: }
266:
267: /*
268: * TCP protocol interface to socket abstraction.
269: */
270:
271: /*
272: * User issued close, and wish to trail through shutdown states:
273: * if never received SYN, just forget it. If got a SYN from peer,
274: * but haven't sent FIN, then go to FIN_WAIT_1 state to send peer a FIN.
275: * If already got a FIN from peer, then almost done; go to LAST_ACK
276: * state. In all other cases, have already sent FIN to peer (e.g.
277: * after PRU_SHUTDOWN), and just have to play tedious game waiting
278: * for peer to send FIN or not respond to keep-alives, etc.
279: * We can let the user exit from the close as soon as the FIN is acked.
280: */
281: void
1.1.1.6 root 282: tcp_sockclosed(struct tcpcb *tp)
1.1 root 283: {
284:
285: DEBUG_CALL("tcp_sockclosed");
286: DEBUG_ARG("tp = %lx", (long)tp);
1.1.1.4 root 287:
1.1 root 288: switch (tp->t_state) {
289:
290: case TCPS_CLOSED:
291: case TCPS_LISTEN:
292: case TCPS_SYN_SENT:
293: tp->t_state = TCPS_CLOSED;
294: tp = tcp_close(tp);
295: break;
296:
297: case TCPS_SYN_RECEIVED:
298: case TCPS_ESTABLISHED:
299: tp->t_state = TCPS_FIN_WAIT_1;
300: break;
301:
302: case TCPS_CLOSE_WAIT:
303: tp->t_state = TCPS_LAST_ACK;
304: break;
305: }
306: if (tp)
307: tcp_output(tp);
308: }
309:
1.1.1.4 root 310: /*
1.1 root 311: * Connect to a host on the Internet
312: * Called by tcp_input
313: * Only do a connect, the tcp fields will be set in tcp_input
314: * return 0 if there's a result of the connect,
315: * else return -1 means we're still connecting
316: * The return value is almost always -1 since the socket is
1.1.1.4 root 317: * nonblocking. Connect returns after the SYN is sent, and does
1.1 root 318: * not wait for ACK+SYN.
319: */
1.1.1.6 root 320: int tcp_fconnect(struct socket *so)
1.1 root 321: {
1.1.1.6 root 322: Slirp *slirp = so->slirp;
1.1 root 323: int ret=0;
1.1.1.4 root 324:
1.1 root 325: DEBUG_CALL("tcp_fconnect");
326: DEBUG_ARG("so = %lx", (long )so);
327:
1.1.1.7 ! root 328: if( (ret = so->s = qemu_socket(AF_INET,SOCK_STREAM,0)) >= 0) {
1.1 root 329: int opt, s=so->s;
330: struct sockaddr_in addr;
331:
332: fd_nonblock(s);
333: opt = 1;
334: setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(opt ));
335: opt = 1;
336: setsockopt(s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(opt ));
1.1.1.4 root 337:
1.1 root 338: addr.sin_family = AF_INET;
1.1.1.6 root 339: if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) ==
340: slirp->vnetwork_addr.s_addr) {
1.1 root 341: /* It's an alias */
1.1.1.6 root 342: if (so->so_faddr.s_addr == slirp->vnameserver_addr.s_addr) {
1.1.1.7 ! root 343: if (get_dns_addr(&addr.sin_addr) < 0)
! 344: addr.sin_addr = loopback_addr;
1.1.1.6 root 345: } else {
1.1 root 346: addr.sin_addr = loopback_addr;
347: }
348: } else
349: addr.sin_addr = so->so_faddr;
350: addr.sin_port = so->so_fport;
1.1.1.4 root 351:
1.1 root 352: DEBUG_MISC((dfd, " connect()ing, addr.sin_port=%d, "
1.1.1.4 root 353: "addr.sin_addr.s_addr=%.16s\n",
1.1 root 354: ntohs(addr.sin_port), inet_ntoa(addr.sin_addr)));
355: /* We don't care what port we get */
356: ret = connect(s,(struct sockaddr *)&addr,sizeof (addr));
1.1.1.4 root 357:
1.1 root 358: /*
359: * If it's not in progress, it failed, so we just return 0,
360: * without clearing SS_NOFDREF
361: */
362: soisfconnecting(so);
363: }
364:
365: return(ret);
366: }
367:
368: /*
369: * Accept the socket and connect to the local-host
1.1.1.4 root 370: *
1.1 root 371: * We have a problem. The correct thing to do would be
372: * to first connect to the local-host, and only if the
373: * connection is accepted, then do an accept() here.
1.1.1.4 root 374: * But, a) we need to know who's trying to connect
1.1 root 375: * to the socket to be able to SYN the local-host, and
376: * b) we are already connected to the foreign host by
377: * the time it gets to accept(), so... We simply accept
378: * here and SYN the local-host.
1.1.1.4 root 379: */
1.1 root 380: void
1.1.1.6 root 381: tcp_connect(struct socket *inso)
1.1 root 382: {
1.1.1.6 root 383: Slirp *slirp = inso->slirp;
1.1 root 384: struct socket *so;
385: struct sockaddr_in addr;
1.1.1.5 root 386: socklen_t addrlen = sizeof(struct sockaddr_in);
1.1 root 387: struct tcpcb *tp;
388: int s, opt;
389:
390: DEBUG_CALL("tcp_connect");
391: DEBUG_ARG("inso = %lx", (long)inso);
1.1.1.4 root 392:
1.1 root 393: /*
394: * If it's an SS_ACCEPTONCE socket, no need to socreate()
395: * another socket, just use the accept() socket.
396: */
397: if (inso->so_state & SS_FACCEPTONCE) {
398: /* FACCEPTONCE already have a tcpcb */
399: so = inso;
400: } else {
1.1.1.6 root 401: if ((so = socreate(slirp)) == NULL) {
1.1 root 402: /* If it failed, get rid of the pending connection */
403: closesocket(accept(inso->s,(struct sockaddr *)&addr,&addrlen));
404: return;
405: }
406: if (tcp_attach(so) < 0) {
407: free(so); /* NOT sofree */
408: return;
409: }
410: so->so_laddr = inso->so_laddr;
411: so->so_lport = inso->so_lport;
412: }
1.1.1.4 root 413:
1.1 root 414: (void) tcp_mss(sototcpcb(so), 0);
415:
416: if ((s = accept(inso->s,(struct sockaddr *)&addr,&addrlen)) < 0) {
417: tcp_close(sototcpcb(so)); /* This will sofree() as well */
418: return;
419: }
420: fd_nonblock(s);
421: opt = 1;
422: setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int));
423: opt = 1;
424: setsockopt(s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int));
1.1.1.3 root 425: opt = 1;
426: setsockopt(s,IPPROTO_TCP,TCP_NODELAY,(char *)&opt,sizeof(int));
1.1.1.4 root 427:
1.1 root 428: so->so_fport = addr.sin_port;
429: so->so_faddr = addr.sin_addr;
430: /* Translate connections from localhost to the real hostname */
431: if (so->so_faddr.s_addr == 0 || so->so_faddr.s_addr == loopback_addr.s_addr)
1.1.1.6 root 432: so->so_faddr = slirp->vhost_addr;
1.1.1.4 root 433:
1.1 root 434: /* Close the accept() socket, set right state */
435: if (inso->so_state & SS_FACCEPTONCE) {
436: closesocket(so->s); /* If we only accept once, close the accept() socket */
437: so->so_state = SS_NOFDREF; /* Don't select it yet, even though we have an FD */
438: /* if it's not FACCEPTONCE, it's already NOFDREF */
439: }
440: so->s = s;
1.1.1.6 root 441: so->so_state |= SS_INCOMING;
1.1.1.4 root 442:
1.1 root 443: so->so_iptos = tcp_tos(so);
444: tp = sototcpcb(so);
445:
446: tcp_template(tp);
1.1.1.4 root 447:
1.1 root 448: tp->t_state = TCPS_SYN_SENT;
449: tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT;
1.1.1.6 root 450: tp->iss = slirp->tcp_iss;
451: slirp->tcp_iss += TCP_ISSINCR/2;
1.1 root 452: tcp_sendseqinit(tp);
453: tcp_output(tp);
454: }
455:
456: /*
457: * Attach a TCPCB to a socket.
458: */
459: int
1.1.1.6 root 460: tcp_attach(struct socket *so)
1.1 root 461: {
462: if ((so->so_tcpcb = tcp_newtcpcb(so)) == NULL)
463: return -1;
1.1.1.4 root 464:
1.1.1.6 root 465: insque(so, &so->slirp->tcb);
1.1 root 466:
467: return 0;
468: }
469:
470: /*
471: * Set the socket's type of service field
472: */
1.1.1.4 root 473: static const struct tos_t tcptos[] = {
1.1 root 474: {0, 20, IPTOS_THROUGHPUT, 0}, /* ftp data */
475: {21, 21, IPTOS_LOWDELAY, EMU_FTP}, /* ftp control */
476: {0, 23, IPTOS_LOWDELAY, 0}, /* telnet */
477: {0, 80, IPTOS_THROUGHPUT, 0}, /* WWW */
478: {0, 513, IPTOS_LOWDELAY, EMU_RLOGIN|EMU_NOCONNECT}, /* rlogin */
479: {0, 514, IPTOS_LOWDELAY, EMU_RSH|EMU_NOCONNECT}, /* shell */
480: {0, 544, IPTOS_LOWDELAY, EMU_KSH}, /* kshell */
481: {0, 543, IPTOS_LOWDELAY, 0}, /* klogin */
482: {0, 6667, IPTOS_THROUGHPUT, EMU_IRC}, /* IRC */
483: {0, 6668, IPTOS_THROUGHPUT, EMU_IRC}, /* IRC undernet */
484: {0, 7070, IPTOS_LOWDELAY, EMU_REALAUDIO }, /* RealAudio control */
485: {0, 113, IPTOS_LOWDELAY, EMU_IDENT }, /* identd protocol */
486: {0, 0, 0, 0}
487: };
488:
1.1.1.6 root 489: static struct emu_t *tcpemu = NULL;
1.1.1.4 root 490:
1.1 root 491: /*
492: * Return TOS according to the above table
493: */
494: u_int8_t
1.1.1.6 root 495: tcp_tos(struct socket *so)
1.1 root 496: {
497: int i = 0;
498: struct emu_t *emup;
1.1.1.4 root 499:
1.1 root 500: while(tcptos[i].tos) {
501: if ((tcptos[i].fport && (ntohs(so->so_fport) == tcptos[i].fport)) ||
502: (tcptos[i].lport && (ntohs(so->so_lport) == tcptos[i].lport))) {
503: so->so_emu = tcptos[i].emu;
504: return tcptos[i].tos;
505: }
506: i++;
507: }
1.1.1.4 root 508:
1.1 root 509: /* Nope, lets see if there's a user-added one */
510: for (emup = tcpemu; emup; emup = emup->next) {
511: if ((emup->fport && (ntohs(so->so_fport) == emup->fport)) ||
512: (emup->lport && (ntohs(so->so_lport) == emup->lport))) {
513: so->so_emu = emup->emu;
514: return emup->tos;
515: }
516: }
1.1.1.4 root 517:
1.1 root 518: return 0;
519: }
520:
521: /*
522: * Emulate programs that try and connect to us
523: * This includes ftp (the data connection is
524: * initiated by the server) and IRC (DCC CHAT and
525: * DCC SEND) for now
1.1.1.4 root 526: *
1.1 root 527: * NOTE: It's possible to crash SLiRP by sending it
528: * unstandard strings to emulate... if this is a problem,
529: * more checks are needed here
530: *
531: * XXX Assumes the whole command came in one packet
1.1.1.4 root 532: *
1.1 root 533: * XXX Some ftp clients will have their TOS set to
534: * LOWDELAY and so Nagel will kick in. Because of this,
535: * we'll get the first letter, followed by the rest, so
536: * we simply scan for ORT instead of PORT...
537: * DCC doesn't have this problem because there's other stuff
538: * in the packet before the DCC command.
1.1.1.4 root 539: *
540: * Return 1 if the mbuf m is still valid and should be
1.1 root 541: * sbappend()ed
1.1.1.4 root 542: *
1.1 root 543: * NOTE: if you return 0 you MUST m_free() the mbuf!
544: */
545: int
1.1.1.6 root 546: tcp_emu(struct socket *so, struct mbuf *m)
1.1 root 547: {
1.1.1.6 root 548: Slirp *slirp = so->slirp;
1.1 root 549: u_int n1, n2, n3, n4, n5, n6;
1.1.1.5 root 550: char buff[257];
1.1 root 551: u_int32_t laddr;
552: u_int lport;
553: char *bptr;
1.1.1.4 root 554:
1.1 root 555: DEBUG_CALL("tcp_emu");
556: DEBUG_ARG("so = %lx", (long)so);
557: DEBUG_ARG("m = %lx", (long)m);
1.1.1.4 root 558:
1.1 root 559: switch(so->so_emu) {
560: int x, i;
1.1.1.4 root 561:
1.1 root 562: case EMU_IDENT:
563: /*
564: * Identification protocol as per rfc-1413
565: */
1.1.1.4 root 566:
1.1 root 567: {
568: struct socket *tmpso;
569: struct sockaddr_in addr;
1.1.1.5 root 570: socklen_t addrlen = sizeof(struct sockaddr_in);
1.1 root 571: struct sbuf *so_rcv = &so->so_rcv;
1.1.1.4 root 572:
1.1 root 573: memcpy(so_rcv->sb_wptr, m->m_data, m->m_len);
574: so_rcv->sb_wptr += m->m_len;
575: so_rcv->sb_rptr += m->m_len;
576: m->m_data[m->m_len] = 0; /* NULL terminate */
577: if (strchr(m->m_data, '\r') || strchr(m->m_data, '\n')) {
1.1.1.4 root 578: if (sscanf(so_rcv->sb_data, "%u%*[ ,]%u", &n1, &n2) == 2) {
1.1 root 579: HTONS(n1);
580: HTONS(n2);
581: /* n2 is the one on our host */
1.1.1.6 root 582: for (tmpso = slirp->tcb.so_next;
583: tmpso != &slirp->tcb;
584: tmpso = tmpso->so_next) {
1.1 root 585: if (tmpso->so_laddr.s_addr == so->so_laddr.s_addr &&
586: tmpso->so_lport == n2 &&
587: tmpso->so_faddr.s_addr == so->so_faddr.s_addr &&
588: tmpso->so_fport == n1) {
589: if (getsockname(tmpso->s,
590: (struct sockaddr *)&addr, &addrlen) == 0)
591: n2 = ntohs(addr.sin_port);
592: break;
593: }
594: }
595: }
1.1.1.5 root 596: so_rcv->sb_cc = snprintf(so_rcv->sb_data,
597: so_rcv->sb_datalen,
598: "%d,%d\r\n", n1, n2);
1.1 root 599: so_rcv->sb_rptr = so_rcv->sb_data;
600: so_rcv->sb_wptr = so_rcv->sb_data + so_rcv->sb_cc;
601: }
602: m_free(m);
603: return 0;
604: }
1.1.1.4 root 605:
1.1 root 606: case EMU_FTP: /* ftp */
1.1.1.6 root 607: *(m->m_data+m->m_len) = 0; /* NUL terminate for strstr */
1.1 root 608: if ((bptr = (char *)strstr(m->m_data, "ORT")) != NULL) {
609: /*
610: * Need to emulate the PORT command
1.1.1.4 root 611: */
612: x = sscanf(bptr, "ORT %u,%u,%u,%u,%u,%u\r\n%256[^\177]",
1.1 root 613: &n1, &n2, &n3, &n4, &n5, &n6, buff);
614: if (x < 6)
615: return 1;
1.1.1.4 root 616:
1.1 root 617: laddr = htonl((n1 << 24) | (n2 << 16) | (n3 << 8) | (n4));
618: lport = htons((n5 << 8) | (n6));
1.1.1.4 root 619:
1.1.1.6 root 620: if ((so = tcp_listen(slirp, INADDR_ANY, 0, laddr,
621: lport, SS_FACCEPTONCE)) == NULL) {
1.1 root 622: return 1;
1.1.1.6 root 623: }
1.1 root 624: n6 = ntohs(so->so_fport);
1.1.1.4 root 625:
1.1 root 626: n5 = (n6 >> 8) & 0xff;
627: n6 &= 0xff;
1.1.1.4 root 628:
1.1 root 629: laddr = ntohl(so->so_faddr.s_addr);
1.1.1.4 root 630:
1.1 root 631: n1 = ((laddr >> 24) & 0xff);
632: n2 = ((laddr >> 16) & 0xff);
633: n3 = ((laddr >> 8) & 0xff);
634: n4 = (laddr & 0xff);
1.1.1.4 root 635:
1.1 root 636: m->m_len = bptr - m->m_data; /* Adjust length */
1.1.1.5 root 637: m->m_len += snprintf(bptr, m->m_hdr.mh_size - m->m_len,
638: "ORT %d,%d,%d,%d,%d,%d\r\n%s",
639: n1, n2, n3, n4, n5, n6, x==7?buff:"");
1.1 root 640: return 1;
641: } else if ((bptr = (char *)strstr(m->m_data, "27 Entering")) != NULL) {
642: /*
643: * Need to emulate the PASV response
644: */
1.1.1.4 root 645: x = sscanf(bptr, "27 Entering Passive Mode (%u,%u,%u,%u,%u,%u)\r\n%256[^\177]",
1.1 root 646: &n1, &n2, &n3, &n4, &n5, &n6, buff);
647: if (x < 6)
648: return 1;
1.1.1.4 root 649:
1.1 root 650: laddr = htonl((n1 << 24) | (n2 << 16) | (n3 << 8) | (n4));
651: lport = htons((n5 << 8) | (n6));
1.1.1.4 root 652:
1.1.1.6 root 653: if ((so = tcp_listen(slirp, INADDR_ANY, 0, laddr,
654: lport, SS_FACCEPTONCE)) == NULL) {
1.1 root 655: return 1;
1.1.1.6 root 656: }
1.1 root 657: n6 = ntohs(so->so_fport);
1.1.1.4 root 658:
1.1 root 659: n5 = (n6 >> 8) & 0xff;
660: n6 &= 0xff;
1.1.1.4 root 661:
1.1 root 662: laddr = ntohl(so->so_faddr.s_addr);
1.1.1.4 root 663:
1.1 root 664: n1 = ((laddr >> 24) & 0xff);
665: n2 = ((laddr >> 16) & 0xff);
666: n3 = ((laddr >> 8) & 0xff);
667: n4 = (laddr & 0xff);
1.1.1.4 root 668:
1.1 root 669: m->m_len = bptr - m->m_data; /* Adjust length */
1.1.1.5 root 670: m->m_len += snprintf(bptr, m->m_hdr.mh_size - m->m_len,
671: "27 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n%s",
672: n1, n2, n3, n4, n5, n6, x==7?buff:"");
1.1.1.4 root 673:
1.1 root 674: return 1;
675: }
1.1.1.4 root 676:
1.1 root 677: return 1;
1.1.1.4 root 678:
1.1 root 679: case EMU_KSH:
680: /*
681: * The kshell (Kerberos rsh) and shell services both pass
682: * a local port port number to carry signals to the server
683: * and stderr to the client. It is passed at the beginning
684: * of the connection as a NUL-terminated decimal ASCII string.
685: */
686: so->so_emu = 0;
687: for (lport = 0, i = 0; i < m->m_len-1; ++i) {
688: if (m->m_data[i] < '0' || m->m_data[i] > '9')
689: return 1; /* invalid number */
690: lport *= 10;
691: lport += m->m_data[i] - '0';
692: }
693: if (m->m_data[m->m_len-1] == '\0' && lport != 0 &&
1.1.1.6 root 694: (so = tcp_listen(slirp, INADDR_ANY, 0, so->so_laddr.s_addr,
695: htons(lport), SS_FACCEPTONCE)) != NULL)
1.1.1.5 root 696: m->m_len = snprintf(m->m_data, m->m_hdr.mh_size, "%d",
697: ntohs(so->so_fport)) + 1;
1.1 root 698: return 1;
1.1.1.4 root 699:
1.1 root 700: case EMU_IRC:
701: /*
702: * Need to emulate DCC CHAT, DCC SEND and DCC MOVE
703: */
704: *(m->m_data+m->m_len) = 0; /* NULL terminate the string for strstr */
705: if ((bptr = (char *)strstr(m->m_data, "DCC")) == NULL)
706: return 1;
1.1.1.4 root 707:
1.1 root 708: /* The %256s is for the broken mIRC */
709: if (sscanf(bptr, "DCC CHAT %256s %u %u", buff, &laddr, &lport) == 3) {
1.1.1.6 root 710: if ((so = tcp_listen(slirp, INADDR_ANY, 0,
711: htonl(laddr), htons(lport),
712: SS_FACCEPTONCE)) == NULL) {
1.1 root 713: return 1;
1.1.1.6 root 714: }
1.1 root 715: m->m_len = bptr - m->m_data; /* Adjust length */
1.1.1.5 root 716: m->m_len += snprintf(bptr, m->m_hdr.mh_size,
717: "DCC CHAT chat %lu %u%c\n",
718: (unsigned long)ntohl(so->so_faddr.s_addr),
719: ntohs(so->so_fport), 1);
1.1 root 720: } else if (sscanf(bptr, "DCC SEND %256s %u %u %u", buff, &laddr, &lport, &n1) == 4) {
1.1.1.6 root 721: if ((so = tcp_listen(slirp, INADDR_ANY, 0,
722: htonl(laddr), htons(lport),
723: SS_FACCEPTONCE)) == NULL) {
1.1 root 724: return 1;
1.1.1.6 root 725: }
1.1 root 726: m->m_len = bptr - m->m_data; /* Adjust length */
1.1.1.5 root 727: m->m_len += snprintf(bptr, m->m_hdr.mh_size,
728: "DCC SEND %s %lu %u %u%c\n", buff,
729: (unsigned long)ntohl(so->so_faddr.s_addr),
730: ntohs(so->so_fport), n1, 1);
1.1 root 731: } else if (sscanf(bptr, "DCC MOVE %256s %u %u %u", buff, &laddr, &lport, &n1) == 4) {
1.1.1.6 root 732: if ((so = tcp_listen(slirp, INADDR_ANY, 0,
733: htonl(laddr), htons(lport),
734: SS_FACCEPTONCE)) == NULL) {
1.1 root 735: return 1;
1.1.1.6 root 736: }
1.1 root 737: m->m_len = bptr - m->m_data; /* Adjust length */
1.1.1.5 root 738: m->m_len += snprintf(bptr, m->m_hdr.mh_size,
739: "DCC MOVE %s %lu %u %u%c\n", buff,
740: (unsigned long)ntohl(so->so_faddr.s_addr),
741: ntohs(so->so_fport), n1, 1);
1.1 root 742: }
743: return 1;
744:
745: case EMU_REALAUDIO:
1.1.1.4 root 746: /*
1.1 root 747: * RealAudio emulation - JP. We must try to parse the incoming
748: * data and try to find the two characters that contain the
749: * port number. Then we redirect an udp port and replace the
750: * number with the real port we got.
751: *
752: * The 1.0 beta versions of the player are not supported
753: * any more.
1.1.1.4 root 754: *
1.1 root 755: * A typical packet for player version 1.0 (release version):
1.1.1.4 root 756: *
757: * 0000:50 4E 41 00 05
1.1.1.6 root 758: * 0000:00 01 00 02 1B D7 00 00 67 E6 6C DC 63 00 12 50 ........g.l.c..P
1.1 root 759: * 0010:4E 43 4C 49 45 4E 54 20 31 30 31 20 41 4C 50 48 NCLIENT 101 ALPH
760: * 0020:41 6C 00 00 52 00 17 72 61 66 69 6C 65 73 2F 76 Al..R..rafiles/v
761: * 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 762: *
1.1 root 763: * Now the port number 0x1BD7 is found at offset 0x04 of the
764: * Now the port number 0x1BD7 is found at offset 0x04 of the
765: * second packet. This time we received five bytes first and
766: * then the rest. You never know how many bytes you get.
767: *
768: * A typical packet for player version 2.0 (beta):
1.1.1.4 root 769: *
1.1.1.6 root 770: * 0000:50 4E 41 00 06 00 02 00 00 00 01 00 02 1B C1 00 PNA.............
771: * 0010:00 67 75 78 F5 63 00 0A 57 69 6E 32 2E 30 2E 30 .gux.c..Win2.0.0
1.1 root 772: * 0020:2E 35 6C 00 00 52 00 1C 72 61 66 69 6C 65 73 2F .5l..R..rafiles/
773: * 0030:77 65 62 73 69 74 65 2F 32 30 72 65 6C 65 61 73 website/20releas
774: * 0040:65 2E 72 61 79 53 00 00 06 36 42 e.rayS...6B
1.1.1.4 root 775: *
1.1 root 776: * Port number 0x1BC1 is found at offset 0x0d.
1.1.1.4 root 777: *
1.1 root 778: * This is just a horrible switch statement. Variable ra tells
779: * us where we're going.
780: */
1.1.1.4 root 781:
1.1 root 782: bptr = m->m_data;
783: while (bptr < m->m_data + m->m_len) {
784: u_short p;
785: static int ra = 0;
1.1.1.4 root 786: char ra_tbl[4];
787:
1.1 root 788: ra_tbl[0] = 0x50;
789: ra_tbl[1] = 0x4e;
790: ra_tbl[2] = 0x41;
791: ra_tbl[3] = 0;
1.1.1.4 root 792:
1.1 root 793: switch (ra) {
794: case 0:
795: case 2:
796: case 3:
797: if (*bptr++ != ra_tbl[ra]) {
798: ra = 0;
799: continue;
800: }
801: break;
1.1.1.4 root 802:
1.1 root 803: case 1:
804: /*
805: * We may get 0x50 several times, ignore them
806: */
807: if (*bptr == 0x50) {
808: ra = 1;
809: bptr++;
810: continue;
811: } else if (*bptr++ != ra_tbl[ra]) {
812: ra = 0;
813: continue;
814: }
815: break;
1.1.1.4 root 816:
817: case 4:
818: /*
1.1 root 819: * skip version number
820: */
821: bptr++;
822: break;
1.1.1.4 root 823:
824: case 5:
1.1 root 825: /*
826: * The difference between versions 1.0 and
827: * 2.0 is here. For future versions of
828: * the player this may need to be modified.
829: */
830: if (*(bptr + 1) == 0x02)
831: bptr += 8;
832: else
833: bptr += 4;
1.1.1.4 root 834: break;
835:
1.1 root 836: case 6:
837: /* This is the field containing the port
838: * number that RA-player is listening to.
839: */
1.1.1.4 root 840: lport = (((u_char*)bptr)[0] << 8)
1.1 root 841: + ((u_char *)bptr)[1];
1.1.1.4 root 842: if (lport < 6970)
1.1 root 843: lport += 256; /* don't know why */
844: if (lport < 6970 || lport > 7170)
845: return 1; /* failed */
1.1.1.4 root 846:
1.1 root 847: /* try to get udp port between 6970 - 7170 */
848: for (p = 6970; p < 7071; p++) {
1.1.1.6 root 849: if (udp_listen(slirp, INADDR_ANY,
850: htons(p),
1.1 root 851: so->so_laddr.s_addr,
852: htons(lport),
853: SS_FACCEPTONCE)) {
854: break;
855: }
856: }
857: if (p == 7071)
858: p = 0;
859: *(u_char *)bptr++ = (p >> 8) & 0xff;
860: *(u_char *)bptr++ = p & 0xff;
1.1.1.4 root 861: ra = 0;
1.1 root 862: return 1; /* port redirected, we're done */
1.1.1.4 root 863: break;
864:
1.1 root 865: default:
1.1.1.4 root 866: ra = 0;
1.1 root 867: }
868: ra++;
869: }
1.1.1.4 root 870: return 1;
871:
1.1 root 872: default:
873: /* Ooops, not emulated, won't call tcp_emu again */
874: so->so_emu = 0;
875: return 1;
876: }
877: }
878:
879: /*
880: * Do misc. config of SLiRP while its running.
881: * Return 0 if this connections is to be closed, 1 otherwise,
882: * return 2 if this is a command-line connection
883: */
1.1.1.6 root 884: int tcp_ctl(struct socket *so)
1.1 root 885: {
1.1.1.6 root 886: Slirp *slirp = so->slirp;
887: struct sbuf *sb = &so->so_snd;
888: struct ex_list *ex_ptr;
889: int do_pty;
890:
891: DEBUG_CALL("tcp_ctl");
892: DEBUG_ARG("so = %lx", (long )so);
893:
894: if (so->so_faddr.s_addr != slirp->vhost_addr.s_addr) {
895: /* Check if it's pty_exec */
896: for (ex_ptr = slirp->exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
897: if (ex_ptr->ex_fport == so->so_fport &&
898: so->so_faddr.s_addr == ex_ptr->ex_addr.s_addr) {
899: if (ex_ptr->ex_pty == 3) {
900: so->s = -1;
901: so->extra = (void *)ex_ptr->ex_exec;
902: return 1;
903: }
904: do_pty = ex_ptr->ex_pty;
905: DEBUG_MISC((dfd, " executing %s \n",ex_ptr->ex_exec));
906: return fork_exec(so, ex_ptr->ex_exec, do_pty);
907: }
908: }
909: }
910: sb->sb_cc =
911: snprintf(sb->sb_wptr, sb->sb_datalen - (sb->sb_wptr - sb->sb_data),
912: "Error: No application configured.\r\n");
913: sb->sb_wptr += sb->sb_cc;
914: return 0;
1.1 root 915: }
unix.superglobalmegacorp.com