aboutsummaryrefslogtreecommitdiff
path: root/slip.c
diff options
context:
space:
mode:
Diffstat (limited to 'slip.c')
-rw-r--r--slip.c208
1 files changed, 110 insertions, 98 deletions
diff --git a/slip.c b/slip.c
index 3b448f4..889663a 100644
--- a/slip.c
+++ b/slip.c
@@ -1,4 +1,37 @@
-/* SLIP send/recv code, from RFC 1055 */
+/*
+ * slip.c
+ * ------
+ * SLIP send/recv code, based on RFC 1055
+ *
+ * Copyright (c) 2016, NORDUnet A/S All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the NORDUnet nor the names of its contributors may
+ * be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
#include <stdio.h> /* perror */
@@ -11,16 +44,34 @@
#define ESC_END 0334 /* ESC ESC_END means END data byte */
#define ESC_ESC 0335 /* ESC ESC_ESC means ESC data byte */
-/* SLIP_SEND: sends a packet of length "len", starting at
- * location "p".
+#define check_send_char(c) \
+ if (hal_serial_send_char(c) != HAL_OK) \
+ return perror("hal_serial_send_char"), HAL_ERROR_RPC_TRANSPORT;
+
+/* Send a single character with SLIP escaping.
*/
-int hal_slip_send(const uint8_t * const ptr, const size_t len)
+hal_error_t hal_slip_send_char(const uint8_t c)
{
- int i;
- uint8_t *p = (uint8_t *)ptr;
+ switch (c) {
+ case END:
+ check_send_char(ESC);
+ check_send_char(ESC_END);
+ break;
+ case ESC:
+ check_send_char(ESC);
+ check_send_char(ESC_ESC);
+ break;
+ default:
+ check_send_char(c);
+ }
-#define check_send_char(c) if (hal_slip_send_char(c) == -1) return perror("write"), -1;
+ return HAL_OK;
+}
+/* Send a message with SLIP framing.
+ */
+hal_error_t hal_slip_send(const uint8_t * const buf, const size_t len)
+{
/* send an initial END character to flush out any data that may
* have accumulated in the receiver due to line noise
*/
@@ -29,113 +80,74 @@ int hal_slip_send(const uint8_t * const ptr, const size_t len)
/* for each byte in the packet, send the appropriate character
* sequence
*/
- for (i = 0; i < len; ++i) {
- switch (*p) {
- /* if it's the same code as an END character, we send a
- * special two character code so as not to make the
- * receiver think we sent an END
- */
- case END:
- check_send_char(ESC);
- check_send_char(ESC_END);
- break;
-
- /* if it's the same code as an ESC character,
- * we send a special two character code so as not
- * to make the receiver think we sent an ESC
- */
- case ESC:
- check_send_char(ESC);
- check_send_char(ESC_ESC);
- break;
-
- /* otherwise, we just send the character
- */
- default:
- check_send_char(*p);
- }
-
- p++;
+ for (int i = 0; i < len; ++i) {
+ hal_error_t ret;
+ if ((ret = hal_slip_send_char(buf[i])) != HAL_OK)
+ return ret;
}
/* tell the receiver that we're done sending the packet
*/
check_send_char(END);
- return 0;
-#undef check_send_char
+ return HAL_OK;
}
-/* SLIP_RECV: receives a packet into the buffer located at "p".
- * If more than len bytes are received, the packet will
- * be truncated.
- * Returns the number of bytes stored in the buffer.
+#define check_recv_char(c) \
+ if (hal_serial_recv_char(c) != HAL_OK) \
+ return perror("hal_serial_recv_char"), HAL_ERROR_RPC_TRANSPORT;
+
+/* Receive a single character into a buffer, with SLIP un-escaping
*/
-int hal_slip_recv(uint8_t * const p, const size_t len)
+hal_error_t hal_slip_recv_char(uint8_t * const buf, size_t * const len, const size_t maxlen, int * const complete)
{
+#define buf_push(c) do { if (*len < maxlen) buf[(*len)++] = c; } while (0)
+ static int esc_flag = 0;
uint8_t c;
- size_t received = 0;
-
-#define check_recv_char(c) if (hal_slip_recv_char(&c) == -1) return perror("read"), -1;
-
- /* sit in a loop reading bytes until we put together
- * a whole packet.
- * Make sure not to copy them into the packet if we
- * run out of room.
- */
- while (1) {
- /* get a character to process
- */
- check_recv_char(c);
-
- /* handle bytestuffing if necessary
- */
- switch (c) {
-
- /* if it's an END character then we're done with
- * the packet
- */
- case END:
- /* a minor optimization: if there is no
- * data in the packet, ignore it. This is
- * meant to avoid bothering IP with all
- * the empty packets generated by the
- * duplicate END characters which are in
- * turn sent to try to detect line noise.
- */
- if (received)
- return received;
- else
- break;
-
- /* if it's the same code as an ESC character, wait
- * and get another character and then figure out
- * what to store in the packet based on that.
- */
- case ESC:
- check_recv_char(c);
-
- /* if "c" is not one of these two, then we
- * have a protocol violation. The best bet
- * seems to be to leave the byte alone and
- * just stuff it into the packet
- */
- switch(c) {
+ hal_error_t ret = hal_serial_recv_char(&c);
+ if (ret != HAL_OK)
+ return perror("hal_slip_recv_char"), ret;
+ *complete = 0;
+ switch (c) {
+ case END:
+ if (*len)
+ *complete = 1;
+ break;
+ case ESC:
+ esc_flag = 1;
+ break;
+ default:
+ if (esc_flag) {
+ esc_flag = 0;
+ switch (c) {
case ESC_END:
- c = END;
+ buf_push(END);
break;
case ESC_ESC:
- c = ESC;
+ buf_push(ESC);
break;
+ default:
+ buf_push(c);
}
-
- /* here we fall into the default handler and let
- * it store the character for us
- */
- default:
- if (received < len)
- p[received++] = c;
}
+ else {
+ buf_push(c);
+ }
+ break;
+ }
+ return HAL_OK;
+}
+
+/* Receive a message with SLIP framing, blocking mode.
+ */
+hal_error_t hal_slip_recv(uint8_t * const buf, size_t * const len, const size_t maxlen)
+{
+ int complete;
+ hal_error_t ret;
+
+ while (1) {
+ ret = hal_slip_recv_char(buf, len, maxlen, &complete);
+ if ((ret != HAL_OK) || complete)
+ return ret;
}
-#undef check_recv_char
}