xiuos/Ubiquitous/XiZi_IIoT/resources/ethernet/netdev/netdev_register.c

213 lines
5.8 KiB
C

/*
* Copyright (c) 2006-2022, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2019-03-18 ChenYong First version
*/
/**
* @file netdev_register.c
* @brief register net dev function for net driver
* @version 3.0
* @author AIIT XUOS Lab
* @date 2023-08-07
*/
/*************************************************
File name: netdev_register.c
Description: register net dev function for net driver
Others: take RT-Thread v4.0.2/components/driver/serial/serial.c for references
https://github.com/RT-Thread/rt-thread/tree/v4.0.2
History:
1. Date: 2023-08-07
Author: AIIT XUOS Lab
Modification:
1. support net dev register, unregister function
*************************************************/
#include <assert.h>
#include <def.h>
#include <netdev.h>
#include <netdev_ipaddr.h>
#include <string.h>
#include <xs_isr.h>
#include <xs_kdbg.h>
struct netdev** get_netdev_listhead()
{
static struct netdev* netdev_listhead = NULL;
return &netdev_listhead;
}
struct netdev** get_default_netdev()
{
static struct netdev* netdev_default = NULL;
return &netdev_default;
}
static netdev_callback_fn g_netdev_register_callback = NULL;
static netdev_callback_fn g_netdev_default_change_callback = NULL;
int netdev_register(struct netdev* netdev, const char* name, void* user_data)
{
CHECK(netdev != NULL);
CHECK(name != NULL);
// set flag mask, assert network is down
uint16_t flag_mask = 0;
flag_mask = NETDEV_FLAG_UP | NETDEV_FLAG_LINK_UP | NETDEV_FLAG_INTERNET_UP | NETDEV_FLAG_DHCP;
netdev->flags &= ~flag_mask;
// clear dev setting
ip_addr_set_zero(&(netdev->ip_addr));
ip_addr_set_zero(&(netdev->netmask));
ip_addr_set_zero(&(netdev->gw));
IP_SET_TYPE_VAL(netdev->ip_addr, IPADDR_TYPE_V4);
IP_SET_TYPE_VAL(netdev->netmask, IPADDR_TYPE_V4);
IP_SET_TYPE_VAL(netdev->gw, IPADDR_TYPE_V4);
#if NETDEV_IPV6
for (index = 0; index < NETDEV_IPV6_NUM_ADDRESSES; index++) {
ip_addr_set_zero(&(netdev->ip6_addr[index]));
IP_SET_TYPE_VAL(netdev->ip_addr, IPADDR_TYPE_V6);
}
#endif /* NETDEV_IPV6 */
// clear DNS servers
for (uint16_t idx = 0; idx < NETDEV_DNS_SERVERS_NUM; idx++) {
ip_addr_set_zero(&(netdev->dns_servers[idx]));
IP_SET_TYPE_VAL(netdev->ip_addr, IPADDR_TYPE_V4);
}
// clear callback fn
netdev->addr_callback = NULL;
netdev->status_callback = NULL;
// validate name
uint32_t name_len = strlen(name);
if (name_len < NAME_NUM_MAX) {
strncpy(netdev->name, name, name_len);
netdev->name[name_len] = '\0';
} else {
SYS_KDEBUG_LOG(NETDEV_DEBUG, ("[%s] name too long.\n", __func__));
strncpy(netdev->name, name, NAME_NUM_MAX - 1);
netdev->name[NAME_NUM_MAX - 1] = '\0';
}
netdev->user_data = user_data;
InitSingleLinkList(&(netdev->list));
// insert netdev to global list
x_base lock = DISABLE_INTERRUPT();
if (NETDEV_LISTHEAD == NULL) {
NETDEV_LISTHEAD = netdev;
} else {
SingleLinkListNodeInsert(&(NETDEV_LISTHEAD->list), &(netdev->list));
}
ENABLE_INTERRUPT(lock);
if (NETDEV_DEFAULT == NULL) {
// set first met netdev to default netdev
netdev_set_default(NETDEV_LISTHEAD);
}
if (g_netdev_register_callback) {
g_netdev_register_callback(netdev, NETDEV_CB_REGISTER);
}
return EOK;
}
/**
* This function will unregister network interface device and
* delete it from network interface device list.
*
* @param netdev the network interface device object
*
* @return 0: unregistered successfully
* -1: unregistered failed
*/
int netdev_unregister(struct netdev* netdev)
{
CHECK(netdev);
if (NETDEV_LISTHEAD == NULL) {
return -ERROR;
}
// remove netdev from netdev list
x_base lock = DISABLE_INTERRUPT();
struct netdev* current_dev = NETDEV_LISTHEAD;
SINGLE_LINKLIST_FOR_EACH_ENTRY(current_dev, &(NETDEV_LISTHEAD->list), list)
{
// found netdev in list
if (current_dev == netdev) {
if (NETDEV_LISTHEAD == current_dev && NULL == SingleLinkListGetNextNode(&(current_dev->list))) {
// netdev is the only one in list
NETDEV_LISTHEAD = NULL;
} else {
SingleLinkListRmNode(&(NETDEV_LISTHEAD->list), &(current_dev->list));
}
// deal default netdev
if (current_dev == NETDEV_DEFAULT) {
NETDEV_DEFAULT = NULL;
}
break;
}
}
ENABLE_INTERRUPT(lock);
if (NETDEV_DEFAULT == NULL) {
netdev_set_default(NETDEV_LISTHEAD);
}
// clean netdev if found one
if (current_dev == netdev) {
memset(netdev, 0, sizeof(*netdev));
}
return EOK;
}
/**
* This function will set default network interface device.
*
* @param netdev the network interface device to change
*/
void netdev_set_default(struct netdev* netdev)
{
if (netdev && (netdev != NETDEV_DEFAULT)) {
NETDEV_DEFAULT = netdev;
// set default function
if (netdev->ops && netdev->ops->set_default) {
netdev->ops->set_default(netdev);
}
// default change callback
if (g_netdev_default_change_callback) {
g_netdev_default_change_callback(netdev, NETDEV_CB_DEFAULT_CHANGE);
}
SYS_KDEBUG_LOG(NETDEV_DEBUG, ("Setting default network interface device name(%s) successfully.\n", netdev->name));
}
}
/**
* This function will set register callback
*
* @param register_callback the network register callback
*
*/
void netdev_set_register_callback(netdev_callback_fn register_callback)
{
g_netdev_register_callback = register_callback;
}
void netdev_set_default_change_callback(netdev_callback_fn default_change_cb)
{
g_netdev_default_change_callback = default_change_cb;
}