Changeset 7b64cf0 in mainline


Ignore:
Timestamp:
2013-05-16T11:09:44Z (12 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
4510e06
Parents:
2093fbe
Message:

More complete implementation of the SLIP service and protocol.

Note that the suggested EXCHANGE_PARALLEL session does not work due to
the effects of:

#508 Parallel sessions don't mix well with call forwarding

Besides of that, the ns8250 driver will not allow opening the device
more than once, which also needs to be addressed.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/srv/net/slip/slip.c

    r2093fbe r7b64cf0  
    3636
    3737#include <stdio.h>
     38#include <stdint.h>
    3839#include <loc.h>
    3940#include <inet/iplink_srv.h>
     41#include <device/char_dev.h>
    4042#include <io/log.h>
    4143#include <errno.h>
     
    4547
    4648#define SLIP_MTU        1006    /* as per RFC 1055 */
     49
     50#define SLIP_END        0300
     51#define SLIP_ESC        0333
     52#define SLIP_ESC_END    0334
     53#define SLIP_ESC_ESC    0335
    4754
    4855static int slip_open(iplink_srv_t *);
     
    6471};
    6572
     73static uint8_t slip_send_buf[SLIP_MTU + 2];
     74static size_t slip_send_pending;
     75
     76static uint8_t slip_recv_buf[SLIP_MTU + 2];
     77static size_t slip_recv_pending;
     78static size_t slip_recv_read;
     79
    6680int slip_open(iplink_srv_t *srv)
    6781{
     
    7690}
    7791
     92static void write_flush(async_sess_t *sess)
     93{
     94        size_t written = 0;
     95
     96        while (slip_send_pending > 0) {
     97                ssize_t size;
     98
     99                size = char_dev_write(sess, &slip_send_buf[written],
     100                    slip_send_pending);
     101                if (size < 0) {
     102                        log_msg(LOG_DEFAULT, LVL_ERROR,
     103                            "char_dev_write() returned %d",
     104                            (int) size);
     105                        slip_send_pending = 0;
     106                        break;
     107                }
     108                written += size;
     109                slip_send_pending -= size;
     110        }
     111}
     112
     113static void write_buffered(async_sess_t *sess, uint8_t ch)
     114{
     115        if (slip_send_pending == sizeof(slip_send_buf))
     116                write_flush(sess);
     117        slip_send_buf[slip_send_pending++] = ch;
     118}
     119
    78120int slip_send(iplink_srv_t *srv, iplink_srv_sdu_t *sdu)
    79121{
     122        async_sess_t *sess = (async_sess_t *) srv->arg;
     123        uint8_t *data = sdu->data;
     124        unsigned i;
     125
    80126        log_msg(LOG_DEFAULT, LVL_DEBUG, "slip_send()");
    81         return ENOTSUP;
     127
     128        /*
     129         * Strictly speaking, this is not prescribed by the RFC, but the RFC
     130         * suggests to start with sending a SLIP_END byte as a synchronization
     131         * measure for dealing with previous possible noise on the line.
     132         */
     133        write_buffered(sess, SLIP_END);
     134
     135        for (i = 0; i < sdu->size; i++) {
     136                switch (data[i]) {
     137                case SLIP_END:
     138                        write_buffered(sess, SLIP_ESC);
     139                        write_buffered(sess, SLIP_ESC_END);     
     140                        break;
     141                case SLIP_ESC:
     142                        write_buffered(sess, SLIP_ESC);
     143                        write_buffered(sess, SLIP_ESC_ESC);
     144                        break;
     145                default:
     146                        write_buffered(sess, data[i]);
     147                        break;
     148                }
     149        }
     150        write_buffered(sess, SLIP_END);
     151        write_flush(sess);
     152
     153        return EOK;
    82154}
    83155
     
    110182        log_msg(LOG_DEFAULT, LVL_DEBUG, "slip_client_conn()");
    111183        iplink_conn(iid, icall, &slip_iplink);
     184}
     185
     186static uint8_t read_buffered(async_sess_t *sess)
     187{
     188        while (slip_recv_pending == 0) {
     189                ssize_t size;
     190
     191                size = char_dev_read(sess, slip_recv_buf,
     192                    sizeof(slip_recv_buf));
     193                if (size < 0) {
     194                        log_msg(LOG_DEFAULT, LVL_ERROR,
     195                            "char_dev_read() returned %d", (int) size);
     196                        return SLIP_END;
     197                }
     198                slip_recv_pending = size;
     199                slip_recv_read = 0;
     200        }
     201        slip_recv_pending--;
     202        return slip_recv_buf[slip_recv_read++];
     203}
     204
     205static int slip_recv_fibril(void *arg)
     206{
     207        async_sess_t *sess = (async_sess_t *) arg;
     208        static uint8_t recv_final[SLIP_MTU];
     209        iplink_srv_sdu_t sdu;
     210        uint8_t ch;
     211        int rc;
     212
     213        sdu.lsrc.ipv4 = 0;
     214        sdu.ldest.ipv4 = 0;
     215        sdu.data = recv_final;
     216
     217        while (true) {
     218                for (sdu.size = 0; sdu.size < sizeof(recv_final); /**/) {
     219                        ch = read_buffered(sess);
     220                        switch (ch) {
     221                        case SLIP_END:
     222                                if (sdu.size == 0) {
     223                                        /*
     224                                         * Discard the empty SLIP datagram.
     225                                         */
     226                                        break;
     227                                }
     228                                goto pass;
     229
     230                        case SLIP_ESC:
     231                                ch = read_buffered(sess);
     232                                if (ch == SLIP_ESC_END) {
     233                                        recv_final[sdu.size++] = SLIP_END;
     234                                        break;
     235                                } else if (ch ==  SLIP_ESC_ESC) {
     236                                        recv_final[sdu.size++] = SLIP_ESC;
     237                                        break;
     238                                }
     239
     240                                /*
     241                                 * The RFC suggests to simply insert the wrongly
     242                                 * escaped character into the packet so we fall
     243                                 * through.
     244                                 */
     245 
     246                        default:
     247                                recv_final[sdu.size++] = ch;
     248                                break;
     249                        }
     250                       
     251                }
     252
     253                /*
     254                 * We have reached the limit of our MTU. Regardless of whether
     255                 * the datagram is properly ended with SLIP_END, pass it along.
     256                 * If the next character is really SLIP_END, nothing
     257                 * catastrophic happens. The algorithm will just see an
     258                 * artificially empty SLIP datagram and life will go on.
     259                 */
     260
     261pass:
     262                rc = iplink_ev_recv(&slip_iplink, &sdu);
     263                if (rc != EOK) {
     264                        log_msg(LOG_DEFAULT, LVL_ERROR,
     265                            "iplink_ev_recv() returned %d", rc);
     266                }
     267        }
     268
     269        return 0;
    112270}
    113271
     
    118276        category_id_t iplinkcid;
    119277        async_sess_t *sess = NULL;
     278        fid_t fid;
    120279        int rc;
    121280
     
    147306        }
    148307
    149         sess = loc_service_connect(EXCHANGE_SERIALIZE, svcid, 0);
     308        /*
     309         * Create a parallel session because we will need to be able to both
     310         * read and write from the char_dev.
     311         */
     312        sess = loc_service_connect(EXCHANGE_PARALLEL, svcid, 0);
    150313        if (!sess) {
    151314                log_msg(LOG_DEFAULT, LVL_ERROR,
     
    154317                return rc;
    155318        }
     319        slip_iplink.arg = sess;
    156320
    157321        rc = loc_service_register(linkstr, &linksid);
     
    166330        if (rc != EOK) {
    167331                log_msg(LOG_DEFAULT, LVL_ERROR,
    168                     "Filed to add service %d (%s) to category %d (%s).",
     332                    "Failed to add service %d (%s) to category %d (%s).",
    169333                    (int) linksid, linkstr, (int) iplinkcid, CAT_IPLINK);
    170334                goto fail;
    171335        }
     336
     337        fid = fibril_create(slip_recv_fibril, sess);
     338        if (!fid) {
     339                log_msg(LOG_DEFAULT, LVL_ERROR,
     340                    "Failed to create receive fibril.");
     341                goto fail;
     342        }
     343        fibril_add_ready(fid);
    172344
    173345        return EOK;
Note: See TracChangeset for help on using the changeset viewer.