blob: 584646c9b4cb2f3a06fa555d3012d183f0e39a68 [file] [log] [blame]
/*
*
* Copyright (c) 2021 Project CHIP Authors
* Copyright (c) 2018 Nest Labs, Inc.
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @file
* General utility methods for the P6 platform.
*/
/* this file behaves like a config.h, comes first */
#include <platform/internal/CHIPDeviceLayerInternal.h>
#include <cy_lwip.h>
#include <cy_wcm.h>
#include <lib/support/CodeUtils.h>
#include <lib/support/ErrorStr.h>
#include <lib/support/logging/CHIPLogging.h>
#include <platform/P6/P6Utils.h>
#include "lwip/icmp.h"
#include "lwip/inet.h"
#include "lwip/inet_chksum.h"
#include "lwip/mem.h"
#include "lwip/netif.h"
#include "lwip/opt.h"
#include "lwip/prot/ip4.h"
#include "lwip/raw.h"
#include "lwip/sockets.h"
#include "lwip/sys.h"
#include "lwip/timeouts.h"
#include <malloc.h>
#include <platform/P6/P6Config.h>
using namespace ::chip::DeviceLayer::Internal;
using chip::DeviceLayer::Internal::DeviceNetworkInfo;
/** ping delay - in milliseconds */
#ifndef PING_DELAY
#define PING_DELAY 2000
#endif
/** ping identifier - must fit on a u16_t */
#ifndef PING_ID
#define PING_ID 0xAFAF
#endif
/** ping additional data size to include in the packet */
#ifndef PING_DATA_SIZE
#define PING_DATA_SIZE 64
#endif
/** ping receive timeout - in milliseconds */
#ifndef PING_RCV_TIMEO
#define PING_RCV_TIMEO 5000
#endif
/* Ping IP Header len for IPv4 */
#define IP_HDR_LEN 20
/* Ping Response length */
#define PING_RESPONSE_LEN 64
/* Enable Ping via Socket API or RAW API */
#define PING_USE_SOCKETS 1
namespace {
wifi_config_t wifi_conf;
wifi_mode_t WiFiMode;
bool wcm_init_done;
/* ping variables */
const ip_addr_t * ping_target;
u16_t ping_seq_num;
u32_t ping_time;
#if !PING_USE_SOCKETS
struct raw_pcb * ping_pcb;
#endif /* PING_USE_SOCKETS */
} // namespace
typedef struct
{
struct icmp_echo_hdr hdr;
uint8_t data[PING_DATA_SIZE];
} icmp_packet_t;
CHIP_ERROR P6Utils::IsAPEnabled(bool & apEnabled)
{
apEnabled = (WiFiMode == WIFI_MODE_AP || WiFiMode == WIFI_MODE_APSTA);
return CHIP_NO_ERROR;
}
CHIP_ERROR P6Utils::IsStationEnabled(bool & staEnabled)
{
staEnabled = (WiFiMode == WIFI_MODE_STA || WiFiMode == WIFI_MODE_APSTA);
return CHIP_NO_ERROR;
}
bool P6Utils::IsStationProvisioned(void)
{
wifi_config_t stationConfig;
return (p6_wifi_get_config(WIFI_IF_STA, &stationConfig) == CHIP_NO_ERROR && strlen((const char *) stationConfig.sta.ssid) != 0);
}
CHIP_ERROR P6Utils::IsStationConnected(bool & connected)
{
CHIP_ERROR err = CHIP_NO_ERROR;
connected = cy_wcm_is_connected_to_ap();
return err;
}
CHIP_ERROR P6Utils::StartWiFiLayer(void)
{
CHIP_ERROR err = CHIP_NO_ERROR;
cy_rslt_t result = CY_RSLT_SUCCESS;
cy_wcm_config_t wcm_config;
wcm_config.interface = CY_WCM_INTERFACE_TYPE_AP_STA;
ChipLogProgress(DeviceLayer, "Starting P6 WiFi layer");
if (wcm_init_done == false)
{
result = cy_wcm_init(&wcm_config);
if (result != CY_RSLT_SUCCESS)
{
err = CHIP_ERROR_INTERNAL;
ChipLogError(DeviceLayer, "StartWiFiLayer() P6 Wi-Fi Started Failed: %s", chip::ErrorStr(err));
SuccessOrExit(err);
}
wcm_init_done = true;
}
exit:
return err;
}
CHIP_ERROR P6Utils::EnableStationMode(void)
{
CHIP_ERROR err = CHIP_NO_ERROR;
ChipLogProgress(DeviceLayer, "EnableStationMode");
/* If Station Mode is already set , update Mode to APSTA Mode */
if (WiFiMode == WIFI_MODE_AP)
{
WiFiMode = WIFI_MODE_APSTA;
}
else
{
WiFiMode = WIFI_MODE_STA;
}
wifi_set_mode(WiFiMode);
return err;
}
CHIP_ERROR P6Utils::SetAPMode(bool enabled)
{
CHIP_ERROR err = CHIP_NO_ERROR;
ChipLogProgress(DeviceLayer, "SetAPMode");
/* If AP Mode is already set , update Mode to APSTA Mode */
if (enabled)
{
if (WiFiMode == WIFI_MODE_STA)
{
WiFiMode = WIFI_MODE_APSTA;
}
else
{
WiFiMode = WIFI_MODE_AP;
}
}
else
{
if (WiFiMode == WIFI_MODE_APSTA)
{
WiFiMode = WIFI_MODE_STA;
}
else if (WiFiMode == WIFI_MODE_AP)
{
WiFiMode = WIFI_MODE_NULL;
}
}
return err;
}
const char * P6Utils::WiFiModeToStr(wifi_mode_t wifiMode)
{
switch (wifiMode)
{
case WIFI_MODE_NULL:
return "NULL";
case WIFI_MODE_STA:
return "STA";
case WIFI_MODE_AP:
return "AP";
case WIFI_MODE_APSTA:
return "STA+AP";
default:
return "(unknown)";
}
}
CHIP_ERROR P6Utils::GetWiFiSSID(char * buf, size_t bufSize)
{
size_t num = 0;
return P6Config::ReadConfigValueStr(P6Config::kConfigKey_WiFiSSID, buf, bufSize, num);
}
CHIP_ERROR P6Utils::StoreWiFiSSID(char * buf, size_t size)
{
return P6Config::WriteConfigValueStr(P6Config::kConfigKey_WiFiSSID, buf, size);
}
CHIP_ERROR P6Utils::GetWiFiPassword(char * buf, size_t bufSize)
{
size_t num = 0;
return P6Config::ReadConfigValueStr(P6Config::kConfigKey_WiFiPassword, buf, bufSize, num);
}
CHIP_ERROR P6Utils::StoreWiFiPassword(char * buf, size_t size)
{
return P6Config::WriteConfigValueStr(P6Config::kConfigKey_WiFiPassword, buf, size);
}
CHIP_ERROR P6Utils::GetWiFiSecurityCode(uint32_t & security)
{
return P6Config::ReadConfigValue(P6Config::kConfigKey_WiFiSecurity, security);
}
CHIP_ERROR P6Utils::StoreWiFiSecurityCode(uint32_t security)
{
return P6Config::WriteConfigValue(P6Config::kConfigKey_WiFiSecurity, security);
}
CHIP_ERROR P6Utils::wifi_get_mode(uint32_t & mode)
{
return P6Config::ReadConfigValue(P6Config::kConfigKey_WiFiMode, mode);
}
CHIP_ERROR P6Utils::wifi_set_mode(uint32_t mode)
{
return P6Config::WriteConfigValue(P6Config::kConfigKey_WiFiMode, mode);
}
CHIP_ERROR P6Utils::p6_wifi_set_config(wifi_interface_t interface, wifi_config_t * conf)
{
CHIP_ERROR err = CHIP_NO_ERROR;
if (interface == WIFI_IF_STA)
{
/* Store Wi-Fi Configurations in Storage */
err = StoreWiFiSSID((char *) conf->sta.ssid, strlen((char *) conf->sta.ssid));
SuccessOrExit(err);
err = StoreWiFiPassword((char *) conf->sta.password, strlen((char *) conf->sta.password));
SuccessOrExit(err);
err = StoreWiFiSecurityCode(conf->sta.security);
SuccessOrExit(err);
populate_wifi_config_t(&wifi_conf, interface, &conf->sta.ssid, &conf->sta.password, conf->sta.security);
}
else
{
populate_wifi_config_t(&wifi_conf, interface, &conf->ap.ssid, &conf->ap.password, conf->ap.security);
wifi_conf.ap.channel = conf->ap.channel;
wifi_conf.ap.ip_settings.ip_address = conf->ap.ip_settings.ip_address;
wifi_conf.ap.ip_settings.netmask = conf->ap.ip_settings.netmask;
wifi_conf.ap.ip_settings.gateway = conf->ap.ip_settings.gateway;
}
exit:
return err;
}
CHIP_ERROR P6Utils::p6_wifi_get_config(wifi_interface_t interface, wifi_config_t * conf)
{
uint32 code = 0;
CHIP_ERROR err = CHIP_NO_ERROR;
if (interface == WIFI_IF_STA)
{
if (P6Config::ConfigValueExists(P6Config::kConfigKey_WiFiSSID) &&
P6Config::ConfigValueExists(P6Config::kConfigKey_WiFiPassword) &&
P6Config::ConfigValueExists(P6Config::kConfigKey_WiFiSecurity))
{
/* Retrieve Wi-Fi Configurations from Storage */
err = GetWiFiSSID((char *) conf->sta.ssid, sizeof(conf->sta.ssid));
SuccessOrExit(err);
err = GetWiFiPassword((char *) conf->sta.password, sizeof(conf->sta.password));
SuccessOrExit(err);
err = GetWiFiSecurityCode(code);
SuccessOrExit(err);
conf->sta.security = static_cast<cy_wcm_security_t>(code);
}
else
{
populate_wifi_config_t(conf, interface, &wifi_conf.sta.ssid, &wifi_conf.sta.password, wifi_conf.sta.security);
}
}
else
{
populate_wifi_config_t(conf, interface, &wifi_conf.ap.ssid, &wifi_conf.ap.password, wifi_conf.ap.security);
conf->ap.channel = wifi_conf.ap.channel;
conf->ap.ip_settings.ip_address = wifi_conf.ap.ip_settings.ip_address;
conf->ap.ip_settings.netmask = wifi_conf.ap.ip_settings.netmask;
conf->ap.ip_settings.gateway = wifi_conf.ap.ip_settings.gateway;
}
exit:
return err;
}
CHIP_ERROR P6Utils::GetWiFiStationProvision(Internal::DeviceNetworkInfo & netInfo, bool includeCredentials)
{
CHIP_ERROR err = CHIP_NO_ERROR;
wifi_config_t stationConfig;
err = p6_wifi_get_config(WIFI_IF_STA, &stationConfig);
SuccessOrExit(err);
ChipLogProgress(DeviceLayer, "GetWiFiStationProvision");
VerifyOrExit(strlen((const char *) stationConfig.sta.ssid) != 0, err = CHIP_ERROR_INCORRECT_STATE);
netInfo.NetworkId = kWiFiStationNetworkId;
netInfo.FieldPresent.NetworkId = true;
memcpy(netInfo.WiFiSSID, stationConfig.sta.ssid,
min(strlen(reinterpret_cast<char *>(stationConfig.sta.ssid)) + 1, sizeof(netInfo.WiFiSSID)));
// Enforce that netInfo wifiSSID is null terminated
netInfo.WiFiSSID[kMaxWiFiSSIDLength] = '\0';
if (includeCredentials)
{
static_assert(sizeof(netInfo.WiFiKey) < 255, "Our min might not fit in netInfo.WiFiKeyLen");
netInfo.WiFiKeyLen = static_cast<uint8_t>(min(strlen((char *) stationConfig.sta.password), sizeof(netInfo.WiFiKey)));
memcpy(netInfo.WiFiKey, stationConfig.sta.password, netInfo.WiFiKeyLen);
}
exit:
return err;
}
CHIP_ERROR P6Utils::SetWiFiStationProvision(const Internal::DeviceNetworkInfo & netInfo)
{
CHIP_ERROR err = CHIP_NO_ERROR;
wifi_config_t wifiConfig;
ChipLogProgress(DeviceLayer, "SetWiFiStationProvision");
char wifiSSID[kMaxWiFiSSIDLength + 1];
size_t netInfoSSIDLen = strlen(netInfo.WiFiSSID);
// Ensure that P6 station mode is enabled. This is required before p6_wifi_set_config
// can be called.
err = P6Utils::EnableStationMode();
SuccessOrExit(err);
// Enforce that wifiSSID is null terminated before copying it
memcpy(wifiSSID, netInfo.WiFiSSID, min(netInfoSSIDLen + 1, sizeof(wifiSSID)));
if (netInfoSSIDLen + 1 < sizeof(wifiSSID))
{
wifiSSID[netInfoSSIDLen] = '\0';
}
else
{
wifiSSID[kMaxWiFiSSIDLength] = '\0';
}
// Initialize an P6 wifi_config_t structure based on the new provision information.
populate_wifi_config_t(&wifiConfig, WIFI_IF_STA, (cy_wcm_ssid_t *) wifiSSID, (cy_wcm_passphrase_t *) netInfo.WiFiKey);
// Configure the P6 WiFi interface.
ReturnLogErrorOnFailure(p6_wifi_set_config(WIFI_IF_STA, &wifiConfig));
ChipLogProgress(DeviceLayer, "WiFi station provision set (SSID: %s)", netInfo.WiFiSSID);
exit:
return err;
}
CHIP_ERROR P6Utils::ClearWiFiStationProvision(void)
{
CHIP_ERROR err = CHIP_NO_ERROR;
wifi_config_t stationConfig;
ChipLogProgress(DeviceLayer, "ClearWiFiStationProvision");
// Clear the P6 WiFi station configuration.
memset(&stationConfig.sta, 0, sizeof(stationConfig.sta));
ReturnLogErrorOnFailure(p6_wifi_set_config(WIFI_IF_STA, &stationConfig));
return err;
}
CHIP_ERROR P6Utils::p6_wifi_disconnect(void)
{
CHIP_ERROR err = CHIP_NO_ERROR;
cy_rslt_t result = CY_RSLT_SUCCESS;
ChipLogProgress(DeviceLayer, "p6_wifi_disconnect");
result = cy_wcm_disconnect_ap();
if (result != CY_RSLT_SUCCESS)
{
ChipLogError(DeviceLayer, "p6_wifi_disconnect() failed result %ld", result);
err = CHIP_ERROR_INTERNAL;
}
return err;
}
CHIP_ERROR P6Utils::p6_wifi_connect(void)
{
CHIP_ERROR err = CHIP_NO_ERROR;
cy_rslt_t result = CY_RSLT_SUCCESS;
wifi_config_t stationConfig;
cy_wcm_connect_params_t connect_param;
cy_wcm_ip_address_t ip_addr;
p6_wifi_get_config(WIFI_IF_STA, &stationConfig);
memset(&connect_param, 0, sizeof(cy_wcm_connect_params_t));
memset(&ip_addr, 0, sizeof(cy_wcm_ip_address_t));
memcpy(&connect_param.ap_credentials.SSID, &stationConfig.sta.ssid, strlen((char *) stationConfig.sta.ssid));
memcpy(&connect_param.ap_credentials.password, &stationConfig.sta.password, strlen((char *) stationConfig.sta.password));
connect_param.ap_credentials.security = stationConfig.sta.security;
ChipLogProgress(DeviceLayer, "Connecting to AP : [%s] \r\n", connect_param.ap_credentials.SSID);
result = cy_wcm_connect_ap(&connect_param, &ip_addr);
if (result != CY_RSLT_SUCCESS)
{
ChipLogError(DeviceLayer, "p6_wifi_connect() failed result %ld", result);
err = CHIP_ERROR_INTERNAL;
}
return err;
}
#define INITIALISER_IPV4_ADDRESS1(addr_var, addr_val) addr_var = { CY_WCM_IP_VER_V4, { .v4 = (uint32_t)(addr_val) } }
#define MAKE_IPV4_ADDRESS1(a, b, c, d) ((((uint32_t) d) << 24) | (((uint32_t) c) << 16) | (((uint32_t) b) << 8) | ((uint32_t) a))
static const cy_wcm_ip_setting_t ap_mode_ip_settings2 = {
INITIALISER_IPV4_ADDRESS1(.ip_address, MAKE_IPV4_ADDRESS1(192, 168, 0, 2)),
INITIALISER_IPV4_ADDRESS1(.gateway, MAKE_IPV4_ADDRESS1(192, 168, 0, 2)),
INITIALISER_IPV4_ADDRESS1(.netmask, MAKE_IPV4_ADDRESS1(255, 255, 255, 0)),
};
CHIP_ERROR P6Utils::p6_start_ap(void)
{
CHIP_ERROR err = CHIP_NO_ERROR;
cy_rslt_t result = CY_RSLT_SUCCESS;
wifi_config_t stationConfig;
memset(&stationConfig, 0, sizeof(stationConfig));
p6_wifi_get_config(WIFI_IF_AP, &stationConfig);
cy_wcm_ap_config_t ap_conf;
memset(&ap_conf, 0, sizeof(cy_wcm_ap_config_t));
memcpy(ap_conf.ap_credentials.SSID, &stationConfig.ap.ssid, strlen((const char *) stationConfig.ap.ssid));
memcpy(ap_conf.ap_credentials.password, &stationConfig.ap.password, strlen((const char *) stationConfig.ap.password));
memcpy(&ap_conf.ip_settings, &stationConfig.ap.ip_settings, sizeof(stationConfig.ap.ip_settings));
ap_conf.ap_credentials.security = stationConfig.ap.security;
ap_conf.channel = stationConfig.ap.channel;
ChipLogProgress(DeviceLayer, "p6_start_ap %s \r\n", ap_conf.ap_credentials.SSID);
/* Start AP */
result = cy_wcm_start_ap(&ap_conf);
if (result != CY_RSLT_SUCCESS)
{
ChipLogError(DeviceLayer, "cy_wcm_start_ap() failed result %ld", result);
err = CHIP_ERROR_INTERNAL;
}
/* Link Local IPV6 AP address for AP */
cy_wcm_ip_address_t ipv6_addr;
result = cy_wcm_get_ipv6_addr(CY_WCM_INTERFACE_TYPE_AP, CY_WCM_IPV6_LINK_LOCAL, &ipv6_addr, 1);
if (result != CY_RSLT_SUCCESS)
{
ChipLogError(DeviceLayer, "cy_wcm_get_ipv6_addr() failed result %ld", result);
err = CHIP_ERROR_INTERNAL;
}
return err;
}
CHIP_ERROR P6Utils::p6_stop_ap(void)
{
CHIP_ERROR err = CHIP_NO_ERROR;
cy_rslt_t result = CY_RSLT_SUCCESS;
/* Stop AP */
result = cy_wcm_stop_ap();
if (result != CY_RSLT_SUCCESS)
{
ChipLogError(DeviceLayer, "cy_wcm_stop_ap failed result %ld", result);
err = CHIP_ERROR_INTERNAL;
}
return err;
}
void P6Utils::populate_wifi_config_t(wifi_config_t * wifi_config, wifi_interface_t interface, const cy_wcm_ssid_t * ssid,
const cy_wcm_passphrase_t * password, cy_wcm_security_t security)
{
CY_ASSERT(wifi_config != NULL);
// Use interface param to determine which config to fill out
if (interface == WIFI_IF_STA || interface == WIFI_IF_STA_AP)
{
memset(&wifi_config->sta, 0, sizeof(wifi_config_sta_t));
memcpy(wifi_config->sta.ssid, ssid, chip::min(strlen((char *) ssid) + 1, sizeof(cy_wcm_ssid_t)));
memcpy(wifi_config->sta.password, password, chip::min(strlen((char *) password) + 1, sizeof(cy_wcm_ssid_t)));
wifi_config->sta.security = security;
}
if (interface == WIFI_IF_AP || interface == WIFI_IF_STA_AP)
{
memset(&wifi_config->ap, 0, sizeof(wifi_config_ap_t));
memcpy(wifi_config->ap.ssid, ssid, chip::min(strlen((char *) ssid) + 1, sizeof(cy_wcm_ssid_t)));
memcpy(wifi_config->ap.password, password, chip::min(strlen((char *) password) + 1, sizeof(cy_wcm_ssid_t)));
wifi_config->ap.security = security;
}
}
/* Ping implementation
*
*/
static void print_ip4(uint32_t ip)
{
unsigned int bytes[4];
bytes[0] = ip & 0xFF;
bytes[1] = (ip >> 8) & 0xFF;
bytes[2] = (ip >> 16) & 0xFF;
bytes[3] = (ip >> 24) & 0xFF;
printf("Addr = %d.%d.%d.%d\n", bytes[0], bytes[1], bytes[2], bytes[3]);
}
static void ping_prepare_echo(icmp_packet_t * iecho, uint16_t len)
{
int i;
ICMPH_TYPE_SET(&iecho->hdr, ICMP_ECHO);
ICMPH_CODE_SET(&iecho->hdr, 0);
iecho->hdr.chksum = 0;
iecho->hdr.id = PING_ID;
iecho->hdr.seqno = htons(++(ping_seq_num));
/* fill the additional data buffer with some data */
for (i = 0; i < (int) sizeof(iecho->data); i++)
{
iecho->data[i] = (uint8_t) i;
}
iecho->hdr.chksum = inet_chksum(iecho, len);
}
/* Ping using socket API */
#if PING_USE_SOCKETS
static err_t ping_send(int s, const ip_addr_t * addr)
{
int err;
icmp_packet_t iecho;
struct sockaddr_in to;
ping_prepare_echo(&iecho, (u16_t) sizeof(icmp_packet_t));
printf("\r\nPinging to Gateway ");
print_ip4(addr->u_addr.ip4.addr);
/* Send the ping request */
to.sin_len = sizeof(to);
to.sin_family = AF_INET;
inet_addr_from_ip4addr(&to.sin_addr, ip_2_ip4(addr));
err = lwip_sendto(s, &iecho, sizeof(icmp_packet_t), 0, (struct sockaddr *) &to, sizeof(to));
return (err ? ERR_OK : ERR_VAL);
}
static void ping_recv(int s)
{
char buf[PING_RESPONSE_LEN];
int fromlen;
int len;
struct sockaddr_in from;
struct ip_hdr * iphdr;
struct icmp_echo_hdr * iecho;
do
{
len = lwip_recvfrom(s, buf, sizeof(buf), 0, (struct sockaddr *) &from, (socklen_t *) &fromlen);
if (len >= (int) (sizeof(struct ip_hdr) + sizeof(struct icmp_echo_hdr)))
{
iphdr = (struct ip_hdr *) buf;
iecho = (struct icmp_echo_hdr *) (buf + (IPH_HL(iphdr) * 4));
if ((iecho->id == PING_ID) && (iecho->seqno == htons(ping_seq_num)) && (ICMPH_TYPE(iecho) == ICMP_ER))
{
printf("Ping was successful Elapsed time : %" U32_F " ms\n", sys_now() - ping_time);
return; /* Echo reply received - return success */
}
}
} while (len > 0);
if (len == 0)
{
printf("ping: recv - %" U32_F " ms - timeout\r\n", (sys_now() - ping_time));
}
}
static void ping_socket()
{
int s;
int ret;
#if LWIP_SO_SNDRCVTIMEO_NONSTANDARD
int timeout = PING_RCV_TIMEO;
#else
struct timeval timeout;
timeout.tv_sec = PING_RCV_TIMEO / 1000;
timeout.tv_usec = (PING_RCV_TIMEO % 1000) * 1000;
#endif
s = lwip_socket(AF_INET, SOCK_RAW, IP_PROTO_ICMP);
if (s < 0)
{
return;
}
ret = lwip_setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
LWIP_ASSERT("setting receive timeout failed", ret == 0);
LWIP_UNUSED_ARG(ret);
while (1)
{
if (ping_send(s, ping_target) == ERR_OK)
{
ping_time = sys_now();
ping_recv(s);
}
else
{
printf("ping: send error");
}
sys_msleep(PING_DELAY);
}
}
#else
/* Ping using the raw ip */
static u8_t ping_recv_raw(void * arg, struct raw_pcb * pcb, struct pbuf * p, const ip_addr_t * addr)
{
struct icmp_echo_hdr * iecho;
LWIP_UNUSED_ARG(arg);
LWIP_UNUSED_ARG(pcb);
LWIP_UNUSED_ARG(addr);
LWIP_ASSERT("p != NULL", p != NULL);
if ((p->tot_len >= (IP_HDR_LEN + sizeof(struct icmp_echo_hdr))) && pbuf_header(p, -IP_HDR_LEN) == 0)
{
iecho = (struct icmp_echo_hdr *) p->payload;
if ((iecho->id == PING_ID) && (iecho->seqno == lwip_htons(ping_seq_num)))
{
printf("Ping was successful Elapsed time : %" U32_F " ms\n", sys_now() - ping_time);
/* do some ping result processing */
pbuf_free(p);
return 1; /* eat the packet */
}
/* not eaten, restore original packet */
pbuf_header(p, IP_HDR_LEN);
}
return 0; /* don't eat the packet */
}
static void ping_send_raw(struct raw_pcb * raw, const ip_addr_t * addr)
{
struct pbuf * p;
icmp_packet_t * iecho;
size_t ping_size = sizeof(icmp_packet_t);
printf("\r\nPinging to Gateway ");
print_ip4(addr->u_addr.ip4.addr);
LWIP_ASSERT("ping_size <= 0xffff", ping_size <= 0xffff);
p = pbuf_alloc(PBUF_IP, (u16_t) ping_size, PBUF_RAM);
if (!p)
{
return;
}
if ((p->len == p->tot_len) && (p->next == NULL))
{
iecho = (icmp_packet_t *) p->payload;
ping_prepare_echo(iecho, (u16_t) ping_size);
raw_sendto(raw, p, addr);
ping_time = sys_now();
}
pbuf_free(p);
}
static void ping_timeout(void * arg)
{
struct raw_pcb * pcb = (struct raw_pcb *) arg;
LWIP_ASSERT("ping_timeout: no pcb given!", pcb != NULL);
ping_send_raw(pcb, ping_target);
sys_timeout(PING_DELAY, ping_timeout, pcb);
}
void ping_raw(void)
{
ping_pcb = raw_new(IP_PROTO_ICMP);
LWIP_ASSERT("ping_pcb != NULL", ping_pcb != NULL);
raw_recv(ping_pcb, ping_recv_raw, NULL);
raw_bind(ping_pcb, IP_ADDR_ANY);
ping_send_raw(ping_pcb, ping_target);
sys_timeout(PING_DELAY, ping_timeout, ping_pcb);
}
#endif
CHIP_ERROR P6Utils::ping_init(void)
{
CHIP_ERROR err = CHIP_NO_ERROR;
struct netif * net_interface = NULL;
net_interface = cy_lwip_get_interface(CY_LWIP_STA_NW_INTERFACE);
ping_target = &net_interface->gw;
/* Ping to Gateway address */
if (ping_target)
{
#if PING_USE_SOCKETS
ping_socket();
#else
ping_raw();
#endif
}
else
{
ChipLogError(DeviceLayer, "ping_thread failed: Invalid IP address for Ping");
err = CHIP_ERROR_INTERNAL;
}
return err;
}
static int xtlv_hdr_size(uint16_t opts, const uint8_t ** data)
{
int len = (int) OFFSETOF(xtlv_t, data); /* nominal */
if (opts & XTLV_OPTION_LENU8)
{
--len;
}
if (opts & XTLV_OPTION_IDU8)
{
--len;
}
return len;
}
static int xtlv_size_for_data(int dlen, uint16_t opts, const uint8_t ** data)
{
int hsz;
hsz = xtlv_hdr_size(opts, data);
return ((opts & XTLV_OPTION_ALIGN32) ? P6_ALIGN_SIZE(dlen + hsz, 4) : (dlen + hsz));
}
static int xtlv_len(const xtlv_t * elt, uint16_t opts)
{
const uint8_t * lenp;
int len;
lenp = (const uint8_t *) &elt->len; /* nominal */
if (opts & XTLV_OPTION_IDU8)
{
--lenp;
}
if (opts & XTLV_OPTION_LENU8)
{
len = *lenp;
}
else
{
len = _LTOH16_UA(lenp);
}
return len;
}
static int xtlv_id(const xtlv_t * elt, uint16_t opts)
{
int id = 0;
if (opts & XTLV_OPTION_IDU8)
{
id = *(const uint8_t *) elt;
}
else
{
id = _LTOH16_UA((const uint8_t *) elt);
}
return id;
}
static void xtlv_unpack_xtlv(const xtlv_t * xtlv, uint16_t * type, uint16_t * len, const uint8_t ** data, uint16_t opts)
{
if (type)
{
*type = (uint16_t) xtlv_id(xtlv, opts);
}
if (len)
{
*len = (uint16_t) xtlv_len(xtlv, opts);
}
if (data)
{
*data = (const uint8_t *) xtlv + xtlv_hdr_size(opts, data);
}
}
void P6Utils::unpack_xtlv_buf(const uint8_t * tlv_buf, uint16_t buflen, wl_cnt_ver_30_t * cnt, wl_cnt_ge40mcst_v1_t * cnt_ge40)
{
uint16_t len;
uint16_t type;
int size;
const xtlv_t * ptlv;
int sbuflen = buflen;
const uint8_t * data;
int hdr_size;
hdr_size = xtlv_hdr_size(XTLV_OPTION_ALIGN32, &data);
while (sbuflen >= hdr_size)
{
ptlv = (const xtlv_t *) tlv_buf;
xtlv_unpack_xtlv(ptlv, &type, &len, &data, XTLV_OPTION_ALIGN32);
size = xtlv_size_for_data(len, XTLV_OPTION_ALIGN32, &data);
sbuflen -= size;
if (sbuflen < 0) /* check for buffer overrun */
{
break;
}
if (type == 0x100)
{
memcpy(cnt, (wl_cnt_ver_30_t *) data, sizeof(wl_cnt_ver_30_t));
}
if (type == 0x400)
{
memcpy(cnt_ge40, (wl_cnt_ge40mcst_v1_t *) data, sizeof(wl_cnt_ge40mcst_v1_t));
}
tlv_buf += size;
}
}
/* Get the Heap total size for P6 Linker file */
uint32_t get_heap_total()
{
extern uint8_t __HeapBase; /* Symbol exported by the linker. */
extern uint8_t __HeapLimit; /* Symbol exported by the linker. */
uint8_t * heap_base = (uint8_t *) &__HeapBase;
uint8_t * heap_limit = (uint8_t *) &__HeapLimit;
return (uint32_t)(heap_limit - heap_base);
}
/* Populate Heap info based on heap total size and Current Heap usage */
void P6Utils::heap_usage(heap_info_t * heap)
{
struct mallinfo mall_info = mallinfo();
heap->HeapMax = mall_info.arena;
heap->HeapUsed = mall_info.uordblks;
heap->HeapFree = get_heap_total() - mall_info.uordblks;
}