aboutsummaryrefslogblamecommitdiff
path: root/slip.c
blob: 3b448f4d176d231a344d85e242f885cc5db07233 (plain) (tree)












































































































































                                                                                       
/* 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
}