1029 lines
33 KiB
C
Executable File
1029 lines
33 KiB
C
Executable File
/****************************************************************************
|
|
|
|
Copyright(c) 2019 by Aerospace C.Power (Chongqing) Microelectronics. ALL RIGHTS RESERVED.
|
|
|
|
This Information is proprietary to Aerospace C.Power (Chongqing) Microelectronics and MAY NOT
|
|
be copied by any method or incorporated into another program without
|
|
the express written consent of Aerospace C.Power. This Information or any portion
|
|
thereof remains the property of Aerospace C.Power. The Information contained herein
|
|
is believed to be accurate and Aerospace C.Power assumes no responsibility or
|
|
liability for its use in any way and conveys no license or title under
|
|
any patent or copyright and makes no representation or warranty that this
|
|
Information is free from patent or copyright infringement.
|
|
|
|
****************************************************************************/
|
|
|
|
/* os shim inlcude */
|
|
#include "os_utils_api.h"
|
|
|
|
/* common inlcude */
|
|
#include "iot_config_api.h"
|
|
#include "iot_app_api.h"
|
|
#include "iot_plc_api.h"
|
|
#include "iot_ntoh_api.h"
|
|
#include "iot_utils_api.h"
|
|
#include "iot_addr_hash_table_api.h"
|
|
#include "iot_oem_api.h"
|
|
|
|
/* to resolve conflict with lwip internal definition. fortunately the value
|
|
* is the same.
|
|
*/
|
|
#ifdef ERR_OK
|
|
#undef ERR_OK
|
|
#endif
|
|
|
|
/* lwip internal includes */
|
|
#include "lwip/opt.h"
|
|
#include "lwip/sys.h"
|
|
#include "lwip/tcpip.h"
|
|
#include "lwip/snmp.h"
|
|
#include "lwip/dhcp.h"
|
|
#include "lwip/etharp.h"
|
|
#include "lwip/ethip6.h"
|
|
|
|
#include "netif/netif_uart.h"
|
|
#include "netif/netif_eth.h"
|
|
|
|
#if IOT_LWIP_NETIF_PLC_SUPPORT
|
|
|
|
#define netif_plc_printf iot_printf
|
|
|
|
#if PLC_SUPPORT_CCO_ROLE
|
|
|
|
#define IOT_MAC_RT_ENTRY_MAX 8
|
|
|
|
#define IOT_MAC_RT_HASH_TABLE_SIZE 4
|
|
|
|
#else /* PLC_SUPPORT_CCO_ROLE */
|
|
|
|
#define IOT_MAC_RT_ENTRY_MAX 16
|
|
|
|
#define IOT_MAC_RT_HASH_TABLE_SIZE 5
|
|
|
|
#endif /* PLC_SUPPORT_CCO_ROLE */
|
|
|
|
/* route entry target network definition */
|
|
#define IOT_MAC_RT_TO_INVAL 0
|
|
#define IOT_MAC_RT_TO_PLC 1
|
|
#define IOT_MAC_RT_TO_ETH 2
|
|
|
|
/* mac address based route entry */
|
|
typedef struct _iot_mac_route_entry {
|
|
/* hash table entry */
|
|
iot_addr_hash_entry_t entry;
|
|
/* timestamp of the last use. unit is 1ms */
|
|
uint64_t last_ts;
|
|
/* gateway to the final destination. big endian */
|
|
uint8_t gw_addr[IOT_MAC_ADDR_LEN];
|
|
/* gateway network type. see IOT_MAC_RT_TO_XXX */
|
|
uint8_t gw_type :4,
|
|
/* reserved for future */
|
|
rsvd :4;
|
|
} iot_mac_route_entry_t;
|
|
|
|
/* plc link state info */
|
|
typedef struct _iot_netif_plc_state {
|
|
/* plc app register status. 1 means registered */
|
|
uint8_t app_reg;
|
|
/* plc link status */
|
|
uint8_t link_ready;
|
|
/* flag to mark if cert test command ever detected */
|
|
uint8_t cert_test_detected;
|
|
/* plc device role. See IOT_PLC_DEV_ROLE_XXX */
|
|
uint8_t role;
|
|
/* local device mac address */
|
|
uint8_t addr[IOT_MAC_ADDR_LEN];
|
|
/* cco mac address */
|
|
uint8_t cco_addr[IOT_MAC_ADDR_LEN];
|
|
/* local device tei */
|
|
uint16_t dev_tei;
|
|
} iot_netif_plc_state_t;
|
|
|
|
/* global data strcucture for plc network interface */
|
|
typedef struct _netif_plc_global {
|
|
/* plc network interface descriptor */
|
|
struct netif netif;
|
|
/* IPv4 configurations */
|
|
ip_addr_t ipaddr;
|
|
ip_addr_t uart_ipaddr;
|
|
ip_addr_t netmask;
|
|
ip_addr_t gateway;
|
|
/* plc lib app handle */
|
|
iot_plc_app_h plc_app_h;
|
|
/* plc status info */
|
|
iot_netif_plc_state_t plc_state;
|
|
/* uart peer mac address, big endian */
|
|
uint8_t uart_peer_addr[IOT_MAC_ADDR_LEN];
|
|
/* mac address based route table */
|
|
iot_addr_hash_table_h rt_table;
|
|
} netif_plc_global_t;
|
|
|
|
static netif_plc_global_t *p_netif_plc = NULL;
|
|
|
|
static const uint8_t ipv4mcast[] = {0x01, 0x00, 0x5e};
|
|
|
|
static void netif_plc_gen_ipaddr(uint16_t tei)
|
|
{
|
|
uint32_t tmp;
|
|
uint8_t ip4_addr[IOT_IP4_ADDR_LEN] = { 0 };
|
|
|
|
/* if oem ip info is enabled and the ip method is customer setted,
|
|
* if the oem ip is valid, set the ip into the netif. */
|
|
if((IOT_OEM_IP_ENABLE == iot_oem_ip_is_enabled()) &&
|
|
(IOT_OEM_IP_METHOD_CUSTOMER == iot_oem_get_ip_method())) {
|
|
iot_oem_get_local_ip4_addr(ip4_addr);
|
|
if(IOT_OEM_IP4_IS_VALID == iot_oem_ip4_addr_is_valid(ip4_addr)) {
|
|
IP_ADDR4(&p_netif_plc->ipaddr,
|
|
ip4_addr[0], ip4_addr[1], ip4_addr[2], ip4_addr[3]);
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
tmp = ip_addr_get_ip4_u32(&p_netif_plc->ipaddr);
|
|
tmp = iot_ntohl(tmp);
|
|
tmp &= 0xFFFF0000;
|
|
tmp += tei;
|
|
tmp = iot_htonl(tmp);
|
|
ip_addr_set_ip4_u32(&p_netif_plc->ipaddr, tmp);
|
|
|
|
out:
|
|
tmp = ip_addr_get_ip4_u32(&p_netif_plc->uart_ipaddr);
|
|
tmp = iot_ntohl(tmp);
|
|
tmp &= 0xFFFF0000;
|
|
tmp += tei;
|
|
tmp = iot_htonl(tmp);
|
|
ip_addr_set_ip4_u32(&p_netif_plc->uart_ipaddr, tmp);
|
|
}
|
|
|
|
static void netif_plc_gen_ip4_netmask_addr()
|
|
{
|
|
uint8_t ip4_netmask[IOT_IP4_ADDR_LEN] = { 0 };
|
|
|
|
if((IOT_OEM_IP_ENABLE == iot_oem_ip_is_enabled()) &&
|
|
(IOT_OEM_IP_METHOD_CUSTOMER == iot_oem_get_ip_method())) {
|
|
iot_oem_get_local_ip4_netmask(ip4_netmask);
|
|
if(IOT_OEM_IP4_MASK_IS_VALID ==
|
|
iot_oem_ip4_netmask_is_valid(ip4_netmask)) {
|
|
IP_ADDR4(&p_netif_plc->netmask,
|
|
ip4_netmask[0], ip4_netmask[1], ip4_netmask[2], ip4_netmask[3]);
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
static void netif_plc_rpt_to_stack(uint8_t *data, uint16_t len, uint8_t unicast)
|
|
{
|
|
struct pbuf *p;
|
|
|
|
p = pbuf_alloc(PBUF_LINK, len, PBUF_POOL);
|
|
|
|
if (p != NULL) {
|
|
pbuf_take(p, data, len);
|
|
pbuf_realloc(p, len);
|
|
|
|
LINK_STATS_INC(link.recv);
|
|
MIB2_STATS_NETIF_ADD(&p_netif_plc->netif, ifinoctets, p->len);
|
|
if (unicast) {
|
|
MIB2_STATS_NETIF_INC(&p_netif_plc->netif, ifinucastpkts);
|
|
} else {
|
|
MIB2_STATS_NETIF_INC(&p_netif_plc->netif, ifinnucastpkts);
|
|
}
|
|
/* deliver to upper stack */
|
|
p_netif_plc->netif.input(p, &p_netif_plc->netif);
|
|
} else {
|
|
/* drop packet */
|
|
LINK_STATS_INC(link.memerr);
|
|
LINK_STATS_INC(link.drop);
|
|
MIB2_STATS_NETIF_INC(&p_netif_plc->netif, ifindiscards);
|
|
}
|
|
}
|
|
|
|
#if IOT_LWIP_NETIF_PLC_ETH_SUPPORT
|
|
|
|
#define netif_plc_send_ip4 etharp_output
|
|
|
|
#define netif_plc_send_ip6 ethip6_output
|
|
|
|
#define NETIF_PLC_APP_ID IOT_PLC_ETHERNET_ID
|
|
|
|
static void netif_plc_free_callback(iot_addr_hash_entry_t *entry,
|
|
void* param)
|
|
{
|
|
iot_mac_route_entry_t **old_entry = param, *tmp_entry;
|
|
|
|
tmp_entry = (iot_mac_route_entry_t *)entry;
|
|
if (*old_entry == NULL) {
|
|
*old_entry = tmp_entry;
|
|
} else if ((*old_entry)->last_ts > tmp_entry->last_ts) {
|
|
*old_entry = tmp_entry;
|
|
}
|
|
}
|
|
|
|
static void netif_plc_add_addr_rt(uint8_t *gw_addr, uint8_t *dst_addr,
|
|
uint8_t type)
|
|
{
|
|
iot_mac_route_entry_t *entry;
|
|
uint64_t curr_ts = os_boot_time64();
|
|
|
|
IOT_ASSERT(type);
|
|
|
|
entry = (iot_mac_route_entry_t *)iot_addr_hash_table_find(
|
|
p_netif_plc->rt_table, dst_addr);
|
|
|
|
if (entry) {
|
|
entry->last_ts = curr_ts;
|
|
entry->gw_type = type;
|
|
return;
|
|
}
|
|
|
|
/* entry not exist, try to add it */
|
|
entry = (iot_mac_route_entry_t *)iot_addr_hash_table_alloc(
|
|
p_netif_plc->rt_table);
|
|
if (entry == NULL) {
|
|
/* try to free some least used entry */
|
|
iot_addr_hash_table_loop(p_netif_plc->rt_table,
|
|
netif_plc_free_callback, &entry);
|
|
IOT_ASSERT(entry);
|
|
iot_addr_hash_table_remove(p_netif_plc->rt_table,
|
|
&entry->entry);
|
|
}
|
|
|
|
iot_mac_addr_cpy(entry->gw_addr, gw_addr);
|
|
iot_mac_addr_cpy(entry->entry.addr, dst_addr);
|
|
entry->gw_type = type;
|
|
entry->last_ts = curr_ts;
|
|
iot_addr_hash_table_add(p_netif_plc->rt_table, &entry->entry);
|
|
}
|
|
|
|
static uint8_t netif_plc_get_addr_rt(uint8_t *dst_addr, uint8_t *gw_addr)
|
|
{
|
|
iot_mac_route_entry_t *entry;
|
|
|
|
entry = (iot_mac_route_entry_t *)iot_addr_hash_table_find(
|
|
p_netif_plc->rt_table, dst_addr);
|
|
|
|
if (entry) {
|
|
iot_mac_addr_cpy(gw_addr, entry->gw_addr);
|
|
return entry->gw_type;
|
|
}
|
|
|
|
return IOT_MAC_RT_TO_INVAL;
|
|
}
|
|
|
|
static err_t netif_plc_send(struct netif *netif, struct pbuf *p)
|
|
{
|
|
uint8_t unicast;
|
|
iot_pkt_t *pkt = NULL, *to_cco_pkt = NULL;
|
|
struct eth_hdr *ethhdr;
|
|
struct pbuf *tmp_p;
|
|
uint8_t tmp_addr[IOT_MAC_ADDR_LEN];
|
|
uint8_t gw_type;
|
|
|
|
(void)netif;
|
|
BUILD_BUG_ON(ETH_PAD_SIZE == 0);
|
|
|
|
ethhdr = (struct eth_hdr *)p->payload;
|
|
if ((ethhdr->dest.addr[0] & 1) != 0) {
|
|
if (!iot_mac_is_bcast(ethhdr->dest.addr) &&
|
|
!os_mem_cmp(ethhdr->dest.addr, ipv4mcast, sizeof(ipv4mcast))) {
|
|
goto out;
|
|
}
|
|
unicast = 0;
|
|
} else {
|
|
unicast = 1;
|
|
}
|
|
|
|
IOT_ASSERT(iot_mac_addr_cmp(ethhdr->src.addr, p_netif_plc->plc_state.addr));
|
|
if (unicast == 0) {
|
|
pkt = iot_plc_alloc_msdu(p_netif_plc->plc_app_h,
|
|
IOT_PLC_MSG_TYPE_BCAST_1HOP, IOT_PLC_ACK_TYPE_NONE,
|
|
(uint8_t *)bcast_mac, p_netif_plc->plc_state.addr, 0,
|
|
p->tot_len, IOT_PLC_MAX_RETRY_CNT);
|
|
if (p_netif_plc->plc_state.role != IOT_PLC_DEV_ROLE_CCO) {
|
|
/* send a unicast packet to cco for forwarding as well */
|
|
to_cco_pkt = iot_plc_alloc_msdu(p_netif_plc->plc_app_h,
|
|
IOT_PLC_MSG_TYPE_UNICAST, IOT_PLC_ACK_TYPE_NONE,
|
|
p_netif_plc->plc_state.cco_addr,
|
|
p_netif_plc->plc_state.addr, 0,
|
|
p->tot_len, IOT_PLC_MAX_RETRY_CNT);
|
|
}
|
|
/* foward packet to uart link */
|
|
netif_plc_to_uart_send_by_pbuf(p);
|
|
/* foward packet to eth link */
|
|
netif_plc_to_eth_send_by_pbuf(p);
|
|
} else if (iot_mac_addr_cmp(ethhdr->dest.addr,
|
|
p_netif_plc->uart_peer_addr)) {
|
|
/* foward packet to uart link */
|
|
netif_plc_to_uart_send_by_pbuf(p);
|
|
} else {
|
|
gw_type = netif_plc_get_addr_rt(ethhdr->dest.addr, tmp_addr);
|
|
switch (gw_type) {
|
|
case IOT_MAC_RT_TO_PLC:
|
|
{
|
|
/* destination is behind a plc node */
|
|
pkt = iot_plc_alloc_msdu(p_netif_plc->plc_app_h,
|
|
IOT_PLC_MSG_TYPE_UNICAST, IOT_PLC_ACK_TYPE_NONE,
|
|
tmp_addr, p_netif_plc->plc_state.addr, 0,
|
|
p->tot_len, IOT_PLC_MAX_RETRY_CNT);
|
|
break;
|
|
}
|
|
case IOT_MAC_RT_TO_INVAL:
|
|
{
|
|
/* send to plc link directly */
|
|
pkt = iot_plc_alloc_msdu(p_netif_plc->plc_app_h,
|
|
IOT_PLC_MSG_TYPE_UNICAST, IOT_PLC_ACK_TYPE_NONE,
|
|
ethhdr->dest.addr, p_netif_plc->plc_state.addr, 0,
|
|
p->tot_len, IOT_PLC_MAX_RETRY_CNT);
|
|
break;
|
|
}
|
|
case IOT_MAC_RT_TO_ETH:
|
|
{
|
|
/* send to eth link */
|
|
netif_plc_to_eth_send_by_pbuf(p);
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
if (pkt) {
|
|
tmp_p = p;
|
|
while (tmp_p) {
|
|
os_mem_cpy(iot_pkt_tail(pkt), tmp_p->payload, tmp_p->len);
|
|
iot_pkt_put(pkt, tmp_p->len);
|
|
MIB2_STATS_NETIF_ADD(netif, ifoutoctets, tmp_p->len);
|
|
tmp_p = tmp_p->next;
|
|
}
|
|
/* send to plc link */
|
|
iot_plc_send_msdu(p_netif_plc->plc_app_h, pkt);
|
|
LINK_STATS_INC(link.xmit);
|
|
if (unicast) {
|
|
MIB2_STATS_NETIF_INC(netif, ifoutucastpkts);
|
|
} else {
|
|
MIB2_STATS_NETIF_INC(netif, ifinnucastpkts);
|
|
}
|
|
} else {
|
|
LINK_STATS_INC(link.memerr);
|
|
LINK_STATS_INC(link.drop);
|
|
MIB2_STATS_NETIF_INC(netif, ifoutdiscards);
|
|
}
|
|
if (to_cco_pkt) {
|
|
tmp_p = p;
|
|
while (tmp_p) {
|
|
os_mem_cpy(iot_pkt_tail(to_cco_pkt), tmp_p->payload, tmp_p->len);
|
|
iot_pkt_put(to_cco_pkt, tmp_p->len);
|
|
tmp_p = tmp_p->next;
|
|
}
|
|
/* send to plc link */
|
|
iot_plc_send_msdu(p_netif_plc->plc_app_h, to_cco_pkt);
|
|
}
|
|
|
|
out:
|
|
return ERR_OK;
|
|
}
|
|
|
|
static void netif_plc_recv(uint8_t *dst, uint8_t *src, uint8_t *data,
|
|
uint16_t len)
|
|
{
|
|
uint8_t unicast;
|
|
struct eth_hdr *ethhdr;
|
|
uint8_t tmp_addr[IOT_MAC_ADDR_LEN];
|
|
|
|
(void)src;
|
|
(void)dst;
|
|
|
|
if (len < sizeof(*ethhdr)) {
|
|
goto out;
|
|
}
|
|
|
|
ethhdr = (struct eth_hdr *)data;
|
|
if ((ethhdr->dest.addr[0] & 1) != 0) {
|
|
if (!iot_mac_is_bcast(ethhdr->dest.addr) &&
|
|
!os_mem_cmp(ethhdr->dest.addr, ipv4mcast, sizeof(ipv4mcast))) {
|
|
goto out;
|
|
}
|
|
unicast = 0;
|
|
/* foward packet to uart link */
|
|
netif_plc_to_uart_send_by_data(data, len);
|
|
/* foward packet to eth link */
|
|
netif_plc_to_eth_send_by_data(data, len);
|
|
} else {
|
|
unicast = 1;
|
|
if (iot_mac_addr_cmp(ethhdr->dest.addr,
|
|
p_netif_plc->uart_peer_addr)) {
|
|
/* foward packet to uart link */
|
|
netif_plc_to_uart_send_by_data(data, len);
|
|
} else if (IOT_MAC_RT_TO_ETH == netif_plc_get_addr_rt(ethhdr->dest.addr,
|
|
tmp_addr)) {
|
|
/* foward packet to eth link */
|
|
netif_plc_to_eth_send_by_data(data, len);
|
|
}
|
|
}
|
|
|
|
if ((ethhdr->src.addr[0] & 1) == 0) {
|
|
if (!iot_mac_addr_cmp(ethhdr->src.addr, src)) {
|
|
/* source is behind a plc node, save the mapping */
|
|
netif_plc_add_addr_rt(src, ethhdr->src.addr, IOT_MAC_RT_TO_PLC);
|
|
}
|
|
}
|
|
|
|
netif_plc_rpt_to_stack(data, len, unicast);
|
|
|
|
out:
|
|
return;
|
|
}
|
|
|
|
#else /* IOT_LWIP_NETIF_PLC_ETH_SUPPORT */
|
|
|
|
#define netif_plc_send_ip6 NULL
|
|
|
|
#define NETIF_PLC_APP_ID IOT_PLC_IP_ID
|
|
|
|
static uint16_t netif_ipaddr_to_tei(const ip4_addr_t *addr)
|
|
{
|
|
uint32_t tmp;
|
|
uint16_t tei;
|
|
|
|
tmp = ip4_addr_get_u32(addr);
|
|
tmp = iot_ntohl(tmp);
|
|
tei = tmp & 0xFFFF;
|
|
return tei;
|
|
}
|
|
|
|
static err_t netif_plc_send(struct netif *netif, struct pbuf *p)
|
|
{
|
|
(void)netif;
|
|
(void)p;
|
|
IOT_ASSERT(0);
|
|
return ERR_OK;
|
|
}
|
|
|
|
static err_t netif_plc_send_ip4(struct netif *netif, struct pbuf *p,
|
|
const ip4_addr_t *ipaddr)
|
|
{
|
|
uint8_t unicast;
|
|
struct pbuf *tmp_p;
|
|
iot_pkt_t *pkt, *to_cco_pkt = NULL;
|
|
|
|
if (ip4_addr_isbroadcast(ipaddr, netif) || ip4_addr_ismulticast(ipaddr)) {
|
|
unicast = 0;
|
|
if (p_netif_plc->plc_state.role != IOT_PLC_DEV_ROLE_CCO) {
|
|
pkt = iot_plc_alloc_msdu(p_netif_plc->plc_app_h,
|
|
IOT_PLC_MSG_TYPE_BCAST_1HOP, IOT_PLC_ACK_TYPE_NONE,
|
|
(uint8_t *)bcast_mac, p_netif_plc->plc_state.addr, 0,
|
|
p->tot_len, IOT_PLC_MAX_RETRY_CNT);
|
|
/* send a unicast packet to cco as well */
|
|
to_cco_pkt = iot_plc_alloc_msdu(p_netif_plc->plc_app_h,
|
|
IOT_PLC_MSG_TYPE_UNICAST, IOT_PLC_ACK_TYPE_NONE,
|
|
p_netif_plc->plc_state.cco_addr,
|
|
p_netif_plc->plc_state.addr, 0,
|
|
p->tot_len, IOT_PLC_MAX_RETRY_CNT);
|
|
} else {
|
|
pkt = iot_plc_alloc_msdu(p_netif_plc->plc_app_h,
|
|
IOT_PLC_MSG_TYPE_BCAST, IOT_PLC_ACK_TYPE_NONE,
|
|
(uint8_t *)bcast_mac, p_netif_plc->plc_state.addr, 0,
|
|
p->tot_len, IOT_PLC_MAX_RETRY_CNT);
|
|
}
|
|
} else {
|
|
unicast = 1;
|
|
pkt = iot_plc_alloc_msdu_by_tei(p_netif_plc->plc_app_h,
|
|
IOT_PLC_MSG_TYPE_UNICAST, IOT_PLC_ACK_TYPE_NONE,
|
|
netif_ipaddr_to_tei(ipaddr), p_netif_plc->plc_state.addr, 0,
|
|
p->tot_len, IOT_PLC_MAX_RETRY_CNT);
|
|
}
|
|
if (pkt) {
|
|
tmp_p = p;
|
|
while (tmp_p) {
|
|
os_mem_cpy(iot_pkt_tail(pkt), tmp_p->payload, tmp_p->len);
|
|
iot_pkt_put(pkt, tmp_p->len);
|
|
MIB2_STATS_NETIF_ADD(netif, ifoutoctets, tmp_p->len);
|
|
tmp_p = tmp_p->next;
|
|
}
|
|
/* send to plc link */
|
|
iot_plc_send_msdu(p_netif_plc->plc_app_h, pkt);
|
|
LINK_STATS_INC(link.xmit);
|
|
if (unicast) {
|
|
MIB2_STATS_NETIF_INC(netif, ifoutucastpkts);
|
|
} else {
|
|
MIB2_STATS_NETIF_INC(netif, ifinnucastpkts);
|
|
}
|
|
} else {
|
|
LINK_STATS_INC(link.memerr);
|
|
LINK_STATS_INC(link.drop);
|
|
MIB2_STATS_NETIF_INC(netif, ifoutdiscards);
|
|
}
|
|
if (to_cco_pkt) {
|
|
tmp_p = p;
|
|
while (tmp_p) {
|
|
os_mem_cpy(iot_pkt_tail(to_cco_pkt), tmp_p->payload, tmp_p->len);
|
|
iot_pkt_put(to_cco_pkt, tmp_p->len);
|
|
tmp_p = tmp_p->next;
|
|
}
|
|
/* send to plc link */
|
|
iot_plc_send_msdu(p_netif_plc->plc_app_h, to_cco_pkt);
|
|
}
|
|
|
|
out:
|
|
return ERR_OK;
|
|
}
|
|
|
|
static void netif_plc_recv(uint8_t *dst, uint8_t *src, uint8_t *data,
|
|
uint16_t len)
|
|
{
|
|
uint8_t unicast;
|
|
|
|
(void)src;
|
|
if (iot_mac_is_bcast(dst)) {
|
|
unicast = 0;
|
|
} else {
|
|
unicast = 1;
|
|
}
|
|
|
|
netif_plc_rpt_to_stack(data, len, unicast);
|
|
}
|
|
|
|
#endif /* IOT_LWIP_NETIF_PLC_ETH_SUPPORT */
|
|
|
|
static err_t plcif_init(struct netif *netif)
|
|
{
|
|
netif->name[0] = 'p';
|
|
netif->name[1] = 'c';
|
|
netif->linkoutput = netif_plc_send;
|
|
|
|
#if LWIP_IPV4
|
|
netif->output = netif_plc_send_ip4;
|
|
#endif /* LWIP_IPV4 */
|
|
|
|
#if IOT_LWIP_NETIF_PLC_DHCP_SUPPORT
|
|
/* make sure MTU can be fit into two 520 PB to imrpove efficiency */
|
|
netif->mtu = 980;
|
|
#else
|
|
/* make sure MTU can be fit into one 520 PB to imrpove efficiency */
|
|
netif->mtu = 480;
|
|
#endif
|
|
|
|
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_IGMP;
|
|
netif->hwaddr_len = IOT_MAC_ADDR_LEN;
|
|
|
|
#if LWIP_IPV6
|
|
/* make sure MTU is no less than ipv6 minimum requirement */
|
|
netif->mtu = 1280;
|
|
netif->output_ip6 = netif_plc_send_ip6;
|
|
netif->ip6_autoconfig_enabled = 1;
|
|
netif->flags |= NETIF_FLAG_MLD6;
|
|
#endif /* LWIP_IPV6 */
|
|
|
|
#if IOT_LWIP_NETIF_PLC_ETH_SUPPORT
|
|
netif->flags |= NETIF_FLAG_ETHERNET | NETIF_FLAG_ETHARP;
|
|
#endif
|
|
|
|
NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, 200000);
|
|
|
|
return ERR_OK;
|
|
}
|
|
|
|
static void netif_plc_turn_on(uint8_t *addr, uint16_t tei)
|
|
{
|
|
if (!iot_mac_addr_cmp(addr,
|
|
p_netif_plc->netif.hwaddr)) {
|
|
iot_mac_addr_cpy(p_netif_plc->netif.hwaddr, addr);
|
|
netif_eth_set_mac_addr(p_netif_plc->netif.hwaddr);
|
|
}
|
|
|
|
#if LWIP_IPV6
|
|
netif_create_ip6_linklocal_address(&p_netif_plc->netif, 1);
|
|
iot_printf("plc ip6 linklocal address: ");
|
|
ip6_addr_debug_print(0xFFFFFFFF & ~LWIP_DBG_HALT,
|
|
netif_ip6_addr(&p_netif_plc->netif, 0));
|
|
iot_printf("\n");
|
|
#endif
|
|
|
|
if (IOT_LWIP_NETIF_PLC_DHCP_SUPPORT == 0) {
|
|
netif_plc_gen_ipaddr(tei);
|
|
netif_plc_gen_ip4_netmask_addr();
|
|
netif_set_addr(&p_netif_plc->netif,
|
|
ip_2_ip4(&p_netif_plc->ipaddr),
|
|
ip_2_ip4(&p_netif_plc->netmask),
|
|
ip_2_ip4(&p_netif_plc->gateway));
|
|
netif_plc_to_uart_state_chg(1, &p_netif_plc->uart_ipaddr,
|
|
&p_netif_plc->netmask, &p_netif_plc->gateway,
|
|
p_netif_plc->netif.mtu);
|
|
netif_set_up(&p_netif_plc->netif);
|
|
netif_set_link_up(&p_netif_plc->netif);
|
|
} else {
|
|
netif_set_up(&p_netif_plc->netif);
|
|
netif_set_link_up(&p_netif_plc->netif);
|
|
dhcp_start(&p_netif_plc->netif);
|
|
netif_plc_to_uart_state_chg(1, NULL, NULL, NULL,
|
|
p_netif_plc->netif.mtu);
|
|
}
|
|
}
|
|
|
|
static void netif_plc_turn_off()
|
|
{
|
|
netif_set_link_down(&p_netif_plc->netif);
|
|
netif_set_down(&p_netif_plc->netif);
|
|
netif_plc_to_uart_state_chg(0, NULL, NULL, NULL, p_netif_plc->netif.mtu);
|
|
}
|
|
|
|
static void netif_plc_callback_intern(void *ctx)
|
|
{
|
|
iot_pkt_t *pkt = ctx;
|
|
iot_plc_msg_header_t *hdr;
|
|
|
|
hdr = (iot_plc_msg_header_t *)iot_pkt_block_ptr(pkt, IOT_PKT_BLOCK_DATA);
|
|
|
|
if (hdr->app_id != IOT_PLC_APP_ID_BCAST &&
|
|
hdr->app_id != NETIF_PLC_APP_ID) {
|
|
goto out;
|
|
}
|
|
|
|
if (p_netif_plc->plc_state.app_reg == 0 &&
|
|
hdr->msg_id != IOT_PLC_MSG_APP_REG_CONF) {
|
|
/* only handle app register confirm message before app registered */
|
|
goto out;
|
|
}
|
|
|
|
switch (hdr->msg_id) {
|
|
case IOT_PLC_MSG_APP_REG_CONF:
|
|
{
|
|
iot_plc_app_reg_conf_t *rpt = (iot_plc_app_reg_conf_t *)(hdr + 1);
|
|
if (rpt->result == IOT_PLC_SUCCESS ||
|
|
rpt->result == IOT_PLC_SUCCESS_MODIFIED) {
|
|
p_netif_plc->plc_state.app_reg = 1;
|
|
/* try to get the local device info */
|
|
iot_plc_query_dev_info(p_netif_plc->plc_app_h,
|
|
IOT_PLC_API_REQ_ID_DEFAULT);
|
|
netif_plc_printf("%s PLC lib registered msdu type %lu, prio %lu\n",
|
|
__FUNCTION__, rpt->type, rpt->prio);
|
|
if (!iot_plc_is_client_mode()) {
|
|
/* bring up stack earlier for CCO role device */
|
|
iot_mac_addr_cpy(p_netif_plc->plc_state.addr, rpt->dev_mac);
|
|
netif_plc_turn_on(rpt->dev_mac, 1);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case IOT_PLC_MSG_DEV_STATE_CHANGE_RPT:
|
|
{
|
|
iot_plc_dev_state_change_rpt_t* rpt =
|
|
(iot_plc_dev_state_change_rpt_t *)(hdr + 1);
|
|
|
|
if (rpt->is_ready) {
|
|
if (!p_netif_plc->plc_state.link_ready) {
|
|
/* turn on plc network interface */
|
|
if (iot_plc_is_client_mode()) {
|
|
netif_plc_turn_on(rpt->local_mac, rpt->dev_tei);
|
|
} else {
|
|
if (!iot_mac_addr_cmp(rpt->local_mac,
|
|
p_netif_plc->netif.hwaddr)) {
|
|
/* CCO is up earlier, so turn off and on again */
|
|
netif_plc_turn_off();
|
|
netif_plc_turn_on(rpt->local_mac, rpt->dev_tei);
|
|
}
|
|
}
|
|
p_netif_plc->plc_state.link_ready = 1;
|
|
}
|
|
} else {
|
|
if (iot_plc_is_client_mode()) {
|
|
if (p_netif_plc->plc_state.link_ready) {
|
|
/* turn off plc network interface */
|
|
p_netif_plc->plc_state.link_ready = 0;
|
|
netif_plc_turn_off();
|
|
}
|
|
}
|
|
}
|
|
p_netif_plc->plc_state.role = rpt->dev_role;
|
|
p_netif_plc->plc_state.dev_tei = rpt->dev_tei;
|
|
p_netif_plc->plc_state.cert_test_detected = rpt->cert_test_detected;
|
|
iot_mac_addr_cpy(p_netif_plc->plc_state.addr, rpt->local_mac);
|
|
iot_mac_addr_cpy(p_netif_plc->plc_state.cco_addr, rpt->cco_mac);
|
|
netif_plc_printf("%s PLC link state ready %lu, role %lu, nid %lu, "
|
|
"cco addr %02X:%02X:%02X:%02X:%02X:%02X\n",
|
|
__FUNCTION__, rpt->is_ready, rpt->dev_role, rpt->nid,
|
|
rpt->cco_mac[0], rpt->cco_mac[1], rpt->cco_mac[2],
|
|
rpt->cco_mac[3], rpt->cco_mac[4], rpt->cco_mac[5]);
|
|
break;
|
|
}
|
|
case IOT_PLC_MSG_DEV_INFO_RPT:
|
|
{
|
|
iot_plc_dev_info_rpt_t* rpt = (iot_plc_dev_info_rpt_t *)(hdr + 1);
|
|
p_netif_plc->plc_state.link_ready = rpt->is_ready;
|
|
p_netif_plc->plc_state.role = rpt->dev_role;
|
|
iot_mac_addr_cpy(p_netif_plc->plc_state.addr, rpt->local_mac);
|
|
iot_mac_addr_cpy(p_netif_plc->plc_state.cco_addr, rpt->cco_mac);
|
|
|
|
netif_plc_printf("%s PLC link state ready %lu, role %lu, cco addr "
|
|
"%02X:%02X:%02X:%02X:%02X:%02X\n",
|
|
__FUNCTION__, rpt->is_ready, rpt->dev_role,
|
|
rpt->cco_mac[0], rpt->cco_mac[1], rpt->cco_mac[2],
|
|
rpt->cco_mac[3], rpt->cco_mac[4], rpt->cco_mac[5]);
|
|
break;
|
|
}
|
|
case IOT_PLC_MSG_MSDU_RECV:
|
|
{
|
|
iot_plc_msdu_recv_t *msdu = NULL;
|
|
/* report 645 data to concentrator or CLI */
|
|
if (!p_netif_plc->plc_state.link_ready) {
|
|
break;
|
|
}
|
|
msdu = (iot_plc_msdu_recv_t *)(hdr + 1);
|
|
netif_plc_recv(msdu->dst, msdu->src, msdu->data, msdu->len);
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
out:
|
|
if (pkt) {
|
|
iot_pkt_free(pkt);
|
|
}
|
|
}
|
|
|
|
static void netif_plc_status_callback(struct netif *state_netif)
|
|
{
|
|
if (netif_is_up(state_netif)) {
|
|
#if LWIP_IPV4
|
|
netif_plc_printf("status_callback==UP, local interface IP is %s\n",
|
|
ip4addr_ntoa(netif_ip4_addr(state_netif)));
|
|
#else
|
|
netif_plc_printf("status_callback==UP\n");
|
|
#endif
|
|
} else {
|
|
netif_plc_printf("status_callback==DOWN\n");
|
|
}
|
|
}
|
|
|
|
static void netif_plc_link_callback(struct netif *state_netif)
|
|
{
|
|
if (netif_is_link_up(state_netif)) {
|
|
netif_plc_printf("link_callback==UP\n");
|
|
} else {
|
|
netif_plc_printf("link_callback==DOWN\n");
|
|
}
|
|
}
|
|
|
|
uint8_t netif_is_ready(void)
|
|
{
|
|
if (p_netif_plc) {
|
|
if (netif_is_up(&p_netif_plc->netif) &&
|
|
netif_is_link_up(&p_netif_plc->netif)) {
|
|
return 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static void netif_plc_callback(void *param, iot_pkt_t *pkt)
|
|
{
|
|
(void)param;
|
|
/* post message to tcpip thread for handling */
|
|
tcpip_callback_with_block(netif_plc_callback_intern, pkt, 0);
|
|
}
|
|
|
|
void netif_plc_init()
|
|
{
|
|
ip_addr_t ipaddr, netmask, gateway;
|
|
iot_plc_app_t plc_app_cfg;
|
|
|
|
#if IOT_LWIP_NETIF_PLC_DHCP_SUPPORT || IOT_LWIP_NETIF_PLC_UART_SUPPORT
|
|
BUILD_BUG_ON(IOT_LWIP_NETIF_PLC_ETH_SUPPORT);
|
|
#endif
|
|
|
|
if (p_netif_plc)
|
|
return;
|
|
|
|
p_netif_plc = os_mem_malloc(IOT_LWIP_MID, sizeof(*p_netif_plc));
|
|
IOT_ASSERT(p_netif_plc);
|
|
|
|
#if IOT_LWIP_NETIF_PLC_ETH_SUPPORT
|
|
p_netif_plc->rt_table = iot_addr_hash_table_create(IOT_LWIP_MID,
|
|
IOT_MAC_RT_ENTRY_MAX, sizeof(iot_mac_route_entry_t),
|
|
IOT_MAC_RT_HASH_TABLE_SIZE);
|
|
#endif
|
|
|
|
ip_addr_set_zero_ip4(&gateway);
|
|
ip_addr_set_zero_ip4(&ipaddr);
|
|
ip_addr_set_zero_ip4(&netmask);
|
|
|
|
/* by default, plc network use static IP and IP address is assigned by
|
|
* below rules.
|
|
* 1. plc network nodes use 10.0.xxx.yyy. xxx.yyy is the TEI of the plc
|
|
* node. see netif_plc_gen_ipaddr.
|
|
* 2. uart peer use 10.10.xxx.yyy. xxx.yyy is the TEI of the plc node uart
|
|
* connected to.
|
|
* 3. gateway use 10.100.0.1
|
|
* 4. gateway can use DHCP range from 10.100.0.2 - 10.100.aaa.bbb
|
|
* for other devices connected to gateway.
|
|
*/
|
|
IP_ADDR4(&p_netif_plc->gateway, 10, 100, 0, 1);
|
|
IP_ADDR4(&p_netif_plc->ipaddr, 10, 0, 0, 0);
|
|
IP_ADDR4(&p_netif_plc->uart_ipaddr, 10, 10, 0, 0);
|
|
IP_ADDR4(&p_netif_plc->netmask, 255, 0, 0, 0);
|
|
|
|
netif_add(&p_netif_plc->netif, ip_2_ip4(&ipaddr), ip_2_ip4(&netmask),
|
|
ip_2_ip4(&gateway), NULL, plcif_init, tcpip_input);
|
|
netif_set_default(&p_netif_plc->netif);
|
|
|
|
/* register smart grid app to plc network */
|
|
plc_app_cfg.app_id = NETIF_PLC_APP_ID;
|
|
plc_app_cfg.param = p_netif_plc;
|
|
plc_app_cfg.prio = 0;
|
|
plc_app_cfg.recv = netif_plc_callback;
|
|
p_netif_plc->plc_app_h = iot_plc_register_app(&plc_app_cfg);
|
|
IOT_ASSERT(p_netif_plc->plc_app_h);
|
|
|
|
netif_set_status_callback(&p_netif_plc->netif, netif_plc_status_callback);
|
|
|
|
netif_set_link_callback(&p_netif_plc->netif, netif_plc_link_callback);
|
|
}
|
|
|
|
#else /* IOT_LWIP_NETIF_PLC_SUPPORT */
|
|
|
|
void netif_plc_init()
|
|
{
|
|
}
|
|
|
|
#endif /* IOT_LWIP_NETIF_PLC_SUPPORT */
|
|
|
|
#if IOT_LWIP_NETIF_PLC_UART_SUPPORT
|
|
|
|
void netif_uart_to_plc_send(iot_pkt_t *pkt)
|
|
{
|
|
iot_pkt_t *plc_pkt;
|
|
uint8_t unicast;
|
|
struct eth_hdr *ethhdr;
|
|
|
|
/* check ethernet header */
|
|
ethhdr = (struct eth_hdr *)iot_pkt_data(pkt);
|
|
iot_mac_addr_cpy(p_netif_plc->uart_peer_addr, ethhdr->src.addr);
|
|
if ((ethhdr->dest.addr[0] & 1) != 0) {
|
|
if (!iot_mac_is_bcast(ethhdr->dest.addr) &&
|
|
!os_mem_cmp(ethhdr->dest.addr, ipv4mcast, sizeof(ipv4mcast))) {
|
|
goto out;
|
|
}
|
|
unicast = 0;
|
|
} else {
|
|
unicast = 1;
|
|
}
|
|
if (unicast) {
|
|
if (iot_mac_addr_cmp(ethhdr->dest.addr, p_netif_plc->plc_state.addr)) {
|
|
/* unicast packet to local device */
|
|
netif_plc_rpt_to_stack(iot_pkt_data(pkt),
|
|
(uint16_t)iot_pkt_data_len(pkt), 1);
|
|
} else {
|
|
/* unicast packet to other device, forward to plc link */
|
|
plc_pkt = iot_plc_alloc_msdu(p_netif_plc->plc_app_h,
|
|
IOT_PLC_MSG_TYPE_UNICAST, IOT_PLC_ACK_TYPE_NONE,
|
|
ethhdr->dest.addr, p_netif_plc->plc_state.addr, 0,
|
|
(uint16_t)iot_pkt_data_len(pkt), IOT_PLC_MAX_RETRY_CNT);
|
|
os_mem_cpy(iot_pkt_tail(plc_pkt), iot_pkt_data(pkt),
|
|
iot_pkt_data_len(pkt));
|
|
iot_pkt_put(plc_pkt, iot_pkt_data_len(pkt));
|
|
iot_plc_send_msdu(p_netif_plc->plc_app_h, plc_pkt);
|
|
}
|
|
} else {
|
|
/* broadcast packet, report to local device */
|
|
netif_plc_rpt_to_stack(iot_pkt_data(pkt),
|
|
(uint16_t)iot_pkt_data_len(pkt), 1);
|
|
|
|
/* forward to surrounding devices */
|
|
plc_pkt = iot_plc_alloc_msdu(p_netif_plc->plc_app_h,
|
|
IOT_PLC_MSG_TYPE_BCAST_1HOP, IOT_PLC_ACK_TYPE_NONE,
|
|
ethhdr->dest.addr, p_netif_plc->plc_state.addr, 0,
|
|
(uint16_t)iot_pkt_data_len(pkt), IOT_PLC_MAX_RETRY_CNT);
|
|
os_mem_cpy(iot_pkt_tail(plc_pkt), iot_pkt_data(pkt),
|
|
iot_pkt_data_len(pkt));
|
|
iot_pkt_put(plc_pkt, iot_pkt_data_len(pkt));
|
|
iot_plc_send_msdu(p_netif_plc->plc_app_h, plc_pkt);
|
|
|
|
/* forward to cco device */
|
|
if (p_netif_plc->plc_state.role != IOT_PLC_DEV_ROLE_CCO) {
|
|
plc_pkt = iot_plc_alloc_msdu(p_netif_plc->plc_app_h,
|
|
IOT_PLC_MSG_TYPE_UNICAST, IOT_PLC_ACK_TYPE_NONE,
|
|
p_netif_plc->plc_state.cco_addr, p_netif_plc->plc_state.addr, 0,
|
|
(uint16_t)iot_pkt_data_len(pkt), IOT_PLC_MAX_RETRY_CNT);
|
|
os_mem_cpy(iot_pkt_tail(plc_pkt), iot_pkt_data(pkt),
|
|
iot_pkt_data_len(pkt));
|
|
iot_pkt_put(plc_pkt, iot_pkt_data_len(pkt));
|
|
iot_plc_send_msdu(p_netif_plc->plc_app_h, plc_pkt);
|
|
}
|
|
}
|
|
out:
|
|
iot_pkt_free(pkt);
|
|
}
|
|
|
|
#else /* IOT_LWIP_NETIF_PLC_UART_SUPPORT */
|
|
|
|
void netif_uart_to_plc_send(iot_pkt_t *pkt)
|
|
{
|
|
iot_pkt_free(pkt);
|
|
}
|
|
|
|
#endif /* IOT_LWIP_NETIF_PLC_UART_SUPPORT */
|
|
|
|
#if IOT_LWIP_NETIF_PLC_TO_ETH_SUPPORT
|
|
|
|
void netif_eth_to_plc_send(iot_pkt_t *pkt)
|
|
{
|
|
iot_pkt_t *plc_pkt;
|
|
uint8_t unicast;
|
|
struct eth_hdr *ethhdr;
|
|
uint8_t tmp_addr[IOT_MAC_ADDR_LEN];
|
|
uint8_t gw_type;
|
|
|
|
/* check ethernet header */
|
|
ethhdr = (struct eth_hdr *)iot_pkt_data(pkt);
|
|
if ((ethhdr->dest.addr[0] & 1) != 0) {
|
|
if (!iot_mac_is_bcast(ethhdr->dest.addr) &&
|
|
!os_mem_cmp(ethhdr->dest.addr, ipv4mcast, sizeof(ipv4mcast))) {
|
|
goto out;
|
|
}
|
|
unicast = 0;
|
|
} else {
|
|
unicast = 1;
|
|
}
|
|
if (unicast) {
|
|
if (iot_mac_addr_cmp(ethhdr->dest.addr,
|
|
p_netif_plc->plc_state.addr)) {
|
|
/* unicast packet to local device */
|
|
netif_plc_rpt_to_stack(iot_pkt_data(pkt),
|
|
(uint16_t)iot_pkt_data_len(pkt), 1);
|
|
} else {
|
|
gw_type = netif_plc_get_addr_rt(ethhdr->dest.addr, tmp_addr);
|
|
switch (gw_type) {
|
|
case IOT_MAC_RT_TO_PLC:
|
|
{
|
|
/* unicast packet to device behind a plc node,
|
|
* forward to plc link.
|
|
*/
|
|
plc_pkt = iot_plc_alloc_msdu(p_netif_plc->plc_app_h,
|
|
IOT_PLC_MSG_TYPE_UNICAST, IOT_PLC_ACK_TYPE_NONE,
|
|
tmp_addr, p_netif_plc->plc_state.addr, 0,
|
|
(uint16_t)iot_pkt_data_len(pkt), IOT_PLC_MAX_RETRY_CNT);
|
|
os_mem_cpy(iot_pkt_tail(plc_pkt), iot_pkt_data(pkt),
|
|
iot_pkt_data_len(pkt));
|
|
iot_pkt_put(plc_pkt, iot_pkt_data_len(pkt));
|
|
iot_plc_send_msdu(p_netif_plc->plc_app_h, plc_pkt);
|
|
break;
|
|
}
|
|
case IOT_MAC_RT_TO_INVAL:
|
|
{
|
|
/* unicast packet to plc node, forward to plc link */
|
|
plc_pkt = iot_plc_alloc_msdu(p_netif_plc->plc_app_h,
|
|
IOT_PLC_MSG_TYPE_UNICAST, IOT_PLC_ACK_TYPE_NONE,
|
|
ethhdr->dest.addr, p_netif_plc->plc_state.addr, 0,
|
|
(uint16_t)iot_pkt_data_len(pkt), IOT_PLC_MAX_RETRY_CNT);
|
|
os_mem_cpy(iot_pkt_tail(plc_pkt), iot_pkt_data(pkt),
|
|
iot_pkt_data_len(pkt));
|
|
iot_pkt_put(plc_pkt, iot_pkt_data_len(pkt));
|
|
iot_plc_send_msdu(p_netif_plc->plc_app_h, plc_pkt);
|
|
break;
|
|
}
|
|
case IOT_MAC_RT_TO_ETH:
|
|
{
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
/* broadcast packet, report to local device */
|
|
netif_plc_rpt_to_stack(iot_pkt_data(pkt),
|
|
(uint16_t)iot_pkt_data_len(pkt), 0);
|
|
|
|
/* broadcast to plc network */
|
|
plc_pkt = iot_plc_alloc_msdu(p_netif_plc->plc_app_h,
|
|
IOT_PLC_MSG_TYPE_BCAST, IOT_PLC_ACK_TYPE_NONE,
|
|
(uint8_t *)bcast_mac, p_netif_plc->plc_state.addr, 0,
|
|
(uint16_t)iot_pkt_data_len(pkt), IOT_PLC_MAX_RETRY_CNT);
|
|
os_mem_cpy(iot_pkt_tail(plc_pkt), iot_pkt_data(pkt),
|
|
iot_pkt_data_len(pkt));
|
|
iot_pkt_put(plc_pkt, iot_pkt_data_len(pkt));
|
|
iot_plc_send_msdu(p_netif_plc->plc_app_h, plc_pkt);
|
|
}
|
|
|
|
if ((ethhdr->src.addr[0] & 1) == 0) {
|
|
/* source is behind ethernet, save the mapping */
|
|
netif_plc_add_addr_rt(p_netif_plc->netif.hwaddr, ethhdr->src.addr,
|
|
IOT_MAC_RT_TO_ETH);
|
|
}
|
|
out:
|
|
iot_pkt_free(pkt);
|
|
}
|
|
|
|
#else /* IOT_LWIP_NETIF_PLC_TO_ETH_SUPPORT */
|
|
|
|
void netif_eth_to_plc_send(iot_pkt_t *pkt)
|
|
{
|
|
iot_pkt_free(pkt);
|
|
}
|
|
|
|
#endif /* IOT_LWIP_NETIF_PLC_TO_ETH_SUPPORT */
|