diff options
Diffstat (limited to 'slip.c')
-rw-r--r-- | slip.c | 208 |
1 files changed, 110 insertions, 98 deletions
@@ -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 } |