aboutsummaryrefslogtreecommitdiff
path: root/slip.c
diff options
context:
space:
mode:
Diffstat (limited to 'slip.c')
-rw-r--r--slip.c141
1 files changed, 141 insertions, 0 deletions
diff --git a/slip.c b/slip.c
new file mode 100644
index 0000000..3b448f4
--- /dev/null
+++ b/slip.c
@@ -0,0 +1,141 @@
+/* SLIP send/recv code, from RFC 1055 */
+
+#include <stdio.h> /* perror */
+
+#include "slip_internal.h"
+
+/* SLIP special character codes
+ */
+#define END 0300 /* indicates end of packet */
+#define ESC 0333 /* indicates byte stuffing */
+#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".
+ */
+int hal_slip_send(const uint8_t * const ptr, const size_t len)
+{
+ int i;
+ uint8_t *p = (uint8_t *)ptr;
+
+#define check_send_char(c) if (hal_slip_send_char(c) == -1) return perror("write"), -1;
+
+ /* send an initial END character to flush out any data that may
+ * have accumulated in the receiver due to line noise
+ */
+ check_send_char(END);
+
+ /* 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++;
+ }
+
+ /* tell the receiver that we're done sending the packet
+ */
+ check_send_char(END);
+
+ return 0;
+#undef check_send_char
+}
+
+/* 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.
+ */
+int hal_slip_recv(uint8_t * const p, const size_t len)
+{
+ 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) {
+ case ESC_END:
+ c = END;
+ break;
+ case ESC_ESC:
+ c = ESC;
+ break;
+ }
+
+ /* here we fall into the default handler and let
+ * it store the character for us
+ */
+ default:
+ if (received < len)
+ p[received++] = c;
+ }
+ }
+#undef check_recv_char
+}