diff --git a/Makefile.dep b/Makefile.dep index 0c2f4d7ce506..971d6251a5c5 100644 --- a/Makefile.dep +++ b/Makefile.dep @@ -46,6 +46,8 @@ endif ifneq (,$(filter sixlowpan,$(USEMODULE))) USEMODULE += ieee802154 USEMODULE += net_help + USEMODULE += netapi + USEMODULE += netdev_base USEMODULE += pktbuf USEMODULE += posix USEMODULE += vtimer diff --git a/sys/net/link_layer/sixlowpan/core.c b/sys/net/link_layer/sixlowpan/core.c index e733e053cd0e..3683e26ef5b8 100644 --- a/sys/net/link_layer/sixlowpan/core.c +++ b/sys/net/link_layer/sixlowpan/core.c @@ -87,6 +87,8 @@ typedef struct __attribute__((packed)) _reassembly_buf_t { * + 6LoWPAN Dispatch byte */ } _reassembly_buf_t; +static uint16_t _current_frag_tag = 0; +static mutex_t _current_frag_tag_mutex = MUTEX_INIT; static _reassembly_buf_t *_reassembly_buf_head = NULL; static mutex_t _reassembly_mutex = MUTEX_INIT; @@ -453,12 +455,102 @@ static int _handle_received(netapi_rcv_pkt_t *rcv, void *src, size_t src_len, } } +static size_t _snd_collect_headers(uint8_t **headers, netapi_snd_pkt_t *snd, + size_t snd_ulh_len, void *comp_dispatch, + size_t comp_dispatch_len) +{ + *headers = pktbuf_alloc(snd_ulh_len + comp_dispatch_len); + size_t offset = comp_dispatch_len; + netdev_hlist_t *ptr = snd->ulh; + + if (headers == NULL) { + return 0; + } + + pktbuf_copy(*headers, comp_dispatch, comp_dispatch_len); + + if (ptr != NULL) { + do { + netdev_hlist_t *next = ptr->next; + pktbuf_copy(&((*headers)[offset]), ptr->header, ptr->header_len); + pktbuf_release(ptr->header); + offset += ptr->header_len; + pktbuf_release(ptr); + ptr = next; + } while (ptr != snd->ulh); + } + + return offset; +} + +/* TODO: define transceiver equivalent */ +static inline int _transfer_send(kernel_pid_t mac_pid, netdev_hlist_t *ulhs, + void *addr, size_t addr_len, void *data, + size_t data_len); +{ + return netapi_send_data2(mac_pid, ulhs, addr, addr_len, data, data_len); +} + static int _handle_send(kernel_pid_t mac_pid, netapi_snd_pkt_t *snd, size_t max_data_size, sixlowpan_iphc_status_t iphc_status) { + uint8_t *comp_dispatch = NULL; + size_t comp_dispatch_len = 0; + void *upper_ulh; + size_t upper_ulh_len = netdev_get_hlist_len(snd->ulh); + if (iphc_status == LOWPAN_IPHC_ENABLE) { /* TODO */ } + else { + comp_dispatches = (uint8_t *)pktbuf_alloc(comp_dispatches, sizeof(uint8_t)); + comp_dispatches[comp_dispatches_len] = SIXLOWPAN_IPV6_DISPATCH; + comp_dispatches_len = sizeof(uint8_t); + } + + upper_ulh_len = _snd_collect_headers(&upper_ulh, snd, upper_ulh_len, + comp_dispatch, comp_dispatch_len); + + if (upper_ulh_len + snd->data_len > max_data_size) { + uint16_t tag; + int res, offset = 0; + + mutex_lock(&_current_frag_tag_mutex); + tag = _current_frag_tag++; + mutex_unlock(&_current_frag_tag_mutex); + + if ((res = _snd_first_fragment(tag, upper_ulh, upper_ulh_len, snd, + max_data_size)) < 0) { + return res; + } + + offset += res; + + while (offset < (long long int)max_data_size) { + if ((res = _snd_nth_fragment(tag, upper_ulh, upper_ulh_len, snd, + max_data_size, (uint16_t)offset)) < 0) { + return res; + } + } + } + else { + netdev_hlist_t *hdr = (netdev_hlist_t *)pktbuf_alloc(sizeof(netdev_hlist_t)); + if (hdr == NULL) { + /* TODO what else needs to be released? */ + pktbuf_release(upper_ulh); + return -ENOBUFS; + } + hdr->next = hdr; + hdr->prev = hdr; + hdr->header = upper_ulh; + hdr->header_len = upper_ulh_len; + + _transfer_send(mac_pid, hdr, snd->dest, snd->dest_len, snd->data, + snd->data_len); + pktbuf_release(hdr); + } + + pktbuf_release(upper_ulh); return 0; } @@ -660,7 +752,9 @@ static void *_control(void *arg) kernel_pid_t sixlowpan_init(kernel_pid_t mac_pid, char *stack, int stacksize, char priority, int flags, const char *name) { - return thread_create(stack, stacksize, priority, flags, _control, &mac_pid, name); + kernel_pid_t mypid = thread_create(stack, stacksize, priority, flags, _control, &mac_pid, name); + netapi_register(mac_pid, mypid); + return mypid; } /**