1 /** 2 * @file 3 * 4 * @defgroup zepif ZEP - ZigBee Encapsulation Protocol 5 * @ingroup netifs 6 * A netif implementing the ZigBee Encapsulation Protocol (ZEP). 7 * This is used to tunnel 6LowPAN over UDP. 8 * 9 * Usage (there must be a default netif before!): 10 * @code{.c} 11 * netif_add(&zep_netif, NULL, NULL, NULL, NULL, zepif_init, tcpip_6lowpan_input); 12 * netif_create_ip6_linklocal_address(&zep_netif, 1); 13 * netif_set_up(&zep_netif); 14 * netif_set_link_up(&zep_netif); 15 * @endcode 16 */ 17 18 /* 19 * Copyright (c) 2018 Simon Goldschmidt 20 * All rights reserved. 21 * 22 * Redistribution and use in source and binary forms, with or without modification, 23 * are permitted provided that the following conditions are met: 24 * 25 * 1. Redistributions of source code must retain the above copyright notice, 26 * this list of conditions and the following disclaimer. 27 * 2. Redistributions in binary form must reproduce the above copyright notice, 28 * this list of conditions and the following disclaimer in the documentation 29 * and/or other materials provided with the distribution. 30 * 3. The name of the author may not be used to endorse or promote products 31 * derived from this software without specific prior written permission. 32 * 33 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 34 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 35 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 36 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 37 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 38 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 39 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 40 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 41 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 42 * OF SUCH DAMAGE. 43 * 44 * This file is part of the lwIP TCP/IP stack. 45 * 46 * Author: Simon Goldschmidt <goldsimon@gmx.de> 47 * 48 */ 49 50 #include "netif/zepif.h" 51 52 #if LWIP_IPV6 && LWIP_UDP 53 54 #include "netif/lowpan6.h" 55 #include "lwip/udp.h" 56 #include "lwip/timeouts.h" 57 #include <string.h> 58 59 /** Define this to 1 to loop back TX packets for testing */ 60 #ifndef ZEPIF_LOOPBACK 61 #define ZEPIF_LOOPBACK 0 62 #endif 63 64 #define ZEP_MAX_DATA_LEN 127 65 66 #ifdef PACK_STRUCT_USE_INCLUDES 67 # include "arch/bpstruct.h" 68 #endif 69 PACK_STRUCT_BEGIN 70 struct zep_hdr { 71 PACK_STRUCT_FLD_8(u8_t prot_id[2]); 72 PACK_STRUCT_FLD_8(u8_t prot_version); 73 PACK_STRUCT_FLD_8(u8_t type); 74 PACK_STRUCT_FLD_8(u8_t channel_id); 75 PACK_STRUCT_FIELD(u16_t device_id); 76 PACK_STRUCT_FLD_8(u8_t crc_mode); 77 PACK_STRUCT_FLD_8(u8_t unknown_1); 78 PACK_STRUCT_FIELD(u32_t timestamp[2]); 79 PACK_STRUCT_FIELD(u32_t seq_num); 80 PACK_STRUCT_FLD_8(u8_t unknown_2[10]); 81 PACK_STRUCT_FLD_8(u8_t len); 82 } PACK_STRUCT_STRUCT; 83 PACK_STRUCT_END 84 #ifdef PACK_STRUCT_USE_INCLUDES 85 # include "arch/epstruct.h" 86 #endif 87 88 struct zepif_state { 89 struct zepif_init init; 90 struct udp_pcb *pcb; 91 u32_t seqno; 92 }; 93 94 static u8_t zep_lowpan_timer_running; 95 96 /* Helper function that calls the 6LoWPAN timer and reschedules itself */ 97 static void 98 zep_lowpan_timer(void *arg) 99 { 100 lowpan6_tmr(); 101 if (zep_lowpan_timer_running) { 102 sys_timeout(LOWPAN6_TMR_INTERVAL, zep_lowpan_timer, arg); 103 } 104 } 105 106 /* Pass received pbufs into 6LowPAN netif */ 107 static void 108 zepif_udp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, 109 const ip_addr_t *addr, u16_t port) 110 { 111 err_t err; 112 struct netif *netif_lowpan6 = (struct netif *)arg; 113 struct zep_hdr *zep; 114 115 LWIP_ASSERT("arg != NULL", arg != NULL); 116 LWIP_ASSERT("pcb != NULL", pcb != NULL); 117 LWIP_UNUSED_ARG(pcb); /* for LWIP_NOASSERT */ 118 LWIP_UNUSED_ARG(addr); 119 LWIP_UNUSED_ARG(port); 120 if (p == NULL) { 121 return; 122 } 123 124 /* Parse and hide the ZEP header */ 125 if (p->len < sizeof(struct zep_hdr)) { 126 /* need the zep_hdr in one piece */ 127 goto err_return; 128 } 129 zep = (struct zep_hdr *)p->payload; 130 if (zep->prot_id[0] != 'E') { 131 goto err_return; 132 } 133 if (zep->prot_id[1] != 'X') { 134 goto err_return; 135 } 136 if (zep->prot_version != 2) { 137 /* we only support this version for now */ 138 goto err_return; 139 } 140 if (zep->type != 1) { 141 goto err_return; 142 } 143 if (zep->crc_mode != 1) { 144 goto err_return; 145 } 146 if (zep->len != p->tot_len - sizeof(struct zep_hdr)) { 147 goto err_return; 148 } 149 /* everything seems to be OK, hide the ZEP header */ 150 if (pbuf_remove_header(p, sizeof(struct zep_hdr))) { 151 goto err_return; 152 } 153 /* TODO Check CRC? */ 154 /* remove CRC trailer */ 155 pbuf_realloc(p, p->tot_len - 2); 156 157 /* Call into 6LoWPAN code. */ 158 err = netif_lowpan6->input(p, netif_lowpan6); 159 if (err == ERR_OK) { 160 return; 161 } 162 err_return: 163 pbuf_free(p); 164 } 165 166 /* Send 6LoWPAN TX packets as UDP broadcast */ 167 static err_t 168 zepif_linkoutput(struct netif *netif, struct pbuf *p) 169 { 170 err_t err; 171 struct pbuf *q; 172 struct zep_hdr *zep; 173 struct zepif_state *state; 174 175 LWIP_ASSERT("invalid netif", netif != NULL); 176 LWIP_ASSERT("invalid pbuf", p != NULL); 177 178 if (p->tot_len > ZEP_MAX_DATA_LEN) { 179 return ERR_VAL; 180 } 181 LWIP_ASSERT("TODO: support chained pbufs", p->next == NULL); 182 183 state = (struct zepif_state *)netif->state; 184 LWIP_ASSERT("state->pcb != NULL", state->pcb != NULL); 185 186 q = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct zep_hdr) + p->tot_len, PBUF_RAM); 187 if (q == NULL) { 188 return ERR_MEM; 189 } 190 zep = (struct zep_hdr *)q->payload; 191 memset(zep, 0, sizeof(struct zep_hdr)); 192 zep->prot_id[0] = 'E'; 193 zep->prot_id[1] = 'X'; 194 zep->prot_version = 2; 195 zep->type = 1; /* Data */ 196 zep->channel_id = 0; /* whatever */ 197 zep->device_id = lwip_htons(1); /* whatever */ 198 zep->crc_mode = 1; 199 zep->unknown_1 = 0xff; 200 zep->seq_num = lwip_htonl(state->seqno); 201 state->seqno++; 202 zep->len = (u8_t)p->tot_len; 203 204 err = pbuf_copy_partial_pbuf(q, p, p->tot_len, sizeof(struct zep_hdr)); 205 if (err == ERR_OK) { 206 #if ZEPIF_LOOPBACK 207 zepif_udp_recv(netif, state->pcb, pbuf_clone(PBUF_RAW, PBUF_RAM, q), NULL, 0); 208 #endif 209 err = udp_sendto(state->pcb, q, state->init.zep_dst_ip_addr, state->init.zep_dst_udp_port); 210 } 211 pbuf_free(q); 212 213 return err; 214 } 215 216 /** 217 * @ingroup zepif 218 * Set up a raw 6LowPAN netif and surround it with input- and output 219 * functions for ZEP 220 */ 221 err_t 222 zepif_init(struct netif *netif) 223 { 224 err_t err; 225 struct zepif_init *init_state = (struct zepif_init *)netif->state; 226 struct zepif_state *state = (struct zepif_state *)mem_malloc(sizeof(struct zepif_state)); 227 228 LWIP_ASSERT("zepif needs an input callback", netif->input != NULL); 229 230 if (state == NULL) { 231 return ERR_MEM; 232 } 233 memset(state, 0, sizeof(struct zepif_state)); 234 if (init_state != NULL) { 235 memcpy(&state->init, init_state, sizeof(struct zepif_init)); 236 } 237 if (state->init.zep_src_udp_port == 0) { 238 state->init.zep_src_udp_port = ZEPIF_DEFAULT_UDP_PORT; 239 } 240 if (state->init.zep_dst_udp_port == 0) { 241 state->init.zep_dst_udp_port = ZEPIF_DEFAULT_UDP_PORT; 242 } 243 #if LWIP_IPV4 244 if (state->init.zep_dst_ip_addr == NULL) { 245 /* With IPv4 enabled, default to broadcasting packets if no address is set */ 246 state->init.zep_dst_ip_addr = IP_ADDR_BROADCAST; 247 } 248 #endif /* LWIP_IPV4 */ 249 250 netif->state = NULL; 251 252 state->pcb = udp_new_ip_type(IPADDR_TYPE_ANY); 253 if (state->pcb == NULL) { 254 err = ERR_MEM; 255 goto err_ret; 256 } 257 err = udp_bind(state->pcb, state->init.zep_src_ip_addr, state->init.zep_src_udp_port); 258 if (err != ERR_OK) { 259 goto err_ret; 260 } 261 if (state->init.zep_netif != NULL) { 262 udp_bind_netif(state->pcb, state->init.zep_netif); 263 } 264 LWIP_ASSERT("udp_bind(lowpan6_broadcast_pcb) failed", err == ERR_OK); 265 ip_set_option(state->pcb, SOF_BROADCAST); 266 udp_recv(state->pcb, zepif_udp_recv, netif); 267 268 err = lowpan6_if_init(netif); 269 LWIP_ASSERT("lowpan6_if_init set a state", netif->state == NULL); 270 if (err == ERR_OK) { 271 netif->state = state; 272 netif->hwaddr_len = 6; 273 if (init_state != NULL) { 274 memcpy(netif->hwaddr, init_state->addr, 6); 275 } else { 276 u8_t i; 277 for (i = 0; i < 6; i++) { 278 netif->hwaddr[i] = i; 279 } 280 netif->hwaddr[0] &= 0xfc; 281 } 282 netif->linkoutput = zepif_linkoutput; 283 284 if (!zep_lowpan_timer_running) { 285 sys_timeout(LOWPAN6_TMR_INTERVAL, zep_lowpan_timer, NULL); 286 zep_lowpan_timer_running = 1; 287 } 288 289 return ERR_OK; 290 } 291 292 err_ret: 293 if (state->pcb != NULL) { 294 udp_remove(state->pcb); 295 } 296 mem_free(state); 297 return err; 298 } 299 300 #endif /* LWIP_IPV6 && LWIP_UDP */ 301