|
|
1.1 root 1: #include <string.h>
2: #include <stdlib.h>
3: #include <stdio.h>
4: #include <assert.h>
5: #include <errno.h>
6: #include <byteswap.h>
7: #include <ipxe/timer.h>
8: #include <ipxe/iobuf.h>
9: #include <ipxe/malloc.h>
10: #include <ipxe/retry.h>
11: #include <ipxe/refcnt.h>
12: #include <ipxe/xfer.h>
13: #include <ipxe/open.h>
14: #include <ipxe/uri.h>
15: #include <ipxe/netdevice.h>
16: #include <ipxe/tcpip.h>
17: #include <ipxe/tcp.h>
18:
19: /** @file
20: *
21: * TCP protocol
22: *
23: */
24:
25: FILE_LICENCE ( GPL2_OR_LATER );
26:
27: /** A TCP connection */
28: struct tcp_connection {
29: /** Reference counter */
30: struct refcnt refcnt;
31: /** List of TCP connections */
32: struct list_head list;
33:
34: /** Flags */
35: unsigned int flags;
36:
37: /** Data transfer interface */
38: struct interface xfer;
39:
40: /** Remote socket address */
41: struct sockaddr_tcpip peer;
42: /** Local port */
43: unsigned int local_port;
44:
45: /** Current TCP state */
46: unsigned int tcp_state;
47: /** Previous TCP state
48: *
49: * Maintained only for debug messages
50: */
51: unsigned int prev_tcp_state;
52: /** Current sequence number
53: *
54: * Equivalent to SND.UNA in RFC 793 terminology.
55: */
56: uint32_t snd_seq;
57: /** Unacknowledged sequence count
58: *
59: * Equivalent to (SND.NXT-SND.UNA) in RFC 793 terminology.
60: */
61: uint32_t snd_sent;
62: /** Send window
63: *
64: * Equivalent to SND.WND in RFC 793 terminology
65: */
66: uint32_t snd_win;
67: /** Current acknowledgement number
68: *
69: * Equivalent to RCV.NXT in RFC 793 terminology.
70: */
71: uint32_t rcv_ack;
72: /** Receive window
73: *
74: * Equivalent to RCV.WND in RFC 793 terminology.
75: */
76: uint32_t rcv_win;
77: /** Received timestamp value
78: *
79: * Updated when a packet is received; copied to ts_recent when
80: * the window is advanced.
81: */
82: uint32_t ts_val;
83: /** Most recent received timestamp that advanced the window
84: *
85: * Equivalent to TS.Recent in RFC 1323 terminology.
86: */
87: uint32_t ts_recent;
88:
89: /** Transmit queue */
90: struct list_head tx_queue;
91: /** Receive queue */
92: struct list_head rx_queue;
93: /** Retransmission timer */
94: struct retry_timer timer;
95: /** Shutdown (TIME_WAIT) timer */
96: struct retry_timer wait;
97: };
98:
99: /** TCP flags */
100: enum tcp_flags {
101: /** TCP data transfer interface has been closed */
102: TCP_XFER_CLOSED = 0x0001,
103: /** TCP timestamps are enabled */
104: TCP_TS_ENABLED = 0x0002,
105: /** TCP acknowledgement is pending */
106: TCP_ACK_PENDING = 0x0004,
107: };
108:
109: /** TCP internal header
110: *
111: * This is the header that replaces the TCP header for packets
112: * enqueued on the receive queue.
113: */
114: struct tcp_rx_queued_header {
115: /** SEQ value, in host-endian order
116: *
117: * This represents the SEQ value at the time the packet is
118: * enqueued, and so excludes the SYN, if present.
119: */
120: uint32_t seq;
121: /** Flags
122: *
123: * Only FIN is valid within this flags byte; all other flags
124: * have already been processed by the time the packet is
125: * enqueued.
126: */
127: uint8_t flags;
128: /** Reserved */
129: uint8_t reserved[3];
130: };
131:
132: /**
133: * List of registered TCP connections
134: */
135: static LIST_HEAD ( tcp_conns );
136:
137: /* Forward declarations */
138: static struct interface_descriptor tcp_xfer_desc;
139: static void tcp_expired ( struct retry_timer *timer, int over );
140: static void tcp_wait_expired ( struct retry_timer *timer, int over );
141: static int tcp_rx_ack ( struct tcp_connection *tcp, uint32_t ack,
142: uint32_t win );
143:
144: /**
145: * Name TCP state
146: *
147: * @v state TCP state
148: * @ret name Name of TCP state
149: */
150: static inline __attribute__ (( always_inline )) const char *
151: tcp_state ( int state ) {
152: switch ( state ) {
153: case TCP_CLOSED: return "CLOSED";
154: case TCP_LISTEN: return "LISTEN";
155: case TCP_SYN_SENT: return "SYN_SENT";
156: case TCP_SYN_RCVD: return "SYN_RCVD";
157: case TCP_ESTABLISHED: return "ESTABLISHED";
158: case TCP_FIN_WAIT_1: return "FIN_WAIT_1";
159: case TCP_FIN_WAIT_2: return "FIN_WAIT_2";
160: case TCP_CLOSING_OR_LAST_ACK: return "CLOSING/LAST_ACK";
161: case TCP_TIME_WAIT: return "TIME_WAIT";
162: case TCP_CLOSE_WAIT: return "CLOSE_WAIT";
163: default: return "INVALID";
164: }
165: }
166:
167: /**
168: * Dump TCP state transition
169: *
170: * @v tcp TCP connection
171: */
172: static inline __attribute__ (( always_inline )) void
173: tcp_dump_state ( struct tcp_connection *tcp ) {
174:
175: if ( tcp->tcp_state != tcp->prev_tcp_state ) {
176: DBGC ( tcp, "TCP %p transitioned from %s to %s\n", tcp,
177: tcp_state ( tcp->prev_tcp_state ),
178: tcp_state ( tcp->tcp_state ) );
179: }
180: tcp->prev_tcp_state = tcp->tcp_state;
181: }
182:
183: /**
184: * Dump TCP flags
185: *
186: * @v flags TCP flags
187: */
188: static inline __attribute__ (( always_inline )) void
189: tcp_dump_flags ( struct tcp_connection *tcp, unsigned int flags ) {
190: if ( flags & TCP_RST )
191: DBGC2 ( tcp, " RST" );
192: if ( flags & TCP_SYN )
193: DBGC2 ( tcp, " SYN" );
194: if ( flags & TCP_PSH )
195: DBGC2 ( tcp, " PSH" );
196: if ( flags & TCP_FIN )
197: DBGC2 ( tcp, " FIN" );
198: if ( flags & TCP_ACK )
199: DBGC2 ( tcp, " ACK" );
200: }
201:
202: /***************************************************************************
203: *
204: * Open and close
205: *
206: ***************************************************************************
207: */
208:
209: /**
210: * Bind TCP connection to local port
211: *
212: * @v tcp TCP connection
213: * @v port Local port number
214: * @ret rc Return status code
215: *
216: * If the port is 0, the connection is assigned an available port
217: * between 1024 and 65535.
218: */
219: static int tcp_bind ( struct tcp_connection *tcp, unsigned int port ) {
220: struct tcp_connection *existing;
221: uint16_t try_port;
222: unsigned int i;
223:
224: /* If no port is specified, find an available port */
225: if ( ! port ) {
226: try_port = random();
227: for ( i = 0 ; i < 65536 ; i++ ) {
228: try_port++;
229: if ( try_port < 1024 )
230: continue;
231: if ( tcp_bind ( tcp, try_port ) == 0 )
232: return 0;
233: }
234: DBGC ( tcp, "TCP %p could not bind: no free ports\n", tcp );
235: return -EADDRINUSE;
236: }
237:
238: /* Attempt bind to local port */
239: list_for_each_entry ( existing, &tcp_conns, list ) {
240: if ( existing->local_port == port ) {
241: DBGC ( tcp, "TCP %p could not bind: port %d in use\n",
242: tcp, port );
243: return -EADDRINUSE;
244: }
245: }
246: tcp->local_port = port;
247:
248: DBGC ( tcp, "TCP %p bound to port %d\n", tcp, port );
249: return 0;
250: }
251:
252: /**
253: * Open a TCP connection
254: *
255: * @v xfer Data transfer interface
256: * @v peer Peer socket address
257: * @v local Local socket address, or NULL
258: * @ret rc Return status code
259: */
260: static int tcp_open ( struct interface *xfer, struct sockaddr *peer,
261: struct sockaddr *local ) {
262: struct sockaddr_tcpip *st_peer = ( struct sockaddr_tcpip * ) peer;
263: struct sockaddr_tcpip *st_local = ( struct sockaddr_tcpip * ) local;
264: struct tcp_connection *tcp;
265: unsigned int bind_port;
266: int rc;
267:
268: /* Allocate and initialise structure */
269: tcp = zalloc ( sizeof ( *tcp ) );
270: if ( ! tcp )
271: return -ENOMEM;
272: DBGC ( tcp, "TCP %p allocated\n", tcp );
273: ref_init ( &tcp->refcnt, NULL );
274: intf_init ( &tcp->xfer, &tcp_xfer_desc, &tcp->refcnt );
275: timer_init ( &tcp->timer, tcp_expired, &tcp->refcnt );
276: timer_init ( &tcp->wait, tcp_wait_expired, &tcp->refcnt );
277: tcp->prev_tcp_state = TCP_CLOSED;
278: tcp->tcp_state = TCP_STATE_SENT ( TCP_SYN );
279: tcp_dump_state ( tcp );
280: tcp->snd_seq = random();
281: INIT_LIST_HEAD ( &tcp->tx_queue );
282: INIT_LIST_HEAD ( &tcp->rx_queue );
283: memcpy ( &tcp->peer, st_peer, sizeof ( tcp->peer ) );
284:
285: /* Bind to local port */
286: bind_port = ( st_local ? ntohs ( st_local->st_port ) : 0 );
287: if ( ( rc = tcp_bind ( tcp, bind_port ) ) != 0 )
288: goto err;
289:
290: /* Start timer to initiate SYN */
291: start_timer_nodelay ( &tcp->timer );
292:
293: /* Attach parent interface, transfer reference to connection
294: * list and return
295: */
296: intf_plug_plug ( &tcp->xfer, xfer );
297: list_add ( &tcp->list, &tcp_conns );
298: return 0;
299:
300: err:
301: ref_put ( &tcp->refcnt );
302: return rc;
303: }
304:
305: /**
306: * Close TCP connection
307: *
308: * @v tcp TCP connection
309: * @v rc Reason for close
310: *
311: * Closes the data transfer interface. If the TCP state machine is in
312: * a suitable state, the connection will be deleted.
313: */
314: static void tcp_close ( struct tcp_connection *tcp, int rc ) {
315: struct io_buffer *iobuf;
316: struct io_buffer *tmp;
317:
318: /* Close data transfer interface */
319: intf_shutdown ( &tcp->xfer, rc );
320: tcp->flags |= TCP_XFER_CLOSED;
321:
322: /* If we are in CLOSED, or have otherwise not yet received a
323: * SYN (i.e. we are in LISTEN or SYN_SENT), just delete the
324: * connection.
325: */
326: if ( ! ( tcp->tcp_state & TCP_STATE_RCVD ( TCP_SYN ) ) ) {
327:
328: /* Transition to CLOSED for the sake of debugging messages */
329: tcp->tcp_state = TCP_CLOSED;
330: tcp_dump_state ( tcp );
331:
332: /* Free any unprocessed I/O buffers */
333: list_for_each_entry_safe ( iobuf, tmp, &tcp->rx_queue, list ) {
334: list_del ( &iobuf->list );
335: free_iob ( iobuf );
336: }
337:
338: /* Free any unsent I/O buffers */
339: list_for_each_entry_safe ( iobuf, tmp, &tcp->tx_queue, list ) {
340: list_del ( &iobuf->list );
341: free_iob ( iobuf );
342: }
343:
344: /* Remove from list and drop reference */
345: stop_timer ( &tcp->timer );
346: list_del ( &tcp->list );
347: ref_put ( &tcp->refcnt );
348: DBGC ( tcp, "TCP %p connection deleted\n", tcp );
349: return;
350: }
351:
352: /* If we have not had our SYN acknowledged (i.e. we are in
353: * SYN_RCVD), pretend that it has been acknowledged so that we
354: * can send a FIN without breaking things.
355: */
356: if ( ! ( tcp->tcp_state & TCP_STATE_ACKED ( TCP_SYN ) ) )
357: tcp_rx_ack ( tcp, ( tcp->snd_seq + 1 ), 0 );
358:
359: /* If we have no data remaining to send, start sending FIN */
360: if ( list_empty ( &tcp->tx_queue ) ) {
361: tcp->tcp_state |= TCP_STATE_SENT ( TCP_FIN );
362: tcp_dump_state ( tcp );
363: }
364: }
365:
366: /***************************************************************************
367: *
368: * Transmit data path
369: *
370: ***************************************************************************
371: */
372:
373: /**
374: * Calculate transmission window
375: *
376: * @v tcp TCP connection
377: * @ret len Maximum length that can be sent in a single packet
378: */
379: static size_t tcp_xmit_win ( struct tcp_connection *tcp ) {
380: size_t len;
381:
382: /* Not ready if we're not in a suitable connection state */
383: if ( ! TCP_CAN_SEND_DATA ( tcp->tcp_state ) )
384: return 0;
385:
386: /* Length is the minimum of the receiver's window and the path MTU */
387: len = tcp->snd_win;
388: if ( len > TCP_PATH_MTU )
389: len = TCP_PATH_MTU;
390:
391: return len;
392: }
393:
394: /**
395: * Process TCP transmit queue
396: *
397: * @v tcp TCP connection
398: * @v max_len Maximum length to process
399: * @v dest I/O buffer to fill with data, or NULL
400: * @v remove Remove data from queue
401: * @ret len Length of data processed
402: *
403: * This processes at most @c max_len bytes from the TCP connection's
404: * transmit queue. Data will be copied into the @c dest I/O buffer
405: * (if provided) and, if @c remove is true, removed from the transmit
406: * queue.
407: */
408: static size_t tcp_process_tx_queue ( struct tcp_connection *tcp, size_t max_len,
409: struct io_buffer *dest, int remove ) {
410: struct io_buffer *iobuf;
411: struct io_buffer *tmp;
412: size_t frag_len;
413: size_t len = 0;
414:
415: list_for_each_entry_safe ( iobuf, tmp, &tcp->tx_queue, list ) {
416: frag_len = iob_len ( iobuf );
417: if ( frag_len > max_len )
418: frag_len = max_len;
419: if ( dest ) {
420: memcpy ( iob_put ( dest, frag_len ), iobuf->data,
421: frag_len );
422: }
423: if ( remove ) {
424: iob_pull ( iobuf, frag_len );
425: if ( ! iob_len ( iobuf ) ) {
426: list_del ( &iobuf->list );
427: free_iob ( iobuf );
428: }
429: }
430: len += frag_len;
431: max_len -= frag_len;
432: }
433: return len;
434: }
435:
436: /**
437: * Transmit any outstanding data
438: *
439: * @v tcp TCP connection
440: *
441: * Transmits any outstanding data on the connection.
442: *
443: * Note that even if an error is returned, the retransmission timer
444: * will have been started if necessary, and so the stack will
445: * eventually attempt to retransmit the failed packet.
446: */
447: static int tcp_xmit ( struct tcp_connection *tcp ) {
448: struct io_buffer *iobuf;
449: struct tcp_header *tcphdr;
450: struct tcp_mss_option *mssopt;
451: struct tcp_timestamp_padded_option *tsopt;
452: void *payload;
453: unsigned int flags;
454: size_t len = 0;
455: uint32_t seq_len;
456: uint32_t app_win;
457: uint32_t max_rcv_win;
458: int rc;
459:
460: /* If retransmission timer is already running, do nothing */
461: if ( timer_running ( &tcp->timer ) )
462: return 0;
463:
464: /* Calculate both the actual (payload) and sequence space
465: * lengths that we wish to transmit.
466: */
467: if ( TCP_CAN_SEND_DATA ( tcp->tcp_state ) ) {
468: len = tcp_process_tx_queue ( tcp, tcp_xmit_win ( tcp ),
469: NULL, 0 );
470: }
471: seq_len = len;
472: flags = TCP_FLAGS_SENDING ( tcp->tcp_state );
473: if ( flags & ( TCP_SYN | TCP_FIN ) ) {
474: /* SYN or FIN consume one byte, and we can never send both */
475: assert ( ! ( ( flags & TCP_SYN ) && ( flags & TCP_FIN ) ) );
476: seq_len++;
477: }
478: tcp->snd_sent = seq_len;
479:
480: /* If we have nothing to transmit, stop now */
481: if ( ( seq_len == 0 ) && ! ( tcp->flags & TCP_ACK_PENDING ) )
482: return 0;
483:
484: /* If we are transmitting anything that requires
485: * acknowledgement (i.e. consumes sequence space), start the
486: * retransmission timer. Do this before attempting to
487: * allocate the I/O buffer, in case allocation itself fails.
488: */
489: if ( seq_len )
490: start_timer ( &tcp->timer );
491:
492: /* Allocate I/O buffer */
493: iobuf = alloc_iob ( len + MAX_LL_NET_HEADER_LEN );
494: if ( ! iobuf ) {
495: DBGC ( tcp, "TCP %p could not allocate iobuf for %08x..%08x "
496: "%08x\n", tcp, tcp->snd_seq, ( tcp->snd_seq + seq_len ),
497: tcp->rcv_ack );
498: return -ENOMEM;
499: }
500: iob_reserve ( iobuf, MAX_LL_NET_HEADER_LEN );
501:
502: /* Fill data payload from transmit queue */
503: tcp_process_tx_queue ( tcp, len, iobuf, 0 );
504:
505: /* Expand receive window if possible */
506: max_rcv_win = ( ( freemem * 3 ) / 4 );
507: if ( max_rcv_win > TCP_MAX_WINDOW_SIZE )
508: max_rcv_win = TCP_MAX_WINDOW_SIZE;
509: app_win = xfer_window ( &tcp->xfer );
510: if ( max_rcv_win > app_win )
511: max_rcv_win = app_win;
512: max_rcv_win &= ~0x03; /* Keep everything dword-aligned */
513: if ( tcp->rcv_win < max_rcv_win )
514: tcp->rcv_win = max_rcv_win;
515:
516: /* Fill up the TCP header */
517: payload = iobuf->data;
518: if ( flags & TCP_SYN ) {
519: mssopt = iob_push ( iobuf, sizeof ( *mssopt ) );
520: mssopt->kind = TCP_OPTION_MSS;
521: mssopt->length = sizeof ( *mssopt );
522: mssopt->mss = htons ( TCP_MSS );
523: }
524: if ( ( flags & TCP_SYN ) || ( tcp->flags & TCP_TS_ENABLED ) ) {
525: tsopt = iob_push ( iobuf, sizeof ( *tsopt ) );
526: memset ( tsopt->nop, TCP_OPTION_NOP, sizeof ( tsopt->nop ) );
527: tsopt->tsopt.kind = TCP_OPTION_TS;
528: tsopt->tsopt.length = sizeof ( tsopt->tsopt );
529: tsopt->tsopt.tsval = htonl ( currticks() );
530: tsopt->tsopt.tsecr = htonl ( tcp->ts_recent );
531: }
532: if ( len != 0 )
533: flags |= TCP_PSH;
534: tcphdr = iob_push ( iobuf, sizeof ( *tcphdr ) );
535: memset ( tcphdr, 0, sizeof ( *tcphdr ) );
536: tcphdr->src = htons ( tcp->local_port );
537: tcphdr->dest = tcp->peer.st_port;
538: tcphdr->seq = htonl ( tcp->snd_seq );
539: tcphdr->ack = htonl ( tcp->rcv_ack );
540: tcphdr->hlen = ( ( payload - iobuf->data ) << 2 );
541: tcphdr->flags = flags;
542: tcphdr->win = htons ( tcp->rcv_win );
543: tcphdr->csum = tcpip_chksum ( iobuf->data, iob_len ( iobuf ) );
544:
545: /* Dump header */
546: DBGC2 ( tcp, "TCP %p TX %d->%d %08x..%08x %08x %4zd",
547: tcp, ntohs ( tcphdr->src ), ntohs ( tcphdr->dest ),
548: ntohl ( tcphdr->seq ), ( ntohl ( tcphdr->seq ) + seq_len ),
549: ntohl ( tcphdr->ack ), len );
550: tcp_dump_flags ( tcp, tcphdr->flags );
551: DBGC2 ( tcp, "\n" );
552:
553: /* Transmit packet */
554: if ( ( rc = tcpip_tx ( iobuf, &tcp_protocol, NULL, &tcp->peer, NULL,
555: &tcphdr->csum ) ) != 0 ) {
556: DBGC ( tcp, "TCP %p could not transmit %08x..%08x %08x: %s\n",
557: tcp, tcp->snd_seq, ( tcp->snd_seq + tcp->snd_sent ),
558: tcp->rcv_ack, strerror ( rc ) );
559: return rc;
560: }
561:
562: /* Clear ACK-pending flag */
563: tcp->flags &= ~TCP_ACK_PENDING;
564:
565: return 0;
566: }
567:
568: /**
569: * Retransmission timer expired
570: *
571: * @v timer Retransmission timer
572: * @v over Failure indicator
573: */
574: static void tcp_expired ( struct retry_timer *timer, int over ) {
575: struct tcp_connection *tcp =
576: container_of ( timer, struct tcp_connection, timer );
577:
578: DBGC ( tcp, "TCP %p timer %s in %s for %08x..%08x %08x\n", tcp,
579: ( over ? "expired" : "fired" ), tcp_state ( tcp->tcp_state ),
580: tcp->snd_seq, ( tcp->snd_seq + tcp->snd_sent ), tcp->rcv_ack );
581:
582: assert ( ( tcp->tcp_state == TCP_SYN_SENT ) ||
583: ( tcp->tcp_state == TCP_SYN_RCVD ) ||
584: ( tcp->tcp_state == TCP_ESTABLISHED ) ||
585: ( tcp->tcp_state == TCP_FIN_WAIT_1 ) ||
586: ( tcp->tcp_state == TCP_CLOSE_WAIT ) ||
587: ( tcp->tcp_state == TCP_CLOSING_OR_LAST_ACK ) );
588:
589: if ( over ) {
590: /* If we have finally timed out and given up,
591: * terminate the connection
592: */
593: tcp->tcp_state = TCP_CLOSED;
594: tcp_dump_state ( tcp );
595: tcp_close ( tcp, -ETIMEDOUT );
596: } else {
597: /* Otherwise, retransmit the packet */
598: tcp_xmit ( tcp );
599: }
600: }
601:
602: /**
603: * Shutdown timer expired
604: *
605: * @v timer Shutdown timer
606: * @v over Failure indicator
607: */
608: static void tcp_wait_expired ( struct retry_timer *timer, int over __unused ) {
609: struct tcp_connection *tcp =
610: container_of ( timer, struct tcp_connection, wait );
611:
612: assert ( tcp->tcp_state == TCP_TIME_WAIT );
613:
614: DBGC ( tcp, "TCP %p wait complete in %s for %08x..%08x %08x\n", tcp,
615: tcp_state ( tcp->tcp_state ), tcp->snd_seq,
616: ( tcp->snd_seq + tcp->snd_sent ), tcp->rcv_ack );
617:
618: tcp->tcp_state = TCP_CLOSED;
619: tcp_dump_state ( tcp );
620: tcp_close ( tcp, 0 );
621: }
622:
623: /**
624: * Send RST response to incoming packet
625: *
626: * @v in_tcphdr TCP header of incoming packet
627: * @ret rc Return status code
628: */
629: static int tcp_xmit_reset ( struct tcp_connection *tcp,
630: struct sockaddr_tcpip *st_dest,
631: struct tcp_header *in_tcphdr ) {
632: struct io_buffer *iobuf;
633: struct tcp_header *tcphdr;
634: int rc;
635:
636: /* Allocate space for dataless TX buffer */
637: iobuf = alloc_iob ( MAX_LL_NET_HEADER_LEN );
638: if ( ! iobuf ) {
639: DBGC ( tcp, "TCP %p could not allocate iobuf for RST "
640: "%08x..%08x %08x\n", tcp, ntohl ( in_tcphdr->ack ),
641: ntohl ( in_tcphdr->ack ), ntohl ( in_tcphdr->seq ) );
642: return -ENOMEM;
643: }
644: iob_reserve ( iobuf, MAX_LL_NET_HEADER_LEN );
645:
646: /* Construct RST response */
647: tcphdr = iob_push ( iobuf, sizeof ( *tcphdr ) );
648: memset ( tcphdr, 0, sizeof ( *tcphdr ) );
649: tcphdr->src = in_tcphdr->dest;
650: tcphdr->dest = in_tcphdr->src;
651: tcphdr->seq = in_tcphdr->ack;
652: tcphdr->ack = in_tcphdr->seq;
653: tcphdr->hlen = ( ( sizeof ( *tcphdr ) / 4 ) << 4 );
654: tcphdr->flags = ( TCP_RST | TCP_ACK );
655: tcphdr->win = htons ( TCP_MAX_WINDOW_SIZE );
656: tcphdr->csum = tcpip_chksum ( iobuf->data, iob_len ( iobuf ) );
657:
658: /* Dump header */
659: DBGC2 ( tcp, "TCP %p TX %d->%d %08x..%08x %08x %4d",
660: tcp, ntohs ( tcphdr->src ), ntohs ( tcphdr->dest ),
661: ntohl ( tcphdr->seq ), ( ntohl ( tcphdr->seq ) ),
662: ntohl ( tcphdr->ack ), 0 );
663: tcp_dump_flags ( tcp, tcphdr->flags );
664: DBGC2 ( tcp, "\n" );
665:
666: /* Transmit packet */
667: if ( ( rc = tcpip_tx ( iobuf, &tcp_protocol, NULL, st_dest,
668: NULL, &tcphdr->csum ) ) != 0 ) {
669: DBGC ( tcp, "TCP %p could not transmit RST %08x..%08x %08x: "
670: "%s\n", tcp, ntohl ( in_tcphdr->ack ),
671: ntohl ( in_tcphdr->ack ), ntohl ( in_tcphdr->seq ),
672: strerror ( rc ) );
673: return rc;
674: }
675:
676: return 0;
677: }
678:
679: /***************************************************************************
680: *
681: * Receive data path
682: *
683: ***************************************************************************
684: */
685:
686: /**
687: * Identify TCP connection by local port number
688: *
689: * @v local_port Local port
690: * @ret tcp TCP connection, or NULL
691: */
692: static struct tcp_connection * tcp_demux ( unsigned int local_port ) {
693: struct tcp_connection *tcp;
694:
695: list_for_each_entry ( tcp, &tcp_conns, list ) {
696: if ( tcp->local_port == local_port )
697: return tcp;
698: }
699: return NULL;
700: }
701:
702: /**
703: * Parse TCP received options
704: *
705: * @v tcp TCP connection
706: * @v data Raw options data
707: * @v len Raw options length
708: * @v options Options structure to fill in
709: */
710: static void tcp_rx_opts ( struct tcp_connection *tcp, const void *data,
711: size_t len, struct tcp_options *options ) {
712: const void *end = ( data + len );
713: const struct tcp_option *option;
714: unsigned int kind;
715:
716: memset ( options, 0, sizeof ( *options ) );
717: while ( data < end ) {
718: option = data;
719: kind = option->kind;
720: if ( kind == TCP_OPTION_END )
721: return;
722: if ( kind == TCP_OPTION_NOP ) {
723: data++;
724: continue;
725: }
726: switch ( kind ) {
727: case TCP_OPTION_MSS:
728: options->mssopt = data;
729: break;
730: case TCP_OPTION_TS:
731: options->tsopt = data;
732: break;
733: default:
734: DBGC ( tcp, "TCP %p received unknown option %d\n",
735: tcp, kind );
736: break;
737: }
738: data += option->length;
739: }
740: }
741:
742: /**
743: * Consume received sequence space
744: *
745: * @v tcp TCP connection
746: * @v seq_len Sequence space length to consume
747: */
748: static void tcp_rx_seq ( struct tcp_connection *tcp, uint32_t seq_len ) {
749:
750: /* Sanity check */
751: assert ( seq_len > 0 );
752:
753: /* Update acknowledgement number */
754: tcp->rcv_ack += seq_len;
755:
756: /* Update window */
757: if ( tcp->rcv_win > seq_len ) {
758: tcp->rcv_win -= seq_len;
759: } else {
760: tcp->rcv_win = 0;
761: }
762:
763: /* Update timestamp */
764: tcp->ts_recent = tcp->ts_val;
765:
766: /* Mark ACK as pending */
767: tcp->flags |= TCP_ACK_PENDING;
768: }
769:
770: /**
771: * Handle TCP received SYN
772: *
773: * @v tcp TCP connection
774: * @v seq SEQ value (in host-endian order)
775: * @v options TCP options
776: * @ret rc Return status code
777: */
778: static int tcp_rx_syn ( struct tcp_connection *tcp, uint32_t seq,
779: struct tcp_options *options ) {
780:
781: /* Synchronise sequence numbers on first SYN */
782: if ( ! ( tcp->tcp_state & TCP_STATE_RCVD ( TCP_SYN ) ) ) {
783: tcp->rcv_ack = seq;
784: if ( options->tsopt )
785: tcp->flags |= TCP_TS_ENABLED;
786: }
787:
788: /* Ignore duplicate SYN */
789: if ( seq != tcp->rcv_ack )
790: return 0;
791:
792: /* Acknowledge SYN */
793: tcp_rx_seq ( tcp, 1 );
794:
795: /* Mark SYN as received and start sending ACKs with each packet */
796: tcp->tcp_state |= ( TCP_STATE_SENT ( TCP_ACK ) |
797: TCP_STATE_RCVD ( TCP_SYN ) );
798:
799: return 0;
800: }
801:
802: /**
803: * Handle TCP received ACK
804: *
805: * @v tcp TCP connection
806: * @v ack ACK value (in host-endian order)
807: * @v win WIN value (in host-endian order)
808: * @ret rc Return status code
809: */
810: static int tcp_rx_ack ( struct tcp_connection *tcp, uint32_t ack,
811: uint32_t win ) {
812: uint32_t ack_len = ( ack - tcp->snd_seq );
813: size_t len;
814: unsigned int acked_flags;
815:
816: /* Check for out-of-range or old duplicate ACKs */
817: if ( ack_len > tcp->snd_sent ) {
818: DBGC ( tcp, "TCP %p received ACK for %08x..%08x, "
819: "sent only %08x..%08x\n", tcp, tcp->snd_seq,
820: ( tcp->snd_seq + ack_len ), tcp->snd_seq,
821: ( tcp->snd_seq + tcp->snd_sent ) );
822:
823: if ( TCP_HAS_BEEN_ESTABLISHED ( tcp->tcp_state ) ) {
824: /* Just ignore what might be old duplicate ACKs */
825: return 0;
826: } else {
827: /* Send RST if an out-of-range ACK is received
828: * on a not-yet-established connection, as per
829: * RFC 793.
830: */
831: return -EINVAL;
832: }
833: }
834:
835: /* Ignore ACKs that don't actually acknowledge any new data.
836: * (In particular, do not stop the retransmission timer; this
837: * avoids creating a sorceror's apprentice syndrome when a
838: * duplicate ACK is received and we still have data in our
839: * transmit queue.)
840: */
841: if ( ack_len == 0 )
842: return 0;
843:
844: /* Stop the retransmission timer */
845: stop_timer ( &tcp->timer );
846:
847: /* Determine acknowledged flags and data length */
848: len = ack_len;
849: acked_flags = ( TCP_FLAGS_SENDING ( tcp->tcp_state ) &
850: ( TCP_SYN | TCP_FIN ) );
851: if ( acked_flags )
852: len--;
853:
854: /* Update SEQ and sent counters, and window size */
855: tcp->snd_seq = ack;
856: tcp->snd_sent = 0;
857: tcp->snd_win = win;
858:
859: /* Remove any acknowledged data from transmit queue */
860: tcp_process_tx_queue ( tcp, len, NULL, 1 );
861:
862: /* Mark SYN/FIN as acknowledged if applicable. */
863: if ( acked_flags )
864: tcp->tcp_state |= TCP_STATE_ACKED ( acked_flags );
865:
866: /* Start sending FIN if we've had all possible data ACKed */
867: if ( list_empty ( &tcp->tx_queue ) && ( tcp->flags & TCP_XFER_CLOSED ) )
868: tcp->tcp_state |= TCP_STATE_SENT ( TCP_FIN );
869:
870: return 0;
871: }
872:
873: /**
874: * Handle TCP received data
875: *
876: * @v tcp TCP connection
877: * @v seq SEQ value (in host-endian order)
878: * @v iobuf I/O buffer
879: * @ret rc Return status code
880: *
881: * This function takes ownership of the I/O buffer.
882: */
883: static int tcp_rx_data ( struct tcp_connection *tcp, uint32_t seq,
884: struct io_buffer *iobuf ) {
885: uint32_t already_rcvd;
886: uint32_t len;
887: int rc;
888:
889: /* Ignore duplicate or out-of-order data */
890: already_rcvd = ( tcp->rcv_ack - seq );
891: len = iob_len ( iobuf );
892: if ( already_rcvd >= len ) {
893: free_iob ( iobuf );
894: return 0;
895: }
896: iob_pull ( iobuf, already_rcvd );
897: len -= already_rcvd;
898:
899: /* Acknowledge new data */
900: tcp_rx_seq ( tcp, len );
901:
902: /* Deliver data to application */
903: if ( ( rc = xfer_deliver_iob ( &tcp->xfer, iobuf ) ) != 0 ) {
904: DBGC ( tcp, "TCP %p could not deliver %08x..%08x: %s\n",
905: tcp, seq, ( seq + len ), strerror ( rc ) );
906: return rc;
907: }
908:
909: return 0;
910: }
911:
912: /**
913: * Handle TCP received FIN
914: *
915: * @v tcp TCP connection
916: * @v seq SEQ value (in host-endian order)
917: * @ret rc Return status code
918: */
919: static int tcp_rx_fin ( struct tcp_connection *tcp, uint32_t seq ) {
920:
921: /* Ignore duplicate or out-of-order FIN */
922: if ( seq != tcp->rcv_ack )
923: return 0;
924:
925: /* Acknowledge FIN */
926: tcp_rx_seq ( tcp, 1 );
927:
928: /* Mark FIN as received */
929: tcp->tcp_state |= TCP_STATE_RCVD ( TCP_FIN );
930:
931: /* Close connection */
932: tcp_close ( tcp, 0 );
933:
934: return 0;
935: }
936:
937: /**
938: * Handle TCP received RST
939: *
940: * @v tcp TCP connection
941: * @v seq SEQ value (in host-endian order)
942: * @ret rc Return status code
943: */
944: static int tcp_rx_rst ( struct tcp_connection *tcp, uint32_t seq ) {
945:
946: /* Accept RST only if it falls within the window. If we have
947: * not yet received a SYN, then we have no window to test
948: * against, so fall back to checking that our SYN has been
949: * ACKed.
950: */
951: if ( tcp->tcp_state & TCP_STATE_RCVD ( TCP_SYN ) ) {
952: if ( ! tcp_in_window ( seq, tcp->rcv_ack, tcp->rcv_win ) )
953: return 0;
954: } else {
955: if ( ! ( tcp->tcp_state & TCP_STATE_ACKED ( TCP_SYN ) ) )
956: return 0;
957: }
958:
959: /* Abort connection */
960: tcp->tcp_state = TCP_CLOSED;
961: tcp_dump_state ( tcp );
962: tcp_close ( tcp, -ECONNRESET );
963:
964: DBGC ( tcp, "TCP %p connection reset by peer\n", tcp );
965: return -ECONNRESET;
966: }
967:
968: /**
969: * Enqueue received TCP packet
970: *
971: * @v tcp TCP connection
972: * @v seq SEQ value (in host-endian order)
973: * @v flags TCP flags
974: * @v iobuf I/O buffer
975: */
976: static void tcp_rx_enqueue ( struct tcp_connection *tcp, uint32_t seq,
977: uint8_t flags, struct io_buffer *iobuf ) {
978: struct tcp_rx_queued_header *tcpqhdr;
979: struct io_buffer *queued;
980: size_t len;
981: uint32_t seq_len;
982:
983: /* Calculate remaining flags and sequence length. Note that
984: * SYN, if present, has already been processed by this point.
985: */
986: flags &= TCP_FIN;
987: len = iob_len ( iobuf );
988: seq_len = ( len + ( flags ? 1 : 0 ) );
989:
990: /* Discard immediately (to save memory) if:
991: *
992: * a) we have not yet received a SYN (and so have no defined
993: * receive window), or
994: * b) the packet lies entirely outside the receive window, or
995: * c) there is no further content to process.
996: */
997: if ( ( ! ( tcp->tcp_state & TCP_STATE_RCVD ( TCP_SYN ) ) ) ||
998: ( tcp_cmp ( seq, tcp->rcv_ack + tcp->rcv_win ) >= 0 ) ||
999: ( tcp_cmp ( seq + seq_len, tcp->rcv_ack ) < 0 ) ||
1000: ( seq_len == 0 ) ) {
1001: free_iob ( iobuf );
1002: return;
1003: }
1004:
1005: /* Add internal header */
1006: tcpqhdr = iob_push ( iobuf, sizeof ( *tcpqhdr ) );
1007: tcpqhdr->seq = seq;
1008: tcpqhdr->flags = flags;
1009:
1010: /* Add to RX queue */
1011: list_for_each_entry ( queued, &tcp->rx_queue, list ) {
1012: tcpqhdr = queued->data;
1013: if ( tcp_cmp ( seq, tcpqhdr->seq ) < 0 )
1014: break;
1015: }
1016: list_add_tail ( &iobuf->list, &queued->list );
1017: }
1018:
1019: /**
1020: * Process receive queue
1021: *
1022: * @v tcp TCP connection
1023: */
1024: static void tcp_process_rx_queue ( struct tcp_connection *tcp ) {
1025: struct io_buffer *iobuf;
1026: struct tcp_rx_queued_header *tcpqhdr;
1027: uint32_t seq;
1028: unsigned int flags;
1029: size_t len;
1030:
1031: /* Process all applicable received buffers. Note that we
1032: * cannot use list_for_each_entry() to iterate over the RX
1033: * queue, since tcp_discard() may remove packets from the RX
1034: * queue while we are processing.
1035: */
1036: while ( ( iobuf = list_first_entry ( &tcp->rx_queue, struct io_buffer,
1037: list ) ) ) {
1038:
1039: /* Stop processing when we hit the first gap */
1040: tcpqhdr = iobuf->data;
1041: if ( tcp_cmp ( tcpqhdr->seq, tcp->rcv_ack ) > 0 )
1042: break;
1043:
1044: /* Strip internal header and remove from RX queue */
1045: list_del ( &iobuf->list );
1046: seq = tcpqhdr->seq;
1047: flags = tcpqhdr->flags;
1048: iob_pull ( iobuf, sizeof ( *tcpqhdr ) );
1049: len = iob_len ( iobuf );
1050:
1051: /* Handle new data, if any */
1052: tcp_rx_data ( tcp, seq, iob_disown ( iobuf ) );
1053: seq += len;
1054:
1055: /* Handle FIN, if present */
1056: if ( flags & TCP_FIN ) {
1057: tcp_rx_fin ( tcp, seq );
1058: seq++;
1059: }
1060: }
1061: }
1062:
1063: /**
1064: * Process received packet
1065: *
1066: * @v iobuf I/O buffer
1067: * @v st_src Partially-filled source address
1068: * @v st_dest Partially-filled destination address
1069: * @v pshdr_csum Pseudo-header checksum
1070: * @ret rc Return status code
1071: */
1072: static int tcp_rx ( struct io_buffer *iobuf,
1073: struct sockaddr_tcpip *st_src,
1074: struct sockaddr_tcpip *st_dest __unused,
1075: uint16_t pshdr_csum ) {
1076: struct tcp_header *tcphdr = iobuf->data;
1077: struct tcp_connection *tcp;
1078: struct tcp_options options;
1079: size_t hlen;
1080: uint16_t csum;
1081: uint32_t seq;
1082: uint32_t ack;
1083: uint32_t win;
1084: unsigned int flags;
1085: size_t len;
1086: uint32_t seq_len;
1087: int rc;
1088:
1089: /* Sanity check packet */
1090: if ( iob_len ( iobuf ) < sizeof ( *tcphdr ) ) {
1091: DBG ( "TCP packet too short at %zd bytes (min %zd bytes)\n",
1092: iob_len ( iobuf ), sizeof ( *tcphdr ) );
1093: rc = -EINVAL;
1094: goto discard;
1095: }
1096: hlen = ( ( tcphdr->hlen & TCP_MASK_HLEN ) / 16 ) * 4;
1097: if ( hlen < sizeof ( *tcphdr ) ) {
1098: DBG ( "TCP header too short at %zd bytes (min %zd bytes)\n",
1099: hlen, sizeof ( *tcphdr ) );
1100: rc = -EINVAL;
1101: goto discard;
1102: }
1103: if ( hlen > iob_len ( iobuf ) ) {
1104: DBG ( "TCP header too long at %zd bytes (max %zd bytes)\n",
1105: hlen, iob_len ( iobuf ) );
1106: rc = -EINVAL;
1107: goto discard;
1108: }
1109: csum = tcpip_continue_chksum ( pshdr_csum, iobuf->data,
1110: iob_len ( iobuf ) );
1111: if ( csum != 0 ) {
1112: DBG ( "TCP checksum incorrect (is %04x including checksum "
1113: "field, should be 0000)\n", csum );
1114: rc = -EINVAL;
1115: goto discard;
1116: }
1117:
1118: /* Parse parameters from header and strip header */
1119: tcp = tcp_demux ( ntohs ( tcphdr->dest ) );
1120: seq = ntohl ( tcphdr->seq );
1121: ack = ntohl ( tcphdr->ack );
1122: win = ntohs ( tcphdr->win );
1123: flags = tcphdr->flags;
1124: tcp_rx_opts ( tcp, ( ( ( void * ) tcphdr ) + sizeof ( *tcphdr ) ),
1125: ( hlen - sizeof ( *tcphdr ) ), &options );
1126: if ( options.tsopt )
1127: tcp->ts_val = ntohl ( options.tsopt->tsval );
1128: iob_pull ( iobuf, hlen );
1129: len = iob_len ( iobuf );
1130: seq_len = ( len + ( ( flags & TCP_SYN ) ? 1 : 0 ) +
1131: ( ( flags & TCP_FIN ) ? 1 : 0 ) );
1132:
1133: /* Dump header */
1134: DBGC2 ( tcp, "TCP %p RX %d<-%d %08x %08x..%08x %4zd",
1135: tcp, ntohs ( tcphdr->dest ), ntohs ( tcphdr->src ),
1136: ntohl ( tcphdr->ack ), ntohl ( tcphdr->seq ),
1137: ( ntohl ( tcphdr->seq ) + seq_len ), len );
1138: tcp_dump_flags ( tcp, tcphdr->flags );
1139: DBGC2 ( tcp, "\n" );
1140:
1141: /* If no connection was found, send RST */
1142: if ( ! tcp ) {
1143: tcp_xmit_reset ( tcp, st_src, tcphdr );
1144: rc = -ENOTCONN;
1145: goto discard;
1146: }
1147:
1148: /* Handle ACK, if present */
1149: if ( flags & TCP_ACK ) {
1150: if ( ( rc = tcp_rx_ack ( tcp, ack, win ) ) != 0 ) {
1151: tcp_xmit_reset ( tcp, st_src, tcphdr );
1152: goto discard;
1153: }
1154: }
1155:
1156: /* Force an ACK if this packet is out of order */
1157: if ( ( tcp->tcp_state & TCP_STATE_RCVD ( TCP_SYN ) ) &&
1158: ( seq != tcp->rcv_ack ) ) {
1159: tcp->flags |= TCP_ACK_PENDING;
1160: }
1161:
1162: /* Handle SYN, if present */
1163: if ( flags & TCP_SYN ) {
1164: tcp_rx_syn ( tcp, seq, &options );
1165: seq++;
1166: }
1167:
1168: /* Handle RST, if present */
1169: if ( flags & TCP_RST ) {
1170: if ( ( rc = tcp_rx_rst ( tcp, seq ) ) != 0 )
1171: goto discard;
1172: }
1173:
1174: /* Enqueue received data */
1175: tcp_rx_enqueue ( tcp, seq, flags, iob_disown ( iobuf ) );
1176:
1177: /* Process receive queue */
1178: tcp_process_rx_queue ( tcp );
1179:
1180: /* Dump out any state change as a result of the received packet */
1181: tcp_dump_state ( tcp );
1182:
1183: /* Send out any pending data */
1184: tcp_xmit ( tcp );
1185:
1186: /* If this packet was the last we expect to receive, set up
1187: * timer to expire and cause the connection to be freed.
1188: */
1189: if ( TCP_CLOSED_GRACEFULLY ( tcp->tcp_state ) ) {
1190: stop_timer ( &tcp->wait );
1191: start_timer_fixed ( &tcp->wait, ( 2 * TCP_MSL ) );
1192: }
1193:
1194: return 0;
1195:
1196: discard:
1197: /* Free received packet */
1198: free_iob ( iobuf );
1199: return rc;
1200: }
1201:
1202: /** TCP protocol */
1203: struct tcpip_protocol tcp_protocol __tcpip_protocol = {
1204: .name = "TCP",
1205: .rx = tcp_rx,
1206: .tcpip_proto = IP_TCP,
1207: };
1208:
1209: /**
1210: * Discard some cached TCP data
1211: *
1212: * @ret discarded Number of cached items discarded
1213: */
1214: static unsigned int tcp_discard ( void ) {
1215: struct tcp_connection *tcp;
1216: struct io_buffer *iobuf;
1217: unsigned int discarded = 0;
1218:
1219: /* Try to drop one queued RX packet from each connection */
1220: list_for_each_entry ( tcp, &tcp_conns, list ) {
1221: list_for_each_entry_reverse ( iobuf, &tcp->rx_queue, list ) {
1222: list_del ( &iobuf->list );
1223: free_iob ( iobuf );
1224: discarded++;
1225: break;
1226: }
1227: }
1228:
1229: return discarded;
1230: }
1231:
1232: /** TCP cache discarder */
1233: struct cache_discarder tcp_cache_discarder __cache_discarder = {
1234: .discard = tcp_discard,
1235: };
1236:
1237: /***************************************************************************
1238: *
1239: * Data transfer interface
1240: *
1241: ***************************************************************************
1242: */
1243:
1244: /**
1245: * Close interface
1246: *
1247: * @v tcp TCP connection
1248: * @v rc Reason for close
1249: */
1250: static void tcp_xfer_close ( struct tcp_connection *tcp, int rc ) {
1251:
1252: /* Close data transfer interface */
1253: tcp_close ( tcp, rc );
1254:
1255: /* Transmit FIN, if possible */
1256: tcp_xmit ( tcp );
1257: }
1258:
1259: /**
1260: * Check flow control window
1261: *
1262: * @v tcp TCP connection
1263: * @ret len Length of window
1264: */
1265: static size_t tcp_xfer_window ( struct tcp_connection *tcp ) {
1266:
1267: /* Not ready if data queue is non-empty. This imposes a limit
1268: * of only one unACKed packet in the TX queue at any time; we
1269: * do this to conserve memory usage.
1270: */
1271: if ( ! list_empty ( &tcp->tx_queue ) )
1272: return 0;
1273:
1274: /* Return TCP window length */
1275: return tcp_xmit_win ( tcp );
1276: }
1277:
1278: /**
1279: * Deliver datagram as I/O buffer
1280: *
1281: * @v tcp TCP connection
1282: * @v iobuf Datagram I/O buffer
1283: * @v meta Data transfer metadata
1284: * @ret rc Return status code
1285: */
1286: static int tcp_xfer_deliver ( struct tcp_connection *tcp,
1287: struct io_buffer *iobuf,
1288: struct xfer_metadata *meta __unused ) {
1289:
1290: /* Enqueue packet */
1291: list_add_tail ( &iobuf->list, &tcp->tx_queue );
1292:
1293: /* Transmit data, if possible */
1294: tcp_xmit ( tcp );
1295:
1296: return 0;
1297: }
1298:
1299: /** TCP data transfer interface operations */
1300: static struct interface_operation tcp_xfer_operations[] = {
1301: INTF_OP ( xfer_deliver, struct tcp_connection *, tcp_xfer_deliver ),
1302: INTF_OP ( xfer_window, struct tcp_connection *, tcp_xfer_window ),
1303: INTF_OP ( intf_close, struct tcp_connection *, tcp_xfer_close ),
1304: };
1305:
1306: /** TCP data transfer interface descriptor */
1307: static struct interface_descriptor tcp_xfer_desc =
1308: INTF_DESC ( struct tcp_connection, xfer, tcp_xfer_operations );
1309:
1310: /***************************************************************************
1311: *
1312: * Openers
1313: *
1314: ***************************************************************************
1315: */
1316:
1317: /** TCP socket opener */
1318: struct socket_opener tcp_socket_opener __socket_opener = {
1319: .semantics = TCP_SOCK_STREAM,
1320: .family = AF_INET,
1321: .open = tcp_open,
1322: };
1323:
1324: /** Linkage hack */
1325: int tcp_sock_stream = TCP_SOCK_STREAM;
1326:
1327: /**
1328: * Open TCP URI
1329: *
1330: * @v xfer Data transfer interface
1331: * @v uri URI
1332: * @ret rc Return status code
1333: */
1334: static int tcp_open_uri ( struct interface *xfer, struct uri *uri ) {
1335: struct sockaddr_tcpip peer;
1336:
1337: /* Sanity check */
1338: if ( ! uri->host )
1339: return -EINVAL;
1340:
1341: memset ( &peer, 0, sizeof ( peer ) );
1342: peer.st_port = htons ( uri_port ( uri, 0 ) );
1343: return xfer_open_named_socket ( xfer, SOCK_STREAM,
1344: ( struct sockaddr * ) &peer,
1345: uri->host, NULL );
1346: }
1347:
1348: /** TCP URI opener */
1349: struct uri_opener tcp_uri_opener __uri_opener = {
1350: .scheme = "tcp",
1351: .open = tcp_open_uri,
1352: };
1353:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.