/* * 6LoWPAN MAC - layer 2 implementations * * Copyright (C) 2013 INRIA. * * This file is subject to the terms and conditions of the GNU Lesser General * Public License. See the file LICENSE in the top level directory for more * details. * * @ingroup sixlowpan * @{ * @file sixlowmac.c * @brief 6lowpan link layer functions * @author Stephan Zeisberg * @author Martin Lenders * @author Eric Engel * @author Oliver Gesch * @author Oliver Hahm * @} */ #include #include #include #include "thread.h" #include "msg.h" #include "radio/radio.h" #include "net_if.h" #include "sixlowpan/mac.h" #include "ip.h" #include "icmp.h" #include "lowpan.h" #include "ieee802154_frame.h" #include "net_help.h" #define ENABLE_DEBUG (0) #if ENABLE_DEBUG #define DEBUG_ENABLED #endif #include "debug.h" #define RADIO_STACK_SIZE (KERNEL_CONF_STACKSIZE_MAIN) #define RADIO_RCV_BUF_SIZE (64) #define RADIO_SENDING_DELAY (1000) #define DEFAULT_IEEE_802154_PAN_ID (0x1234) char radio_stack_buffer[RADIO_STACK_SIZE]; msg_t msg_q[RADIO_RCV_BUF_SIZE]; uint8_t lowpan_mac_buf[PAYLOAD_SIZE]; static uint8_t macdsn; static inline void mac_frame_short_to_eui64(net_if_eui64_t *eui64, uint8_t *frame_short) { eui64->uint32[0] = HTONL(0x000000ff); eui64->uint16[2] = HTONS(0xfe00); eui64->uint8[6] = frame_short[1]; eui64->uint8[7] = frame_short[0]; } void recv_ieee802154_frame(void) { msg_t m; #if (defined(MODULE_AT86RF231) | \ defined(MODULE_CC2420) | \ defined(MODULE_MC1322X)) ieee802154_packet_t *p; #else radio_packet_t *p; uint8_t hdrlen; #endif uint8_t length; ieee802154_frame_t frame; net_if_eui64_t src, dst; msg_init_queue(msg_q, RADIO_RCV_BUF_SIZE); while (1) { msg_receive(&m); if (m.type == PKT_PENDING) { #if (defined(MODULE_AT86RF231) | \ defined(MODULE_CC2420) | \ defined(MODULE_MC1322X)) p = (ieee802154_packet_t *) m.content.ptr; memcpy(&frame, &p->frame, sizeof(ieee802154_frame_t)); length = p->frame.payload_len; #else p = (radio_packet_t *) m.content.ptr; hdrlen = ieee802154_frame_read(p->data, &frame, p->length); length = p->length - hdrlen - IEEE_802154_FCS_LEN; #endif #ifdef DEBUG_ENABLED DEBUG("INFO: Received IEEE 802.15.4. packet (length = %d):\n", length); DEBUG("INFO: FCF:\n"); ieee802154_frame_print_fcf_frame(&frame); DEBUG("Sender:"); for (uint8_t i = 0; i < 8; i++) { printf("%02x ", frame.src_addr[i]); } DEBUG("\n"); DEBUG("Receiver:"); for (size_t i = 0; i < 8; i++) { printf("%02x ", frame.dest_addr[i]); } DEBUG("\n"); DEBUG("Payload:\n"); for (uint8_t i = 0; i < frame.payload_len; i++) { printf("%02x ", frame.payload[i]); if (!((i + 1) % 16) || i == frame.payload_len - 1) { printf("\n"); } } #endif if (frame.fcf.src_addr_m == IEEE_802154_SHORT_ADDR_M) { mac_frame_short_to_eui64(&src, frame.src_addr); } else if (frame.fcf.src_addr_m == IEEE_802154_LONG_ADDR_M) { memcpy(&src, frame.src_addr, 8); } else { DEBUG("Unknown IEEE 802.15.4 source address mode.\n"); continue; } if (frame.fcf.dest_addr_m == IEEE_802154_SHORT_ADDR_M) { mac_frame_short_to_eui64(&dst, frame.dest_addr); } else if (frame.fcf.dest_addr_m == IEEE_802154_LONG_ADDR_M) { memcpy(&dst, frame.dest_addr, 8); } else { DEBUG("Unknown IEEE 802.15.4 destination address mode.\n"); continue; } /* deliver packet to network(6lowpan)-layer */ lowpan_read(frame.payload, length, &src, &dst); /* TODO: get interface ID somehow */ p->processing--; } else if (m.type == ENOBUFFER) { DEBUG("Transceiver buffer full"); } else { DEBUG("Unknown packet received"); } } } void set_ieee802154_fcf_values(ieee802154_frame_t *frame, uint8_t dest_mode, uint8_t src_mode) { frame->fcf.frame_type = IEEE_802154_DATA_FRAME; frame->fcf.sec_enb = 0; frame->fcf.frame_pend = 0; frame->fcf.ack_req = 0; frame->fcf.panid_comp = (frame->dest_pan_id == frame->src_pan_id); frame->fcf.frame_ver = 0; frame->fcf.src_addr_m = src_mode; frame->fcf.dest_addr_m = dest_mode; #ifdef DEBUG_ENABLED ieee802154_frame_print_fcf_frame(frame); #endif } void set_ieee802154_frame_values(int if_id, uint16_t dest_pan, ieee802154_frame_t *frame) { int32_t pan_id = net_if_get_pan_id(if_id); // TODO: addresse aus ip paket auslesen und in frame einfuegen if (pan_id < 0) { frame->dest_pan_id = NTOLES(dest_pan); frame->src_pan_id = HTOLES(DEFAULT_IEEE_802154_PAN_ID); } else { frame->dest_pan_id = NTOLES(dest_pan); frame->src_pan_id = HTOLES((uint16_t)pan_id); } frame->seq_nr = macdsn; macdsn++; } int sixlowpan_mac_prepare_ieee802144_frame( ieee802154_frame_t *frame, int if_id, uint16_t dest_pan, const void *dest, uint8_t dest_len, const void *payload, uint8_t length, uint8_t mcast) { uint8_t src_mode = net_if_get_src_address_mode(if_id); uint8_t dest_mode; uint16_t *fcs; set_ieee802154_frame_values(if_id, dest_pan, frame); if (dest_len == 8) { dest_mode = IEEE_802154_LONG_ADDR_M; } else if (dest_len == 2) { dest_mode = IEEE_802154_SHORT_ADDR_M; } else { DEBUG("Illegal IEEE 802.15.4 address for address length %d\n", dest_len); return -1; } set_ieee802154_fcf_values(frame, dest_mode, src_mode); if (src_mode == IEEE_802154_LONG_ADDR_M) { net_if_get_eui64((net_if_eui64_t *)&frame->src_addr[0], if_id, 0); } else if (src_mode == IEEE_802154_SHORT_ADDR_M) { uint16_t src = HTONS(net_if_get_hardware_address(if_id)); memcpy(&frame->src_addr[0], &src, 2); } else { DEBUG("Illegal IEEE 802.15.4 address mode: %d\n", src_mode); return -1; } if (mcast) { memset(&frame->dest_addr[0], 0xff, dest_len); } else { memcpy(&frame->dest_addr[0], dest, dest_len); } frame->payload = (uint8_t *)payload; // payload won't be changed so cast is legal. frame->payload_len = length; uint8_t hdrlen = ieee802154_frame_get_hdr_len(frame); memset(&lowpan_mac_buf, 0, PAYLOAD_SIZE); ieee802154_frame_init(frame, (uint8_t *)&lowpan_mac_buf); memcpy(&lowpan_mac_buf[hdrlen], frame->payload, frame->payload_len); /* set FCS */ fcs = (uint16_t *)&lowpan_mac_buf[frame->payload_len + hdrlen]; *fcs = ieee802154_frame_get_fcs(lowpan_mac_buf, frame->payload_len + hdrlen); DEBUG("IEEE802.15.4 frame - FCF: %02X %02X DPID: %02X SPID: %02X DSN: %02X\n", lowpan_mac_buf[0], lowpan_mac_buf[1], frame->dest_pan_id, frame->src_pan_id, frame->seq_nr); return hdrlen; } int sixlowpan_mac_send_data(int if_id, const void *dest, uint8_t dest_len, const void *payload, uint8_t payload_len, uint8_t mcast) { if (mcast) { return net_if_send_packet_broadcast(IEEE_802154_SHORT_ADDR_M, payload, payload_len); } else { if (dest_len == 8) { return net_if_send_packet_long(if_id, (net_if_eui64_t *) dest, payload, (size_t)payload_len); } else if (dest_len == 2) { return net_if_send_packet(if_id, NTOHS(*((uint16_t *)dest)), payload, (size_t)payload_len); } } return -1; } int sixlowpan_mac_send_ieee802154_frame(int if_id, const void *dest, uint8_t dest_len, const void *payload, uint8_t payload_len, uint8_t mcast) { if (net_if_get_interface(if_id) && net_if_get_interface(if_id)->transceivers & IEEE802154_TRANSCEIVER) { return sixlowpan_mac_send_data(if_id, dest, dest_len, payload, payload_len, mcast); } else { ieee802154_frame_t frame; uint16_t dest_pan = HTONS(0xabcd); uint8_t length; int hdrlen = sixlowpan_mac_prepare_ieee802144_frame(&frame, if_id, dest_pan, dest, dest_len, payload, payload_len, mcast); if (hdrlen < 0) { return -1; } length = hdrlen + frame.payload_len + IEEE_802154_FCS_LEN; return sixlowpan_mac_send_data(if_id, dest, dest_len, lowpan_mac_buf, length, mcast); } } int sixlowpan_mac_init(void) { int recv_pid = thread_create(radio_stack_buffer, RADIO_STACK_SIZE, PRIORITY_MAIN - 2, CREATE_STACKTEST, recv_ieee802154_frame , "radio"); int if_id = -1; while ((if_id = net_if_iter_interfaces(if_id)) >= 0) { net_if_register(if_id, recv_pid); } macdsn = rand() % 256; return recv_pid; }