mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
197 lines
5.5 KiB
C
197 lines
5.5 KiB
C
/*
|
|
* Copyright (C) 2015 Kaspar Schleiser <kaspar@schleiser.de>
|
|
*
|
|
* This file is subject to the terms and conditions of the GNU Lesser
|
|
* General Public License v2.1. See the file LICENSE in the top level
|
|
* directory for more details.
|
|
*/
|
|
|
|
#include <assert.h>
|
|
|
|
#include <sys/uio.h>
|
|
|
|
#include "net/netdev.h"
|
|
#include "net/gnrc.h"
|
|
#include "cc110x.h"
|
|
#include "cc110x-netdev.h"
|
|
#include "net/gnrc/netif.h"
|
|
#include "od.h"
|
|
|
|
#define ENABLE_DEBUG (0)
|
|
#include "debug.h"
|
|
|
|
static int _send(gnrc_netif_t *netif, gnrc_pktsnip_t *pkt)
|
|
{
|
|
cc110x_pkt_t cc110x_pkt;
|
|
netdev_t *dev = netif->dev;
|
|
netdev_cc110x_t *netdev_cc110x = (netdev_cc110x_t *) dev;
|
|
cc110x_t *cc110x = &netdev_cc110x->cc110x;
|
|
|
|
assert(pkt != NULL);
|
|
assert(dev->driver == &netdev_cc110x_driver);
|
|
|
|
gnrc_netif_hdr_t *netif_hdr;
|
|
gnrc_pktsnip_t *payload;
|
|
|
|
payload = pkt->next;
|
|
|
|
if (pkt->type != GNRC_NETTYPE_NETIF) {
|
|
DEBUG("gnrc_cc110x: First header was not generic netif header\n");
|
|
gnrc_pktbuf_release(pkt);
|
|
return -EBADMSG;
|
|
}
|
|
|
|
netif_hdr = (gnrc_netif_hdr_t *) pkt->data;
|
|
|
|
/* set up header */
|
|
if (netif_hdr->src_l2addr_len == 1) {
|
|
uint8_t *_src_addr = gnrc_netif_hdr_get_src_addr(netif_hdr);
|
|
cc110x_pkt.phy_src = *_src_addr;
|
|
}
|
|
else {
|
|
cc110x_pkt.phy_src = cc110x->radio_address;
|
|
}
|
|
|
|
if (netif_hdr->flags & (GNRC_NETIF_HDR_FLAGS_BROADCAST |
|
|
GNRC_NETIF_HDR_FLAGS_MULTICAST)) {
|
|
cc110x_pkt.address = 0;
|
|
}
|
|
else {
|
|
uint8_t *_dst_addr = gnrc_netif_hdr_get_dst_addr(netif_hdr);
|
|
cc110x_pkt.address = _dst_addr[netif_hdr->dst_l2addr_len-1];
|
|
}
|
|
|
|
switch (payload->type) {
|
|
#ifdef MODULE_GNRC_SIXLOWPAN
|
|
case GNRC_NETTYPE_SIXLOWPAN:
|
|
cc110x_pkt.flags = 1;
|
|
break;
|
|
#endif
|
|
default:
|
|
cc110x_pkt.flags = 0;
|
|
}
|
|
|
|
struct iovec vector;
|
|
vector.iov_base = (char*)&cc110x_pkt;
|
|
vector.iov_len = sizeof(cc110x_pkt_t);
|
|
|
|
unsigned payload_len = 0;
|
|
uint8_t *pos = cc110x_pkt.data;
|
|
|
|
while (payload) {
|
|
payload_len += payload->size;
|
|
|
|
if (payload_len > CC110X_MAX_DATA_LENGTH) {
|
|
DEBUG("gnrc_cc110x: payload length exceeds maximum"
|
|
"(%u>%u)\n", payload_len, CC110X_MAX_DATA_LENGTH);
|
|
gnrc_pktbuf_release(pkt);
|
|
return -EBADMSG;
|
|
}
|
|
|
|
memcpy(pos, payload->data, payload->size);
|
|
pos += payload->size;
|
|
payload = payload->next;
|
|
}
|
|
|
|
/* pkt has been copied into iovec, we're done with it. */
|
|
gnrc_pktbuf_release(pkt);
|
|
|
|
cc110x_pkt.length = (uint8_t) payload_len + CC110X_HEADER_LENGTH;
|
|
|
|
DEBUG("gnrc_cc110x: sending packet from %u to %u with payload "
|
|
"length %u\n",
|
|
(unsigned)cc110x_pkt.phy_src,
|
|
(unsigned)cc110x_pkt.address,
|
|
(unsigned)cc110x_pkt.length);
|
|
|
|
return dev->driver->send(dev, &vector, 1);
|
|
}
|
|
|
|
static gnrc_pktsnip_t *_recv(gnrc_netif_t *netif)
|
|
{
|
|
netdev_t *dev = netif->dev;
|
|
cc110x_t *cc110x = &((netdev_cc110x_t*) dev)->cc110x;
|
|
|
|
cc110x_pkt_t *cc110x_pkt = &cc110x->pkt_buf.packet;
|
|
|
|
int payload_length = cc110x_pkt->length - CC110X_HEADER_LENGTH;
|
|
|
|
int nettype;
|
|
|
|
int addr_len;
|
|
switch (cc110x_pkt->flags) {
|
|
#ifdef MODULE_GNRC_SIXLOWPAN
|
|
case 1:
|
|
addr_len = 8;
|
|
nettype = GNRC_NETTYPE_SIXLOWPAN;
|
|
break;
|
|
#endif
|
|
default:
|
|
addr_len = 1;
|
|
nettype = GNRC_NETTYPE_UNDEF;
|
|
}
|
|
|
|
/* copy packet payload into pktbuf */
|
|
gnrc_pktsnip_t *pkt = gnrc_pktbuf_add(NULL, cc110x_pkt->data,
|
|
payload_length, nettype);
|
|
|
|
if(!pkt) {
|
|
DEBUG("gnrc_cc110x: _recv: cannot allocate pktsnip.\n");
|
|
return NULL;
|
|
}
|
|
|
|
|
|
gnrc_pktsnip_t *netif_hdr;
|
|
netif_hdr = gnrc_pktbuf_add(NULL, NULL,
|
|
sizeof(gnrc_netif_hdr_t) + 2*addr_len,
|
|
GNRC_NETTYPE_NETIF);
|
|
|
|
if (netif_hdr == NULL) {
|
|
DEBUG("gnrc_cc110x: no space left in packet buffer\n");
|
|
gnrc_pktbuf_release(pkt);
|
|
return NULL;
|
|
}
|
|
|
|
gnrc_netif_hdr_init(netif_hdr->data, addr_len, addr_len);
|
|
if (addr_len == 8) {
|
|
uint64_t src_addr = cc110x_pkt->phy_src;
|
|
uint64_t dst_addr = cc110x_pkt->address;
|
|
gnrc_netif_hdr_set_src_addr(netif_hdr->data, (uint8_t*)&src_addr, addr_len);
|
|
gnrc_netif_hdr_set_dst_addr(netif_hdr->data, (uint8_t*)&dst_addr, addr_len);
|
|
}
|
|
else {
|
|
gnrc_netif_hdr_set_src_addr(netif_hdr->data, (uint8_t*)&cc110x_pkt->phy_src, addr_len);
|
|
gnrc_netif_hdr_set_dst_addr(netif_hdr->data, (uint8_t*)&cc110x_pkt->address, addr_len);
|
|
}
|
|
|
|
((gnrc_netif_hdr_t *)netif_hdr->data)->if_pid = thread_getpid();
|
|
((gnrc_netif_hdr_t *)netif_hdr->data)->lqi = cc110x->pkt_buf.lqi;
|
|
((gnrc_netif_hdr_t *)netif_hdr->data)->rssi = cc110x->pkt_buf.rssi;
|
|
|
|
DEBUG("gnrc_cc110x: received packet from %02x of length %u\n",
|
|
(unsigned)cc110x_pkt->phy_src,
|
|
(unsigned)cc110x_pkt->length-CC110X_HEADER_LENGTH);
|
|
#if defined(MODULE_OD) && ENABLE_DEBUG
|
|
od_hex_dump(cc110x_pkt->data, payload_length, OD_WIDTH_DEFAULT);
|
|
#endif
|
|
|
|
|
|
pkt->next = netif_hdr;
|
|
|
|
return pkt;
|
|
}
|
|
|
|
static const gnrc_netif_ops_t _cc110x_ops = {
|
|
.send = _send,
|
|
.recv = _recv,
|
|
.get = gnrc_netif_get_from_netdev,
|
|
.set = gnrc_netif_set_from_netdev,
|
|
};
|
|
|
|
gnrc_netif_t *gnrc_netif_cc110x_create(char *stack, int stacksize, char priority,
|
|
char *name, netdev_t *dev)
|
|
{
|
|
return gnrc_netif_create(stack, stacksize, priority, name, dev,
|
|
&_cc110x_ops);
|
|
}
|