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