1195972f6Sopenharmony_ci/** 2195972f6Sopenharmony_ci * @file 3195972f6Sopenharmony_ci * 4195972f6Sopenharmony_ci * @defgroup zepif ZEP - ZigBee Encapsulation Protocol 5195972f6Sopenharmony_ci * @ingroup netifs 6195972f6Sopenharmony_ci * A netif implementing the ZigBee Encapsulation Protocol (ZEP). 7195972f6Sopenharmony_ci * This is used to tunnel 6LowPAN over UDP. 8195972f6Sopenharmony_ci * 9195972f6Sopenharmony_ci * Usage (there must be a default netif before!): 10195972f6Sopenharmony_ci * @code{.c} 11195972f6Sopenharmony_ci * netif_add(&zep_netif, NULL, NULL, NULL, NULL, zepif_init, tcpip_6lowpan_input); 12195972f6Sopenharmony_ci * netif_create_ip6_linklocal_address(&zep_netif, 1); 13195972f6Sopenharmony_ci * netif_set_up(&zep_netif); 14195972f6Sopenharmony_ci * netif_set_link_up(&zep_netif); 15195972f6Sopenharmony_ci * @endcode 16195972f6Sopenharmony_ci */ 17195972f6Sopenharmony_ci 18195972f6Sopenharmony_ci/* 19195972f6Sopenharmony_ci * Copyright (c) 2018 Simon Goldschmidt 20195972f6Sopenharmony_ci * All rights reserved. 21195972f6Sopenharmony_ci * 22195972f6Sopenharmony_ci * Redistribution and use in source and binary forms, with or without modification, 23195972f6Sopenharmony_ci * are permitted provided that the following conditions are met: 24195972f6Sopenharmony_ci * 25195972f6Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright notice, 26195972f6Sopenharmony_ci * this list of conditions and the following disclaimer. 27195972f6Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright notice, 28195972f6Sopenharmony_ci * this list of conditions and the following disclaimer in the documentation 29195972f6Sopenharmony_ci * and/or other materials provided with the distribution. 30195972f6Sopenharmony_ci * 3. The name of the author may not be used to endorse or promote products 31195972f6Sopenharmony_ci * derived from this software without specific prior written permission. 32195972f6Sopenharmony_ci * 33195972f6Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 34195972f6Sopenharmony_ci * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 35195972f6Sopenharmony_ci * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 36195972f6Sopenharmony_ci * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 37195972f6Sopenharmony_ci * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 38195972f6Sopenharmony_ci * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 39195972f6Sopenharmony_ci * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 40195972f6Sopenharmony_ci * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 41195972f6Sopenharmony_ci * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 42195972f6Sopenharmony_ci * OF SUCH DAMAGE. 43195972f6Sopenharmony_ci * 44195972f6Sopenharmony_ci * This file is part of the lwIP TCP/IP stack. 45195972f6Sopenharmony_ci * 46195972f6Sopenharmony_ci * Author: Simon Goldschmidt <goldsimon@gmx.de> 47195972f6Sopenharmony_ci * 48195972f6Sopenharmony_ci */ 49195972f6Sopenharmony_ci 50195972f6Sopenharmony_ci#include "netif/zepif.h" 51195972f6Sopenharmony_ci 52195972f6Sopenharmony_ci#if LWIP_IPV6 && LWIP_UDP 53195972f6Sopenharmony_ci 54195972f6Sopenharmony_ci#include "netif/lowpan6.h" 55195972f6Sopenharmony_ci#include "lwip/udp.h" 56195972f6Sopenharmony_ci#include "lwip/timeouts.h" 57195972f6Sopenharmony_ci#include <string.h> 58195972f6Sopenharmony_ci 59195972f6Sopenharmony_ci/** Define this to 1 to loop back TX packets for testing */ 60195972f6Sopenharmony_ci#ifndef ZEPIF_LOOPBACK 61195972f6Sopenharmony_ci#define ZEPIF_LOOPBACK 0 62195972f6Sopenharmony_ci#endif 63195972f6Sopenharmony_ci 64195972f6Sopenharmony_ci#define ZEP_MAX_DATA_LEN 127 65195972f6Sopenharmony_ci 66195972f6Sopenharmony_ci#ifdef PACK_STRUCT_USE_INCLUDES 67195972f6Sopenharmony_ci# include "arch/bpstruct.h" 68195972f6Sopenharmony_ci#endif 69195972f6Sopenharmony_ciPACK_STRUCT_BEGIN 70195972f6Sopenharmony_cistruct zep_hdr { 71195972f6Sopenharmony_ci PACK_STRUCT_FLD_8(u8_t prot_id[2]); 72195972f6Sopenharmony_ci PACK_STRUCT_FLD_8(u8_t prot_version); 73195972f6Sopenharmony_ci PACK_STRUCT_FLD_8(u8_t type); 74195972f6Sopenharmony_ci PACK_STRUCT_FLD_8(u8_t channel_id); 75195972f6Sopenharmony_ci PACK_STRUCT_FIELD(u16_t device_id); 76195972f6Sopenharmony_ci PACK_STRUCT_FLD_8(u8_t crc_mode); 77195972f6Sopenharmony_ci PACK_STRUCT_FLD_8(u8_t unknown_1); 78195972f6Sopenharmony_ci PACK_STRUCT_FIELD(u32_t timestamp[2]); 79195972f6Sopenharmony_ci PACK_STRUCT_FIELD(u32_t seq_num); 80195972f6Sopenharmony_ci PACK_STRUCT_FLD_8(u8_t unknown_2[10]); 81195972f6Sopenharmony_ci PACK_STRUCT_FLD_8(u8_t len); 82195972f6Sopenharmony_ci} PACK_STRUCT_STRUCT; 83195972f6Sopenharmony_ciPACK_STRUCT_END 84195972f6Sopenharmony_ci#ifdef PACK_STRUCT_USE_INCLUDES 85195972f6Sopenharmony_ci# include "arch/epstruct.h" 86195972f6Sopenharmony_ci#endif 87195972f6Sopenharmony_ci 88195972f6Sopenharmony_cistruct zepif_state { 89195972f6Sopenharmony_ci struct zepif_init init; 90195972f6Sopenharmony_ci struct udp_pcb *pcb; 91195972f6Sopenharmony_ci u32_t seqno; 92195972f6Sopenharmony_ci}; 93195972f6Sopenharmony_ci 94195972f6Sopenharmony_cistatic u8_t zep_lowpan_timer_running; 95195972f6Sopenharmony_ci 96195972f6Sopenharmony_ci/* Helper function that calls the 6LoWPAN timer and reschedules itself */ 97195972f6Sopenharmony_cistatic void 98195972f6Sopenharmony_cizep_lowpan_timer(void *arg) 99195972f6Sopenharmony_ci{ 100195972f6Sopenharmony_ci lowpan6_tmr(); 101195972f6Sopenharmony_ci if (zep_lowpan_timer_running) { 102195972f6Sopenharmony_ci sys_timeout(LOWPAN6_TMR_INTERVAL, zep_lowpan_timer, arg); 103195972f6Sopenharmony_ci } 104195972f6Sopenharmony_ci} 105195972f6Sopenharmony_ci 106195972f6Sopenharmony_ci/* Pass received pbufs into 6LowPAN netif */ 107195972f6Sopenharmony_cistatic void 108195972f6Sopenharmony_cizepif_udp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, 109195972f6Sopenharmony_ci const ip_addr_t *addr, u16_t port) 110195972f6Sopenharmony_ci{ 111195972f6Sopenharmony_ci err_t err; 112195972f6Sopenharmony_ci struct netif *netif_lowpan6 = (struct netif *)arg; 113195972f6Sopenharmony_ci struct zep_hdr *zep; 114195972f6Sopenharmony_ci 115195972f6Sopenharmony_ci LWIP_ASSERT("arg != NULL", arg != NULL); 116195972f6Sopenharmony_ci LWIP_ASSERT("pcb != NULL", pcb != NULL); 117195972f6Sopenharmony_ci LWIP_UNUSED_ARG(pcb); /* for LWIP_NOASSERT */ 118195972f6Sopenharmony_ci LWIP_UNUSED_ARG(addr); 119195972f6Sopenharmony_ci LWIP_UNUSED_ARG(port); 120195972f6Sopenharmony_ci if (p == NULL) { 121195972f6Sopenharmony_ci return; 122195972f6Sopenharmony_ci } 123195972f6Sopenharmony_ci 124195972f6Sopenharmony_ci /* Parse and hide the ZEP header */ 125195972f6Sopenharmony_ci if (p->len < sizeof(struct zep_hdr)) { 126195972f6Sopenharmony_ci /* need the zep_hdr in one piece */ 127195972f6Sopenharmony_ci goto err_return; 128195972f6Sopenharmony_ci } 129195972f6Sopenharmony_ci zep = (struct zep_hdr *)p->payload; 130195972f6Sopenharmony_ci if (zep->prot_id[0] != 'E') { 131195972f6Sopenharmony_ci goto err_return; 132195972f6Sopenharmony_ci } 133195972f6Sopenharmony_ci if (zep->prot_id[1] != 'X') { 134195972f6Sopenharmony_ci goto err_return; 135195972f6Sopenharmony_ci } 136195972f6Sopenharmony_ci if (zep->prot_version != 2) { 137195972f6Sopenharmony_ci /* we only support this version for now */ 138195972f6Sopenharmony_ci goto err_return; 139195972f6Sopenharmony_ci } 140195972f6Sopenharmony_ci if (zep->type != 1) { 141195972f6Sopenharmony_ci goto err_return; 142195972f6Sopenharmony_ci } 143195972f6Sopenharmony_ci if (zep->crc_mode != 1) { 144195972f6Sopenharmony_ci goto err_return; 145195972f6Sopenharmony_ci } 146195972f6Sopenharmony_ci if (zep->len != p->tot_len - sizeof(struct zep_hdr)) { 147195972f6Sopenharmony_ci goto err_return; 148195972f6Sopenharmony_ci } 149195972f6Sopenharmony_ci /* everything seems to be OK, hide the ZEP header */ 150195972f6Sopenharmony_ci if (pbuf_remove_header(p, sizeof(struct zep_hdr))) { 151195972f6Sopenharmony_ci goto err_return; 152195972f6Sopenharmony_ci } 153195972f6Sopenharmony_ci /* TODO Check CRC? */ 154195972f6Sopenharmony_ci /* remove CRC trailer */ 155195972f6Sopenharmony_ci pbuf_realloc(p, p->tot_len - 2); 156195972f6Sopenharmony_ci 157195972f6Sopenharmony_ci /* Call into 6LoWPAN code. */ 158195972f6Sopenharmony_ci err = netif_lowpan6->input(p, netif_lowpan6); 159195972f6Sopenharmony_ci if (err == ERR_OK) { 160195972f6Sopenharmony_ci return; 161195972f6Sopenharmony_ci } 162195972f6Sopenharmony_cierr_return: 163195972f6Sopenharmony_ci pbuf_free(p); 164195972f6Sopenharmony_ci} 165195972f6Sopenharmony_ci 166195972f6Sopenharmony_ci/* Send 6LoWPAN TX packets as UDP broadcast */ 167195972f6Sopenharmony_cistatic err_t 168195972f6Sopenharmony_cizepif_linkoutput(struct netif *netif, struct pbuf *p) 169195972f6Sopenharmony_ci{ 170195972f6Sopenharmony_ci err_t err; 171195972f6Sopenharmony_ci struct pbuf *q; 172195972f6Sopenharmony_ci struct zep_hdr *zep; 173195972f6Sopenharmony_ci struct zepif_state *state; 174195972f6Sopenharmony_ci 175195972f6Sopenharmony_ci LWIP_ASSERT("invalid netif", netif != NULL); 176195972f6Sopenharmony_ci LWIP_ASSERT("invalid pbuf", p != NULL); 177195972f6Sopenharmony_ci 178195972f6Sopenharmony_ci if (p->tot_len > ZEP_MAX_DATA_LEN) { 179195972f6Sopenharmony_ci return ERR_VAL; 180195972f6Sopenharmony_ci } 181195972f6Sopenharmony_ci LWIP_ASSERT("TODO: support chained pbufs", p->next == NULL); 182195972f6Sopenharmony_ci 183195972f6Sopenharmony_ci state = (struct zepif_state *)netif->state; 184195972f6Sopenharmony_ci LWIP_ASSERT("state->pcb != NULL", state->pcb != NULL); 185195972f6Sopenharmony_ci 186195972f6Sopenharmony_ci q = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct zep_hdr) + p->tot_len, PBUF_RAM); 187195972f6Sopenharmony_ci if (q == NULL) { 188195972f6Sopenharmony_ci return ERR_MEM; 189195972f6Sopenharmony_ci } 190195972f6Sopenharmony_ci zep = (struct zep_hdr *)q->payload; 191195972f6Sopenharmony_ci memset(zep, 0, sizeof(struct zep_hdr)); 192195972f6Sopenharmony_ci zep->prot_id[0] = 'E'; 193195972f6Sopenharmony_ci zep->prot_id[1] = 'X'; 194195972f6Sopenharmony_ci zep->prot_version = 2; 195195972f6Sopenharmony_ci zep->type = 1; /* Data */ 196195972f6Sopenharmony_ci zep->channel_id = 0; /* whatever */ 197195972f6Sopenharmony_ci zep->device_id = lwip_htons(1); /* whatever */ 198195972f6Sopenharmony_ci zep->crc_mode = 1; 199195972f6Sopenharmony_ci zep->unknown_1 = 0xff; 200195972f6Sopenharmony_ci zep->seq_num = lwip_htonl(state->seqno); 201195972f6Sopenharmony_ci state->seqno++; 202195972f6Sopenharmony_ci zep->len = (u8_t)p->tot_len; 203195972f6Sopenharmony_ci 204195972f6Sopenharmony_ci err = pbuf_copy_partial_pbuf(q, p, p->tot_len, sizeof(struct zep_hdr)); 205195972f6Sopenharmony_ci if (err == ERR_OK) { 206195972f6Sopenharmony_ci#if ZEPIF_LOOPBACK 207195972f6Sopenharmony_ci zepif_udp_recv(netif, state->pcb, pbuf_clone(PBUF_RAW, PBUF_RAM, q), NULL, 0); 208195972f6Sopenharmony_ci#endif 209195972f6Sopenharmony_ci err = udp_sendto(state->pcb, q, state->init.zep_dst_ip_addr, state->init.zep_dst_udp_port); 210195972f6Sopenharmony_ci } 211195972f6Sopenharmony_ci pbuf_free(q); 212195972f6Sopenharmony_ci 213195972f6Sopenharmony_ci return err; 214195972f6Sopenharmony_ci} 215195972f6Sopenharmony_ci 216195972f6Sopenharmony_ci/** 217195972f6Sopenharmony_ci * @ingroup zepif 218195972f6Sopenharmony_ci * Set up a raw 6LowPAN netif and surround it with input- and output 219195972f6Sopenharmony_ci * functions for ZEP 220195972f6Sopenharmony_ci */ 221195972f6Sopenharmony_cierr_t 222195972f6Sopenharmony_cizepif_init(struct netif *netif) 223195972f6Sopenharmony_ci{ 224195972f6Sopenharmony_ci err_t err; 225195972f6Sopenharmony_ci struct zepif_init *init_state = (struct zepif_init *)netif->state; 226195972f6Sopenharmony_ci struct zepif_state *state = (struct zepif_state *)mem_malloc(sizeof(struct zepif_state)); 227195972f6Sopenharmony_ci 228195972f6Sopenharmony_ci LWIP_ASSERT("zepif needs an input callback", netif->input != NULL); 229195972f6Sopenharmony_ci 230195972f6Sopenharmony_ci if (state == NULL) { 231195972f6Sopenharmony_ci return ERR_MEM; 232195972f6Sopenharmony_ci } 233195972f6Sopenharmony_ci memset(state, 0, sizeof(struct zepif_state)); 234195972f6Sopenharmony_ci if (init_state != NULL) { 235195972f6Sopenharmony_ci memcpy(&state->init, init_state, sizeof(struct zepif_init)); 236195972f6Sopenharmony_ci } 237195972f6Sopenharmony_ci if (state->init.zep_src_udp_port == 0) { 238195972f6Sopenharmony_ci state->init.zep_src_udp_port = ZEPIF_DEFAULT_UDP_PORT; 239195972f6Sopenharmony_ci } 240195972f6Sopenharmony_ci if (state->init.zep_dst_udp_port == 0) { 241195972f6Sopenharmony_ci state->init.zep_dst_udp_port = ZEPIF_DEFAULT_UDP_PORT; 242195972f6Sopenharmony_ci } 243195972f6Sopenharmony_ci#if LWIP_IPV4 244195972f6Sopenharmony_ci if (state->init.zep_dst_ip_addr == NULL) { 245195972f6Sopenharmony_ci /* With IPv4 enabled, default to broadcasting packets if no address is set */ 246195972f6Sopenharmony_ci state->init.zep_dst_ip_addr = IP_ADDR_BROADCAST; 247195972f6Sopenharmony_ci } 248195972f6Sopenharmony_ci#endif /* LWIP_IPV4 */ 249195972f6Sopenharmony_ci 250195972f6Sopenharmony_ci netif->state = NULL; 251195972f6Sopenharmony_ci 252195972f6Sopenharmony_ci state->pcb = udp_new_ip_type(IPADDR_TYPE_ANY); 253195972f6Sopenharmony_ci if (state->pcb == NULL) { 254195972f6Sopenharmony_ci err = ERR_MEM; 255195972f6Sopenharmony_ci goto err_ret; 256195972f6Sopenharmony_ci } 257195972f6Sopenharmony_ci err = udp_bind(state->pcb, state->init.zep_src_ip_addr, state->init.zep_src_udp_port); 258195972f6Sopenharmony_ci if (err != ERR_OK) { 259195972f6Sopenharmony_ci goto err_ret; 260195972f6Sopenharmony_ci } 261195972f6Sopenharmony_ci if (state->init.zep_netif != NULL) { 262195972f6Sopenharmony_ci udp_bind_netif(state->pcb, state->init.zep_netif); 263195972f6Sopenharmony_ci } 264195972f6Sopenharmony_ci LWIP_ASSERT("udp_bind(lowpan6_broadcast_pcb) failed", err == ERR_OK); 265195972f6Sopenharmony_ci ip_set_option(state->pcb, SOF_BROADCAST); 266195972f6Sopenharmony_ci udp_recv(state->pcb, zepif_udp_recv, netif); 267195972f6Sopenharmony_ci 268195972f6Sopenharmony_ci err = lowpan6_if_init(netif); 269195972f6Sopenharmony_ci LWIP_ASSERT("lowpan6_if_init set a state", netif->state == NULL); 270195972f6Sopenharmony_ci if (err == ERR_OK) { 271195972f6Sopenharmony_ci netif->state = state; 272195972f6Sopenharmony_ci netif->hwaddr_len = 6; 273195972f6Sopenharmony_ci if (init_state != NULL) { 274195972f6Sopenharmony_ci memcpy(netif->hwaddr, init_state->addr, 6); 275195972f6Sopenharmony_ci } else { 276195972f6Sopenharmony_ci u8_t i; 277195972f6Sopenharmony_ci for (i = 0; i < 6; i++) { 278195972f6Sopenharmony_ci netif->hwaddr[i] = i; 279195972f6Sopenharmony_ci } 280195972f6Sopenharmony_ci netif->hwaddr[0] &= 0xfc; 281195972f6Sopenharmony_ci } 282195972f6Sopenharmony_ci netif->linkoutput = zepif_linkoutput; 283195972f6Sopenharmony_ci 284195972f6Sopenharmony_ci if (!zep_lowpan_timer_running) { 285195972f6Sopenharmony_ci sys_timeout(LOWPAN6_TMR_INTERVAL, zep_lowpan_timer, NULL); 286195972f6Sopenharmony_ci zep_lowpan_timer_running = 1; 287195972f6Sopenharmony_ci } 288195972f6Sopenharmony_ci 289195972f6Sopenharmony_ci return ERR_OK; 290195972f6Sopenharmony_ci } 291195972f6Sopenharmony_ci 292195972f6Sopenharmony_cierr_ret: 293195972f6Sopenharmony_ci if (state->pcb != NULL) { 294195972f6Sopenharmony_ci udp_remove(state->pcb); 295195972f6Sopenharmony_ci } 296195972f6Sopenharmony_ci mem_free(state); 297195972f6Sopenharmony_ci return err; 298195972f6Sopenharmony_ci} 299195972f6Sopenharmony_ci 300195972f6Sopenharmony_ci#endif /* LWIP_IPV6 && LWIP_UDP */ 301