/* * barebox RATP implementation. * This is the barebox implementation for the Reliable Asynchronous * Transfer Protocol (RATP) as described in RFC916. * * Copyright (C) 2015 Pengutronix, Sascha Hauer * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #define pr_fmt(fmt) "ratp: " fmt #include #include #include #include #include #include #include /* * RATP packet format: * * Byte No. * * +-------------------------------+ * | | * 1 | Synch Leader | Hex 01 * | | * +-------------------------------+ * | S | A | F | R | S | A | E | S | * 2 | Y | C | I | S | N | N | O | O | Control * | N | K | N | T | | | R | | * +-------------------------------+ * | | * 3 | Data length (0-255) | * | | * +-------------------------------+ * | | * 4 | Header Checksum | * | | * +-------------------------------+ * */ struct ratp_header { uint8_t synch; uint8_t control; uint8_t data_length; uint8_t cksum; }; #define RATP_CONTROL_SO (1 << 0) #define RATP_CONTROL_EOR (1 << 1) #define RATP_CONTROL_AN (1 << 2) #define RATP_CONTROL_SN (1 << 3) #define RATP_CONTROL_RST (1 << 4) #define RATP_CONTROL_FIN (1 << 5) #define RATP_CONTROL_ACK (1 << 6) #define RATP_CONTROL_SYN (1 << 7) enum ratp_state { RATP_STATE_LISTEN, RATP_STATE_SYN_SENT, RATP_STATE_SYN_RECEIVED, RATP_STATE_ESTABLISHED, RATP_STATE_FIN_WAIT, RATP_STATE_LAST_ACK, RATP_STATE_CLOSING, RATP_STATE_TIME_WAIT, RATP_STATE_CLOSED, }; struct ratp_message { void *buf; size_t len; struct list_head list; void (*complete)(void *ctx, int status); void *complete_ctx; int eor; }; static char *ratp_state_str[] = { [RATP_STATE_LISTEN] = "LISTEN", [RATP_STATE_SYN_SENT] = "SYN_SENT", [RATP_STATE_SYN_RECEIVED] = "SYN_RECEIVED", [RATP_STATE_ESTABLISHED] = "ESTABLISHED", [RATP_STATE_FIN_WAIT] = "FIN_WAIT", [RATP_STATE_LAST_ACK] = "LAST_ACK", [RATP_STATE_CLOSING] = "CLOSING", [RATP_STATE_TIME_WAIT] = "TIME_WAIT", [RATP_STATE_CLOSED] = "CLOSED", }; struct ratp_internal { struct ratp *ratp; enum ratp_state state; int sn_sent; int sn_received; int active; void *recvbuf; void *sendbuf; int sendbuf_len; struct list_head recvmsg; struct list_head sendmsg; struct ratp_message *sendmsg_current; uint64_t timewait_timer_start; uint64_t retransmission_timer_start; int max_retransmission; int retransmission_count; int srtt; int rto; int status; int in_ratp; }; static bool ratp_sn(struct ratp_header *hdr) { return hdr->control & RATP_CONTROL_SN ? 1 : 0; } static bool ratp_an(struct ratp_header *hdr) { return hdr->control & RATP_CONTROL_AN ? 1 : 0; } #define ratp_set_sn(sn) (sn ? RATP_CONTROL_SN : 0) #define ratp_set_an(an) (an ? RATP_CONTROL_AN : 0) #define ratp_set_next_sn(sn) (((sn + 1) % 2) ? RATP_CONTROL_SN : 0) #define ratp_set_next_an(an) (((an + 1) % 2) ? RATP_CONTROL_AN : 0) static inline int ratp_header_ok(struct ratp_internal *ri, struct ratp_header *h) { uint8_t cksum; int ret; cksum = h->control; cksum += h->data_length; cksum += h->cksum; ret = cksum == 0xff ? 1 : 0; if (ret) pr_vdebug("Header ok\n"); else pr_vdebug("Header cksum failed: %02x\n", cksum); return ret; } static bool ratp_has_data(struct ratp_header *hdr) { if (hdr->control & RATP_CONTROL_SO) return 1; if (!(hdr->control & (RATP_CONTROL_SYN | RATP_CONTROL_RST | RATP_CONTROL_FIN)) && hdr->data_length) return 1; return 0; } static void ratp_print_header(struct ratp_internal *ri, struct ratp_header *hdr, const char *prefix) { uint8_t control = hdr->control; pr_debug("%s>%s %s %s %s %s %s %s %s< len: %-3d\n", prefix, control & RATP_CONTROL_SO ? "so" : "--", control & RATP_CONTROL_EOR ? "eor" : "---", control & RATP_CONTROL_AN ? "an" : "--", control & RATP_CONTROL_SN ? "sn" : "--", control & RATP_CONTROL_RST ? "rst" : "---", control & RATP_CONTROL_FIN ? "fin" : "---", control & RATP_CONTROL_ACK ? "ack" : "---", control & RATP_CONTROL_SYN ? "syn" : "---", hdr->data_length); #ifdef VERBOSE_DEBUG if (hdr->data_length) memory_display(hdr + 1, 0, hdr->data_length, 1, 0); #endif } static void ratp_create_packet(struct ratp_internal *ri, struct ratp_header *hdr, uint8_t control, uint8_t length) { hdr->synch = 0x1; hdr->control = control; hdr->data_length = length; hdr->cksum = (control + length) ^ 0xff; } static void ratp_state_change(struct ratp_internal *ri, enum ratp_state state) { pr_debug("state %-10s -> %-10s\n", ratp_state_str[ri->state], ratp_state_str[state]); ri->state = state; } #define RATP_CONTROL_SO (1 << 0) #define RATP_CONTROL_EOR (1 << 1) #define RATP_CONTROL_AN (1 << 2) #define RATP_CONTROL_SN (1 << 3) #define RATP_CONTROL_RST (1 << 4) #define RATP_CONTROL_FIN (1 << 5) #define RATP_CONTROL_ACK (1 << 6) #define RATP_CONTROL_SYN (1 << 7) static int ratp_send_pkt(struct ratp_internal *ri, void *pkt, int length) { struct ratp_header *hdr = (void *)pkt; ratp_print_header(ri, hdr, "send"); if (ratp_has_data(hdr) || (hdr->control & (RATP_CONTROL_SYN | RATP_CONTROL_RST | RATP_CONTROL_FIN))) { memcpy(ri->sendbuf, pkt, length); ri->sn_sent = ratp_sn(hdr); ri->sendbuf_len = length; ri->retransmission_timer_start = get_time_ns(); ri->retransmission_count = 0; } return ri->ratp->send(ri->ratp, pkt, length); } static int ratp_send_hdr(struct ratp_internal *ri, uint8_t control) { struct ratp_header hdr = {}; ratp_create_packet(ri, &hdr, control, 0); return ratp_send_pkt(ri, &hdr, sizeof(hdr)); } static int ratp_recv_char(struct ratp_internal *ri, uint8_t *data, int poll_timeout_ms) { uint64_t start; int ret; start = get_time_ns(); while (1) { ret = ri->ratp->recv(ri->ratp, data); if (ret < 0 && ret != -EAGAIN) return ret; if (ret == 0) return 0; if (is_timeout(start, poll_timeout_ms * MSECOND)) return -EAGAIN; } } static int ratp_recv_pkt_header(struct ratp_internal *ri, struct ratp_header *hdr, int poll_timeout_ms) { int ret; uint8_t buf; do { ret = ratp_recv_char(ri, &buf, 0); if (ret < 0) return ret; hdr->synch = buf; } while (hdr->synch != 1); ret = ratp_recv_char(ri, &buf, poll_timeout_ms); if (ret < 0) return ret; hdr->control = buf; ret = ratp_recv_char(ri, &buf, poll_timeout_ms); if (ret < 0) return ret; hdr->data_length = buf; ret = ratp_recv_char(ri, &buf, poll_timeout_ms); if (ret < 0) return ret; hdr->cksum = buf; if (!ratp_header_ok(ri, hdr)) return -EAGAIN; return 0; } static int ratp_recv_pkt_data(struct ratp_internal *ri, void *data, uint8_t len, int poll_timeout_ms) { uint16_t crc_expect, crc_read; int ret, i; for (i = 0; i < len + 2; i++) { ret = ratp_recv_char(ri, data + i, poll_timeout_ms); if (ret < 0) return ret; } crc_expect = crc_itu_t(0, data, len); crc_read = get_unaligned_be16(data + len); if (crc_expect != crc_read) { pr_vdebug("Wrong CRC: expected: 0x%04x, got 0x%04x\n", crc_expect, crc_read); return -EBADMSG; } else { pr_vdebug("correct CRC: 0x%04x\n", crc_expect); } return 0; } static int ratp_recv_pkt(struct ratp_internal *ri, void *pkt, int poll_timeout_ms) { struct ratp_header *hdr = pkt; void *data = pkt + sizeof(struct ratp_header); int ret; ret = ratp_recv_pkt_header(ri, hdr, poll_timeout_ms); if (ret < 0) return ret; if (hdr->control & (RATP_CONTROL_SO | RATP_CONTROL_RST | RATP_CONTROL_SYN | RATP_CONTROL_FIN)) return 0; if (hdr->data_length) { ret = ratp_recv_pkt_data(ri, data, hdr->data_length, poll_timeout_ms); if (ret) return ret; } return 0; } static bool ratp_an_expected(struct ratp_internal *ri, struct ratp_header *hdr) { return ratp_an(hdr) == (ri->sn_sent + 1) % 2; } static bool ratp_sn_expected(struct ratp_internal *ri, struct ratp_header *hdr) { return ratp_sn(hdr) == (ri->sn_received + 1) % 2; } static int ratp_send_ack(struct ratp_internal *ri, struct ratp_header *hdr) { uint8_t control; int ret; control = ratp_set_sn(ratp_an(hdr)) | ratp_set_next_an(ratp_sn(hdr)) | RATP_CONTROL_ACK; ret = ratp_send_hdr(ri, control); if (ret) return ret; return 0; } static int ratp_send_next_data(struct ratp_internal *ri) { uint16_t crc; uint8_t control; struct ratp_header *hdr; uint8_t *data; int pktlen; struct ratp_message *msg; int len; if (ri->sendmsg_current) { pr_err("%s: busy\n", __func__); return -EBUSY; } if (list_empty(&ri->sendmsg)) return 0; msg = list_first_entry(&ri->sendmsg, struct ratp_message, list); ri->sendmsg_current = msg; list_del(&msg->list); len = msg->len; control = ratp_set_next_sn(ri->sn_sent) | ratp_set_next_an(ri->sn_received) | RATP_CONTROL_ACK; hdr = msg->buf; data = (uint8_t *)(hdr + 1); if (msg->eor) control |= RATP_CONTROL_EOR; pktlen = sizeof(struct ratp_header); if (len > 1) { pktlen += len + 2; crc = crc_itu_t(0, data, len); put_unaligned_be16(crc, data + len); } else if (len == 1) { control |= RATP_CONTROL_SO; len = *data; } ratp_create_packet(ri, hdr, control, len); ri->retransmission_count = 0; ratp_send_pkt(ri, msg->buf, pktlen); return 0; } static void ratp_start_time_wait_timer(struct ratp_internal *ri) { ri->timewait_timer_start = get_time_ns(); } static void ratp_msg_done(struct ratp_internal *ri, struct ratp_message *msg, int status) { int alpha, beta, rtt; if (!status) { rtt = (unsigned long)(get_time_ns() - ri->retransmission_timer_start) / MSECOND; alpha = 8; beta = 15; ri->srtt = (alpha * ri->srtt + (10 - alpha) * rtt) / 10; ri->rto = max(200, beta * ri->srtt / 10); pr_debug("%s: done. SRTT: %dms RTO: %dms status: %d\n", __func__, ri->srtt, ri->rto, ri->status); } if (msg->complete) msg->complete(msg->complete_ctx, status); free(msg->buf); free(msg); } /* * This procedure details the behavior of the LISTEN state. First * check the packet for the RST flag. If it is set then packet is * discarded and ignored, return and continue the processing * associated with this state. * * We assume now that the RST flag was not set. Check the packet * for the ACK flag. If it is set we have an illegal condition * since no connection has yet been opened. Send a RST packet * with the correct response SN value: * * * * Return to the current state without any further processing. * * We assume now that neither the RST nor the ACK flags were set. * Check the packet for a SYN flag. If it is set then an attempt * is being made to open a connection. Create a TCB for this * connection. The sender has placed its MDL in the LENGTH field, * also specified is the sender's initial SN value. Retrieve and * place them into the TCB. Note that the presence of the SO flag * is ignored since it has no meaning when either of the SYN, RST, * or FIN flags are set. * * Send a SYN packet which acknowledges the SYN received. Choose * the initial SN value and the MDL for this end of the * connection: * * * * and go to the RATP_STATE_SYN_RECEIVED state without any further * processing. * * Any packet not satisfying the above tests is discarded and * ignored. Return to the current state without any further * processing. */ static void ratp_behaviour_a(struct ratp_internal *ri, void *pkt) { struct ratp_header *hdr = pkt; pr_debug("%s\n", __func__); if (hdr->control & RATP_CONTROL_RST) return; if (hdr->control & RATP_CONTROL_ACK) { uint8_t control = RATP_CONTROL_RST; if (hdr->control & RATP_CONTROL_AN) control |= RATP_CONTROL_SN; ratp_send_hdr(ri, control); return; } if (hdr->control & RATP_CONTROL_SYN) { struct ratp_header synack = {}; uint8_t control = RATP_CONTROL_SYN | RATP_CONTROL_ACK; if (!(hdr->control & RATP_CONTROL_SN)) control |= RATP_CONTROL_AN; ratp_create_packet(ri, &synack, control, 255); ratp_send_pkt(ri, &synack, sizeof(synack)); ratp_state_change(ri, RATP_STATE_SYN_RECEIVED); } } /* * This procedure represents the behavior of the SYN-SENT state * and is entered when this end of the connection decides to * execute an active OPEN. * * First, check the packet for the ACK flag. If the ACK flag is * set then check to see if the AN value was as expected. If it * was continue below. Otherwise the AN value was unexpected. If * the RST flag was set then discard the packet and return to the * current state without any further processing, else send a * reset: * * * * Discard the packet and return to the current state without any * further processing. * * At this point either the ACK flag was set and the AN value was * as expected or ACK was not set. Second, check the RST flag. * If the RST flag is set there are two cases: * * . If the ACK flag is set then discard the packet, flush the * retransmission queue, inform the user "Error: Connection * refused", delete the TCB, and go to the CLOSED state without * any further processing. * * 2. If the ACK flag was not set then discard the packet and * return to this state without any further processing. * * At this point we assume the packet contained an ACK which was * Ok, or there was no ACK, and there was no RST. Now check the * packet for the SYN flag. If the ACK flag was set then our SYN * has been acknowledged. Store MDL received in the TCB. At this * point we are technically in the ESTABLISHED state. Send an * acknowledgment packet and any initial data which is queued to * send: * * * * Go to the ESTABLISHED state without any further processing. * * If the SYN flag was set but the ACK was not set then the other * end of the connection has executed an active open also. * Acknowledge the SYN, choose your MDL, and send: * * * * Go to the SYN-RECEIVED state without any further processing. * * Any packet not satisfying the above tests is discarded and * ignored. Return to the current state without any further * processing. */ static void ratp_behaviour_b(struct ratp_internal *ri, void *pkt) { struct ratp_header *hdr = pkt; pr_debug("%s\n", __func__); if ((hdr->control & RATP_CONTROL_ACK) && !ratp_an_expected(ri, hdr)) { if (!(hdr->control & RATP_CONTROL_RST)) { uint8_t control; control = RATP_CONTROL_RST | ratp_set_sn(ratp_an(hdr)); ratp_send_hdr(ri, control); } return; } if (hdr->control & RATP_CONTROL_RST) { if (hdr->control & RATP_CONTROL_ACK) { ri->status = -ECONNREFUSED; pr_debug("Connection refused\n"); ratp_state_change(ri, RATP_STATE_CLOSED); } return; } if (hdr->control & RATP_CONTROL_SYN) { uint8_t control; ri->sn_received = ratp_sn(hdr); if (hdr->control & RATP_CONTROL_ACK) { ratp_state_change(ri, RATP_STATE_ESTABLISHED); if (list_empty(&ri->sendmsg) || ri->sendmsg_current) ratp_send_ack(ri, hdr); else ratp_send_next_data(ri); } else { struct ratp_header synack = {}; control = ratp_set_next_an(ratp_sn(hdr)) | RATP_CONTROL_SYN | RATP_CONTROL_ACK; ratp_create_packet(ri, &synack, control, 255); ratp_send_pkt(ri, &synack, sizeof(synack)); ratp_state_change(ri, RATP_STATE_SYN_RECEIVED); } } } /* * Examine the received SN field value. If the SN value was * expected then return and continue the processing associated * with this state. * * We now assume the SN value was not what was expected. * * If either RST or FIN were set discard the packet and return to * the current state without any further processing. * * If neither RST nor FIN flags were set it is assumed that this * packet is a duplicate of one already received. Send an ACK * back: * * * * Discard the duplicate packet and return to the current state * without any further processing. */ static int ratp_behaviour_c1(struct ratp_internal *ri, void *pkt) { struct ratp_header *hdr = pkt; int ret; pr_debug("%s\n", __func__); if (ratp_sn_expected(ri, hdr)) { pr_vdebug("%s: sn is expected\n", __func__); return 0; } if (!(hdr->control & RATP_CONTROL_RST) && !(hdr->control & RATP_CONTROL_FIN)) { ret = ratp_send_ack(ri, hdr); if (ret) return ret; } return 1; } /* * Examine the received SN field value. If the SN value was * expected then return and continue the processing associated * with this state. * * We now assume the SN value was not what was expected. * * If either RST or FIN were set discard the packet and return to * the current state without any further processing. * * If SYN was set we assume that the other end crashed and has * attempted to open a new connection. We respond by sending a * legal reset: * * * * This will cause the other end, currently in the SYN-SENT state, * to close. Flush the retransmission queue, inform the user * "Error: Connection reset", discard the packet, delete the TCB, * and go to the CLOSED state without any further processing. * * If neither RST, FIN, nor SYN flags were set it is assumed that * this packet is a duplicate of one already received. Send an * ACK back: * * * * Discard the duplicate packet and return to the current state * without any further processing. */ static int ratp_behaviour_c2(struct ratp_internal *ri, void *pkt) { struct ratp_header *hdr = pkt; int ret; pr_debug("%s\n", __func__); if (ratp_sn_expected(ri, hdr)) return 0; if ((hdr->control & RATP_CONTROL_RST) || (hdr->control & RATP_CONTROL_FIN)) return 1; if (hdr->control & RATP_CONTROL_SYN) { uint8_t control; ri->status = -ECONNRESET; pr_debug("Error: Connection reset\n"); control = RATP_CONTROL_RST | RATP_CONTROL_ACK | ratp_set_sn(ratp_an(hdr)) | ratp_set_next_an(ratp_sn(hdr)); ratp_send_hdr(ri, control); ratp_state_change(ri, RATP_STATE_CLOSED); return 1; } pr_debug("Sending ack for duplicate message\n"); ret = ratp_send_ack(ri, hdr); if (ret) return ret; return 1; } /* * The packet is examined for a RST flag. If RST is not set then * return and continue the processing associated with this state. * * RST is now assumed to have been set. If the connection was * originally initiated from the LISTEN state (it was passively * opened) then flush the retransmission queue, discard the * packet, and go to the LISTEN state without any further * processing. * * If instead the connection was initiated actively (came from the * SYN-SENT state) then flush the retransmission queue, inform the * user "Error: Connection refused", discard the packet, delete * the TCB, and go to the CLOSED state without any further * processing. */ static int ratp_behaviour_d1(struct ratp_internal *ri, void *pkt) { struct ratp_header *hdr = pkt; pr_debug("%s\n", __func__); if (!(hdr->control & RATP_CONTROL_RST)) return 0; if (!(ri->active)) { ratp_state_change(ri, RATP_STATE_LISTEN); return 1; } ri->status = -ECONNREFUSED; pr_debug("Error: connection refused\n"); ratp_state_change(ri, RATP_STATE_CLOSED); return 1; } /* * The packet is examined for a RST flag. If RST is not set then * return and continue the processing associated with this state. * * RST is now assumed to have been set. Any data remaining to be * sent is flushed. The retransmission queue is flushed, the user * is informed "Error: Connection reset.", discard the packet, * delete the TCB, and go to the CLOSED state without any further * processing. */ static int ratp_behaviour_d2(struct ratp_internal *ri, void *pkt) { struct ratp_header *hdr = pkt; pr_debug("%s\n", __func__); if (!(hdr->control & RATP_CONTROL_RST)) return 0; ri->status = -ECONNRESET; pr_debug("connection reset\n"); return 0; } /* * The packet is examined for a RST flag. If RST is not set then * return and continue the processing associated with this state. * * RST is now assumed to have been set. Discard the packet, * delete the TCB, and go to the CLOSED state without any further * processing. */ static int ratp_behaviour_d3(struct ratp_internal *ri, void *pkt) { struct ratp_header *hdr = pkt; pr_debug("%s\n", __func__); if (!(hdr->control & RATP_CONTROL_RST)) return 0; ratp_state_change(ri, RATP_STATE_CLOSED); return 1; } /* * Check the presence of the SYN flag. If the SYN flag is not set * then return and continue the processing associated with this * state. * * We now assume that the SYN flag was set. The presence of a SYN * here is an error. Flush the retransmission queue, send a legal * RST packet. * * If the ACK flag was set then send: * * * * If the ACK flag was not set then send: * * * * The user should receive the message "Error: Connection reset.", * then delete the TCB and go to the CLOSED state without any * further processing. */ static int ratp_behaviour_e(struct ratp_internal *ri, void *pkt) { struct ratp_header *hdr = pkt; uint8_t control; pr_debug("%s\n", __func__); if (!(hdr->control & RATP_CONTROL_SYN)) return 0; ri->status = -ECONNRESET; control = RATP_CONTROL_RST; if (hdr->control & RATP_CONTROL_ACK) control |= ratp_set_sn(ratp_an(hdr)); ratp_send_hdr(ri, control); pr_debug("connection reset\n"); ratp_state_change(ri, RATP_STATE_CLOSED); return 1; } /* * Check the presence of the ACK flag. If ACK is not set then * discard the packet and return without any further processing. * * We now assume that the ACK flag was set. If the AN field value * was as expected then return and continue the processing * associated with this state. * * We now assume that the ACK flag was set and that the AN field * value was unexpected. If the connection was originally * initiated from the LISTEN state (it was passively opened) then * flush the retransmission queue, discard the packet, and send a * legal RST packet: * * * * Then delete the TCB and go to the LISTEN state without any * further processing. * * Otherwise the connection was initiated actively (came from the * SYN-SENT state) then inform the user "Error: Connection * refused", flush the retransmission queue, discard the packet, * and send a legal RST packet: * * * * Then delete the TCB and go to the CLOSED state without any * further processing. */ static int ratp_behaviour_f1(struct ratp_internal *ri, void *pkt) { struct ratp_header *hdr = pkt; uint8_t control; pr_debug("%s\n", __func__); if (!(hdr->control & RATP_CONTROL_ACK)) return 1; if (ratp_an_expected(ri, hdr)) return 0; control = RATP_CONTROL_RST | ratp_set_sn(ratp_an(hdr)); ratp_send_hdr(ri, control); if (ri->active) { ratp_state_change(ri, RATP_STATE_CLOSED); ri->status = -ECONNREFUSED; pr_debug("connection refused\n"); } else { ratp_state_change(ri, RATP_STATE_LISTEN); } return 1; } /* * Check the presence of the ACK flag. If ACK is not set then * discard the packet and return without any further processing. * * We now assume that the ACK flag was set. If the AN field value * was as expected then flush the retransmission queue and inform * the user with an "Ok" if a buffer has been entirely * acknowledged. Another packet containing data may now be sent. * Return and continue the processing associated with this state. * * We now assume that the ACK flag was set and that the AN field * value was unexpected. This is assumed to indicate a duplicate * acknowledgment. It is ignored, return and continue the * processing associated with this state. */ static int ratp_behaviour_f2(struct ratp_internal *ri, void *pkt) { struct ratp_header *hdr = pkt; pr_debug("%s\n", __func__); if (!(hdr->control & RATP_CONTROL_ACK)) return 1; if (ratp_an_expected(ri, hdr)) { pr_debug("Data succesfully sent\n"); if (ri->sendmsg_current) ratp_msg_done(ri, ri->sendmsg_current, 0); ri->sendmsg_current = NULL; return 0; } else { pr_vdebug("%s: an not expected\n", __func__); } return 0; } /* * Check the presence of the ACK flag. If ACK is not set then * discard the packet and return without any further processing. * * We now assume that the ACK flag was set. If the AN field value * was as expected then continue the processing associated with * this state. * * We now assume that the ACK flag was set and that the AN field * value was unexpected. This is ignored, return and continue * with the processing associated with this state. */ static int ratp_behaviour_f3(struct ratp_internal *ri, void *pkt) { struct ratp_header *hdr = pkt; pr_debug("%s\n", __func__); if (!(hdr->control & RATP_CONTROL_ACK)) return 1; return 0; } /* * This procedure represents the behavior of the CLOSED state of a * connection. All incoming packets are discarded. If the packet * had the RST flag set take no action. Otherwise it is necessary * to build a RST packet. Since this end is closed the other end * of the connection has incorrect data about the state of the * connection and should be so informed. * * If the ACK flag was set then send: * * * * If the ACK flag was not set then send: * * * * After sending the reset packet return to the current state * without any further processing. */ static int ratp_behaviour_g(struct ratp_internal *ri, void *pkt) { struct ratp_header *hdr = pkt; uint8_t control; pr_debug("%s\n", __func__); if (hdr->control & RATP_CONTROL_RST) return 0; control = RATP_CONTROL_RST; if (hdr->control & RATP_CONTROL_ACK) control |= ratp_set_sn(ratp_an(hdr)); else control |= ratp_set_next_an(ratp_sn(hdr)) | RATP_CONTROL_ACK; ratp_send_hdr(ri, control); return 0; } static int ratp_behaviour_i1(struct ratp_internal *ri, void *pkt); /* * Our SYN has been acknowledged. At this point we are * technically in the ESTABLISHED state. Send any initial data * which is queued to send: * * * * Go to the ESTABLISHED state and execute procedure I1 to process * any data which might be in this packet. * * Any packet not satisfying the above tests is discarded and * ignored. Return to the current state without any further * processing. */ static int ratp_behaviour_h1(struct ratp_internal *ri, void *pkt) { pr_debug("%s\n", __func__); ratp_state_change(ri, RATP_STATE_ESTABLISHED); /* If the input message has data (i.e. it is not just an ACK * without data) then we need to send back an ACK ourselves, * or even data if we have it pending. This is the same * procedure done in i1, so just run it. */ return ratp_behaviour_i1 (ri, pkt); } /* * Check the presence of the FIN flag. If FIN is not set then * continue the processing associated with this state. * * We now assume that the FIN flag was set. This means the other * end has decided to close the connection. Flush the * retransmission queue. If any data remains to be sent then * inform the user "Warning: Data left unsent." The user must * also be informed "Connection closing." An acknowledgment for * the FIN must be sent which also indicates this end is closing: * * * * Go to the LAST-ACK state without any further processing. */ static int ratp_behaviour_h2(struct ratp_internal *ri, void *pkt) { struct ratp_header *hdr = pkt; uint8_t control; pr_debug("%s\n", __func__); if (!(hdr->control & RATP_CONTROL_FIN)) return 0; ri->status = -ENETDOWN; control = ratp_set_sn(ratp_an(hdr)) | ratp_set_next_an(ratp_sn(hdr)) | RATP_CONTROL_FIN | RATP_CONTROL_ACK; ratp_send_hdr(ri, control); ratp_state_change(ri, RATP_STATE_LAST_ACK); ri->sn_received = ratp_sn(hdr); return 1; } /* * This state represents the final behavior of the FIN-WAIT state. * * If the packet did not contain a FIN we assume this packet is a * duplicate and that the other end of the connection has not seen * the FIN packet we sent earlier. Rely upon retransmission of * our earlier FIN packet to inform the other end of our desire to * close. Discard the packet and return without any further * processing. * * At this point we have a packet which should contain a FIN. By * the rules of this protocol an ACK of a FIN requires a FIN, ACK * in response and no data. If the packet contains data we have * detected an illegal condition. Send a reset: * * * Discard the packet, flush the retransmission queue, inform the * ser "Error: Connection reset.", delete the TCB, and go to the * CLOSED state without any further processing. * * We now assume that the FIN flag was set and no data was * contained in the packet. If the AN field value was expected * then this packet acknowledges a previously sent FIN packet. * The other end of the connection is then also assumed to be * closing and expects an acknowledgment. Send an acknowledgment * of the FIN: * * * * Start the 2*SRTT timer associated with the TIME-WAIT state, * discard the packet, and go to the TIME-WAIT state without any * further processing. * * Otherwise the AN field value was unexpected. This indicates a * simultaneous closing by both sides of the connection. Send an * acknowledgment of the FIN: * * * * Discard the packet, and go to the CLOSING state without any * further processing. */ static int ratp_behaviour_h3(struct ratp_internal *ri, void *pkt) { struct ratp_header *hdr = pkt; uint8_t control; int expected; pr_debug("%s\n", __func__); if (!(hdr->control & RATP_CONTROL_FIN)) return 1; if (ratp_has_data(hdr)) { control = ratp_set_sn(ratp_an(hdr)) | ratp_set_next_an(ratp_sn(hdr)) | RATP_CONTROL_RST | RATP_CONTROL_ACK; ratp_send_hdr(ri, control); ri->status = -ECONNRESET; pr_debug("Error: Connection reset\n"); ratp_state_change(ri, RATP_STATE_CLOSED); return 1; } control = ratp_set_sn(ratp_an(hdr)) | ratp_set_next_an(ratp_sn(hdr)) | RATP_CONTROL_ACK; expected = ratp_an_expected(ri, hdr); ratp_send_hdr(ri, control); if (expected) { ratp_state_change(ri, RATP_STATE_TIME_WAIT); ratp_start_time_wait_timer(ri); } else { ratp_state_change(ri, RATP_STATE_CLOSING); } return 1; } /* * This state represents the final behavior of the LAST-ACK state. * * If the AN field value is expected then this ACK is in response * to the FIN, ACK packet recently sent. This is the final * acknowledging message indicating both side's agreement to close * the connection. Discard the packet, flush all queues, delete * the TCB, and go to the CLOSED state without any further * processing. * * Otherwise the AN field value was unexpected. Discard the * packet and remain in the current state without any further * processing. */ static int ratp_behaviour_h4(struct ratp_internal *ri, void *pkt) { struct ratp_header *hdr = pkt; pr_debug("%s\n", __func__); if (ratp_an_expected(ri, hdr)) ratp_state_change(ri, RATP_STATE_CLOSED); return 1; } /* * This state represents the final behavior of the CLOSING state. * * If the AN field value was expected then this packet * acknowledges the FIN packet recently sent. This is the final * acknowledging message indicating both side's agreement to close * the connection. Start the 2*SRTT timer associated with the * TIME-WAIT state, discard the packet, and go to the TIME-WAIT * state without any further processing. * * Otherwise the AN field value was unexpected. Discard the * packet and remain in the current state without any further * processing. */ static int ratp_behaviour_h5(struct ratp_internal *ri, void *pkt) { struct ratp_header *hdr = pkt; pr_debug("%s\n", __func__); if (ratp_an_expected(ri, hdr)) { ratp_state_change(ri, RATP_STATE_TIME_WAIT); ratp_start_time_wait_timer(ri); } return 0; } /* * This state represents the behavior of the TIME-WAIT state. * Check the presence of the ACK flag. If ACK is not set then * discard the packet and return without any further processing. * * Check the presence of the FIN flag. If FIN is not set then * discard the packet and return without any further processing. * * We now assume that the FIN flag was set. This situation * indicates that the last acknowledgment of the FIN packet sent * by the other end of the connection did not arrive. Resend the * acknowledgment: * * * * Restart the 2*SRTT timer, discard the packet, and remain in the * current state without any further processing. */ static int ratp_behaviour_h6(struct ratp_internal *ri, void *pkt) { struct ratp_header *hdr = pkt; uint8_t control; pr_debug("%s\n", __func__); if (!(hdr->control & RATP_CONTROL_ACK)) return 1; if (!(hdr->control & RATP_CONTROL_FIN)) return 1; control = ratp_set_next_sn(ratp_an(hdr)) | RATP_CONTROL_ACK; ratp_send_hdr(ri, control); ratp_start_time_wait_timer(ri); return 0; } static int msg_recv(struct ratp_internal *ri, void *pkt) { struct ratp_header *hdr = pkt; struct ratp_message *msg; pr_debug("%s: Put msg in receive queue\n", __func__); msg = xzalloc(sizeof(*msg)); if (hdr->data_length) { msg->len = hdr->data_length; msg->buf = xzalloc(msg->len); memcpy(msg->buf, pkt + sizeof(struct ratp_header), msg->len); } else { msg->len = 1; msg->buf = xzalloc(1); *(uint8_t *)msg->buf = hdr->data_length; } if (hdr->control & RATP_CONTROL_EOR) msg->eor = 1; list_add_tail(&msg->list, &ri->recvmsg); return 0; } /* * This represents that stage of processing in the ESTABLISHED * state in which all the flag bits have been processed and only * data may remain. The packet is examined to see if it contains * data. If not the packet is now discarded, return to the * current state without any further processing. * * We assume the packet contained data, that either the SO flag * was set or LENGTH is positive. That data is placed into the * user's receive buffers. As these become full the user should * be informed "Receive buffer full." An acknowledgment is sent: * * * * If data is queued to send then it is most efficient to * 'piggyback' this acknowledgment on that data packet. * * The packet is now discarded, return to the ESTABLISHED state * without any further processing. */ static int ratp_behaviour_i1(struct ratp_internal *ri, void *pkt) { struct ratp_header *hdr = pkt; if (!ratp_has_data (hdr)) return 1; pr_vdebug("%s **received** %d\n", __func__, hdr->data_length); ri->sn_received = ratp_sn(hdr); msg_recv(ri, pkt); if (list_empty(&ri->sendmsg) || ri->sendmsg_current) ratp_send_ack(ri, hdr); else ratp_send_next_data(ri); return 0; } /* * State machine as desribed in RFC916 * * STATE BEHAVIOR * =============+======================== * LISTEN | A * -------------+------------------------ * SYN-SENT | B * -------------+------------------------ * SYN-RECEIVED | C1 D1 E F1 H1 * -------------+------------------------ * ESTABLISHED | C2 D2 E F2 H2 I1 * -------------+------------------------ * FIN-WAIT | C2 D2 E F3 H3 * -------------+------------------------ * LAST-ACK | C2 D3 E F3 H4 * -------------+------------------------ * CLOSING | C2 D3 E F3 H5 * -------------+------------------------ * TIME-WAIT | D3 E F3 H6 * -------------+------------------------ * CLOSED | G * -------------+------------------------ */ static int ratp_state_machine(struct ratp_internal *ri, void *pkt) { struct ratp_header *hdr = pkt; int ret; ratp_print_header(ri, hdr, " recv"); pr_debug(" state %s\n", ratp_state_str[ri->state]); switch (ri->state) { case RATP_STATE_LISTEN: ratp_behaviour_a(ri, pkt); break; case RATP_STATE_SYN_SENT: ratp_behaviour_b(ri, pkt); break; case RATP_STATE_SYN_RECEIVED: ret = ratp_behaviour_c1(ri, pkt); if (ret) return ret; ret = ratp_behaviour_d1(ri, pkt); if (ret) return ret; ret = ratp_behaviour_e(ri, pkt); if (ret) return ret; ret = ratp_behaviour_f1(ri, pkt); if (ret) return ret; ret = ratp_behaviour_h1(ri, pkt); if (ret) return ret; break; case RATP_STATE_ESTABLISHED: ret = ratp_behaviour_c2(ri, pkt); if (ret) return ret; ret = ratp_behaviour_d2(ri, pkt); if (ret) return ret; ret = ratp_behaviour_e(ri, pkt); if (ret) return ret; ret = ratp_behaviour_f2(ri, pkt); if (ret) return ret; ret = ratp_behaviour_h2(ri, pkt); if (ret) return ret; ret = ratp_behaviour_i1(ri, pkt); if (ret) return ret; break; case RATP_STATE_FIN_WAIT: ret = ratp_behaviour_c2(ri, pkt); if (ret) return ret; ret = ratp_behaviour_d2(ri, pkt); if (ret) return ret; ret = ratp_behaviour_e(ri, pkt); if (ret) return ret; ret = ratp_behaviour_f3(ri, pkt); if (ret) return ret; ret = ratp_behaviour_h3(ri, pkt); if (ret) return ret; break; case RATP_STATE_LAST_ACK: ret = ratp_behaviour_c2(ri, pkt); if (ret) return ret; ret = ratp_behaviour_d3(ri, pkt); if (ret) return ret; ret = ratp_behaviour_e(ri, pkt); if (ret) return ret; ret = ratp_behaviour_f3(ri, pkt); if (ret) return ret; ret = ratp_behaviour_h4(ri, pkt); if (ret) return ret; break; case RATP_STATE_CLOSING: ret = ratp_behaviour_c2(ri, pkt); if (ret) return ret; ret = ratp_behaviour_d3(ri, pkt); if (ret) return ret; ret = ratp_behaviour_e(ri, pkt); if (ret) return ret; ret = ratp_behaviour_f3(ri, pkt); if (ret) return ret; ret = ratp_behaviour_h5(ri, pkt); if (ret) return ret; break; case RATP_STATE_TIME_WAIT: ret = ratp_behaviour_d3(ri, pkt); if (ret) return ret; ret = ratp_behaviour_e(ri, pkt); if (ret) return ret; ret = ratp_behaviour_f3(ri, pkt); if (ret) return ret; ret = ratp_behaviour_h6(ri, pkt); if (ret) return ret; break; case RATP_STATE_CLOSED: ratp_behaviour_g(ri, pkt); break; }; return 0; } /** * ratp_closed() - Check if a connection is closed * * Return: true if a connection is closed, false otherwise */ bool ratp_closed(struct ratp *ratp) { struct ratp_internal *ri = ratp->internal; if (!ri) return true; return ri->state == RATP_STATE_CLOSED; } /** * ratp_busy() - Check if we are inside the RATP code * * Needed for RATP debugging. The RATP console uses this to determine * if it is called from inside the RATP code. * * Return: true if we are inside the RATP code, false otherwise */ bool ratp_busy(struct ratp *ratp) { struct ratp_internal *ri = ratp->internal; if (!ri) return false; return ri->in_ratp != 0; } /** * ratp_poll() - Execute RATP state machine * @ratp: The RATP link * * This function should be executed periodically to keep the RATP state * machine going. * * Return: 0 if successful, a negative error code otherwise. */ int ratp_poll(struct ratp *ratp) { struct ratp_internal *ri = ratp->internal; int ret; if (!ri) return -ENETDOWN; ri->in_ratp++; ret = ratp_recv_pkt(ri, ri->recvbuf, 100); if (ret == 0) { if (ri->state == RATP_STATE_TIME_WAIT && is_timeout(ri->timewait_timer_start, ri->srtt * 2 * MSECOND)) { pr_debug("2*SRTT timer timed out\n"); ret = -ECONNRESET; goto out; } ret = ratp_state_machine(ri, ri->recvbuf); if (ret < 0) goto out; if (ri->status < 0) { ret = ri->status; goto out; } } if (ri->sendmsg_current && is_timeout(ri->retransmission_timer_start, ri->rto * MSECOND)) { ri->retransmission_count++; if (ri->retransmission_count == ri->max_retransmission) { ri->status = ret = -ETIMEDOUT; ri->state = RATP_STATE_CLOSED; goto out; } pr_debug("%s: retransmit\n", __func__); ratp_print_header(ri, ri->sendbuf, "resend"); ri->retransmission_timer_start = get_time_ns(); ret = ri->ratp->send(ratp, ri->sendbuf, ri->sendbuf_len); if (ret) goto out; } if (!ri->sendmsg_current && !list_empty(&ri->sendmsg)) ratp_send_next_data(ri); ret = 0; out: ri->in_ratp--; return ret; } /** * ratp_establish(): Establish a RATP link * @ratp: The RATP link * @active: if true actively create a connection * @timeout_ms: Timeout in ms to wait until a connection is established. If * 0 wait forever. * * This function establishes a link with the remote end. It expects the * send and receive functions to be set, all other struct ratp_internal members can * be left uninitialized. * * Return: 0 if successful, a negative error code otherwise. */ int ratp_establish(struct ratp *ratp, bool active, int timeout_ms) { struct ratp_internal *ri; int ret; uint64_t start; ri = xzalloc(sizeof(*ri)); ri->ratp = ratp; ratp->internal = ri; ri->recvbuf = xmalloc(512); ri->sendbuf = xmalloc(512); INIT_LIST_HEAD(&ri->recvmsg); INIT_LIST_HEAD(&ri->sendmsg); ri->max_retransmission = 100; ri->srtt = 100; ri->rto = 100; ri->active = active; ri->in_ratp++; if (ri->active) { ratp_send_hdr(ri, RATP_CONTROL_SYN); ratp_state_change(ri, RATP_STATE_SYN_SENT); } start = get_time_ns(); while (1) { ret = ratp_poll(ri->ratp); if (ret < 0) goto out; if (ri->state == RATP_STATE_ESTABLISHED) { ret = 0; goto out; } if (timeout_ms && is_timeout(start, MSECOND * timeout_ms)) { ret = -ETIMEDOUT; goto out; } } out: ri->in_ratp--; if (ret) { free(ri->recvbuf); free(ri->sendbuf); free(ri); ratp->internal = NULL; } return ret; } void ratp_close(struct ratp *ratp) { struct ratp_internal *ri = ratp->internal; struct ratp_message *msg, *tmp; struct ratp_header fin = {}; if (!ri) return; if (ri->state == RATP_STATE_ESTABLISHED || ri->state == RATP_STATE_SYN_RECEIVED) { uint64_t start; u8 control; pr_debug("Closing...\n"); ratp_state_change(ri, RATP_STATE_FIN_WAIT); control = ratp_set_next_sn(ri->sn_sent) | ratp_set_next_an(ri->sn_received) | RATP_CONTROL_FIN | RATP_CONTROL_ACK; ratp_create_packet(ri, &fin, control, 0); ratp_send_pkt(ri, &fin, sizeof(fin)); start = get_time_ns(); while (!is_timeout(start, ri->srtt * MSECOND * 2)) ratp_poll(ratp); } list_for_each_entry_safe(msg, tmp, &ri->sendmsg, list) ratp_msg_done(ri, msg, -ECONNRESET); free(ri->recvbuf); free(ri->sendbuf); free(ri); ratp->internal = NULL; pr_debug("Closed\n"); } /** * ratp_send_complete(): Send data over a RATP link * @ratp: The RATP link * @data: The data buffer * @len: The length of the message to send * @complete: The completion callback for the message * @complete_ctx: context pointer for the completion callback * * Queue a RATP message for transmission. This only queues the message, * ratp_poll has to be called to actually transfer the message. * @complete will be called upon completion of the message. * * Return: 0 if successful, a negative error code otherwise. */ int ratp_send_complete(struct ratp *ratp, const uint8_t *data, size_t len, void (*complete)(void *ctx, int status), void *complete_ctx) { struct ratp_internal *ri = ratp->internal; struct ratp_message *msg; int sent = 0; if (!ri || ri->state != RATP_STATE_ESTABLISHED) return -ENETDOWN; if (!len) return -EINVAL; ri->in_ratp++; while (len) { int now = min((int)len, 255); msg = xzalloc(sizeof(*msg)); msg->buf = xzalloc(sizeof(struct ratp_header) + now + 2); msg->len = now; memcpy(msg->buf + sizeof(struct ratp_header), data + sent, now); list_add_tail(&msg->list, &ri->sendmsg); len -= now; sent += now; } msg->eor = 1; msg->complete = complete; msg->complete_ctx = complete_ctx; ri->in_ratp--; return 0; } /** * ratp_send(): Send data over a RATP link * @ratp: The RATP link * @data: The data buffer * @len: The length of the message to send * * Queue a RATP message for transmission. This only queues the message, * ratp_poll has to be called to actually transfer the message. * * Return: 0 if successful, a negative error code otherwise. */ int ratp_send(struct ratp *ratp, const void *data, size_t len) { return ratp_send_complete(ratp, data, len, NULL, NULL); } /** * ratp_recv() - Receive data from a RATP link * @ratp: The RATP link * @data: Pointer to data * @len: The length of the data in bytes * * If a message is available it fills @data with a pointer to the data. * This function does not wait for new messages. If no data is available * -EAGAIN is returned. If data is received @data has to be freed by the * caller. * * Return: 0 if successful, a negative error code otherwise. */ int ratp_recv(struct ratp *ratp, void **data, size_t *len) { struct ratp_internal *ri = ratp->internal; struct ratp_message *msg, *tmp; void *pos; int num = 0; *len = 0; if (!ri || ri->state != RATP_STATE_ESTABLISHED) return -ENETDOWN; if (list_empty(&ri->recvmsg)) return -EAGAIN; list_for_each_entry(msg, &ri->recvmsg, list) { *len += msg->len; num++; if (msg->eor) goto eor; } return -EAGAIN; eor: *data = malloc(*len); if (!*data) return -ENOMEM; pos = *data; list_for_each_entry_safe(msg, tmp, &ri->recvmsg, list) { memcpy(pos, msg->buf, msg->len); pos += msg->len; list_del(&msg->list); free(msg->buf); free(msg); } return 0; }