Files
kunlun/import/lwip/ports/netif/netif_plc.c
2024-09-28 14:24:04 +08:00

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 */