Date:2011-05-11 12:39:23 (12 years 10 months ago)
Author:Werner Almesberger
Commit:dbad7ae8879d008b638996ad661567dd7db56cb4
Message:tools/dirtpan/: quick and dirty IPv4 over 802.15.4 tunnel (in progress)

Files: tools/dirtpan/Makefile (1 diff)
tools/dirtpan/dirtpan.c (1 diff)

Change Details

tools/dirtpan/Makefile
1#
2# dirtpan/Makefile - Quick and dirty IPv4 over 802.15.4 tunnel
3#
4# Written 2011 by Werner Almesberger
5# Copyright 2011 Werner Almesberger
6#
7# This program is free software; you can redistribute it and/or modify
8# it under the terms of the GNU General Public License as published by
9# the Free Software Foundation; either version 2 of the License, or
10# (at your option) any later version.
11#
12
13
14MAIN = dirtpan
15
16include ../Makefile.common
17
18CFLAGS += -I. -I../../install/lowpan-tools-0.2.2/include/
tools/dirtpan/dirtpan.c
1/*
2 * dirtpan/dirtpan.c - Quick and dirty IPv4 over 802.15.4 tunnel
3 *
4 * Written 2011 by Werner Almesberger
5 * Copyright 2011 Werner Almesberger
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13
14#include <stdint.h>
15#include <stdlib.h>
16#include <stdio.h>
17#include <unistd.h>
18#include <string.h>
19#include <fcntl.h>
20#include <assert.h>
21#include <sys/types.h>
22#include <sys/time.h>
23#include <sys/select.h>
24#include <sys/ioctl.h>
25#include <sys/socket.h>
26#include <linux/if.h>
27#include <linux/if_tun.h>
28
29#include <ieee802154.h>
30
31
32/*
33 * Control byte structure:
34 *
35 * +--7--+--6--+--5--+--4--+--3--+--2--+--1--+
36 * | 0 | 0 | 0 | 0 | seq | pck_type |
37 * +-----+-----+-----+-----+-----+-----+-----+
38 */
39
40#define SEQ 4
41#define PT_MASK 3
42
43enum packet_type {
44    pt_first = 0,
45    pt_next = 1,
46    pt_ack = 2,
47};
48
49
50#define TUN_DEV "/dev/net/tun"
51
52#define MAX_FRAG (127-11-2-1) /* MHDR, FCS, control byte */
53#define MAX_PACKET 2000
54#define MAX_TRIES 5
55#define T_REASS_MS 200
56#define T_ACK_MS 50
57
58
59static enum state {
60    s_idle,
61    s_tx,
62    s_rx,
63} state = s_idle;
64
65
66static int tun, net;
67static uint8_t packet[MAX_PACKET+1];
68static void *pos;
69static int left;
70static int my_seq = 0, peer_seq;
71static int retries;
72static int debug = 0;
73
74
75/* ----- Debugging --------------------------------------------------------- */
76
77
78static void debug_label(const char *label)
79{
80    const char *t;
81
82    switch (state) {
83    case s_idle:
84        t = "--";
85        break;
86    case s_tx:
87        t = "tx";
88        break;
89    case s_rx:
90        t = "rx";
91        break;
92    default:
93        t = "???";
94        break;
95    }
96    fprintf(stderr, "%s(%s)", label, t);
97}
98
99
100static void dump(const void *buf, int size)
101{
102    const uint8_t *p = buf;
103
104    while (size--) {
105        fprintf(stderr, "%s%02x", p == buf ? "" : " ", *p);
106        p++;
107    }
108}
109
110
111static void debug_ip(const char *label, void *buf, int size)
112{
113    if (!debug)
114        return;
115    debug_label(label);
116    fprintf(stderr, ", %d: ", size);
117    dump(buf, size);
118    fprintf(stderr, "\n");
119}
120
121
122static void debug_dirt(const char *label, void *buf, int size)
123{
124    const uint8_t *p = buf;
125
126    if (!debug)
127        return;
128    debug_label(label);
129    fprintf(stderr, ", %d", size);
130    if (size) {
131        fprintf(stderr, ": %02x(%c%d) ",
132            *p, "FNA?"[*p & PT_MASK], *p & SEQ ? 0 : 1);
133        dump(buf+1, size-1);
134    }
135    fprintf(stderr, "\n");
136
137}
138
139
140static void debug_event(const char *label)
141{
142    if (!debug)
143        return;
144    debug_label(label);
145    fprintf(stderr, "\n");
146}
147
148
149/* ----- Timers ------------------------------------------------------------ */
150
151
152static struct timeval t0;
153
154
155static void start_timer(void)
156{
157    gettimeofday(&t0, NULL);
158}
159
160
161static struct timeval *timeout(int ms)
162{
163    static struct timeval t;
164
165    gettimeofday(&t, NULL);
166    t.tv_sec -= t0.tv_sec;
167    t.tv_usec -= t0.tv_usec;
168    t.tv_usec += 1000*ms;
169
170    while (t.tv_usec < 0) {
171        t.tv_sec--;
172        t.tv_usec += 1000000;
173    }
174    while (t.tv_usec > 1000000) {
175        t.tv_sec++;
176        t.tv_usec -= 1000000;
177    }
178    if (t.tv_sec < 0)
179        t.tv_sec = t.tv_usec = 0;
180
181    return &t;
182}
183
184
185/* ----- Packet/frame delivery --------------------------------------------- */
186
187
188static inline int send_size(void)
189{
190    return left > MAX_FRAG ? MAX_FRAG : left;
191}
192
193
194static void write_buf(int fd, void *buf, int size)
195{
196    ssize_t wrote;
197
198    wrote = write(fd, buf, size);
199    if (wrote < 0) {
200        perror("write");
201        return;
202    }
203    if (wrote != size)
204        fprintf(stderr, "short write: %d < %d\n", (int) wrote, size);
205}
206
207
208static void send_frame(void *buf, int size)
209{
210    debug_dirt("->", buf, size);
211    write_buf(net, buf, size);
212}
213
214
215static void send_more(void)
216{
217    uint8_t *p = pos-1;
218
219    *p = (pos == packet+1 ? pt_first : pt_next) | (my_seq ? SEQ : 0);
220    send_frame(p, send_size()+1);
221    start_timer();
222}
223
224
225static void send_ack(int seq)
226{
227    uint8_t ack = pt_ack | (seq ? SEQ : 0);
228
229    send_frame(&ack, 1);
230}
231
232
233/* ----- Main events ------------------------------------------------------- */
234
235
236static void rx_pck(void *buf, int size)
237{
238    const uint8_t *p = buf;
239    uint8_t ctrl, type, seq;
240
241    debug_dirt("-<", buf, size);
242
243    if (size < 1)
244        return;
245
246    ctrl = *p;
247    type = ctrl & PT_MASK;
248    seq = !!(ctrl & SEQ);
249
250    switch (state) {
251    case s_tx:
252        if (type != pt_ack)
253            return;
254        if (seq != my_seq)
255            return;
256        pos += send_size();
257        left -= send_size();
258        if (!left) {
259            state = s_idle;
260            return;
261        }
262        my_seq = !my_seq;
263        retries = 0;
264        send_more();
265        return;
266    case s_rx:
267        if (type == pt_first) {
268            start_timer();
269            state = s_idle;
270            break;
271        }
272        if (type != pt_next)
273            return;
274        if (seq == peer_seq) {
275            send_ack(seq); /* retransmission */
276            return;
277        }
278        goto recv_more;
279    case s_idle:
280        if (type == pt_first)
281            break;
282        if (type == pt_next) {
283            send_ack(seq); /* get rid of it */
284            return;
285        }
286        return;
287    default:
288        abort();
289    }
290
291    if (size < 5)
292        return;
293    left = p[3] << 8 | p[4];
294    if (left > MAX_PACKET+1)
295        return;
296    state = s_rx;
297    pos = packet;
298
299recv_more:
300    if (left < size-1) {
301        send_ack(seq); /* get rid of it */
302        state = s_idle;
303        return;
304    }
305    memcpy(pos, buf+1, size-1);
306    pos += size-1;
307    left -= size-1;
308    peer_seq = seq;
309    send_ack(seq);
310
311    if (!left) {
312        debug_ip("<-", packet, pos-(void *) packet);
313        write_buf(tun, packet, pos-(void *) packet);
314        state = s_idle;
315    }
316}
317
318
319static void tx_pck(void *buf, int size)
320{
321    const uint8_t *p = buf;
322
323    debug_ip(">-", buf, size);
324    assert(state == s_idle);
325    state = s_tx;
326    pos = packet+1;
327    left = p[2] << 8 | p[3];
328    assert(left <= MAX_PACKET);
329    assert(left == size);
330    /*
331     * We could avoid the memcpy by reading directly into "packet"
332     */
333    memcpy(pos, buf, size);
334    my_seq = !my_seq;
335    retries = 0;
336    send_more();
337}
338
339
340static void ack_timeout(void)
341{
342    debug_event("ACK-TO");
343    if (++retries == MAX_TRIES)
344        state = s_idle;
345    else
346        send_more();
347}
348
349
350static void reass_timeout(void)
351{
352    debug_event("REASS-TO");
353    state = s_idle;
354}
355
356
357/* ----- Event dispatcher -------------------------------------------------- */
358
359
360static void event(void)
361{
362    uint8_t buf[MAX_PACKET];
363    struct timeval *to;
364    fd_set rset;
365    int res;
366    ssize_t got;
367
368    FD_ZERO(&rset);
369    FD_SET(net, &rset);
370    switch (state) {
371    case s_idle:
372        FD_SET(tun, &rset);
373        to = NULL;
374        break;
375    case s_rx:
376        to = timeout(T_REASS_MS);
377        break;
378    case s_tx:
379        to = timeout(T_ACK_MS);
380        break;
381    default:
382        abort();
383    }
384    res = select(net > tun ? net+1 : tun+1, &rset, NULL, NULL, to);
385    if (res < 0) {
386        perror("select");
387        return;
388    }
389    if (!res) {
390        switch (state) {
391        case s_rx:
392            reass_timeout();
393            break;
394        case s_tx:
395            ack_timeout();
396            break;
397        default:
398            abort();
399        }
400    }
401    if (FD_ISSET(tun, &rset)) {
402        got = read(tun, buf, sizeof(buf));
403        if (got < 0) {
404            perror("read tun");
405            return;
406        }
407        tx_pck(buf, got);
408    }
409    if (FD_ISSET(net, &rset)) {
410        got = read(net, buf, sizeof(buf));
411        if (got < 0) {
412            perror("read net");
413            return;
414        }
415        rx_pck(buf, got);
416    }
417}
418
419
420/* ----- Setup ------------------------------------------------------------- */
421
422
423static int open_net(uint16_t pan, uint16_t me, uint16_t peer)
424{
425    struct sockaddr_ieee802154 addr;
426    int s;
427
428    s = socket(PF_IEEE802154, SOCK_DGRAM, 0);
429    if (s < 0) {
430        perror("socket 802.15.4");
431        exit(1);
432    }
433
434    addr.family = AF_IEEE802154;
435    addr.addr.addr_type = IEEE802154_ADDR_SHORT;
436    addr.addr.pan_id = pan;
437    addr.addr.short_addr = me;
438
439    if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
440        perror("bind 802.15.4");
441        exit(1);
442    }
443
444    addr.addr.short_addr = peer;
445    if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
446        perror("connect 802.15.4");
447        exit(1);
448    }
449
450    return s;
451}
452
453
454static int open_tun(void)
455{
456    struct ifreq ifr;
457    int fd;
458
459    fd = open(TUN_DEV, O_RDWR);
460    if (fd < 0) {
461        perror(TUN_DEV);
462        exit(1);
463    }
464
465    memset(&ifr, 0, sizeof(ifr));
466    ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
467
468    if (ioctl(fd, TUNSETIFF, (void *) &ifr) < 0) {
469        perror("ioctl TUNSETIFF");
470        exit(1);
471    }
472
473    fprintf(stderr, "%s\n", ifr.ifr_name);
474
475    return fd;
476}
477
478
479/* ----- Command-line processing ------------------------------------------- */
480
481
482static void usage(const char *name)
483{
484    fprintf(stderr, "usage: %s [-d] pan_id src_addr dst_addr\n", name);
485    exit(1);
486}
487
488
489static uint16_t addr(const char *name, const char *s)
490{
491    char *end;
492    unsigned long n;
493
494    n = strtoul(s, &end, 16);
495    if (*end)
496        usage(name);
497    if (n > 0xffff)
498        usage(name);
499    return n;
500}
501
502
503int main(int argc, char **argv)
504{
505    uint16_t pan, src, dst;
506    int c;
507
508    while ((c = getopt(argc, argv, "d")) != EOF)
509        switch (c) {
510        case 'd':
511            debug++;
512            break;
513        default:
514            usage(*argv);
515        }
516
517    switch (argc-optind) {
518    case 3:
519        pan = addr(*argv, argv[optind]);
520        src = addr(*argv, argv[optind+1]);
521        dst = addr(*argv, argv[optind+2]);
522        break;
523    default:
524        usage(*argv);
525    }
526
527    net = open_net(pan, src, dst);
528    tun = open_tun();
529    while (1)
530        event();
531
532    return 0;
533}

Archive Download the corresponding diff file



interactive