mirror of https://github.com/ARMmbed/mbed-os.git
580 lines
18 KiB
C++
580 lines
18 KiB
C++
/*
|
|
* Copyright (c) 2019 ARM Limited
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include "mbed_interface.h"
|
|
#include "mbed_trace.h"
|
|
#include "netsocket/nsapi_types.h"
|
|
#include "mbed_shared_queues.h"
|
|
#include "mbed_poll.h"
|
|
#include "ip4string.h"
|
|
#include "ip6string.h"
|
|
#include "ppp_service.h"
|
|
#include "ppp_impl.h"
|
|
|
|
#if PPP_SUPPORT
|
|
|
|
#define TRACE_GROUP "ppp_serv_if"
|
|
|
|
typedef void (*ppp_sys_timeout_handler)(void *arg);
|
|
|
|
// Number of timers running simultaneous
|
|
#define PPP_TIMER_NUM 5
|
|
// Number of simultaneous memory buffers
|
|
#define PPP_PBUF_HANDLE_NUM 10
|
|
|
|
typedef struct {
|
|
ppp_service *ppp_drv;
|
|
ppp_sys_timeout_handler handler;
|
|
void *arg;
|
|
int equeue_id;
|
|
uint8_t id;
|
|
} ppp_sys_timeout_t;
|
|
|
|
static ppp_sys_timeout_t *timeout[PPP_TIMER_NUM];
|
|
static SingletonPtr<PlatformMutex> ppp_service_if_mutex;
|
|
static uint8_t ppp_service_sys_timeout_id = 0;
|
|
static pbuf pbuf_handles[PPP_PBUF_HANDLE_NUM];
|
|
|
|
#if PPP_TRACE_ENABLE
|
|
#define OUTPUT_BUFFER 0
|
|
#define INPUT_BUFFER 1
|
|
|
|
#define BUFFER_SIZE 5000
|
|
|
|
typedef struct {
|
|
char buffer[BUFFER_SIZE];
|
|
int buffer_index = 0;
|
|
int line_len = 0;
|
|
} trace_buf_t;
|
|
|
|
static trace_buf_t output_trace_buffer;
|
|
static trace_buf_t input_trace_buffer;
|
|
|
|
#if PPP_TRACE_BUFFER_SIZE > 0
|
|
static char cont_trace_buffer[PPP_TRACE_BUFFER_SIZE];
|
|
static int cont_trace_buffer_index = 0;
|
|
#endif
|
|
#endif
|
|
|
|
#if BYTE_ORDER == LITTLE_ENDIAN
|
|
#if !defined(ppp_htons)
|
|
/**
|
|
* Convert an u16_t from host- to network byte order.
|
|
*
|
|
* @param n u16_t in host byte order
|
|
* @return n in network byte order
|
|
*/
|
|
uint16_t ppp_htons(uint16_t n)
|
|
{
|
|
return PP_HTONS(n);
|
|
}
|
|
#endif /* ppp_htons */
|
|
|
|
#if !defined(ppp_htonl)
|
|
/**
|
|
* Convert an u32_t from host- to network byte order.
|
|
*
|
|
* @param n u32_t in host byte order
|
|
* @return n in network byte order
|
|
*/
|
|
uint32_t ppp_htonl(uint32_t n)
|
|
{
|
|
return PP_HTONL(n);
|
|
}
|
|
#endif /* ppp_htonl */
|
|
|
|
#endif /* BYTE_ORDER == LITTLE_ENDIAN */
|
|
|
|
extern "C" {
|
|
|
|
void ppp_ip4_addr_set(nsapi_addr_t *addr, uint32_t *src)
|
|
{
|
|
memset(addr->bytes, 0, NSAPI_IP_BYTES);
|
|
memcpy(addr->bytes, src, 4);
|
|
addr->version = NSAPI_IPv4;
|
|
}
|
|
|
|
struct netif *ppp_netif_add(struct netif *netif, void *state, netif_init_fn init)
|
|
{
|
|
#if PPP_IPV4_SUPPORT
|
|
netif->output = NULL;
|
|
netif->ipv4_up = false;
|
|
#endif /* PPP_IPV4_SUPPORT */
|
|
#if PPP_IPV6_SUPPORT
|
|
netif->output_ip6 = NULL;
|
|
netif->ipv6_up = false;
|
|
#endif
|
|
netif->mtu = 0;
|
|
netif->input = NULL;
|
|
netif->state = state;
|
|
|
|
/* call user specified initialization function for netif */
|
|
if (init(netif) != ERR_OK) {
|
|
return NULL;
|
|
}
|
|
|
|
return netif;
|
|
}
|
|
|
|
err_t ppp_ip_input(struct pbuf *p, struct netif *inp)
|
|
{
|
|
ppp_service *ppp_service_ptr = static_cast<ppp_service *>(inp->service_ptr);
|
|
void *buffer = ppp_memory_buffer_convert_from(p);
|
|
ppp_service_ptr->link_input(static_cast<net_stack_mem_buf_t *>(buffer));
|
|
return ERR_OK;
|
|
}
|
|
|
|
void ppp_set_link_up(struct netif *netif)
|
|
{
|
|
ppp_service *ppp_service_ptr = static_cast<ppp_service *>(netif->service_ptr);
|
|
ppp_service_ptr->link_state(true);
|
|
}
|
|
|
|
void ppp_set_link_down(struct netif *netif)
|
|
{
|
|
ppp_service *ppp_service_ptr = static_cast<ppp_service *>(netif->service_ptr);
|
|
ppp_service_ptr->link_state(false);
|
|
}
|
|
|
|
err_t ppp_call_callback(void *service_ptr, ppp_service_cb callback, void *arg)
|
|
{
|
|
ppp_service *ppp_service_ptr = static_cast<ppp_service *>(service_ptr);
|
|
|
|
int unique_id = ppp_service_ptr->event_queue_get()->call(mbed::callback(callback, arg));
|
|
if (unique_id == 0) {
|
|
return ERR_MEM;
|
|
}
|
|
|
|
return ERR_OK;
|
|
}
|
|
|
|
pbuf *ppp_memory_buffer_allocate(void *memory_manager, uint16_t size, ppp_buf_type_e type)
|
|
{
|
|
ppp_service_if_mutex->lock();
|
|
|
|
int8_t free_index = -1;
|
|
for (int8_t index = 0; index < PPP_PBUF_HANDLE_NUM; index++) {
|
|
if (pbuf_handles[index].buffer == NULL) {
|
|
free_index = index;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (free_index < 0) {
|
|
ppp_service_if_mutex->unlock();
|
|
return NULL;
|
|
}
|
|
|
|
NetStackMemoryManager *mem_mngr = static_cast<NetStackMemoryManager *>(memory_manager);
|
|
|
|
void *buffer;
|
|
if (type == PPP_BUF_HEAP) {
|
|
buffer = mem_mngr->alloc_heap(size, 0);
|
|
} else {
|
|
buffer = mem_mngr->alloc_pool(size, 0);
|
|
}
|
|
|
|
if (!buffer) {
|
|
ppp_service_if_mutex->unlock();
|
|
return NULL;
|
|
}
|
|
|
|
// Must be continuous buffer from pool on alloc
|
|
if (mem_mngr->get_next(buffer) != NULL) {
|
|
mem_mngr->free(buffer);
|
|
ppp_service_if_mutex->unlock();
|
|
return NULL;
|
|
}
|
|
|
|
pbuf_handles[free_index].next = NULL;
|
|
pbuf_handles[free_index].buffer = buffer;
|
|
pbuf_handles[free_index].memory_manager = memory_manager;
|
|
pbuf_handles[free_index].payload = static_cast<uint8_t *>(mem_mngr->get_ptr(buffer));
|
|
pbuf_handles[free_index].len = size;
|
|
pbuf_handles[free_index].tot_len = size;
|
|
pbuf_handles[free_index].payload_start = pbuf_handles[free_index].payload;
|
|
|
|
ppp_service_if_mutex->unlock();
|
|
|
|
return &pbuf_handles[free_index];
|
|
}
|
|
|
|
void ppp_memory_buffer_free(pbuf *buffer)
|
|
{
|
|
ppp_service_if_mutex->lock();
|
|
|
|
int8_t buffer_index = -1;
|
|
for (int8_t index = 0; index < PPP_PBUF_HANDLE_NUM; index++) {
|
|
if (&pbuf_handles[index] == buffer) {
|
|
buffer_index = index;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (buffer_index < 0) {
|
|
ppp_service_if_mutex->unlock();
|
|
return;
|
|
}
|
|
|
|
if (pbuf_handles[buffer_index].buffer != NULL) {
|
|
NetStackMemoryManager *mem_mngr = static_cast<NetStackMemoryManager *>(pbuf_handles[buffer_index].memory_manager);
|
|
mem_mngr->free(pbuf_handles[buffer_index].buffer);
|
|
}
|
|
|
|
memset(&pbuf_handles[buffer_index], 0, sizeof(pbuf));
|
|
|
|
ppp_service_if_mutex->unlock();
|
|
}
|
|
|
|
uint16_t ppp_memory_buffer_pool_alloc_unit_get(void *memory_manager)
|
|
{
|
|
NetStackMemoryManager *mem_mngr = static_cast<NetStackMemoryManager *>(memory_manager);
|
|
return mem_mngr->get_pool_alloc_unit(0);
|
|
}
|
|
|
|
void ppp_memory_buffer_cat(void *memory_manager, pbuf *to_buf, pbuf *cat_buf)
|
|
{
|
|
for (struct pbuf *buf = to_buf; buf != NULL; buf = buf->next) {
|
|
if (buf->next == NULL) {
|
|
buf->next = cat_buf;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void ppp_memory_buffer_set_len(void *memory_manager, pbuf *buf, uint16_t len)
|
|
{
|
|
NetStackMemoryManager *mem_mngr = static_cast<NetStackMemoryManager *>(memory_manager);
|
|
mem_mngr->set_len(buf->buffer, len);
|
|
}
|
|
|
|
struct pbuf *ppp_memory_buffer_convert_to(void *memory_manager, net_stack_mem_buf_t *mem_buf)
|
|
{
|
|
ppp_service_if_mutex->lock();
|
|
|
|
int8_t free_index = -1;
|
|
for (int8_t index = 0; index < PPP_PBUF_HANDLE_NUM; index++) {
|
|
if (pbuf_handles[index].buffer == NULL) {
|
|
free_index = index;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (free_index < 0) {
|
|
ppp_service_if_mutex->unlock();
|
|
return NULL;
|
|
}
|
|
|
|
NetStackMemoryManager *mem_mngr = static_cast<NetStackMemoryManager *>(memory_manager);
|
|
|
|
pbuf_handles[free_index].buffer = mem_buf;
|
|
pbuf_handles[free_index].memory_manager = memory_manager;
|
|
pbuf_handles[free_index].payload = mem_mngr->get_ptr(mem_buf);
|
|
pbuf_handles[free_index].len = mem_mngr->get_len(mem_buf);
|
|
pbuf_handles[free_index].tot_len = mem_mngr->get_total_len(mem_buf);
|
|
pbuf_handles[free_index].payload_start = pbuf_handles[free_index].payload;
|
|
|
|
ppp_service_if_mutex->unlock();
|
|
|
|
return &pbuf_handles[free_index];
|
|
}
|
|
|
|
net_stack_mem_buf_t *ppp_memory_buffer_convert_from(struct pbuf *p)
|
|
{
|
|
NetStackMemoryManager *mem_mngr = static_cast<NetStackMemoryManager *>(p->memory_manager);
|
|
|
|
net_stack_mem_buf_t *first_buffer = p->buffer;
|
|
|
|
struct pbuf *buf_next;
|
|
for (struct pbuf *buf = p; buf != NULL; buf = buf_next) {
|
|
|
|
// Set actual memory buffer length
|
|
mem_mngr->set_len(buf->buffer, buf->len);
|
|
|
|
// Trim the headroom away from buffer if set
|
|
if (buf->payload_start < buf->payload) {
|
|
memmove(buf->payload_start, buf->payload, buf->len);
|
|
}
|
|
|
|
buf_next = buf->next;
|
|
|
|
// If not first buffer cat to first buffer and free
|
|
if (buf->buffer != first_buffer) {
|
|
mem_mngr->cat(first_buffer, buf->buffer);
|
|
buf->buffer = NULL;
|
|
ppp_memory_buffer_free(buf);
|
|
}
|
|
}
|
|
|
|
// Going to upper levels, do not deallocate the actual buffer
|
|
p->buffer = NULL;
|
|
ppp_memory_buffer_free(p);
|
|
|
|
return first_buffer;
|
|
}
|
|
|
|
uint8_t ppp_memory_buffer_remove_header(pbuf *buffer, uint16_t header_len)
|
|
{
|
|
uint8_t *payload = static_cast<uint8_t *>(buffer->payload);
|
|
payload += header_len;
|
|
buffer->payload = payload;
|
|
buffer->len -= header_len;
|
|
return 0;
|
|
}
|
|
|
|
uint8_t ppp_memory_buffer_add_header(struct pbuf *buffer, uint16_t header_len)
|
|
{
|
|
uint32_t payload_headroom_len = static_cast<uint8_t *>(buffer->payload) - static_cast<uint8_t *>(buffer->payload_start);
|
|
|
|
if (payload_headroom_len < header_len) {
|
|
return 1; // failure
|
|
}
|
|
|
|
buffer->payload = static_cast<uint8_t *>(buffer->payload) - header_len;
|
|
buffer->len += header_len;
|
|
|
|
return 0;
|
|
}
|
|
|
|
uint32_t ppp_sys_now(void)
|
|
{
|
|
return osKernelGetTickCount();
|
|
}
|
|
|
|
uint32_t ppp_sys_jiffies(void)
|
|
{
|
|
return ppp_sys_now();
|
|
}
|
|
|
|
sys_prot_t ppp_sys_arch_protect(void *service_ptr)
|
|
{
|
|
ppp_service *ppp_service_ptr = static_cast<ppp_service *>(service_ptr);
|
|
ppp_service_ptr->resource_lock();
|
|
|
|
return (sys_prot_t) 1;
|
|
}
|
|
|
|
void ppp_sys_arch_unprotect(void *service_ptr, sys_prot_t p)
|
|
{
|
|
ppp_service *ppp_service_ptr = static_cast<ppp_service *>(service_ptr);
|
|
ppp_service_ptr->resource_unlock();
|
|
}
|
|
|
|
#if PPP_TRACE_ENABLE
|
|
void ppp_trace_to_ascii_hex_dump(int buffer, int len, char *data)
|
|
{
|
|
char prefix[10];
|
|
trace_buf_t *trace_buffer = NULL;
|
|
if (buffer == OUTPUT_BUFFER) {
|
|
strcpy(prefix, "O:");
|
|
trace_buffer = &output_trace_buffer;
|
|
} else if (buffer == INPUT_BUFFER) {
|
|
strcpy(prefix, "I:");
|
|
trace_buffer = &input_trace_buffer;
|
|
}
|
|
|
|
static char line[100];
|
|
memset(line, 0, 100);
|
|
int index = 0;
|
|
|
|
bool add_prefix = false;
|
|
if (trace_buffer->buffer_index == 0) {
|
|
index += sprintf(&line[index], "\n %" PRIi32 " len: %i buffer index %i line len %i \n", ppp_sys_now(), len, trace_buffer->buffer_index, trace_buffer->line_len);
|
|
add_prefix = true;
|
|
}
|
|
|
|
for (int i = 0; i < len; i++) {
|
|
if ((trace_buffer->line_len % 16) == 0) {
|
|
if (trace_buffer->line_len != 0) {
|
|
index += sprintf(&line[index], "\n");
|
|
trace_buffer->buffer_index += sprintf(&trace_buffer->buffer[trace_buffer->buffer_index], "%s", line);
|
|
index = 0;
|
|
}
|
|
|
|
bool add_ppp_flag = false;
|
|
if (add_prefix) {
|
|
if (data[i] == 0xff || (data[i] == 0x57 && (data[i + 1] == 0x60 || data[i + 1] == 0x6a))) {
|
|
add_ppp_flag = true;
|
|
}
|
|
}
|
|
|
|
index += sprintf(&line[index], "%s %06x%s%s", prefix, trace_buffer->line_len, add_prefix ? " 00 00 88 81" : "", add_ppp_flag ? " 7e" : "");
|
|
if (add_prefix) {
|
|
trace_buffer->line_len += 4;
|
|
}
|
|
if (add_ppp_flag) {
|
|
trace_buffer->line_len += 1;
|
|
}
|
|
add_prefix = false;
|
|
}
|
|
trace_buffer->line_len++;
|
|
index += sprintf(&line[index], " %02x", data[i]);
|
|
}
|
|
|
|
trace_buffer->buffer_index += sprintf(&trace_buffer->buffer[trace_buffer->buffer_index], "%s", line);
|
|
}
|
|
|
|
void ppp_trace_to_ascii_hex_dump_print(int buffer)
|
|
{
|
|
trace_buf_t *trace_buffer = NULL;
|
|
if (buffer == OUTPUT_BUFFER) {
|
|
trace_buffer = &output_trace_buffer;
|
|
} else if (buffer == INPUT_BUFFER) {
|
|
trace_buffer = &input_trace_buffer;
|
|
}
|
|
|
|
#if PPP_TRACE_BUFFER_SIZE == 0
|
|
tr_info("%s", trace_buffer->buffer);
|
|
#endif
|
|
|
|
#if PPP_TRACE_BUFFER_SIZE > 0
|
|
cont_trace_buffer_index += sprintf(&cont_trace_buffer[cont_trace_buffer_index], "%s", trace_buffer->buffer);
|
|
memset(trace_buffer->buffer, 0, BUFFER_SIZE);
|
|
|
|
if (cont_trace_buffer_index > (PPP_TRACE_BUFFER_SIZE - PPP_TRACE_BUFFER_SIZE / 5)) {
|
|
cont_trace_buffer_index = 0;
|
|
}
|
|
#endif
|
|
|
|
trace_buffer->buffer_index = 0;
|
|
trace_buffer->line_len = 0;
|
|
}
|
|
|
|
#endif
|
|
|
|
void ppp_sys_timeout_callback(void *cb_ptr)
|
|
{
|
|
ppp_service_if_mutex->lock();
|
|
|
|
int id = reinterpret_cast<int>(cb_ptr);
|
|
|
|
ppp_sys_timeout_handler handler = NULL;
|
|
void *arg = NULL;
|
|
|
|
for (int8_t i = 0; i < PPP_TIMER_NUM; i++) {
|
|
if (timeout[i] && timeout[i]->id == id) {
|
|
handler = timeout[i]->handler;
|
|
arg = timeout[i]->arg;
|
|
free(timeout[i]);
|
|
timeout[i] = NULL;
|
|
//tr_info("sys timer timeout, i: %i h/a: %p %p, id: %i", i, handler, arg, timeout[i]->equeue_id);
|
|
}
|
|
}
|
|
|
|
ppp_service_if_mutex->unlock();
|
|
|
|
if (handler) {
|
|
handler(arg);
|
|
} else {
|
|
tr_error("Cancelled timeout");
|
|
}
|
|
}
|
|
|
|
void ppp_sys_timeout(void *service_ptr, u32_t msecs, ppp_sys_timeout_handler handler, void *arg)
|
|
{
|
|
ppp_service *ppp_service_ptr = static_cast<ppp_service *>(service_ptr);
|
|
|
|
ppp_service_if_mutex->lock();
|
|
|
|
int8_t free_index = -1;
|
|
|
|
for (int8_t i = 0; i < PPP_TIMER_NUM; i++) {
|
|
if (timeout[i] == NULL && free_index < 0) {
|
|
free_index = i;
|
|
} else if (timeout[i] != NULL && timeout[i]->handler == handler && timeout[i]->arg == arg) {
|
|
tr_error("Timeout already set");
|
|
ppp_service_if_mutex->unlock();
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (free_index < 0) {
|
|
tr_error("No free timeouts");
|
|
ppp_service_if_mutex->unlock();
|
|
}
|
|
|
|
timeout[free_index] = static_cast<ppp_sys_timeout_t *>(malloc(sizeof(ppp_sys_timeout_t)));
|
|
if (!timeout[free_index]) {
|
|
tr_error("No free memory for timeout");
|
|
ppp_service_if_mutex->unlock();
|
|
return;
|
|
}
|
|
|
|
void *cb_ptr = reinterpret_cast<void *>(ppp_service_sys_timeout_id);
|
|
int unique_id = ppp_service_ptr->event_queue_get()->call_in(msecs, mbed::callback(ppp_sys_timeout_callback, cb_ptr));
|
|
if (unique_id == 0) {
|
|
tr_error("No free memory for timeout equeue");
|
|
ppp_service_if_mutex->unlock();
|
|
return;
|
|
}
|
|
|
|
timeout[free_index]->ppp_drv = ppp_service_ptr;
|
|
timeout[free_index]->handler = handler;
|
|
timeout[free_index]->arg = arg;
|
|
timeout[free_index]->equeue_id = unique_id;
|
|
timeout[free_index]->id = ppp_service_sys_timeout_id++;
|
|
|
|
//tr_info("sys timer start, i: %i h/a: %p %p, t: %" PRIx32 " id: %i", free_index, handler, arg, msecs, unique_id);
|
|
|
|
ppp_service_if_mutex->unlock();
|
|
}
|
|
|
|
void ppp_sys_untimeout(ppp_sys_timeout_handler handler, void *arg)
|
|
{
|
|
ppp_service_if_mutex->lock();
|
|
|
|
for (int8_t i = 0; i < PPP_TIMER_NUM; i++) {
|
|
if (timeout[i] != NULL && timeout[i]->handler == handler && timeout[i]->arg == arg) {
|
|
int unique_id = timeout[i]->equeue_id;
|
|
timeout[i]->ppp_drv->event_queue_get()->cancel(unique_id);
|
|
//tr_info("sys timer cancel, i: %i h/a: %p %p, id: %i", i, timeout[i]->handler, timeout[i]->arg, unique_id);
|
|
free(timeout[i]);
|
|
timeout[i] = NULL;
|
|
}
|
|
}
|
|
|
|
ppp_service_if_mutex->unlock();
|
|
}
|
|
|
|
} // extern "C"
|
|
|
|
#if PPP_TRACE_ENABLE && PPP_TRACE_BUFFER_SIZE > 0
|
|
void ppp_trace_to_ascii_hex_dump_print_final(void)
|
|
{
|
|
int start_i = 0;
|
|
|
|
for (int i = 0; i < PPP_TRACE_BUFFER_SIZE; i++) {
|
|
if (cont_trace_buffer[i] == '\n' || cont_trace_buffer[i] == '\0') {
|
|
memcpy(output_trace_buffer.buffer, &cont_trace_buffer[start_i], i - start_i);
|
|
output_trace_buffer.buffer[i - start_i] = 0;
|
|
|
|
tr_info("%s", output_trace_buffer.buffer);
|
|
|
|
if (cont_trace_buffer[i] == '\0') {
|
|
break;
|
|
}
|
|
|
|
start_i = i + 1;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#endif
|