Skip to content

Instantly share code, notes, and snippets.

@akansha-oi
Created August 2, 2025 12:12
Show Gist options
  • Select an option

  • Save akansha-oi/47df4c39bb937c326e037faddaaf113b to your computer and use it in GitHub Desktop.

Select an option

Save akansha-oi/47df4c39bb937c326e037faddaaf113b to your computer and use it in GitHub Desktop.
/*
* Copyright (C) 2009-2016 Realtek Semiconductor Corp.
* All Rights Reserved.
*
* This program is the proprietary software of Realtek Semiconductor
* Corporation and/or its licensors, and only be used, duplicated,
* modified or distributed under the authorized license from Realtek.
*
* ANY USE OF THE SOFTWARE OTHER THAN AS AUTHORIZED UNDER
* THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED.
*
* $Revision$
* $Date$
*
* Purpose : Define diag shell main function.
*
* Feature : The file have include the following module and sub-modules
* 1) main function.
* 2) HTTP API server with comprehensive helper functions for:
* - Safe JSON parsing (extract_json_string, extract_json_int, extract_json_bool)
* - Input validation (is_valid_ip, is_valid_mac, is_valid_port)
* - Standardized response handling (send_error_response, send_success_response)
* - HTTP request parsing (parse_http_request)
* - Thread-safe operations with proper error handling
* 3) RTK SDK Integration - All handlers now use actual RTK functions:
* - Port configuration: rtk_port_link_get, rtk_port_adminEnable_set, rtk_port_speedDuplex_set
* - Flow control: rtk_port_flowCtrlEnable_get/set
* - Rate limiting: rtk_rate_portIgrBwCtrlEnable_get/set, rtk_rate_portIgrBwCtrlRate_get/set
* - Storm control: rtk_rate_portStormCtrlEnable_get/set, rtk_rate_portStormCtrlRate_get/set
* - VLAN management: rtk_vlan_create/destroy, rtk_vlan_port_get/set
* - Port isolation: rtk_port_isolation_get/set for protected port functionality
* - MAC learning: rtk_l2_portLimitLearningCnt_get/set
* - Statistics: rtk_stat_port_get for comprehensive port statistics
*/
/*
* Include Files
*/
#include <common/rt_type.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
#include <stddef.h>
#include <stdlib.h>
#include <diag_util.h>
#include <diag_om.h>
#include <diag_str.h>
#include <diag_debug.h>
#include <parser/cparser.h>
#include <parser/cparser_priv.h>
#include <parser/cparser_token.h>
#include <parser/cparser_tree.h>
#include <osal/memory.h>
#include <pthread.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/udp.h>
#include <sys/sysinfo.h>
#include <sys/statvfs.h>
#include <math.h>
#include <sys/stat.h>
#include <rtk/stat.h>
#include <rtk/port.h>
#include <rtk/phy.h>
#include <rtk/l2.h>
#include <rtk/switch.h>
#include <rtk/vlan.h>
#include <hal/common/halctrl.h>
#include <sys/reboot.h>
#include <stdbool.h>
#include <rtk/rate.h>
#include <rtk/qos.h>
#include <rtk/trap.h>
#include <rtk/acl.h>
#include <rtk/stat.h>
#include <rtk/l2.h>
#include <rtk/mcast.h>
#include <rtk/ipmcast.h>
#include <rtk/mirror.h>
#include <rtk/trunk.h>
#include <rtk/l3.h>
#include <rtk/qos.h>
#include <rtk/rate.h>
#include <rtk/vlan.h>
#include <rtk/stp.h>
#include <rtk/flowctrl.h>
#include <rtk/init.h>
#include <stddef.h>
#include <limits.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#ifdef CONFIG_RISE
#include <hwp/hw_profile.h>
#include <rise/src/rise.h>
#endif
#define BACKENDPORT 8443
#define BUFFER_SIZE 1024
#define MAX_PORTS 16
#define MAX_VLANS 32
#define MAX_USERS 10
#define MAX_COMMUNITIES 10
#define MAX_TRAP_TARGETS 10
#define MAX_ACL_ENTRIES 100
#define MAX_MAC_BINDINGS 1000
#define MAX_MAC_AUTO_BINDINGS 1000
#define MAX_RMON_STATISTICS 100
#define MAX_RMON_HISTORY 100
#define MAX_RMON_ALARMS 100
#define MAX_RMON_EVENTS 100
#define MAX_IGMP_CONFIGS 10
#define MAX_MULTICAST_GROUPS 100
#define MAX_STRING_LEN 64
#define MAX_IP_LEN 16
volatile int server_running = 1;
int i , j , p;
void build_json_response(int client_socket, const char *json_content);
// ============================================================================================================================================================
// GLOBAL DATA STRUCTURES
// ============================================================================================================================================================
// Mutex for thread safety
pthread_mutex_t global_data_mutex = PTHREAD_MUTEX_INITIALIZER;
// System Configuration
typedef struct {
char systemName[MAX_STRING_LEN];
char systemLocation[MAX_STRING_LEN];
char systemContact[MAX_STRING_LEN];
char description[MAX_STRING_LEN];
char objectId[MAX_STRING_LEN];
char version[MAX_STRING_LEN];
char serialNumber[MAX_STRING_LEN];
char macAddress[MAX_STRING_LEN];
char ipAddress[MAX_IP_LEN];
int interfaces;
} SystemConfig;
// Port Configuration
typedef struct {
int port_id;
bool admin_enabled;
char status[16]; // "Up" or "Down"
char speed[16]; // "10M", "100M", "1000M", "Auto"
char duplex[16]; // "Full", "Half", "Auto"
bool flow_control_enabled;
int ingress_rate_limit;
int egress_rate_limit;
bool rate_limit_enabled;
int max_mac_addresses;
bool protected_port;
// Storm control
bool broadcast_suppression;
int broadcast_rate;
bool multicast_suppression;
int multicast_rate;
bool dlf_suppression;
int dlf_rate;
} PortConfig;
// User Management
typedef struct {
char username[MAX_STRING_LEN];
char password[MAX_STRING_LEN];
int level;
int timeout;
bool active;
} UserEntry;
// VLAN Configuration
typedef struct {
int vid;
char vlan_name[MAX_STRING_LEN];
bool active;
char port_members[MAX_STRING_LEN]; // Bitmap or string representation
char ip_address[MAX_IP_LEN];
int dhcp_client;
} VlanConfig;
// QoS Configuration
typedef struct {
int port;
char qos_type[MAX_STRING_LEN];
int priority;
char schedule_mode[16]; // "WRR" or "WFQ"
int weights[8];
} QosConfig;
// SNMP Configuration
typedef struct {
char community[MAX_STRING_LEN];
char access[16]; // "read-only" or "read-write"
bool active;
} SnmpCommunity;
typedef struct {
char ip[MAX_IP_LEN];
char community[MAX_STRING_LEN];
char version[8]; // "v1", "v2c", "v3"
bool active;
} TrapTarget;
// ACL Configuration
typedef struct {
int group_num;
char type[16]; // "standard-ip", "extended-ip", "mac-ip", "mac-arp"
char source_ip[MAX_IP_LEN];
char source_wildcard[MAX_IP_LEN];
char destination_ip[MAX_IP_LEN];
char source_mac[32];
char protocol_type[16];
char action[16]; // "permit" or "deny"
bool active;
} AclEntry;
// Service Access Configuration
// Service Access Configuration
typedef struct {
bool http_enabled;
bool https_enabled;
bool snmp_enabled;
bool telnet_enabled;
bool ssh_enabled;
int http_acl;
int snmp_acl;
int telnet_acl;
int ssh_acl;
} ServiceAccess;
// SNTP Configuration
typedef struct {
bool enabled;
char server_ip[MAX_IP_LEN];
int interval;
} SntpConfig;
// Serial Configuration
typedef struct {
char baud_rate[16];
char char_size[8];
char parity[16];
char stop_bits[8];
char flow_control[16];
} SerialConfig;
// LLDP Configuration
typedef struct {
bool lldp_global;
int hold_multiplier;
int reinit_delay;
int tx_delay;
int tx_interval;
} LldpGlobalConfig;
typedef struct {
int port;
bool enabled;
char manage_ip[MAX_IP_LEN];
bool transmit_enabled;
bool receive_enabled;
} LldpPortConfig;
// MAC Binding Configuration
typedef struct {
int port;
char macAddress[32];
int vlanId;
bool active;
} MacBinding;
// MAC Auto Bind Configuration
typedef struct {
int port;
char macAddress[32];
int vlanId;
bool autoLearned;
bool active;
} MacAutoBind;
// RMON Statistics Configuration
typedef struct {
int port;
int index;
char owner[MAX_STRING_LEN];
// Statistics counters
uint64 etherStatsDropEvents;
uint64 etherStatsPkts;
uint64 etherStatsMulticastPkts;
uint64 etherStatsUndersizePkts;
uint64 etherStatsFragments;
uint64 etherStatsCollisions;
uint64 etherStatsPkts65to127Octets;
uint64 etherStatsPkts256to511Octets;
uint64 etherStatsPkts1024to1518Octets;
uint64 etherStatsOctets;
uint64 etherStatsBroadcastPkts;
uint64 etherStatsCRCAlignErrors;
uint64 etherStatsOversizePkts;
uint64 etherStatsJabbers;
uint64 etherStatsPkts64Octets;
uint64 etherStatsPkts128to255Octets;
uint64 etherStatsPkts512to1023Octets;
bool active;
} RmonStatistics;
// RMON History Configuration
typedef struct {
int port;
int index;
int interval;
int buckets;
char owner[MAX_STRING_LEN];
bool active;
} RmonHistory;
// RMON Alarm Configuration
typedef struct {
char sequenceType[16];
int sequenceIndex;
int interval;
char variable[MAX_STRING_LEN];
char sampleType[16]; // "absolute" or "delta"
uint64 alarmValue;
uint64 risingThreshold;
uint64 fallingThreshold;
int risingEventIndex;
int fallingEventIndex;
char owner[MAX_STRING_LEN];
bool active;
} RmonAlarm;
// RMON Event Configuration
typedef struct {
char sequenceType[16];
int sequenceIndex;
int index;
char description[256];
char type[32]; // "none", "log", "snmptrap", "log-and-trap"
char community[MAX_STRING_LEN];
char lastTimeSent[32];
char owner[MAX_STRING_LEN];
bool active;
} RmonEvent;
// IGMP Snooping Configuration
typedef struct {
bool globalIgmpSnooping;
char vlanId[16];
bool vlanIgmpSnooping;
bool fastLeave;
int fastLeaveTimeout;
int queryMembershipTimeout;
int groupMembershipTimeout;
bool active;
} IgmpSnoopingConfig;
// Multicast Group Information
typedef struct {
char vlanId[16];
char multicastAddress[16];
char memberPorts[MAX_STRING_LEN];
bool active;
} MulticastGroup;
// Global Data Storage
typedef struct {
SystemConfig system;
PortConfig ports[MAX_PORTS];
UserEntry users[MAX_USERS];
VlanConfig vlans[MAX_VLANS];
QosConfig qos_configs[MAX_PORTS];
SnmpCommunity communities[MAX_COMMUNITIES];
TrapTarget trap_targets[MAX_TRAP_TARGETS];
AclEntry acl_entries[MAX_ACL_ENTRIES];
MacBinding mac_bindings[MAX_MAC_BINDINGS];
MacAutoBind mac_auto_bindings[MAX_MAC_AUTO_BINDINGS];
RmonStatistics rmon_statistics[MAX_RMON_STATISTICS];
RmonHistory rmon_history[MAX_RMON_HISTORY];
RmonAlarm rmon_alarms[MAX_RMON_ALARMS];
RmonEvent rmon_events[MAX_RMON_EVENTS];
IgmpSnoopingConfig igmp_configs[MAX_IGMP_CONFIGS];
MulticastGroup multicast_groups[MAX_MULTICAST_GROUPS];
ServiceAccess service_access;
SntpConfig sntp;
SerialConfig serial;
LldpGlobalConfig lldp_global;
LldpPortConfig lldp_ports[MAX_PORTS];
int jumbo_frame_size;
int user_count;
int community_count;
int trap_target_count;
int acl_entry_count;
int vlan_count;
int mac_binding_count;
int mac_auto_binding_count;
int rmon_statistics_count;
int rmon_history_count;
int rmon_alarm_count;
int rmon_event_count;
int igmp_config_count;
int multicast_group_count;
} GlobalDataStore;
// Initialize global data store
GlobalDataStore g_data;
// ============================================================================================================================================================
// UTILITY FUNCTIONS
// ============================================================================================================================================================
// Safe string copy function
void safe_strcpy(char *dest, const char *src, unsigned int dest_size) {
if (dest && src && dest_size > 0) {
strncpy(dest, src, dest_size - 1);
dest[dest_size - 1] = '\0';
}
}
// Safe JSON string extraction with bounds checking
int extract_json_string(const char *json, const char *key, char *out_value, unsigned int out_size) {
if (!json || !key || !out_value || out_size == 0) {
return -1;
}
char search_key[MAX_STRING_LEN];
snprintf(search_key, sizeof(search_key), "\"%s\"", key);
char *key_pos = strstr(json, search_key);
if (!key_pos) {
return -1;
}
char *colon = strchr(key_pos, ':');
if (!colon) {
return -1;
}
colon++;
// Skip whitespace
while (*colon == ' ' || *colon == '\t' || *colon == '\n' || *colon == '\r') {
colon++;
}
if (*colon != '"') {
return -1;
}
colon++; // Skip opening quote
char *end_quote = strchr(colon, '"');
if (!end_quote) {
return -1;
}
unsigned int len = end_quote - colon;
if (len >= out_size) {
len = out_size - 1;
}
strncpy(out_value, colon, len);
out_value[len] = '\0';
return 0;
}
// Safe JSON integer extraction
int extract_json_int(const char *json, const char *key, int *out_value) {
if (!json || !key || !out_value) {
return -1;
}
char search_key[MAX_STRING_LEN];
snprintf(search_key, sizeof(search_key), "\"%s\"", key);
char *key_pos = strstr(json, search_key);
if (!key_pos) {
return -1;
}
char *colon = strchr(key_pos, ':');
if (!colon) {
return -1;
}
colon++;
// Skip whitespace
while (*colon == ' ' || *colon == '\t' || *colon == '\n' || *colon == '\r') {
colon++;
}
*out_value = atoi(colon);
return 0;
}
// Safe JSON boolean extraction
int extract_json_bool(const char *json, const char *key, bool *out_value) {
if (!json || !key || !out_value) {
return -1;
}
char search_key[MAX_STRING_LEN];
snprintf(search_key, sizeof(search_key), "\"%s\"", key);
char *key_pos = strstr(json, search_key);
if (!key_pos) {
return -1;
}
char *colon = strchr(key_pos, ':');
if (!colon) {
return -1;
}
colon++;
// Skip whitespace
while (*colon == ' ' || *colon == '\t' || *colon == '\n' || *colon == '\r') {
colon++;
}
if (strncmp(colon, "true", 4) == 0) {
*out_value = true;
return 0;
} else if (strncmp(colon, "false", 5) == 0) {
*out_value = false;
return 0;
}
return -1;
}
// Helper function to send error response
void send_error_response(int client_socket, int status_code, const char *error_message) {
char response[BUFFER_SIZE];
const char *status_text = (status_code == 400) ? "Bad Request" :
(status_code == 404) ? "Not Found" :
(status_code == 500) ? "Internal Server Error" : "Error";
snprintf(response, sizeof(response),
"HTTP/1.1 %d %s\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Content-Type: application/json\r\n\r\n"
"{\"error\": \"%s\"}",
status_code, status_text, error_message ? error_message : "Unknown error");
send(client_socket, response, strlen(response), 0);
}
// Helper function to send success response with JSON
void send_success_response(int client_socket, const char *json_content) {
if (!json_content) {
send_error_response(client_socket, 500, "No content provided");
return;
}
build_json_response(client_socket, json_content);
}
// Helper function to validate port number
bool is_valid_port(int port, int min_port, int max_port) {
return (port >= min_port && port <= max_port);
}
// Helper function to validate IP address format (basic validation)
bool is_valid_ip(const char *ip) {
if (!ip || strlen(ip) == 0) {
return false;
}
int parts[4];
int count = sscanf(ip, "%d.%d.%d.%d", &parts[0], &parts[1], &parts[2], &parts[3]);
if (count != 4) {
return false;
}
for (i = 0; i < 4; i++) {
if (parts[i] < 0 || parts[i] > 255) {
return false;
}
}
return true;
}
// Helper function to validate MAC address format
bool is_valid_mac(const char *mac) {
if (!mac || strlen(mac) != 17) {
return false;
}
for (i = 0; i < 17; i++) {
if (i % 3 == 2) {
if (mac[i] != ':') {
return false;
}
} else {
if (!isxdigit(mac[i])) {
return false;
}
}
}
return true;
}
// Helper function to create standard HTTP headers
void add_standard_headers(char *response, unsigned int response_size) {
snprintf(response, response_size,
"HTTP/1.1 200 OK\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Content-Type: application/json\r\n\r\n");
}
// Helper function to parse request method and path
int parse_http_request(const char *buffer, char *method, char *path, char **body, char **query) {
if (!buffer || !method || !path) {
return -1;
}
char protocol[16];
if (sscanf(buffer, "%15s %255s %15s", method, path, protocol) != 3) {
return -1;
}
// Split path and query
char *query_start = strchr(path, '?');
if (query_start) {
*query_start = '\0';
*query = query_start + 1;
} else {
*query = "";
}
// Find body
char *body_start = strstr(buffer, "\r\n\r\n");
if (body_start) {
*body = body_start + 4;
} else {
*body = "";
}
return 0;
}
// Thread-safe response builder
void build_json_response(int client_socket, const char *json_content) {
if (!json_content) {
return;
}
unsigned int content_len = strlen(json_content);
unsigned int total_size = content_len + 200; // Headers + content
char *response = malloc(total_size);
if (!response) {
const char *error_response = "HTTP/1.1 500 Internal Server Error\r\n\r\n";
send(client_socket, error_response, strlen(error_response), 0);
return;
}
snprintf(response, total_size,
"HTTP/1.1 200 OK\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Content-Type: application/json\r\n"
"Content-Length: %zu\r\n\r\n%s",
content_len, json_content);
send(client_socket, response, strlen(response), 0);
free(response);
}
void send_response(int client_socket, const char *response)
{
if (response) {
send(client_socket, response, strlen(response), 0);
}
}
static int32
dlag_initial_promt_unit_id(cparser_t *pParser)
{
uint32 unit;
if (diag_om_get_firstAvailableUnit(&unit) != RT_ERR_OK)
{
diag_util_printf("diag_main: Obtain avaliable unit ID fail.\n");
return RT_ERR_FAILED;
}
if (diag_om_set_deviceInfo(unit) != RT_ERR_OK)
{
diag_util_printf("diag_main: set unit %u deviceInfo error.\n", unit);
return RT_ERR_FAILED;
}
diag_om_get_promptString((uint8 *)pParser->cfg.prompt, sizeof(pParser->cfg.prompt), unit);
diag_om_set_unitId(unit);
return RT_ERR_OK;
}
// Helper function to parse IP address into 32-bit integer
uint32 parse_ip_address(const char *ip_str) {
unsigned int a, b, c, d;
if (sscanf(ip_str, "%u.%u.%u.%u", &a, &b, &c, &d) != 4) {
return 0;
}
return (a << 24) | (b << 16) | (c << 8) | d;
}
// Helper function to parse MAC address
int parse_mac_address(const char *mac_str, uint8 *mac_addr) {
unsigned int mac[6];
if (sscanf(mac_str, "%02x:%02x:%02x:%02x:%02x:%02x",
&mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]) != 6) {
return -1;
}
for (i=0; i < 6; i++) {
mac_addr[i] = (uint8)mac[i];
}
return 0;
}
// Helper function to apply ACL rule using RTK SDK
int apply_acl_rule_to_hardware(AclEntry *entry) {
uint32 unit = 0;
rtk_acl_phase_t phase = ACL_PHASE_IGR_ACL;
rtk_acl_id_t entry_idx = entry->group_num;
rtk_acl_action_t action;
int ret;
// Initialize action structure
memset(&action, 0, sizeof(rtk_acl_action_t));
// Configure field matching based on ACL type
if (strcmp(entry->type, "standard-ip") == 0) {
// Configure source IP field
uint32 src_ip = parse_ip_address(entry->source_ip);
uint32 src_mask = parse_ip_address(entry->source_wildcard);
src_mask = ~src_mask; // Convert wildcard to mask
uint8 ip_data[4], ip_mask[4];
ip_data[0] = (src_ip >> 24) & 0xFF;
ip_data[1] = (src_ip >> 16) & 0xFF;
ip_data[2] = (src_ip >> 8) & 0xFF;
ip_data[3] = src_ip & 0xFF;
ip_mask[0] = (src_mask >> 24) & 0xFF;
ip_mask[1] = (src_mask >> 16) & 0xFF;
ip_mask[2] = (src_mask >> 8) & 0xFF;
ip_mask[3] = src_mask & 0xFF;
ret = rtk_acl_ruleEntryField_write(unit, phase, entry_idx,
USER_FIELD_IP4_SIP, ip_data, ip_mask);
if (ret != RT_ERR_OK) {
return -1;
}
}
else if (strcmp(entry->type, "extended-ip") == 0) {
// Configure source IP field
uint32 src_ip = parse_ip_address(entry->source_ip);
uint8 src_data[4], src_mask[4];
src_data[0] = (src_ip >> 24) & 0xFF;
src_data[1] = (src_ip >> 16) & 0xFF;
src_data[2] = (src_ip >> 8) & 0xFF;
src_data[3] = src_ip & 0xFF;
memset(src_mask, 0xFF, 4); // Full match
ret = rtk_acl_ruleEntryField_write(unit, phase, entry_idx,
USER_FIELD_IP4_SIP, src_data, src_mask);
if (ret != RT_ERR_OK) {
return -1;
}
// Configure destination IP field
uint32 dst_ip = parse_ip_address(entry->destination_ip);
uint8 dst_data[4], dst_mask[4];
dst_data[0] = (dst_ip >> 24) & 0xFF;
dst_data[1] = (dst_ip >> 16) & 0xFF;
dst_data[2] = (dst_ip >> 8) & 0xFF;
dst_data[3] = dst_ip & 0xFF;
memset(dst_mask, 0xFF, 4); // Full match
ret = rtk_acl_ruleEntryField_write(unit, phase, entry_idx,
USER_FIELD_IP4_DIP, dst_data, dst_mask);
if (ret != RT_ERR_OK) {
return -1;
}
// Configure protocol type if specified
if (strlen(entry->protocol_type) > 0) {
uint8 proto_data = 0, proto_mask = 0xFF;
if (strcmp(entry->protocol_type, "tcp") == 0) {
proto_data = 6;
} else if (strcmp(entry->protocol_type, "udp") == 0) {
proto_data = 17;
} else if (strcmp(entry->protocol_type, "icmp") == 0) {
proto_data = 1;
}
if (proto_data > 0) {
ret = rtk_acl_ruleEntryField_write(unit, phase, entry_idx,
USER_FIELD_IP4PROTO_IP6NH, &proto_data, &proto_mask);
if (ret != RT_ERR_OK) {
return -1;
}
}
}
}
else if (strcmp(entry->type, "mac-ip") == 0 || strcmp(entry->type, "mac-arp") == 0) {
// Configure source MAC field
uint8 mac_data[6], mac_mask[6];
if (parse_mac_address(entry->source_mac, mac_data) == 0) {
memset(mac_mask, 0xFF, 6); // Full match
ret = rtk_acl_ruleEntryField_write(unit, phase, entry_idx,
USER_FIELD_SMAC, mac_data, mac_mask);
if (ret != RT_ERR_OK) {
return -1;
}
}
// Configure IP field for mac-ip type
if (strcmp(entry->type, "mac-ip") == 0 && strlen(entry->destination_ip) > 0) {
uint32 dst_ip = parse_ip_address(entry->destination_ip);
uint8 ip_data[4], ip_mask[4];
ip_data[0] = (dst_ip >> 24) & 0xFF;
ip_data[1] = (dst_ip >> 16) & 0xFF;
ip_data[2] = (dst_ip >> 8) & 0xFF;
ip_data[3] = dst_ip & 0xFF;
memset(ip_mask, 0xFF, 4); // Full match
ret = rtk_acl_ruleEntryField_write(unit, phase, entry_idx,
USER_FIELD_IP4_DIP, ip_data, ip_mask);
if (ret != RT_ERR_OK) {
return -1;
}
}
// Configure source IP for mac-arp type
if (strcmp(entry->type, "mac-arp") == 0 && strlen(entry->source_ip) > 0) {
uint32 src_ip = parse_ip_address(entry->source_ip);
uint8 ip_data[4], ip_mask[4];
ip_data[0] = (src_ip >> 24) & 0xFF;
ip_data[1] = (src_ip >> 16) & 0xFF;
ip_data[2] = (src_ip >> 8) & 0xFF;
ip_data[3] = src_ip & 0xFF;
memset(ip_mask, 0xFF, 4); // Full match
ret = rtk_acl_ruleEntryField_write(unit, phase, entry_idx,
USER_FIELD_IP4_SIP, ip_data, ip_mask);
if (ret != RT_ERR_OK) {
return -1;
}
}
}
// Configure forward action based on permit/deny
action.igr_acl.fwd_en = ENABLED;
if (strcmp(entry->action, "permit") == 0) {
action.igr_acl.fwd_data.fwd_type = ACL_IGR_ACTION_FWD_PERMIT;
} else {
action.igr_acl.fwd_data.fwd_type = ACL_IGR_ACTION_FWD_DROP;
}
// Set the ACL rule action
ret = rtk_acl_ruleAction_set(unit, phase, entry_idx, &action);
if (ret != RT_ERR_OK) {
return -1;
}
// Enable the ACL rule
ret = rtk_acl_ruleValidate_set(unit, phase, entry_idx, ENABLED);
if (ret != RT_ERR_OK) {
return -1;
}
return 0;
}
// Initialize ACL subsystem
int initialize_acl_system(void) {
uint32 unit = 0;
int ret;
int port;
// Initialize ACL subsystem
ret = rtk_acl_init(unit);
if (ret != RT_ERR_OK) {
return -1;
}
// Enable ACL lookup on all ports (assuming ports 0-27 for typical switch)
for (port = 0; port < 28; port++) {
ret = rtk_acl_portLookupEnable_set(unit, port, ENABLED);
if (ret != RT_ERR_OK) {
continue; // Continue with other ports if one fails
}
}
return 0;
}
// Initialize Statistics subsystem
int initialize_stat_system(void) {
uint32 unit = 0;
int ret;
// Initialize statistics subsystem
ret = rtk_stat_init(unit);
if (ret != RT_ERR_OK) {
return -1;
}
return 0;
}
// Delete ACL entry by group number and type
int delete_acl_entry(int group_num, const char *type) {
for (i=0; i < g_data.acl_entry_count; i++) {
if (g_data.acl_entries[i].active &&
g_data.acl_entries[i].group_num == group_num &&
strcmp(g_data.acl_entries[i].type, type) == 0) {
// Disable the ACL rule in hardware
uint32 unit = 0;
rtk_acl_phase_t phase = ACL_PHASE_IGR_ACL;
rtk_acl_ruleValidate_set(unit, phase, group_num, DISABLED);
// Mark entry as inactive
g_data.acl_entries[i].active = false;
// Compact the array by moving remaining entries
for (j = i; j < g_data.acl_entry_count - 1; j++) {
g_data.acl_entries[j] = g_data.acl_entries[j + 1];
}
g_data.acl_entry_count--;
return 0;
}
}
return -1; // Entry not found
}
// Helper function to parse MAC address for RTK SDK
int parse_mac_for_rtk(const char *mac_str, rtk_mac_t *rtk_mac) {
unsigned int mac[6];
int i;
// Support both formats: AA:BB:CC:DD:EE:FF and AABB.CCDD.EEFF
if (sscanf(mac_str, "%02x:%02x:%02x:%02x:%02x:%02x",
&mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]) == 6) {
// Colon format
for (i = 0; i < 6; i++) {
rtk_mac->octet[i] = (uint8)mac[i];
}
return 0;
} else if (sscanf(mac_str, "%04x.%04x.%04x", &mac[0], &mac[1], &mac[2]) == 3) {
// Dot format
rtk_mac->octet[0] = (mac[0] >> 8) & 0xFF;
rtk_mac->octet[1] = mac[0] & 0xFF;
rtk_mac->octet[2] = (mac[1] >> 8) & 0xFF;
rtk_mac->octet[3] = mac[1] & 0xFF;
rtk_mac->octet[4] = (mac[2] >> 8) & 0xFF;
rtk_mac->octet[5] = mac[2] & 0xFF;
return 0;
}
return -1;
}
// Helper function to format MAC address for display
void format_mac_address(rtk_mac_t *rtk_mac, char *mac_str) {
sprintf(mac_str, "%04x.%04x.%04x",
(rtk_mac->octet[0] << 8) | rtk_mac->octet[1],
(rtk_mac->octet[2] << 8) | rtk_mac->octet[3],
(rtk_mac->octet[4] << 8) | rtk_mac->octet[5]);
}
// Add MAC binding entry to hardware
int add_mac_binding_to_hardware(MacBinding *binding) {
uint32 unit = 0;
rtk_l2_ucastAddr_t l2_addr;
rtk_mac_t rtk_mac;
int ret;
// Parse MAC address
if (parse_mac_for_rtk(binding->macAddress, &rtk_mac) != 0) {
return -1;
}
// Initialize L2 address structure
memset(&l2_addr, 0, sizeof(rtk_l2_ucastAddr_t));
memcpy(&l2_addr.mac, &rtk_mac, sizeof(rtk_mac_t));
l2_addr.vid = binding->vlanId;
l2_addr.port = binding->port;
l2_addr.flags |= RTK_L2_UCAST_FLAG_STATIC; // Static entry
l2_addr.state = RTK_L2_UCAST_STATE_SUSPEND; // Active state
// Add to hardware
ret = rtk_l2_addr_add(unit, &l2_addr);
if (ret != RT_ERR_OK) {
return -1;
}
return 0;
}
// Remove MAC binding from hardware
int remove_mac_binding_from_hardware(const char *macAddress, int vlanId) {
uint32 unit = 0;
rtk_mac_t rtk_mac;
int ret;
// Parse MAC address
if (parse_mac_for_rtk(macAddress, &rtk_mac) != 0) {
return -1;
}
// Remove from hardware
ret = rtk_l2_addr_del(unit, vlanId, &rtk_mac);
if (ret != RT_ERR_OK) {
return -1;
}
return 0;
}
//helper funcitons
int extract_value_string(const char *data, const char *key, char *out_value, uint32_t out_value_size)
{
char *key_position = strstr(data, key);
if (!key_position)
return -1; // Key not found
key_position += strlen(key) + 1; // Move past the key and the colon
while (*key_position == ' ' || *key_position == '\n' || *key_position == '\r')
{
key_position++;
}
if (*key_position != '"')
return -1; // Expected opening quote for string
key_position++; // Skip the opening quote
char *end_position = strchr(key_position, '"');
if (!end_position)
return -1; // No closing quote found
uint32_t value_length = end_position - key_position;
if (value_length >= out_value_size)
return -1; // Output buffer too small
strncpy(out_value, key_position, value_length);
out_value[value_length] = '\0'; // Null-terminate the string
return 0; // Success
}
int extract_value_int(const char *data, const char *key)
{
char *key_position = strstr(data, key);
if (!key_position)
return -1; // Key not found
key_position += strlen(key);
// Skip whitespace and colon
while (*key_position && (*key_position == ' ' || *key_position == '\t' || *key_position == '\n' || *key_position == '\r'))
key_position++;
if (*key_position != ':')
return -1;
key_position++; // Skip colon
// Skip whitespace after colon
while (*key_position && (*key_position == ' ' || *key_position == '\t' || *key_position == '\n' || *key_position == '\r'))
key_position++;
// Skip optional quote
if (*key_position == '"')
key_position++;
return atoi(key_position);
}
int extract_value_duplex(const char *data)
{
return extract_value_int(data, "\"duplex\"");
}
int extract_value_flow_control(const char *data)
{
return extract_value_int(data, "\"flowControl\"");
}
int extract_value_port(const char *data)
{
return extract_value_int(data, "\"port\"");
}
int extract_value_mode(const char *data)
{
return extract_value_int(data, "\"mode\"");
}
int extract_value_speed(const char *data)
{
return extract_value_int(data, "\"speed\"");
}
// Helper function to collect RMON statistics from RTK SDK
int collect_rmon_statistics(int port, RmonStatistics *stats) {
uint32 unit = 0;
uint64 counter_val;
int ret;
if (!stats) {
return -1;
}
// Collect various statistics using RTK SDK
ret = rtk_stat_port_get(unit, port, ETHER_STATS_DROP_EVENTS_INDEX, &counter_val);
if (ret == RT_ERR_OK) stats->etherStatsDropEvents = counter_val;
ret = rtk_stat_port_get(unit, port, ETHER_STATS_MULTICAST_PKTS_INDEX, &counter_val);
if (ret == RT_ERR_OK) stats->etherStatsMulticastPkts = counter_val;
ret = rtk_stat_port_get(unit, port, ETHER_STATS_UNDER_SIZE_PKTS_INDEX, &counter_val);
if (ret == RT_ERR_OK) stats->etherStatsUndersizePkts = counter_val;
ret = rtk_stat_port_get(unit, port, ETHER_STATS_FRAGMENTS_INDEX, &counter_val);
if (ret == RT_ERR_OK) stats->etherStatsFragments = counter_val;
ret = rtk_stat_port_get(unit, port, ETHER_STATS_COLLISIONS_INDEX, &counter_val);
if (ret == RT_ERR_OK) stats->etherStatsCollisions = counter_val;
ret = rtk_stat_port_get(unit, port, ETHER_STATS_PKTS_65TO127OCTETS_INDEX, &counter_val);
if (ret == RT_ERR_OK) stats->etherStatsPkts65to127Octets = counter_val;
ret = rtk_stat_port_get(unit, port, ETHER_STATS_PKTS_256TO511OCTETS_INDEX, &counter_val);
if (ret == RT_ERR_OK) stats->etherStatsPkts256to511Octets = counter_val;
ret = rtk_stat_port_get(unit, port, ETHER_STATS_PKTS_1024TO1518OCTETS_INDEX, &counter_val);
if (ret == RT_ERR_OK) stats->etherStatsPkts1024to1518Octets = counter_val;
ret = rtk_stat_port_get(unit, port, IF_IN_OCTETS_INDEX, &counter_val);
if (ret == RT_ERR_OK) stats->etherStatsOctets = counter_val;
ret = rtk_stat_port_get(unit, port, ETHER_STATS_BROADCAST_PKTS_INDEX, &counter_val);
if (ret == RT_ERR_OK) stats->etherStatsBroadcastPkts = counter_val;
ret = rtk_stat_port_get(unit, port, ETHER_STATS_CRC_ALIGN_ERRORS_INDEX, &counter_val);
if (ret == RT_ERR_OK) stats->etherStatsCRCAlignErrors = counter_val;
ret = rtk_stat_port_get(unit, port, ETHER_STATS_OVERSIZE_PKTS_INDEX, &counter_val);
if (ret == RT_ERR_OK) stats->etherStatsOversizePkts = counter_val;
ret = rtk_stat_port_get(unit, port, ETHER_STATS_JABBERS_INDEX, &counter_val);
if (ret == RT_ERR_OK) stats->etherStatsJabbers = counter_val;
ret = rtk_stat_port_get(unit, port, ETHER_STATS_PKTS_64OCTETS_INDEX, &counter_val);
if (ret == RT_ERR_OK) stats->etherStatsPkts64Octets = counter_val;
ret = rtk_stat_port_get(unit, port, ETHER_STATS_PKTS_128TO255OCTETS_INDEX, &counter_val);
if (ret == RT_ERR_OK) stats->etherStatsPkts128to255Octets = counter_val;
ret = rtk_stat_port_get(unit, port, ETHER_STATS_PKTS_512TO1023OCTETS_INDEX, &counter_val);
if (ret == RT_ERR_OK) stats->etherStatsPkts512to1023Octets = counter_val;
// Calculate total packets
stats->etherStatsPkts = stats->etherStatsPkts64Octets +
stats->etherStatsPkts65to127Octets +
stats->etherStatsPkts128to255Octets +
stats->etherStatsPkts256to511Octets +
stats->etherStatsPkts512to1023Octets +
stats->etherStatsPkts1024to1518Octets;
return 0;
}
// ============================================================================================================================================================
// RMON HANDLERS
// ============================================================================================================================================================
// RMON Statistics handlers
void handle_rmon_statistics_get_request(int client_socket)
{
char json[4096] = "";
int i;
if (g_data.rmon_statistics_count == 0) {
send_success_response(client_socket, "{\"port\":\"1\",\"index\":\"0\",\"owner\":\"admin\",\"stats\":{\"etherStatsDropEvents\":0,\"etherStatsPkts\":0,\"etherStatsMulticastPkts\":0,\"etherStatsUndersizePkts\":0,\"etherStatsFragments\":0,\"etherStatsCollisions\":0,\"etherStatsPkts65to127Octets\":0,\"etherStatsPkts256to511Octets\":0,\"etherStatsPkts1024to1518Octets\":0,\"etherStatsOctets\":0,\"etherStatsBroadcastPkts\":0,\"etherStatsCRCAlignErrors\":0,\"etherStatsOversizePkts\":0,\"etherStatsJabbers\":0,\"etherStatsPkts64Octets\":0,\"etherStatsPkts128to255Octets\":0,\"etherStatsPkts512to1023Octets\":0}}");
return;
}
// Return the first active RMON statistics entry
for (i = 0; i < g_data.rmon_statistics_count; i++) {
if (g_data.rmon_statistics[i].active) {
// Collect real-time statistics
collect_rmon_statistics(g_data.rmon_statistics[i].port, &g_data.rmon_statistics[i]);
sprintf(json,
"{\"port\":\"%d\",\"index\":\"%d\",\"owner\":\"%s\",\"stats\":{"
"\"etherStatsDropEvents\":%llu,\"etherStatsPkts\":%llu,\"etherStatsMulticastPkts\":%llu,"
"\"etherStatsUndersizePkts\":%llu,\"etherStatsFragments\":%llu,\"etherStatsCollisions\":%llu,"
"\"etherStatsPkts65to127Octets\":%llu,\"etherStatsPkts256to511Octets\":%llu,"
"\"etherStatsPkts1024to1518Octets\":%llu,\"etherStatsOctets\":%llu,"
"\"etherStatsBroadcastPkts\":%llu,\"etherStatsCRCAlignErrors\":%llu,"
"\"etherStatsOversizePkts\":%llu,\"etherStatsJabbers\":%llu,"
"\"etherStatsPkts64Octets\":%llu,\"etherStatsPkts128to255Octets\":%llu,"
"\"etherStatsPkts512to1023Octets\":%llu}}",
g_data.rmon_statistics[i].port, g_data.rmon_statistics[i].index, g_data.rmon_statistics[i].owner,
g_data.rmon_statistics[i].etherStatsDropEvents, g_data.rmon_statistics[i].etherStatsPkts,
g_data.rmon_statistics[i].etherStatsMulticastPkts, g_data.rmon_statistics[i].etherStatsUndersizePkts,
g_data.rmon_statistics[i].etherStatsFragments, g_data.rmon_statistics[i].etherStatsCollisions,
g_data.rmon_statistics[i].etherStatsPkts65to127Octets, g_data.rmon_statistics[i].etherStatsPkts256to511Octets,
g_data.rmon_statistics[i].etherStatsPkts1024to1518Octets, g_data.rmon_statistics[i].etherStatsOctets,
g_data.rmon_statistics[i].etherStatsBroadcastPkts, g_data.rmon_statistics[i].etherStatsCRCAlignErrors,
g_data.rmon_statistics[i].etherStatsOversizePkts, g_data.rmon_statistics[i].etherStatsJabbers,
g_data.rmon_statistics[i].etherStatsPkts64Octets, g_data.rmon_statistics[i].etherStatsPkts128to255Octets,
g_data.rmon_statistics[i].etherStatsPkts512to1023Octets);
break;
}
}
send_success_response(client_socket, json);
}
void handle_rmon_statistics_post_request(int client_socket, const char *body)
{
char port_str[8], index_str[8], owner[MAX_STRING_LEN];
int port, index;
// Extract JSON fields
if (extract_json_string(body, "port", port_str, sizeof(port_str)) != 0 ||
extract_json_string(body, "index", index_str, sizeof(index_str)) != 0 ||
extract_json_string(body, "owner", owner, sizeof(owner)) != 0) {
send_error_response(client_socket, 400, "Missing required fields");
return;
}
port = atoi(port_str);
index = atoi(index_str);
// Validate port
if (!is_valid_port(port, 1, 28)) {
send_error_response(client_socket, 400, "Invalid port number");
return;
}
// Check if we have space for more RMON statistics
if (g_data.rmon_statistics_count >= MAX_RMON_STATISTICS) {
send_error_response(client_socket, 400, "Maximum RMON statistics entries reached");
return;
}
// Store RMON statistics entry
int idx = g_data.rmon_statistics_count;
g_data.rmon_statistics[idx].port = port;
g_data.rmon_statistics[idx].index = index;
strcpy(g_data.rmon_statistics[idx].owner, owner);
g_data.rmon_statistics[idx].active = true;
// Collect initial statistics
collect_rmon_statistics(port, &g_data.rmon_statistics[idx]);
g_data.rmon_statistics_count++;
send_success_response(client_socket, "{\"message\":\"RMON statistics configuration applied successfully\"}");
}
void handle_rmon_statistics_delete_request(int client_socket, const char *body)
{
char index_str[8];
int index, i;
// Extract index from JSON
if (extract_json_string(body, "index", index_str, sizeof(index_str)) != 0) {
send_error_response(client_socket, 400, "Index is required");
return;
}
index = atoi(index_str);
// Find and remove the RMON statistics entry
for (i = 0; i < g_data.rmon_statistics_count; i++) {
if (g_data.rmon_statistics[i].active && g_data.rmon_statistics[i].index == index) {
g_data.rmon_statistics[i].active = false;
// Compact the array
int j;
for (j = i; j < g_data.rmon_statistics_count - 1; j++) {
g_data.rmon_statistics[j] = g_data.rmon_statistics[j + 1];
}
g_data.rmon_statistics_count--;
send_success_response(client_socket, "{\"message\":\"RMON statistics configuration deleted successfully\"}");
return;
}
}
send_error_response(client_socket, 404, "RMON statistics entry not found");
}
// RMON History handlers
void handle_rmon_history_get_request(int client_socket)
{
char json[2048] = "";
int i;
if (g_data.rmon_history_count == 0) {
send_success_response(client_socket, "{\"port\":\"1\",\"index\":\"0\",\"interval\":\"1800\",\"buckets\":\"50\",\"owner\":\"admin\",\"totalPages\":1,\"currentPage\":1,\"historyData\":[]}");
return;
}
// Return the first active RMON history entry
for (i = 0; i < g_data.rmon_history_count; i++) {
if (g_data.rmon_history[i].active) {
sprintf(json,
"{\"port\":\"%d\",\"index\":\"%d\",\"interval\":\"%d\",\"buckets\":\"%d\",\"owner\":\"%s\",\"totalPages\":1,\"currentPage\":1,\"historyData\":[]}",
g_data.rmon_history[i].port, g_data.rmon_history[i].index,
g_data.rmon_history[i].interval, g_data.rmon_history[i].buckets,
g_data.rmon_history[i].owner);
break;
}
}
send_success_response(client_socket, json);
}
void handle_rmon_history_post_request(int client_socket, const char *body)
{
char port_str[8], index_str[8], interval_str[16], buckets_str[16], owner[MAX_STRING_LEN];
int port, index, interval, buckets;
// Extract JSON fields
if (extract_json_string(body, "port", port_str, sizeof(port_str)) != 0 ||
extract_json_string(body, "index", index_str, sizeof(index_str)) != 0 ||
extract_json_string(body, "interval", interval_str, sizeof(interval_str)) != 0 ||
extract_json_string(body, "buckets", buckets_str, sizeof(buckets_str)) != 0 ||
extract_json_string(body, "owner", owner, sizeof(owner)) != 0) {
send_error_response(client_socket, 400, "Missing required fields");
return;
}
port = atoi(port_str);
index = atoi(index_str);
interval = atoi(interval_str);
buckets = atoi(buckets_str);
// Validate inputs
if (!is_valid_port(port, 1, 28)) {
send_error_response(client_socket, 400, "Invalid port number");
return;
}
if (interval <= 0) {
send_error_response(client_socket, 400, "Invalid interval");
return;
}
if (buckets <= 0) {
send_error_response(client_socket, 400, "Invalid buckets");
return;
}
// Check if we have space for more RMON history
if (g_data.rmon_history_count >= MAX_RMON_HISTORY) {
send_error_response(client_socket, 400, "Maximum RMON history entries reached");
return;
}
// Store RMON history entry
int idx = g_data.rmon_history_count;
g_data.rmon_history[idx].port = port;
g_data.rmon_history[idx].index = index;
g_data.rmon_history[idx].interval = interval;
g_data.rmon_history[idx].buckets = buckets;
strcpy(g_data.rmon_history[idx].owner, owner);
g_data.rmon_history[idx].active = true;
g_data.rmon_history_count++;
send_success_response(client_socket, "{\"message\":\"RMON history configuration applied successfully\"}");
}
void handle_rmon_history_delete_request(int client_socket, const char *body)
{
char index_str[8];
int index, i;
// Extract index from JSON
if (extract_json_string(body, "index", index_str, sizeof(index_str)) != 0) {
send_error_response(client_socket, 400, "Index is required");
return;
}
index = atoi(index_str);
// Find and remove the RMON history entry
for (i = 0; i < g_data.rmon_history_count; i++) {
if (g_data.rmon_history[i].active && g_data.rmon_history[i].index == index) {
g_data.rmon_history[i].active = false;
// Compact the array
int j;
for (j = i; j < g_data.rmon_history_count - 1; j++) {
g_data.rmon_history[j] = g_data.rmon_history[j + 1];
}
g_data.rmon_history_count--;
send_success_response(client_socket, "{\"message\":\"RMON history configuration deleted successfully\"}");
return;
}
}
send_error_response(client_socket, 404, "RMON history entry not found");
}
// RMON Alarm handlers
void handle_rmon_alarm_get_request(int client_socket)
{
char json[2048] = "[";
bool first = true;
int i;
// Iterate through stored RMON alarms
for (i = 0; i < g_data.rmon_alarm_count && i < MAX_RMON_ALARMS; i++) {
if (g_data.rmon_alarms[i].active) {
if (!first) {
strcat(json, ",");
}
char entry[512];
sprintf(entry,
"{\"sequenceType\":\"%s\",\"sequenceIndex\":\"%d\",\"interval\":\"%d\",\"variable\":\"%s\",\"sampleType\":\"%s\",\"alarmValue\":\"%llu\",\"risingThreshold\":\"%llu\",\"fallingThreshold\":\"%llu\",\"risingEventIndex\":\"%d\",\"fallingEventIndex\":\"%d\",\"owner\":\"%s\"}",
g_data.rmon_alarms[i].sequenceType,
g_data.rmon_alarms[i].sequenceIndex,
g_data.rmon_alarms[i].interval,
g_data.rmon_alarms[i].variable,
g_data.rmon_alarms[i].sampleType,
g_data.rmon_alarms[i].alarmValue,
g_data.rmon_alarms[i].risingThreshold,
g_data.rmon_alarms[i].fallingThreshold,
g_data.rmon_alarms[i].risingEventIndex,
g_data.rmon_alarms[i].fallingEventIndex,
g_data.rmon_alarms[i].owner);
strcat(json, entry);
first = false;
}
}
strcat(json, "]");
send_success_response(client_socket, json);
}
void handle_rmon_alarm_post_request(int client_socket, const char *body)
{
char sequenceType[16], sequenceIndex_str[8], interval_str[16], variable[MAX_STRING_LEN];
char sampleType[16], alarmValue_str[32], risingThreshold_str[32], fallingThreshold_str[32];
char risingEventIndex_str[8], fallingEventIndex_str[8], owner[MAX_STRING_LEN];
// Extract JSON fields
if (extract_json_string(body, "sequenceType", sequenceType, sizeof(sequenceType)) != 0 ||
extract_json_string(body, "sequenceIndex", sequenceIndex_str, sizeof(sequenceIndex_str)) != 0 ||
extract_json_string(body, "interval", interval_str, sizeof(interval_str)) != 0 ||
extract_json_string(body, "variable", variable, sizeof(variable)) != 0 ||
extract_json_string(body, "sampleType", sampleType, sizeof(sampleType)) != 0 ||
extract_json_string(body, "alarmValue", alarmValue_str, sizeof(alarmValue_str)) != 0 ||
extract_json_string(body, "risingThreshold", risingThreshold_str, sizeof(risingThreshold_str)) != 0 ||
extract_json_string(body, "fallingThreshold", fallingThreshold_str, sizeof(fallingThreshold_str)) != 0 ||
extract_json_string(body, "risingEventIndex", risingEventIndex_str, sizeof(risingEventIndex_str)) != 0 ||
extract_json_string(body, "fallingEventIndex", fallingEventIndex_str, sizeof(fallingEventIndex_str)) != 0 ||
extract_json_string(body, "owner", owner, sizeof(owner)) != 0) {
send_error_response(client_socket, 400, "Missing required fields");
return;
}
// Validate sample type
if (strcmp(sampleType, "absolute") != 0 && strcmp(sampleType, "delta") != 0) {
send_error_response(client_socket, 400, "Invalid sample type. Must be 'absolute' or 'delta'");
return;
}
int interval = atoi(interval_str);
if (interval <= 0) {
send_error_response(client_socket, 400, "Invalid interval");
return;
}
// Check if we have space for more RMON alarms
if (g_data.rmon_alarm_count >= MAX_RMON_ALARMS) {
send_error_response(client_socket, 400, "Maximum RMON alarm entries reached");
return;
}
// Store RMON alarm entry
int idx = g_data.rmon_alarm_count;
strcpy(g_data.rmon_alarms[idx].sequenceType, sequenceType);
g_data.rmon_alarms[idx].sequenceIndex = atoi(sequenceIndex_str);
g_data.rmon_alarms[idx].interval = interval;
strcpy(g_data.rmon_alarms[idx].variable, variable);
strcpy(g_data.rmon_alarms[idx].sampleType, sampleType);
g_data.rmon_alarms[idx].alarmValue = atoll(alarmValue_str);
g_data.rmon_alarms[idx].risingThreshold = atoll(risingThreshold_str);
g_data.rmon_alarms[idx].fallingThreshold = atoll(fallingThreshold_str);
g_data.rmon_alarms[idx].risingEventIndex = atoi(risingEventIndex_str);
g_data.rmon_alarms[idx].fallingEventIndex = atoi(fallingEventIndex_str);
strcpy(g_data.rmon_alarms[idx].owner, owner);
g_data.rmon_alarms[idx].active = true;
g_data.rmon_alarm_count++;
send_success_response(client_socket, "{\"message\":\"RMON alarm configuration applied successfully\"}");
}
void handle_rmon_alarm_delete_request(int client_socket, const char *body)
{
char sequenceIndex_str[8];
int sequenceIndex, i;
// Extract sequenceIndex from JSON
if (extract_json_string(body, "sequenceIndex", sequenceIndex_str, sizeof(sequenceIndex_str)) != 0) {
send_error_response(client_socket, 400, "Sequence index is required");
return;
}
sequenceIndex = atoi(sequenceIndex_str);
// Find and remove the RMON alarm entry
for (i = 0; i < g_data.rmon_alarm_count; i++) {
if (g_data.rmon_alarms[i].active && g_data.rmon_alarms[i].sequenceIndex == sequenceIndex) {
g_data.rmon_alarms[i].active = false;
// Compact the array
int j;
for (j = i; j < g_data.rmon_alarm_count - 1; j++) {
g_data.rmon_alarms[j] = g_data.rmon_alarms[j + 1];
}
g_data.rmon_alarm_count--;
send_success_response(client_socket, "{\"message\":\"RMON alarm configuration deleted successfully\"}");
return;
}
}
send_error_response(client_socket, 404, "RMON alarm entry not found");
}
// RMON Event handlers
void handle_rmon_event_get_request(int client_socket)
{
char json[2048] = "[";
bool first = true;
int i;
// Iterate through stored RMON events
for (i = 0; i < g_data.rmon_event_count && i < MAX_RMON_EVENTS; i++) {
if (g_data.rmon_events[i].active) {
if (!first) {
strcat(json, ",");
}
char entry[512];
sprintf(entry,
"{\"sequenceType\":\"%s\",\"sequenceIndex\":\"%d\",\"index\":\"%d\",\"description\":\"%s\",\"type\":\"%s\",\"community\":\"%s\",\"lastTimeSent\":\"%s\",\"owner\":\"%s\"}",
g_data.rmon_events[i].sequenceType,
g_data.rmon_events[i].sequenceIndex,
g_data.rmon_events[i].index,
g_data.rmon_events[i].description,
g_data.rmon_events[i].type,
g_data.rmon_events[i].community,
g_data.rmon_events[i].lastTimeSent,
g_data.rmon_events[i].owner);
strcat(json, entry);
first = false;
}
}
strcat(json, "]");
send_success_response(client_socket, json);
}
void handle_rmon_event_post_request(int client_socket, const char *body)
{
char sequenceType[16], sequenceIndex_str[8], index_str[8], description[256];
char type[32], community[MAX_STRING_LEN], lastTimeSent[32], owner[MAX_STRING_LEN];
// Extract JSON fields
if (extract_json_string(body, "sequenceType", sequenceType, sizeof(sequenceType)) != 0 ||
extract_json_string(body, "sequenceIndex", sequenceIndex_str, sizeof(sequenceIndex_str)) != 0 ||
extract_json_string(body, "index", index_str, sizeof(index_str)) != 0 ||
extract_json_string(body, "description", description, sizeof(description)) != 0 ||
extract_json_string(body, "type", type, sizeof(type)) != 0 ||
extract_json_string(body, "community", community, sizeof(community)) != 0 ||
extract_json_string(body, "lastTimeSent", lastTimeSent, sizeof(lastTimeSent)) != 0 ||
extract_json_string(body, "owner", owner, sizeof(owner)) != 0) {
send_error_response(client_socket, 400, "Missing required fields");
return;
}
// Validate event type
if (strcmp(type, "none") != 0 && strcmp(type, "log") != 0 &&
strcmp(type, "snmptrap") != 0 && strcmp(type, "log-and-trap") != 0) {
send_error_response(client_socket, 400, "Invalid event type");
return;
}
// Check if we have space for more RMON events
if (g_data.rmon_event_count >= MAX_RMON_EVENTS) {
send_error_response(client_socket, 400, "Maximum RMON event entries reached");
return;
}
// Store RMON event entry
int idx = g_data.rmon_event_count;
strcpy(g_data.rmon_events[idx].sequenceType, sequenceType);
g_data.rmon_events[idx].sequenceIndex = atoi(sequenceIndex_str);
g_data.rmon_events[idx].index = atoi(index_str);
strcpy(g_data.rmon_events[idx].description, description);
strcpy(g_data.rmon_events[idx].type, type);
strcpy(g_data.rmon_events[idx].community, community);
strcpy(g_data.rmon_events[idx].lastTimeSent, lastTimeSent);
strcpy(g_data.rmon_events[idx].owner, owner);
g_data.rmon_events[idx].active = true;
g_data.rmon_event_count++;
send_success_response(client_socket, "{\"message\":\"RMON event configuration applied successfully\"}");
}
void handle_rmon_event_delete_request(int client_socket, const char *body)
{
char sequenceIndex_str[8];
int sequenceIndex, i;
// Extract sequenceIndex from JSON
if (extract_json_string(body, "sequenceIndex", sequenceIndex_str, sizeof(sequenceIndex_str)) != 0) {
send_error_response(client_socket, 400, "Sequence index is required");
return;
}
sequenceIndex = atoi(sequenceIndex_str);
// Find and remove the RMON event entry
for (i = 0; i < g_data.rmon_event_count; i++) {
if (g_data.rmon_events[i].active && g_data.rmon_events[i].sequenceIndex == sequenceIndex) {
g_data.rmon_events[i].active = false;
// Compact the array
int j;
for (j = i; j < g_data.rmon_event_count - 1; j++) {
g_data.rmon_events[j] = g_data.rmon_events[j + 1];
}
g_data.rmon_event_count--;
send_success_response(client_socket, "{\"message\":\"RMON event configuration deleted successfully\"}");
return;
}
}
send_error_response(client_socket, 404, "RMON event entry not found");
}
// Helper function to configure IGMP snooping using RTK SDK
int configure_igmp_snooping_rtk(IgmpSnoopingConfig *config) {
uint32 unit = 0;
int ret;
rtk_l2_ipmcMode_t mode;
rtk_enable_t enable;
if (!config || !config->active) {
return -1;
}
// Configure IP multicast mode - use LOOKUP_ON_DIP_AND_FVID for IGMP snooping
mode = LOOKUP_ON_DIP_AND_FVID;
ret = rtk_l2_ipmcMode_set(unit, mode);
if (ret != RT_ERR_OK) {
return -1;
}
// Enable IP multicast address checking
enable = config->globalIgmpSnooping ? ENABLED : DISABLED;
ret = rtk_l2_ipMcastAddrChkEnable_set(unit, enable);
if (ret != RT_ERR_OK) {
return -1;
}
// Configure VLAN-specific settings would require VLAN parsing
// For now, we'll focus on global IGMP snooping control
return 0;
}
// Helper function to add multicast group using RTK SDK
int add_multicast_group_rtk(MulticastGroup *group) {
uint32 unit = 0;
int ret;
rtk_l2_ipMcastAddr_t ipmc_addr;
rtk_vlan_t vid;
rtk_portmask_t portmask;
ipaddr_t dip;
char *token, *ports_copy;
int port_num;
if (!group || !group->active) {
return -1;
}
// Parse VLAN ID from vlanX format
if (sscanf(group->vlanId, "vlan%d", &vid) != 1) {
vid = 1; // default VLAN
}
// Parse multicast IP address
inet_aton(group->multicastAddress, (struct in_addr *)&dip);
// Parse member ports and create portmask
RTK_PORTMASK_RESET(portmask);
ports_copy = strdup(group->memberPorts);
if (ports_copy) {
token = strtok(ports_copy, ",");
while (token) {
port_num = atoi(token);
if (port_num >= 0 && port_num < 28) {
RTK_PORTMASK_PORT_SET(portmask, port_num);
}
token = strtok(NULL, ",");
}
free(ports_copy);
}
// Initialize IP multicast address structure
ret = rtk_l2_ipMcastAddrExt_init(unit, NULL, &ipmc_addr);
if (ret != RT_ERR_OK) {
return -1;
}
// Configure the IP multicast entry
ipmc_addr.rvid = vid;
ipmc_addr.dip = dip;
ipmc_addr.sip = 0; // For (*, G) entries
ipmc_addr.portmask = portmask;
ipmc_addr.fwdIndex = -1; // Auto allocation
// Add the multicast entry to hardware
ret = rtk_l2_ipMcastAddr_add(unit, &ipmc_addr);
if (ret != RT_ERR_OK) {
return -1;
}
return 0;
}
// Helper function to delete multicast group using RTK SDK
int delete_multicast_group_rtk(const char *vlanId, const char *multicastAddress) {
uint32 unit = 0;
int ret;
rtk_vlan_t vid;
ipaddr_t dip;
// Parse VLAN ID from vlanX format
if (sscanf(vlanId, "vlan%d", &vid) != 1) {
vid = 1; // default VLAN
}
// Parse multicast IP address
inet_aton(multicastAddress, (struct in_addr *)&dip);
// Delete the multicast entry from hardware
ret = rtk_l2_ipMcastAddr_del(unit, 0, dip, vid); // SIP=0 for (*, G) entries
if (ret != RT_ERR_OK) {
return -1;
}
return 0;
}
// Initialize L2 and multicast subsystems
int initialize_l2_multicast_system(void) {
uint32 unit = 0;
int ret;
// Initialize L2 subsystem
ret = rtk_l2_init(unit);
if (ret != RT_ERR_OK) {
return -1;
}
// Initialize multicast subsystem
ret = rtk_mcast_init(unit);
if (ret != RT_ERR_OK) {
return -1;
}
// Initialize IP multicast subsystem
ret = rtk_ipmc_init(unit);
if (ret != RT_ERR_OK) {
return -1;
}
return 0;
}
// ============================================================================================================================================================
// IGMP SNOOPING HANDLERS
// ============================================================================================================================================================
// IGMP Snooping Configuration handlers
void handle_igmp_snooping_get_request(int client_socket)
{
char json[1024] = "";
uint32 unit = 0;
rtk_l2_ipmcMode_t mode;
rtk_enable_t igmp_enable;
int ret, i;
// Get current IGMP snooping status from hardware
ret = rtk_l2_ipmcMode_get(unit, &mode);
bool igmp_mode_enabled = (ret == RT_ERR_OK && mode == LOOKUP_ON_DIP_AND_FVID);
ret = rtk_l2_ipMcastAddrChkEnable_get(unit, &igmp_enable);
bool igmp_addr_check = (ret == RT_ERR_OK && igmp_enable == ENABLED);
// Use stored configuration if available, otherwise use hardware status
if (g_data.igmp_config_count > 0) {
for (i = 0; i < g_data.igmp_config_count; i++) {
if (g_data.igmp_configs[i].active) {
sprintf(json,
"{\"globalIgmpSnooping\":\"%s\",\"vlanId\":\"%s\",\"vlanIgmpSnooping\":\"%s\",\"fastLeave\":\"%s\",\"fastLeaveTimeout\":\"%d\",\"queryMembershipTimeout\":\"%d\",\"groupMembershipTimeout\":\"%d\"}",
g_data.igmp_configs[i].globalIgmpSnooping ? "enable" : "disable",
g_data.igmp_configs[i].vlanId,
g_data.igmp_configs[i].vlanIgmpSnooping ? "enable" : "disable",
g_data.igmp_configs[i].fastLeave ? "enable" : "disable",
g_data.igmp_configs[i].fastLeaveTimeout,
g_data.igmp_configs[i].queryMembershipTimeout,
g_data.igmp_configs[i].groupMembershipTimeout);
break;
}
}
} else {
// Return hardware status
sprintf(json,
"{\"globalIgmpSnooping\":\"%s\",\"vlanId\":\"vlan1\",\"vlanIgmpSnooping\":\"%s\",\"fastLeave\":\"disable\",\"fastLeaveTimeout\":\"300000\",\"queryMembershipTimeout\":\"300000\",\"groupMembershipTimeout\":\"400000\"}",
(igmp_mode_enabled && igmp_addr_check) ? "enable" : "disable",
(igmp_mode_enabled && igmp_addr_check) ? "enable" : "disable");
}
send_success_response(client_socket, json);
}
void handle_igmp_snooping_post_request(int client_socket, const char *body)
{
char globalIgmpSnooping[16], vlanId[16], vlanIgmpSnooping[16], fastLeave[16];
char fastLeaveTimeout_str[16], queryMembershipTimeout_str[16], groupMembershipTimeout_str[16];
int fastLeaveTimeout, queryMembershipTimeout, groupMembershipTimeout;
// Extract JSON fields
if (extract_json_string(body, "globalIgmpSnooping", globalIgmpSnooping, sizeof(globalIgmpSnooping)) != 0 ||
extract_json_string(body, "vlanId", vlanId, sizeof(vlanId)) != 0 ||
extract_json_string(body, "vlanIgmpSnooping", vlanIgmpSnooping, sizeof(vlanIgmpSnooping)) != 0 ||
extract_json_string(body, "fastLeave", fastLeave, sizeof(fastLeave)) != 0 ||
extract_json_string(body, "fastLeaveTimeout", fastLeaveTimeout_str, sizeof(fastLeaveTimeout_str)) != 0 ||
extract_json_string(body, "queryMembershipTimeout", queryMembershipTimeout_str, sizeof(queryMembershipTimeout_str)) != 0 ||
extract_json_string(body, "groupMembershipTimeout", groupMembershipTimeout_str, sizeof(groupMembershipTimeout_str)) != 0) {
send_error_response(client_socket, 400, "Missing required fields");
return;
}
// Validate enable/disable values
if (strcmp(globalIgmpSnooping, "enable") != 0 && strcmp(globalIgmpSnooping, "disable") != 0) {
send_error_response(client_socket, 400, "Invalid globalIgmpSnooping value. Must be 'enable' or 'disable'");
return;
}
if (strcmp(vlanIgmpSnooping, "enable") != 0 && strcmp(vlanIgmpSnooping, "disable") != 0) {
send_error_response(client_socket, 400, "Invalid vlanIgmpSnooping value. Must be 'enable' or 'disable'");
return;
}
if (strcmp(fastLeave, "enable") != 0 && strcmp(fastLeave, "disable") != 0) {
send_error_response(client_socket, 400, "Invalid fastLeave value. Must be 'enable' or 'disable'");
return;
}
// Validate timeout values
fastLeaveTimeout = atoi(fastLeaveTimeout_str);
queryMembershipTimeout = atoi(queryMembershipTimeout_str);
groupMembershipTimeout = atoi(groupMembershipTimeout_str);
if (fastLeaveTimeout < 100 || fastLeaveTimeout > 1000000) {
send_error_response(client_socket, 400, "fastLeaveTimeout must be between 100 and 1000000 ms");
return;
}
if (queryMembershipTimeout < 100 || queryMembershipTimeout > 1000000) {
send_error_response(client_socket, 400, "queryMembershipTimeout must be between 100 and 1000000 ms");
return;
}
if (groupMembershipTimeout < 100 || groupMembershipTimeout > 1000000) {
send_error_response(client_socket, 400, "groupMembershipTimeout must be between 100 and 1000000 ms");
return;
}
// Check if we have space for more IGMP configurations or update existing
int idx = -1;
// Look for existing configuration first
for (i = 0; i < g_data.igmp_config_count; i++) {
if (g_data.igmp_configs[i].active && strcmp(g_data.igmp_configs[i].vlanId, vlanId) == 0) {
idx = i;
break;
}
}
// If not found, create new entry
if (idx == -1) {
if (g_data.igmp_config_count >= MAX_IGMP_CONFIGS) {
send_error_response(client_socket, 400, "Maximum IGMP configuration entries reached");
return;
}
idx = g_data.igmp_config_count;
g_data.igmp_config_count++;
}
// Store IGMP configuration
g_data.igmp_configs[idx].globalIgmpSnooping = (strcmp(globalIgmpSnooping, "enable") == 0);
strcpy(g_data.igmp_configs[idx].vlanId, vlanId);
g_data.igmp_configs[idx].vlanIgmpSnooping = (strcmp(vlanIgmpSnooping, "enable") == 0);
g_data.igmp_configs[idx].fastLeave = (strcmp(fastLeave, "enable") == 0);
g_data.igmp_configs[idx].fastLeaveTimeout = fastLeaveTimeout;
g_data.igmp_configs[idx].queryMembershipTimeout = queryMembershipTimeout;
g_data.igmp_configs[idx].groupMembershipTimeout = groupMembershipTimeout;
g_data.igmp_configs[idx].active = true;
// Apply configuration to hardware using RTK SDK
int rtk_ret = configure_igmp_snooping_rtk(&g_data.igmp_configs[idx]);
if (rtk_ret != 0) {
send_error_response(client_socket, 500, "Failed to apply IGMP snooping configuration to hardware");
return;
}
send_success_response(client_socket, "{\"message\":\"IGMP snooping configuration applied successfully\"}");
}
// Multicast Group Information handlers
void handle_multicast_group_get_request(int client_socket)
{
char json[4096] = "{\"groups\":[";
bool first = true;
int i;
// Iterate through stored multicast groups
for (i = 0; i < g_data.multicast_group_count && i < MAX_MULTICAST_GROUPS; i++) {
if (g_data.multicast_groups[i].active) {
if (!first) {
strcat(json, ",");
}
char entry[256];
sprintf(entry,
"{\"vlanId\":\"%s\",\"multicastAddress\":\"%s\",\"memberPorts\":\"%s\"}",
g_data.multicast_groups[i].vlanId,
g_data.multicast_groups[i].multicastAddress,
g_data.multicast_groups[i].memberPorts);
strcat(json, entry);
first = false;
}
}
strcat(json, "]}");
send_success_response(client_socket, json);
}
void handle_multicast_group_post_request(int client_socket, const char *body)
{
char vlanId[16], multicastAddress[16], memberPorts[MAX_STRING_LEN];
// Extract JSON fields
if (extract_json_string(body, "vlanId", vlanId, sizeof(vlanId)) != 0 ||
extract_json_string(body, "multicastAddress", multicastAddress, sizeof(multicastAddress)) != 0 ||
extract_json_string(body, "memberPorts", memberPorts, sizeof(memberPorts)) != 0) {
send_error_response(client_socket, 400, "Missing required fields");
return;
}
// Validate multicast address format (basic validation)
if (!is_valid_ip(multicastAddress)) {
send_error_response(client_socket, 400, "Invalid multicast IP address format");
return;
}
// Check if we have space for more multicast groups
if (g_data.multicast_group_count >= MAX_MULTICAST_GROUPS) {
send_error_response(client_socket, 400, "Maximum multicast group entries reached");
return;
}
// Store multicast group
int idx = g_data.multicast_group_count;
strcpy(g_data.multicast_groups[idx].vlanId, vlanId);
strcpy(g_data.multicast_groups[idx].multicastAddress, multicastAddress);
strcpy(g_data.multicast_groups[idx].memberPorts, memberPorts);
g_data.multicast_groups[idx].active = true;
// Add multicast group to hardware using RTK SDK
int rtk_ret = add_multicast_group_rtk(&g_data.multicast_groups[idx]);
if (rtk_ret != 0) {
send_error_response(client_socket, 500, "Failed to add multicast group to hardware");
return;
}
g_data.multicast_group_count++;
send_success_response(client_socket, "{\"message\":\"Multicast group added successfully\"}");
}
void handle_multicast_group_delete_request(int client_socket, const char *body)
{
char vlanId[16], multicastAddress[16];
int i;
// Extract fields from JSON
if (extract_json_string(body, "vlanId", vlanId, sizeof(vlanId)) != 0 ||
extract_json_string(body, "multicastAddress", multicastAddress, sizeof(multicastAddress)) != 0) {
send_error_response(client_socket, 400, "Missing required fields");
return;
}
// Find and remove the multicast group
for (i = 0; i < g_data.multicast_group_count; i++) {
if (g_data.multicast_groups[i].active &&
strcmp(g_data.multicast_groups[i].vlanId, vlanId) == 0 &&
strcmp(g_data.multicast_groups[i].multicastAddress, multicastAddress) == 0) {
// Delete from hardware first
int rtk_ret = delete_multicast_group_rtk(vlanId, multicastAddress);
if (rtk_ret != 0) {
send_error_response(client_socket, 500, "Failed to delete multicast group from hardware");
return;
}
g_data.multicast_groups[i].active = false;
// Compact the array
int j;
for (j = i; j < g_data.multicast_group_count - 1; j++) {
g_data.multicast_groups[j] = g_data.multicast_groups[j + 1];
}
g_data.multicast_group_count--;
send_success_response(client_socket, "{\"message\":\"Multicast group deleted successfully\"}");
return;
}
}
send_error_response(client_socket, 404, "Multicast group not found");
}
// ============================================================================================================================================================
// MAC TABLE HANDLERS
// ============================================================================================================================================================
// MAC table HTTP handlers
void handle_mac_bind_table_get_request(int client_socket)
{
char json[4096] = "["; // Start JSON array
bool first = true;
int i;
// Iterate through stored MAC bindings
for (i = 0; i < g_data.mac_binding_count && i < MAX_MAC_BINDINGS; i++) {
if (g_data.mac_bindings[i].active) {
if (!first) {
strcat(json, ",");
}
char entry[256];
sprintf(entry,
"{\"port\":%d,\"macAddress\":\"%s\",\"vlanId\":%d}",
g_data.mac_bindings[i].port,
g_data.mac_bindings[i].macAddress,
g_data.mac_bindings[i].vlanId
);
strcat(json, entry);
first = false;
}
}
strcat(json, "]"); // End JSON array
send_success_response(client_socket, json);
}
void handle_mac_bind_table_post_request(int client_socket, const char *body)
{
char port_str[8], macAddress[32], vlanId_str[8];
int port, vlanId;
// Extract JSON fields
if (extract_json_string(body, "port", port_str, sizeof(port_str)) != 0 ||
extract_json_string(body, "macAddress", macAddress, sizeof(macAddress)) != 0 ||
extract_json_string(body, "vlanId", vlanId_str, sizeof(vlanId_str)) != 0) {
send_error_response(client_socket, 400, "All fields are required.");
return;
}
port = atoi(port_str);
vlanId = atoi(vlanId_str);
// Validate port
if (!is_valid_port(port, 1, 28)) {
send_error_response(client_socket, 400, "Invalid port number");
return;
}
// Validate VLAN ID
if (vlanId < 1 || vlanId > 4094) {
send_error_response(client_socket, 400, "Invalid VLAN ID. Must be between 1 and 4094");
return;
}
// Validate MAC address format (support both formats)
if (!is_valid_mac(macAddress)) {
// Try dot format validation
unsigned int mac[3];
if (sscanf(macAddress, "%04x.%04x.%04x", &mac[0], &mac[1], &mac[2]) != 3) {
send_error_response(client_socket, 400, "Invalid MAC Address format. Use: HHHH.HHHH.HHHH or HH:HH:HH:HH:HH:HH");
return;
}
}
// Check if we have space for more MAC bindings
if (g_data.mac_binding_count >= MAX_MAC_BINDINGS) {
send_error_response(client_socket, 400, "Maximum MAC bindings reached");
return;
}
// Store MAC binding
int idx = g_data.mac_binding_count;
g_data.mac_bindings[idx].port = port;
strcpy(g_data.mac_bindings[idx].macAddress, macAddress);
g_data.mac_bindings[idx].vlanId = vlanId;
g_data.mac_bindings[idx].active = true;
// Apply to hardware
if (add_mac_binding_to_hardware(&g_data.mac_bindings[idx]) == 0) {
g_data.mac_binding_count++;
char json[128];
sprintf(json, "{\"message\":\"MAC binding added successfully\",\"data\":{\"port\":%d,\"macAddress\":\"%s\",\"vlanId\":%d}}",
port, macAddress, vlanId);
send_success_response(client_socket, json);
} else {
send_error_response(client_socket, 500, "Failed to apply MAC binding to hardware");
}
}
void handle_mac_bind_table_delete_request(int client_socket, const char *body)
{
char macAddress[32];
int i;
// Extract MAC address from JSON
if (extract_json_string(body, "macAddress", macAddress, sizeof(macAddress)) != 0) {
send_error_response(client_socket, 400, "macAddress is required");
return;
}
// Find and remove the MAC binding
for (i = 0; i < g_data.mac_binding_count; i++) {
if (g_data.mac_bindings[i].active &&
strcmp(g_data.mac_bindings[i].macAddress, macAddress) == 0) {
// Remove from hardware
remove_mac_binding_from_hardware(macAddress, g_data.mac_bindings[i].vlanId);
// Mark as inactive and compact array
g_data.mac_bindings[i].active = false;
// Compact the array
int j;
for (j = i; j < g_data.mac_binding_count - 1; j++) {
g_data.mac_bindings[j] = g_data.mac_bindings[j + 1];
}
g_data.mac_binding_count--;
send_success_response(client_socket, "{\"message\":\"MAC binding deleted successfully\"}");
return;
}
}
send_error_response(client_socket, 404, "MAC binding not found");
}
void handle_mac_auto_bind_get_request(int client_socket)
{
char json[4096] = "["; // Start JSON array
bool first = true;
int i;
// Iterate through stored MAC auto bindings
for (i = 0; i < g_data.mac_auto_binding_count && i < MAX_MAC_AUTO_BINDINGS; i++) {
if (g_data.mac_auto_bindings[i].active) {
if (!first) {
strcat(json, ",");
}
char entry[256];
sprintf(entry,
"{\"port\":%d,\"macAddress\":\"%s\",\"vlanId\":%d,\"autoLearned\":%s}",
g_data.mac_auto_bindings[i].port,
g_data.mac_auto_bindings[i].macAddress,
g_data.mac_auto_bindings[i].vlanId,
g_data.mac_auto_bindings[i].autoLearned ? "true" : "false"
);
strcat(json, entry);
first = false;
}
}
strcat(json, "]"); // End JSON array
send_success_response(client_socket, json);
}
void handle_mac_auto_filter_get_request(int client_socket)
{
// For now, return the same as auto bind table
handle_mac_auto_bind_get_request(client_socket);
}
void handle_mac_filter_get_request(int client_socket)
{
// For now, return the same as auto bind table
handle_mac_auto_bind_get_request(client_socket);
}
// ============================================================================================================================================================
// INITIALIZATION FUNCTIONS
// ============================================================================================================================================================
void initialize_global_data(void) {
pthread_mutex_lock(&global_data_mutex);
// Initialize system config
strcpy(g_data.system.systemName, "");
strcpy(g_data.system.systemLocation, "");
strcpy(g_data.system.systemContact, "");
strcpy(g_data.system.description, "Managed Switch 7.4.8");
strcpy(g_data.system.objectId, "1.3.6.1.4.1.12284.1");
strcpy(g_data.system.version, "Managed Switch 7.4.8");
strcpy(g_data.system.serialNumber, "20200600001");
strcpy(g_data.system.macAddress, "00:28:24:13:D0:9D");
strcpy(g_data.system.ipAddress, "192.168.0.1");
g_data.system.interfaces = 10;
// Initialize port configurations
for ( i = 0; i < MAX_PORTS; i++) {
g_data.ports[i].port_id = i;
g_data.ports[i].admin_enabled = true;
strcpy(g_data.ports[i].status, "Down");
strcpy(g_data.ports[i].speed, "Auto");
strcpy(g_data.ports[i].duplex, "Auto");
g_data.ports[i].flow_control_enabled = false;
g_data.ports[i].ingress_rate_limit = 1000;
g_data.ports[i].egress_rate_limit = 1000;
g_data.ports[i].rate_limit_enabled = false;
g_data.ports[i].max_mac_addresses = 8192;
g_data.ports[i].protected_port = false;
g_data.ports[i].broadcast_suppression = false;
g_data.ports[i].broadcast_rate = 64;
g_data.ports[i].multicast_suppression = false;
g_data.ports[i].multicast_rate = 64;
g_data.ports[i].dlf_suppression = false;
g_data.ports[i].dlf_rate = 64;
}
// Initialize default users
strcpy(g_data.users[0].username, "admin");
strcpy(g_data.users[0].password, "admin123");
g_data.users[0].level = 15;
g_data.users[0].timeout = 300;
g_data.users[0].active = true;
strcpy(g_data.users[1].username, "guest");
strcpy(g_data.users[1].password, "guest123");
g_data.users[1].level = 1;
g_data.users[1].timeout = 60;
g_data.users[1].active = true;
g_data.user_count = 2;
// Initialize default SNMP communities
strcpy(g_data.communities[0].community, "public");
strcpy(g_data.communities[0].access, "read-only");
g_data.communities[0].active = true;
strcpy(g_data.communities[1].community, "private");
strcpy(g_data.communities[1].access, "read-write");
g_data.communities[1].active = true;
g_data.community_count = 2;
// Initialize default trap targets
strcpy(g_data.trap_targets[0].ip, "192.168.1.100");
strcpy(g_data.trap_targets[0].community, "public");
strcpy(g_data.trap_targets[0].version, "v2c");
g_data.trap_targets[0].active = true;
strcpy(g_data.trap_targets[1].ip, "192.168.1.101");
strcpy(g_data.trap_targets[1].community, "private");
strcpy(g_data.trap_targets[1].version, "v3");
g_data.trap_targets[1].active = true;
g_data.trap_target_count = 2;
// Initialize service access
g_data.service_access.http_enabled = true;
g_data.service_access.https_enabled = false;
g_data.service_access.snmp_enabled = true;
g_data.service_access.telnet_enabled = true;
g_data.service_access.ssh_enabled = true;
// Initialize SNTP
g_data.sntp.enabled = true;
strcpy(g_data.sntp.server_ip, "192.168.1.10");
g_data.sntp.interval = 1800;
// Initialize serial config
strcpy(g_data.serial.baud_rate, "38400");
strcpy(g_data.serial.char_size, "8");
strcpy(g_data.serial.parity, "None");
strcpy(g_data.serial.stop_bits, "1");
strcpy(g_data.serial.flow_control, "None");
// Initialize jumbo frame size
g_data.jumbo_frame_size = 6000;
// Initialize QoS configs
for (i = 0; i < MAX_PORTS; i++) {
g_data.qos_configs[i].port = i + 1;
strcpy(g_data.qos_configs[i].qos_type, "NO QOS");
g_data.qos_configs[i].priority = 0;
strcpy(g_data.qos_configs[i].schedule_mode, "WRR");
for (j = 0; j < 8; j++) {
g_data.qos_configs[i].weights[j] = 1;
}
}
// Initialize default VLANs
for (i = 0; i < 9; i++) {
int vid = i + 2;
g_data.vlans[i].vid = vid;
snprintf(g_data.vlans[i].vlan_name, sizeof(g_data.vlans[i].vlan_name), "vlan%d", vid);
g_data.vlans[i].active = true;
strcpy(g_data.vlans[i].port_members, "[u]ge1/1 [u]ge1/2");
snprintf(g_data.vlans[i].ip_address, sizeof(g_data.vlans[i].ip_address), "192.168.%d.1/24", vid);
g_data.vlans[i].dhcp_client = 0;
}
g_data.vlan_count = 9;
g_data.acl_entry_count = 0;
g_data.mac_binding_count = 0;
g_data.mac_auto_binding_count = 0;
g_data.rmon_statistics_count = 0;
g_data.rmon_history_count = 0;
g_data.rmon_alarm_count = 0;
g_data.rmon_event_count = 0;
g_data.igmp_config_count = 0;
g_data.multicast_group_count = 0;
// Initialize ACL subsystem
initialize_acl_system();
// Initialize Statistics subsystem
initialize_stat_system();
// Initialize L2 and multicast subsystems
initialize_l2_multicast_system();
pthread_mutex_unlock(&global_data_mutex);
}
// ============================================================================================================================================================
// PAGE Handlers
// ==============================================================================================================================================================
void handle_health_check_request(int client_socket)
{
char response[BUFFER_SIZE] = "HTTP/1.1 200 OK\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Content-Type: application/json\r\n\r\n";
strcat(response, "{\"status\": \"ok\"}");
send_response(client_socket, response);
}
/*
* 3.4 System Statistics Structure
*/
typedef struct
{
float cpu_usage; // CPU usage percentage
float memory_usage; // Memory usage percentage
long total_memory; // Total RAM in KB
long free_memory; // Free RAM in KB
long total_swap; // Total swap space in KB
long free_swap; // Free swap space in KB
long total_disk; // Total disk space in KB
long free_disk; // Free disk space in KB
float uptime; // System uptime in hours
long uptime_seconds; // Uptime in seconds
long total_memory_mb; // Total RAM in MB
long free_memory_mb; // Free RAM in MB
unsigned int processes; // Number of processes
float load_1min; // Load average (1 min)
float load_5min; // Load average (5 min)
float load_15min; // Load average (15 min)
} SystemStats;
// Function to retrieve system stats
SystemStats get_system_stats(void)
{
SystemStats stats = {0.0, 0.0, 0, 0, 0, 0, 0, 0, 0.0, 0, 0, 0, 0, 0.0, 0.0, 0.0};
struct sysinfo si;
if (sysinfo(&si) == 0)
{
stats.total_memory = si.totalram / 1024; // Total RAM in KB
stats.free_memory = si.freeram / 1024; // Free RAM in KB
stats.total_swap = si.totalswap / 1024; // Total swap space in KB
stats.free_swap = si.freeswap / 1024; // Free swap space in KB
stats.uptime_seconds = si.uptime; // Uptime in seconds
stats.uptime = si.uptime / 3600.0; // Uptime in hours
stats.processes = si.procs; // Number of processes
stats.load_1min = si.loads[0] / 65536.0; // Load average for 1 min
stats.load_5min = si.loads[1] / 65536.0; // Load average for 5 min
stats.load_15min = si.loads[2] / 65536.0; // Load average for 15 min
stats.total_memory_mb = stats.total_memory / 1024; // Total RAM in MB
stats.free_memory_mb = stats.free_memory / 1024; // Free RAM in MB
stats.memory_usage = ((float)(si.totalram - si.freeram) / si.totalram) * 100.0;
}
FILE *fp = fopen("/proc/stat", "r");
if (fp != NULL)
{
char buffer[256];
fgets(buffer, sizeof(buffer), fp);
fclose(fp);
long user, nice, system, idle, iowait, irq, softirq, steal, total;
sscanf(buffer, "cpu %ld %ld %ld %ld %ld %ld %ld %ld", &user, &nice, &system, &idle, &iowait, &irq, &softirq, &steal);
total = user + nice + system + idle + iowait + irq + softirq + steal;
long idle_time = idle + iowait;
stats.cpu_usage = 100.0 * (1.0 - (float)idle_time / total);
}
struct statvfs fs_stats;
if (statvfs("/", &fs_stats) == 0)
{
stats.total_disk = (fs_stats.f_blocks * fs_stats.f_frsize) / 1024; // Total disk space in KB
stats.free_disk = (fs_stats.f_bfree * fs_stats.f_frsize) / 1024; // Free disk space in KB
}
return stats;
}
// Function to execute system command and get the IPv4 address
char *get_ipv4_address(const char *interface)
{
static char ip_address[16]; // Static buffer to hold the result
char command[128];
snprintf(command, sizeof(command), "ifconfig %s | grep 'inet ' | cut -d: -f2 | awk '{printf $1}'", interface);
FILE *fp = popen(command, "r");
if (fp == NULL)
{
perror("popen failed");
return NULL;
}
if (fgets(ip_address, sizeof(ip_address), fp) == NULL)
{
fclose(fp);
return NULL;
}
ip_address[strcspn(ip_address, "\n")] = 0;
fclose(fp);
return ip_address;
}
// Function to execute system command and get the MAC address
char *get_mac_address(const char *interface)
{
static char mac_address[18]; // MAC address in "XX:XX:XX:XX:XX:XX" format
char command[128];
snprintf(command, sizeof(command),
"ip link show %s | awk '/link\\/ether/ {print $2}'", interface);
FILE *fp = popen(command, "r");
if (fp == NULL)
{
perror("popen failed");
return NULL;
}
if (fgets(mac_address, sizeof(mac_address), fp) == NULL)
{
fclose(fp);
return NULL;
}
// Remove trailing newline if present
mac_address[strcspn(mac_address, "\n")] = '\0';
fclose(fp);
return mac_address;
}
void handle_port_status_request(int client_socket)
{
uint32 unit = 0;
char response[BUFFER_SIZE] = "HTTP/1.1 200 OK\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Content-Type: application/json\r\n\r\n";
char port_data[512] = "";
uint32_t rtk_port;
// Get status for ports 8-15 (mapped to ge1/1-8)
for (rtk_port = 8; rtk_port <= 15; rtk_port++)
{
rtk_port_linkStatus_t linkStatus = PORT_LINKDOWN;
rtk_enable_t adminStatus = DISABLED;
char entry[64];
int web_port = rtk_port - 7; // Map RTK port 8->1, 9->2, etc.
// Get actual link status and admin status using RTK APIs
int ret1 = rtk_port_link_get(unit, rtk_port, &linkStatus);
int ret2 = rtk_port_adminEnable_get(unit, rtk_port, &adminStatus);
if (ret1 == RT_ERR_OK && ret2 == RT_ERR_OK)
{
const char *status = "down";
if (adminStatus == ENABLED && linkStatus == PORT_LINKUP) {
status = "up";
} else if (adminStatus == DISABLED) {
status = "disabled";
}
snprintf(entry, sizeof(entry),
"{\"port\": \"ge1/%d\", \"status\": \"%s\"},",
web_port, status);
}
else
{
snprintf(entry, sizeof(entry),
"{\"port\": \"ge1/%d\", \"status\": \"error\"},",
web_port);
}
strncat(port_data, entry, sizeof(port_data) - strlen(port_data) - 1);
}
// Remove trailing comma if present
int len = strlen(port_data);
if (len > 0 && port_data[len - 1] == ',')
port_data[len - 1] = '\0';
char json[600];
snprintf(json, sizeof(json), "[%s]", port_data);
strcat(response, json);
send_response(client_socket, response);
}
void handle_industrial_status_request(int client_socket)
{
SystemStats stats = get_system_stats();
char response[BUFFER_SIZE] = "HTTP/1.1 200 OK\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Content-Type: application/json\r\n\r\n";
char port_status_data[1024] = "";
int rtk_port;
// Get port status for ports 8-15 (mapped to ge1/1-8)
for (rtk_port = 8; rtk_port <= 15; rtk_port++)
{
rtk_port_linkStatus_t linkStatus = PORT_LINKDOWN;
rtk_port_speed_t speed = PORT_SPEED_1000M;
rtk_port_duplex_t duplex = PORT_FULL_DUPLEX;
rtk_enable_t adminStatus = DISABLED;
const char *speed_str = "N/A";
const char *activity = "Idle";
// Get actual port status using RTK APIs
int ret1 = rtk_port_link_get(0, rtk_port, &linkStatus);
int ret3 = rtk_port_adminEnable_get(0, rtk_port, &adminStatus);
// Check if auto-negotiation is enabled
rtk_enable_t autonego_enable = ENABLED;
rtk_enable_t flow_ctrl = DISABLED;
int ret_auto = rtk_port_phyAutoNegoEnable_get(0, rtk_port, &autonego_enable);
if (ret1 == RT_ERR_OK && ret3 == RT_ERR_OK)
{
// Map speed enum to string
if (ret_auto == RT_ERR_OK && autonego_enable == DISABLED) {
// Port is in force mode, get force mode settings
int ret2 = rtk_port_phyForceModeAbility_get(0, rtk_port, &speed, &duplex, &flow_ctrl);
if (ret2 == RT_ERR_OK) {
switch(speed) {
case PORT_SPEED_10M: speed_str = "10M"; break;
case PORT_SPEED_100M: speed_str = "100M"; break;
case PORT_SPEED_1000M: speed_str = "1G"; break;
case PORT_SPEED_2_5G: speed_str = "2.5G"; break;
case PORT_SPEED_5G: speed_str = "5G"; break;
case PORT_SPEED_10G: speed_str = "10G"; break;
default: speed_str = "unknown"; break;
}
}
} else {
// Auto-negotiation enabled, show as auto
speed_str = "Auto";
}
// Determine overall activity status
if (adminStatus == ENABLED && linkStatus == PORT_LINKUP) {
activity = "Active";
} else {
activity = "Idle";
}
snprintf(port_status_data + strlen(port_status_data), sizeof(port_status_data) - strlen(port_status_data),
"{\"linkStatus\": \"%s\", \"speed\": \"%s\", \"activity\": \"%s\"},",
(linkStatus == PORT_LINKUP) ? "Up" : "Down", speed_str, activity);
}
else
{
snprintf(port_status_data + strlen(port_status_data), sizeof(port_status_data) - strlen(port_status_data),
"{\"linkStatus\": \"Error\", \"speed\": \"N/A\", \"activity\": \"Idle\"},");
}
}
// Remove trailing comma if present
int len = strlen(port_status_data);
if (len > 0 && port_status_data[len - 1] == ',')
port_status_data[len - 1] = '\0';
char json[2048];
snprintf(json, sizeof(json),
"{"
"\"status\": \"Online\"," // TODO You may want to make this dynamic
"\"uptime\": %.2f,"
"\"cpuUsage\": %.2f,"
"\"memoryUsage\": %.2f,"
"\"temperature\": 45," // TODO NEED HW Support
"\"powerStatus\": \"Normal\"," // TODO Still hardcoded
"\"ports\": [%s]"
"}",
stats.uptime,
stats.cpu_usage,
stats.memory_usage,
port_status_data);
strcat(response, json);
send_response(client_socket, response);
}
// Function to execute the reboot command
bool execute_reboot(void)
{
reboot(RB_AUTOBOOT);
return true;
}
/*
* 3.3 Network Testing Structures
*/
typedef struct
{
int packets_sent;
int packets_received;
float packet_loss;
float rtt_min;
float rtt_avg;
float rtt_max;
float rtt_mdev;
} PingResult;
PingResult ping_test(const char *ip, int packet_count)
{
PingResult result = {0, 0, 0.0, 0.0, 0.0, 0.0, 0.0}; // Default result
char command[256];
FILE *ping_output;
char buffer[1024];
char *statistics_line = NULL;
char *rtt_line = NULL;
snprintf(command, sizeof(command), "ping -c %d %s", packet_count, ip); // For Unix/Linux systems
printf("Running ping command: %s\n", command);
ping_output = popen(command, "r");
if (ping_output == NULL)
{
perror("popen failed");
return result;
}
while (fgets(buffer, sizeof(buffer), ping_output))
{
printf("Ping Output: %s", buffer);
if (strstr(buffer, "ping statistics"))
{
statistics_line = strdup(buffer); // Save the statistics line
}
if (strstr(buffer, "rtt min/avg/max/mdev"))
{
rtt_line = strdup(buffer); // Save the RTT line
}
}
if (statistics_line)
{
int transmitted, received;
float packet_loss;
sscanf(statistics_line, "%d packets transmitted, %d received, %f%% packet loss",
&transmitted, &received, &packet_loss);
if (isnan(packet_loss))
{
packet_loss = 0.0;
}
result.packets_sent = transmitted;
result.packets_received = received;
result.packet_loss = packet_loss;
free(statistics_line); // Free the allocated memory for the statistics line
}
if (rtt_line)
{
float rtt_min, rtt_avg, rtt_max, rtt_mdev;
sscanf(rtt_line, "rtt min/avg/max/mdev = %f/%f/%f/%f ms",
&rtt_min, &rtt_avg, &rtt_max, &rtt_mdev);
result.rtt_min = rtt_min;
result.rtt_avg = rtt_avg;
result.rtt_max = rtt_max;
result.rtt_mdev = rtt_mdev;
free(rtt_line); // Free the allocated memory for the RTT line
}
fclose(ping_output);
return result;
}
// Removed old parsing functions - using safer versions above
void handle_ping_request(int client_socket, const char *body)
{
char ip[MAX_IP_LEN] = "";
int length = 0, count = 4;
// Use safe JSON extraction
if (extract_json_string(body, "ip", ip, sizeof(ip)) != 0) {
send_error_response(client_socket, 400, "IP address is required");
return;
}
// Validate IP address format
if (!is_valid_ip(ip)) {
send_error_response(client_socket, 400, "Invalid IP address format");
return;
}
extract_json_int(body, "length", &length);
extract_json_int(body, "count", &count);
// Validate count parameter
if (count <= 0 || count > 100) {
count = 4; // Default value
}
printf("\r\nPing test - IP: %s, Length: %d, Count: %d\r\n", ip, length, count);
// Call ping_test function
PingResult result = ping_test(ip, count);
char json[256];
snprintf(json, sizeof(json),
"{\"status\": \"Success\", \"packets_sent\": %d, \"packets_received\": %d, \"packet_loss\": %.2f}",
result.packets_sent, result.packets_received, result.packet_loss);
send_success_response(client_socket, json);
}
void handle_upload_request(int client_socket, const char *buffer, int bytes_read)
{
char response[BUFFER_SIZE] = "HTTP/1.1 200 OK\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Content-Type: application/json\r\n\r\n";
char *boundary = strstr(buffer, "boundary=");
if (!boundary)
{
strcat(response, "{\"error\": \"Invalid multipart form data\"}");
send_response(client_socket, response);
return;
}
boundary += 9;
char *file_content = strstr(buffer, "\r\n\r\n") + 4;
FILE *fp = fopen("/tmp/uploaded_file", "wb");
if (fp)
{
fwrite(file_content, 1, bytes_read - (file_content - buffer), fp);
fclose(fp);
}
char json[128] = "{\"message\": \"File uploaded successfully\"}";
strcat(response, json);
send_response(client_socket, response);
}
void handle_poe_config_get_request(int client_socket)
{
char response[BUFFER_SIZE] = "HTTP/1.1 200 OK\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Content-Type: application/json\r\n\r\n";
char json[512] = "["
"{\"port\": \"ge1/1\", \"pdIpAddress\": \"192.168.1.100\", \"queryInterval\": 30, \"timeoutNumber\": 3, \"bootTime\": 60, \"rebootTimes\": 0}"
"]";
strcat(response, json);
send_response(client_socket, response);
}
void handle_user_management_get_request(int client_socket)
{
pthread_mutex_lock(&global_data_mutex);
char json[2048] = "[";
bool first = true;
for (i = 0; i < g_data.user_count && i < MAX_USERS; i++) {
if (g_data.users[i].active) {
if (!first) {
strcat(json, ",");
}
first = false;
char user_entry[256];
snprintf(user_entry, sizeof(user_entry),
"{\"user\": \"%s\", \"level\": \"%d\", \"password\": \"%s\", \"timeout\": %d}",
g_data.users[i].username,
g_data.users[i].level,
g_data.users[i].password,
g_data.users[i].timeout);
strcat(json, user_entry);
}
}
strcat(json, "]");
pthread_mutex_unlock(&global_data_mutex);
build_json_response(client_socket, json);
}
void handle_user_management_post_request(int client_socket, const char *body)
{
char username[MAX_STRING_LEN] = "";
char password[MAX_STRING_LEN] = "";
int level = 1;
int timeout = 60;
// Extract user data using helper functions
if (extract_json_string(body, "user", username, sizeof(username)) != 0 ||
extract_json_string(body, "password", password, sizeof(password)) != 0) {
send_error_response(client_socket, 400, "Username and password are required");
return;
}
extract_json_int(body, "level", &level);
extract_json_int(body, "timeout", &timeout);
// Validate input parameters
if (strlen(username) == 0 || strlen(password) == 0) {
send_error_response(client_socket, 400, "Username and password cannot be empty");
return;
}
if (level < 1 || level > 15) {
send_error_response(client_socket, 400, "User level must be between 1 and 15");
return;
}
if (timeout < 0 || timeout > 3600) {
send_error_response(client_socket, 400, "Timeout must be between 0 and 3600 seconds");
return;
}
pthread_mutex_lock(&global_data_mutex);
// Check if user already exists
int user_index = -1;
for (i = 0; i < g_data.user_count && i < MAX_USERS; i++) {
if (strcmp(g_data.users[i].username, username) == 0) {
user_index = i;
break;
}
}
bool is_new_user = (user_index == -1);
if (is_new_user) {
// Add new user
if (g_data.user_count >= MAX_USERS) {
pthread_mutex_unlock(&global_data_mutex);
send_error_response(client_socket, 400, "Maximum number of users reached");
return;
}
user_index = g_data.user_count++;
}
// Update user data
safe_strcpy(g_data.users[user_index].username, username, sizeof(g_data.users[user_index].username));
safe_strcpy(g_data.users[user_index].password, password, sizeof(g_data.users[user_index].password));
g_data.users[user_index].level = level;
g_data.users[user_index].timeout = timeout;
g_data.users[user_index].active = true;
pthread_mutex_unlock(&global_data_mutex);
char response_msg[128];
snprintf(response_msg, sizeof(response_msg),
"{\"message\": \"User %s %s\"}",
username,
is_new_user ? "added" : "updated");
send_success_response(client_socket, response_msg);
}
void handle_user_management_delete_request(int client_socket, const char *body)
{
char username[MAX_STRING_LEN] = "";
// Extract username using helper function
if (extract_json_string(body, "user", username, sizeof(username)) != 0) {
send_error_response(client_socket, 400, "Username is required");
return;
}
if (strlen(username) == 0) {
send_error_response(client_socket, 400, "Username cannot be empty");
return;
}
pthread_mutex_lock(&global_data_mutex);
// Find and deactivate user
bool user_found = false;
for (i = 0; i < g_data.user_count && i < MAX_USERS; i++) {
if (strcmp(g_data.users[i].username, username) == 0 && g_data.users[i].active) {
g_data.users[i].active = false;
user_found = true;
break;
}
}
pthread_mutex_unlock(&global_data_mutex);
if (!user_found) {
send_error_response(client_socket, 404, "User not found");
return;
}
char json[128];
snprintf(json, sizeof(json), "{\"message\": \"User %s deleted\"}", username);
send_success_response(client_socket, json);
}
void handle_user_safety_get_request(int client_socket)
{
pthread_mutex_lock(&global_data_mutex);
char response[1024];
snprintf(response, sizeof(response),
"["
"{\"serviceType\":\"HTTP\",\"managementState\":\"%s\",\"aclGroup\":%d},"
"{\"serviceType\":\"SNMP\",\"managementState\":\"%s\",\"aclGroup\":%d},"
"{\"serviceType\":\"TELNET\",\"managementState\":\"%s\",\"aclGroup\":%d},"
"{\"serviceType\":\"SSH\",\"managementState\":\"%s\",\"aclGroup\":%d}"
"]",
g_data.service_access.http_enabled ? "Enable" : "Disable", g_data.service_access.http_acl,
g_data.service_access.snmp_enabled ? "Enable" : "Disable", g_data.service_access.snmp_acl,
g_data.service_access.telnet_enabled ? "Enable" : "Disable", g_data.service_access.telnet_acl,
g_data.service_access.ssh_enabled ? "Enable" : "Disable", g_data.service_access.ssh_acl
);
pthread_mutex_unlock(&global_data_mutex);
build_json_response(client_socket, response);
}
void handle_user_safety_post_request(int client_socket, const char *body)
{
char serviceType[16] = "", managementState[16] = "";
int aclGroup = 0;
if (extract_json_string(body, "serviceType", serviceType, sizeof(serviceType)) != 0 ||
extract_json_string(body, "managementState", managementState, sizeof(managementState)) != 0 ||
extract_json_int(body, "aclGroup", &aclGroup) != 0)
{
send_error_response(client_socket, 400, "Missing or invalid parameters");
return;
}
if (aclGroup < 1 || aclGroup > 99) {
send_error_response(client_socket, 400, "ACL group must be between 1 and 99");
return;
}
pthread_mutex_lock(&global_data_mutex);
bool enable = (strcmp(managementState, "Enable") == 0);
if (strcmp(serviceType, "HTTP") == 0) {
g_data.service_access.http_enabled = enable;
g_data.service_access.http_acl = aclGroup;
} else if (strcmp(serviceType, "SNMP") == 0) {
g_data.service_access.snmp_enabled = enable;
g_data.service_access.snmp_acl = aclGroup;
} else if (strcmp(serviceType, "TELNET") == 0) {
g_data.service_access.telnet_enabled = enable;
g_data.service_access.telnet_acl = aclGroup;
} else if (strcmp(serviceType, "SSH") == 0) {
g_data.service_access.ssh_enabled = enable;
g_data.service_access.ssh_acl = aclGroup;
} else {
pthread_mutex_unlock(&global_data_mutex);
send_error_response(client_socket, 400, "Invalid serviceType");
return;
}
pthread_mutex_unlock(&global_data_mutex);
build_json_response(client_socket, "{\"message\": \"Service access configuration updated\"}");
}
void handle_sntp_config_get_request(int client_socket)
{
char response[BUFFER_SIZE] = "HTTP/1.1 200 OK\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Content-Type: application/json\r\n\r\n";
char json[256] = "{"
"\"sntpEnable\": \"enable\","
"\"serverIp\": \"192.168.1.10\","
"\"interval\": 1800"
"}";
strcat(response, json);
send_response(client_socket, response);
}
void handle_sntp_config_post_request(int client_socket, const char *body)
{
char sntpEnable[16] = "", serverIp[16] = "";
int interval = 0;
// Extract parameters using helper functions
extract_json_string(body, "sntpEnable", sntpEnable, sizeof(sntpEnable));
extract_json_string(body, "serverIp", serverIp, sizeof(serverIp));
extract_json_int(body, "interval", &interval);
// Validate SNTP enable setting
if (strlen(sntpEnable) > 0 && strcmp(sntpEnable, "enable") != 0 && strcmp(sntpEnable, "disable") != 0) {
send_error_response(client_socket, 400, "sntpEnable must be 'enable' or 'disable'");
return;
}
// Validate server IP if provided
if (strlen(serverIp) > 0 && !is_valid_ip(serverIp)) {
send_error_response(client_socket, 400, "Invalid server IP address format");
return;
}
// Validate interval
if (interval < 0 || interval > 86400) { // Max 24 hours
send_error_response(client_socket, 400, "Interval must be between 0 and 86400 seconds");
return;
}
char json[128] = "{\"message\": \"SNTP configuration applied\"}";
send_success_response(client_socket, json);
}
void handle_save_config_request(int client_socket)
{
char response[BUFFER_SIZE] = "HTTP/1.1 200 OK\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Content-Type: application/json\r\n\r\n";
char json[128] = "{\"message\": \"Configuration saved\"}";
strcat(response, json);
send_response(client_socket, response);
}
void handle_port_stats_request(int client_socket)
{
char response[BUFFER_SIZE] = "HTTP/1.1 200 OK\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Content-Type: application/json\r\n\r\n";
char port_list[512] = "";
int port;
for (port = 8; port <= 15; port++)
{
int mapped_port = port - 7; // 8 -> ge1/1
char entry[16];
snprintf(entry, sizeof(entry), "\"ge1/%d\",", mapped_port);
strcat(port_list, entry);
}
// Remove trailing comma
int len = strlen(port_list);
if (len > 0 && port_list[len - 1] == ',')
port_list[len - 1] = '\0';
char json[600];
snprintf(json, sizeof(json), "{ \"ports\": [%s] }", port_list);
strcat(response, json);
send_response(client_socket, response);
}
void handle_get_port_stats_request(int client_socket, const char *query)
{
char response[BUFFER_SIZE] = "HTTP/1.1 200 OK\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Content-Type: application/json\r\n\r\n";
char port_str[16] = "";
// Parse query parameter manually since it's URL encoded
if (strncmp(query, "port=", 5) == 0) {
safe_strcpy(port_str, query + 5, sizeof(port_str));
} else {
send_error_response(client_socket, 400, "Port parameter is required");
return;
}
// Parse port format (ge1/X)
int port_id = 0;
if (strncmp(port_str, "ge1/", 4) == 0) {
port_id = atoi(port_str + 4);
} else {
send_error_response(client_socket, 400, "Invalid port format (expected ge1/X)");
return;
}
if (port_id < 1 || port_id > 8) {
send_error_response(client_socket, 400, "Port ID must be between 1 and 8");
return;
}
int real_port = port_id + 7; // Map ge1/1 => port 8
uint64_t in_octets = 0, in_ucast = 0, in_mcast = 0, in_bcast = 0;
uint64_t in_discards = 0, in_errors = 0;
uint64_t out_octets = 0, out_ucast = 0, out_mcast = 0, out_bcast = 0;
uint64_t out_discards = 0, out_errors = 0;
rtk_stat_port_get(0, real_port, IF_IN_OCTETS_INDEX, &in_octets);
rtk_stat_port_get(0, real_port, IF_IN_UCAST_PKTS_INDEX, &in_ucast);
rtk_stat_port_get(0, real_port, IF_IN_MULTICAST_PKTS_INDEX, &in_mcast);
rtk_stat_port_get(0, real_port, IF_IN_BROADCAST_PKTS_INDEX, &in_bcast);
rtk_stat_port_get(0, real_port, DOT1D_TP_PORT_IN_DISCARDS_INDEX, &in_discards);
rtk_stat_port_get(0, real_port, ETHER_STATS_CRC_ALIGN_ERRORS_INDEX, &in_errors); // Approximate
rtk_stat_port_get(0, real_port, IF_OUT_OCTETS_INDEX, &out_octets);
rtk_stat_port_get(0, real_port, IF_OUT_UCAST_PKTS_CNT_INDEX, &out_ucast);
rtk_stat_port_get(0, real_port, IF_OUT_MULTICAST_PKTS_CNT_INDEX, &out_mcast);
rtk_stat_port_get(0, real_port, IF_OUT_BROADCAST_PKTS_CNT_INDEX, &out_bcast);
rtk_stat_port_get(0, real_port, IF_OUT_DISCARDS_INDEX, &out_discards);
rtk_stat_port_get(0, real_port, TX_ETHER_STATS_CRC_ALIGN_ERRORS_INDEX, &out_errors); // Approximate
uint64_t in_nucast = in_mcast + in_bcast;
uint64_t out_nucast = out_mcast + out_bcast;
// ifInUnknownProtos is not supported, use 0
uint64_t in_unknown_protos = 0;
char json[1024];
snprintf(json, sizeof(json),
"{"
"\"ifInOctets\": %llu, \"ifInUcastPkts\": %llu, \"ifInNUcastPkts\": %llu,"
"\"ifInDiscards\": %llu, \"ifInErrors\": %llu, \"ifInUnknownProtos\": %llu,"
"\"ifOutOctets\": %llu, \"ifOutUcastPkts\": %llu, \"ifOutNUcastPkts\": %llu,"
"\"ifOutDiscards\": %llu, \"ifOutErrors\": %llu"
"}",
in_octets, in_ucast, in_nucast,
in_discards, in_errors, in_unknown_protos,
out_octets, out_ucast, out_nucast,
out_discards, out_errors);
strcat(response, json);
send_response(client_socket, response);
}
void handle_storm_control_post_request(int client_socket, const char *body)
{
char port_str[16] = "";
char broadcast[8] = "", multicast[8] = "", dlf[8] = "";
int bRate = 0, mRate = 0, dRate = 0;
// Extract parameters using helper functions
if (extract_json_string(body, "port", port_str, sizeof(port_str)) != 0) {
send_error_response(client_socket, 400, "Port parameter is required");
return;
}
extract_json_string(body, "broadcastSuppression", broadcast, sizeof(broadcast));
extract_json_string(body, "multicastSuppression", multicast, sizeof(multicast));
extract_json_string(body, "dlfSuppression", dlf, sizeof(dlf));
extract_json_int(body, "broadcastRate", &bRate);
extract_json_int(body, "multicastRate", &mRate);
extract_json_int(body, "dlfRate", &dRate);
// Parse and validate port format (X)
int sdk_port = -1;
if (strncmp(port_str, 4) == 0) {
int logical_port = atoi(port_str + 4);
if (logical_port >= 1 && logical_port <= 8) {
sdk_port = logical_port + 7;
}
}
if (sdk_port < 8 || sdk_port > 15) {
send_error_response(client_socket, 400, "Invalid port format (expected ge1/1 to ge1/8)");
return;
}
// Validate rate parameters
if (bRate < 0 || bRate > 1000 || mRate < 0 || mRate > 1000 || dRate < 0 || dRate > 1000) {
send_error_response(client_socket, 400, "Rate values must be between 0 and 1000");
return;
}
// Apply storm control configuration using RTK APIs
int ret = RT_ERR_OK;
if (strlen(broadcast) > 0) {
rtk_enable_t bEn = (strcmp(broadcast, "On") == 0) ? ENABLED : DISABLED;
ret |= rtk_rate_portStormCtrlEnable_set(0, sdk_port, STORM_GROUP_BROADCAST, bEn);
ret |= rtk_rate_portStormCtrlRate_set(0, sdk_port, STORM_GROUP_BROADCAST, bRate);
}
if (strlen(multicast) > 0) {
rtk_enable_t mEn = (strcmp(multicast, "On") == 0) ? ENABLED : DISABLED;
ret |= rtk_rate_portStormCtrlEnable_set(0, sdk_port, STORM_GROUP_MULTICAST, mEn);
ret |= rtk_rate_portStormCtrlRate_set(0, sdk_port, STORM_GROUP_MULTICAST, mRate);
}
if (strlen(dlf) > 0) {
rtk_enable_t uEn = (strcmp(dlf, "On") == 0) ? ENABLED : DISABLED;
ret |= rtk_rate_portStormCtrlEnable_set(0, sdk_port, STORM_GROUP_UNICAST, uEn);
ret |= rtk_rate_portStormCtrlRate_set(0, sdk_port, STORM_GROUP_UNICAST, dRate);
}
if (ret != RT_ERR_OK) {
send_error_response(client_socket, 500, "Failed to apply storm control configuration");
return;
}
char json[128];
snprintf(json, sizeof(json), "{\"message\": \"Storm control configuration applied to %s\"}", port_str);
send_success_response(client_socket, json);
}
void handle_snmp_community_get_request(int client_socket)
{
pthread_mutex_lock(&global_data_mutex);
char json[1024] = "[";
bool first = true;
for (i = 0; i < g_data.community_count && i < MAX_COMMUNITIES; i++) {
if (g_data.communities[i].active) {
if (!first) {
strcat(json, ",");
}
first = false;
char community_entry[128];
snprintf(community_entry, sizeof(community_entry),
"{\"community\": \"%s\", \"access\": \"%s\"}",
g_data.communities[i].community,
g_data.communities[i].access);
strcat(json, community_entry);
}
}
strcat(json, "]");
pthread_mutex_unlock(&global_data_mutex);
build_json_response(client_socket, json);
}
void handle_snmp_community_post_request(int client_socket, const char *body)
{
char community[32] = "", access[16] = "";
// Extract parameters using helper functions
if (extract_json_string(body, "community", community, sizeof(community)) != 0) {
send_error_response(client_socket, 400, "Community name is required");
return;
}
if (extract_json_string(body, "access", access, sizeof(access)) != 0) {
send_error_response(client_socket, 400, "Access level is required");
return;
}
// Validate access level
if (strcmp(access, "read-only") != 0 && strcmp(access, "read-write") != 0) {
send_error_response(client_socket, 400, "Access must be 'read-only' or 'read-write'");
return;
}
char json[128];
snprintf(json, sizeof(json), "{\"message\": \"SNMP community %s added\"}", community);
send_success_response(client_socket, json);
}
void handle_snmp_community_delete_request(int client_socket, const char *body)
{
char community[32] = "";
// Extract community name using helper function
if (extract_json_string(body, "community", community, sizeof(community)) != 0) {
send_error_response(client_socket, 400, "Community name is required");
return;
}
if (strlen(community) == 0) {
send_error_response(client_socket, 400, "Community name cannot be empty");
return;
}
char json[128];
snprintf(json, sizeof(json), "{\"message\": \"SNMP community %s deleted\"}", community);
send_success_response(client_socket, json);
}
void handle_snmp_community_patch_request(int client_socket, const char *body)
{
char community[32] = "", access[16] = "";
// Extract parameters using helper functions
if (extract_json_string(body, "community", community, sizeof(community)) != 0) {
send_error_response(client_socket, 400, "Community name is required");
return;
}
if (extract_json_string(body, "access", access, sizeof(access)) != 0) {
send_error_response(client_socket, 400, "Access level is required");
return;
}
// Validate access level
if (strcmp(access, "read-only") != 0 && strcmp(access, "read-write") != 0) {
send_error_response(client_socket, 400, "Access must be 'read-only' or 'read-write'");
return;
}
char json[128];
snprintf(json, sizeof(json), "{\"message\": \"SNMP community %s updated\"}", community);
send_success_response(client_socket, json);
}
void handle_trap_targets_get_request(int client_socket)
{
char response[BUFFER_SIZE] = "HTTP/1.1 200 OK\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Content-Type: application/json\r\n\r\n";
char json[256] = "["
"{\"ip\": \"192.168.1.100\", \"community\": \"public\", \"version\": \"v2c\"},"
"{\"ip\": \"192.168.1.101\", \"community\": \"private\", \"version\": \"v3\"}"
"]";
strcat(response, json);
send_response(client_socket, response);
}
void handle_trap_targets_post_request(int client_socket, const char *body)
{
char ip[16] = "", community[32] = "", version[8] = "";
// Extract parameters using helper functions
if (extract_json_string(body, "ip", ip, sizeof(ip)) != 0) {
send_error_response(client_socket, 400, "IP address is required");
return;
}
if (extract_json_string(body, "community", community, sizeof(community)) != 0) {
send_error_response(client_socket, 400, "Community is required");
return;
}
if (extract_json_string(body, "version", version, sizeof(version)) != 0) {
send_error_response(client_socket, 400, "SNMP version is required");
return;
}
// Validate IP address
if (!is_valid_ip(ip)) {
send_error_response(client_socket, 400, "Invalid IP address format");
return;
}
// Validate SNMP version
if (strcmp(version, "v1") != 0 && strcmp(version, "v2c") != 0 && strcmp(version, "v3") != 0) {
send_error_response(client_socket, 400, "SNMP version must be 'v1', 'v2c', or 'v3'");
return;
}
char json[128];
snprintf(json, sizeof(json), "{\"message\": \"Trap target %s added\"}", ip);
send_success_response(client_socket, json);
}
void handle_trap_targets_delete_request(int client_socket, const char *body)
{
char ip[16] = "";
// Extract IP address using helper function
if (extract_json_string(body, "ip", ip, sizeof(ip)) != 0) {
send_error_response(client_socket, 400, "IP address is required");
return;
}
// Validate IP address
if (!is_valid_ip(ip)) {
send_error_response(client_socket, 400, "Invalid IP address format");
return;
}
char json[128];
snprintf(json, sizeof(json), "{\"message\": \"Trap target %s deleted\"}", ip);
send_success_response(client_socket, json);
}
void handle_qos_config_get_request(int client_socket)
{
char response[BUFFER_SIZE] = "HTTP/1.1 200 OK\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Content-Type: application/json\r\n\r\n";
char json[2048] = "[";
int web_port;
for (web_port = 1; web_port <= 8; web_port++)
{
int sdk_port = web_port + 7;
rtk_pri_t priority = 0;
if (rtk_qos_portPri_get(0, sdk_port, &priority) != RT_ERR_OK)
{
priority = 0;
}
const char *qosType = (priority > 0) ? "PORT" : "NO QOS";
char entry[128];
snprintf(entry, sizeof(entry),
"{\"port\": %d, \"qosType\": \"%s\", \"priority\": %d},",
web_port, qosType, priority);
strncat(json, entry, sizeof(json) - strlen(json) - 1);
}
int len = strlen(json);
if (len > 1 && json[len - 1] == ',')
{
json[len - 1] = '\0';
}
strcat(json, "]");
strcat(response, json);
send_response(client_socket, response);
}
void handle_qos_config_post_request(int client_socket, const char *body)
{
char port_str[8] = "", qosType[32] = "";
int priority = 0;
// Extract parameters using helper functions
int port;
if (extract_json_int(body, "port", &port) != 0) {
send_error_response(client_socket, 400, "Port is required");
return;
}
extract_json_string(body, "qosType", qosType, sizeof(qosType));
extract_json_int(body, "priority", &priority);
// Validate port
int web_port = atoi(port_str);
if (!is_valid_port(web_port, 1, 8)) {
send_error_response(client_socket, 400, "Port must be between 1 and 8");
return;
}
// Validate priority
if (priority < 0 || priority > 7) {
send_error_response(client_socket, 400, "Priority must be between 0 and 7");
return;
}
int sdk_port = web_port + 7;
int ret = rtk_qos_portPri_set(0, sdk_port, priority);
if (ret != RT_ERR_OK) {
send_error_response(client_socket, 500, "Failed to apply QoS configuration");
return;
}
char json[128];
snprintf(json, sizeof(json),
"{\"message\": \"QoS config applied to port %d (%s)\", \"result\": \"success\"}",
web_port, qosType);
send_success_response(client_socket, json);
}
void handle_get_qos_schedule_request(int client_socket)
{
char response[BUFFER_SIZE] = "HTTP/1.1 200 OK\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Content-Type: application/json\r\n\r\n";
char json[4096] = "[";
int web_port;
for (web_port = 1; web_port <= 8; web_port++)
{
int sdk_port = web_port + 7;
rtk_qos_scheduling_type_t mode = WRR;
rtk_qos_queue_weights_t qweights = {{0}};
rtk_qos_schedulingAlgorithm_get(0, sdk_port, &mode);
rtk_qos_schedulingQueue_get(0, sdk_port, &qweights);
const char *mode_str = (mode == WFQ) ? "WFQ" : "WRR";
char weights[256] = "[";
int q;
for (q = 0; q < 8; q++)
{
char w[8];
snprintf(w, sizeof(w), "%u,", qweights.weights[q]);
strcat(weights, w);
}
if (weights[strlen(weights) - 1] == ',')
{
weights[strlen(weights) - 1] = '\0';
}
strcat(weights, "]");
char entry[512];
snprintf(entry, sizeof(entry),
"{\"port\": \"%d\", \"mode\": \"%s\", \"weights\": %s},",
web_port, mode_str, weights);
strcat(json, entry);
}
int len = strlen(json);
if (len > 1 && json[len - 1] == ',')
{
json[len - 1] = '\0';
}
strcat(json, "]");
strcat(response, json);
send_response(client_socket, response);
}
void handle_set_qos_schedule_request(int client_socket, const char *body)
{
char response[BUFFER_SIZE] = "HTTP/1.1 200 OK\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Content-Type: application/json\r\n\r\n";
char port_str[8] = "", mode[16] = "";
int weights[8] = {0};
sscanf(body,
"{\"port\":\"%7[^\"]\",\"mode\":\"%15[^\"]\",\"weights\":[%d,%d,%d,%d,%d,%d,%d,%d]}",
port_str, mode,
&weights[0], &weights[1], &weights[2], &weights[3],
&weights[4], &weights[5], &weights[6], &weights[7]);
int web_port = atoi(port_str);
int sdk_port = web_port + 7;
rtk_qos_scheduling_type_t sched_mode = (strcmp(mode, "WFQ") == 0) ? WFQ : WRR;
rtk_qos_queue_weights_t qweights;
int i;
for (i = 0; i < 8; i++)
qweights.weights[i] = weights[i];
int ret1 = rtk_qos_schedulingAlgorithm_set(0, sdk_port, sched_mode);
int ret2 = rtk_qos_schedulingQueue_set(0, sdk_port, &qweights);
char json[128];
snprintf(json, sizeof(json),
"{\"message\": \"QoS schedule applied to port %d\", \"result\": %s}",
web_port, (ret1 == RT_ERR_OK && ret2 == RT_ERR_OK) ? "\"success\"" : "\"fail\"");
strcat(response, json);
send_response(client_socket, response);
}
void handle_not_found(int client_socket)
{
char response[BUFFER_SIZE] = "HTTP/1.1 404 Not Found\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Content-Type: application/json\r\n\r\n"
"{\"error\": \"Endpoint not found\"}";
send_response(client_socket, response);
}
// Additional route handlers using RTK functions
// void handle_port_config_get_request(int client_socket)
// {
// uint32 unit = 0;
// char response[BUFFER_SIZE] = "HTTP/1.1 200 OK\r\n"
// "Access-Control-Allow-Origin: *\r\n"
// "Content-Type: application/json\r\n\r\n";
// char json[2048] = "[";
// int rtk_port;
// // Get port configurations using RTK APIs for ports 8-15 (mapped to ge1/1-8)
// for (rtk_port = 8; rtk_port <= 15; rtk_port++)
// {
// int web_port = rtk_port - 7; // Map RTK port 8->1, 9->2, etc.
// if (web_port > 1) strcat(json, ",");
// rtk_port_linkStatus_t linkStatus = PORT_LINKDOWN;
// rtk_port_speed_t speed = PORT_SPEED_1000M;
// rtk_port_duplex_t duplex = PORT_FULL_DUPLEX;
// rtk_enable_t adminStatus = DISABLED;
// // Get actual port status using RTK APIs
// int ret1 = rtk_port_link_get(unit, rtk_port, &linkStatus);
// int ret3 = rtk_port_adminEnable_get(unit, rtk_port, &adminStatus);
// // Check if auto-negotiation is enabled
// rtk_enable_t autonego_enable = ENABLED;
// rtk_enable_t flow_ctrl = DISABLED;
// int ret_auto = rtk_port_phyAutoNegoEnable_get(unit, rtk_port, &autonego_enable);
// // Map speed enum to string
// const char *speed_str = "Auto";
// const char *duplex_str = "Auto";
// if (ret_auto == RT_ERR_OK && autonego_enable == DISABLED) {
// // Port is in force mode, get force mode settings
// int ret2 = rtk_port_phyForceModeAbility_get(unit, rtk_port, &speed, &duplex, &flow_ctrl);
// if (ret2 == RT_ERR_OK) {
// switch(speed) {
// case PORT_SPEED_10M: speed_str = "10M"; break;
// case PORT_SPEED_100M: speed_str = "100M"; break;
// case PORT_SPEED_1000M: speed_str = "1000M"; break;
// case PORT_SPEED_2_5G: speed_str = "2.5G"; break;
// case PORT_SPEED_5G: speed_str = "5G"; break;
// case PORT_SPEED_10G: speed_str = "10G"; break;
// default: speed_str = "Unknown"; break;
// }
// duplex_str = (duplex == PORT_FULL_DUPLEX) ? "Full" : "Half";
// }
// } else {
// // Auto-negotiation enabled or error occurred
// speed_str = "Auto";
// duplex_str = "Auto";
// }
// char portJson[512];
// sprintf(portJson,
// "{\"port\":\"%d\","
// "\"description\":\"Port ge1/%d\","
// "\"adminStatus\":\"%s\","
// "\"operateStatus\":\"%s\","
// "\"duplex\":\"%s\","
// "\"configSpeed\":\"%s\","
// "\"vlanMode\":\"%s\","
// "\"defaultVlan\":\"%d\"}",
// web_port,
// web_port,
// (ret3 == RT_ERR_OK && adminStatus == ENABLED) ? "Up" : "Down",
// (ret1 == RT_ERR_OK && linkStatus == PORT_LINKUP) ? "Up" : "Down",
// duplex_str,
// speed_str,
// "Not Available", // placeholder: replace with real mode if needed
// 1 // placeholder: replace with actual VLAN ID
// );
// }
// strcat(json, "]");
// strcat(response, json);
// send_response(client_socket, response);
// }
/**
* Extracts an array of integers from a JSON string for a given key.
* @param json The JSON string to parse (e.g., "{\"ports\": [1, -2, 3]}").
* @param key The key whose value is an array of integers.
* @param out_array The output array to store the integers.
* @param max_count The maximum number of integers to extract (size of out_array).
* @return The number of integers extracted, or -1 on error.
*/
int extract_json_array_of_ints(const char *json, const char *key, int *out_array, int max_count) {
// Input validation
if (!json || !key || !out_array || max_count <= 0) {
return -1;
}
// Find the key in the JSON string
unsigned int key_len = strlen(key);
const char *key_start = strstr(json, key);
if (!key_start) {
return -1; // Key not found
}
// Verify the key is properly quoted and followed by a colon
if (key_start[-1] != '"' || key_start[key_len] != '"') {
return -1; // Key not properly quoted
}
const char *colon = key_start + key_len + 1;
while (*colon && isspace(*colon)) colon++; // Skip whitespace
if (*colon != ':') {
return -1; // No colon after key
}
// Find the opening bracket of the array
const char *array_start = colon + 1;
while (*array_start && isspace(*array_start)) array_start++; // Skip whitespace
if (*array_start != '[') {
return -1; // No array start
}
// Parse the array elements
int count = 0;
const char *p = array_start + 1;
while (*p && *p != ']' && count < max_count) {
// Skip whitespace
while (*p && isspace(*p)) p++;
if (*p == ']') break; // Empty array or end of array
// Parse an integer (including negative numbers)
char *endptr;
long value = strtol(p, &endptr, 10);
if (endptr == p) {
return -1; // No valid number found
}
if (value > INT_MAX || value < INT_MIN) {
return -1; // Number out of int range
}
out_array[count++] = (int)value;
// Move to the next element
p = endptr;
while (*p && isspace(*p)) p++; // Skip whitespace
if (*p == ']') break; // End of array
if (*p != ',') {
return -1; // Expected comma or end of array
}
p++; // Skip comma
}
// Check if the array is properly closed
while (*p && isspace(*p)) p++;
if (*p != ']') {
return -1; // Array not closed
}
return count; // Success, return number of integers extracted
}
void handle_port_config_post_request(int client_socket, const char *body)
{
uint32 unit = 0;
char speed[16] = "";
char duplex[16] = "";
char adminStatus[16] = "";
char description[128] = "";
int ports[8]; // Max 8 ports expected
int port_count = extract_json_array_of_ints(body, "ports", ports, 8);
if (port_count <= 0) {
send_error_response(client_socket, 400, "At least one port must be specified");
return;
}
extract_json_string(body, "configSpeed", speed, sizeof(speed));
extract_json_string(body, "adminStatus", adminStatus, sizeof(adminStatus));
extract_json_string(body, "description", description, sizeof(description));
rtk_port_speed_t port_speed = PORT_SPEED_1000M;
rtk_port_duplex_t port_duplex = PORT_FULL_DUPLEX;
rtk_enable_t flow_ctrl = DISABLED;
bool use_force_mode = false;
if (strlen(speed) > 0 && strcmp(speed, "Auto") != 0) {
use_force_mode = true;
if (strcmp(speed, "10M") == 0) port_speed = PORT_SPEED_10M;
else if (strcmp(speed, "100M") == 0) port_speed = PORT_SPEED_100M;
else if (strcmp(speed, "1000M") == 0) port_speed = PORT_SPEED_1000M;
else if (strcmp(speed, "2.5G") == 0) port_speed = PORT_SPEED_2_5G;
else if (strcmp(speed, "5G") == 0) port_speed = PORT_SPEED_5G;
else if (strcmp(speed, "10G") == 0) port_speed = PORT_SPEED_10G;
}
if (strlen(duplex) > 0 && strcmp(duplex, "Auto") != 0) {
use_force_mode = true;
port_duplex = (strcmp(duplex, "Full") == 0) ? PORT_FULL_DUPLEX : PORT_HALF_DUPLEX;
}
for ( i = 0; i < port_count; ++i) {
int web_port = ports[i];
if (!is_valid_port(web_port, 1, 8)) continue;
int rtk_port = web_port + 7;
// Admin status
if (strlen(adminStatus) > 0) {
rtk_enable_t enable = (strcmp(adminStatus, "Up") == 0) ? ENABLED : DISABLED;
if (rtk_port_adminEnable_set(unit, rtk_port, enable) != RT_ERR_OK) {
send_error_response(client_socket, 500, "Failed to set admin status");
return;
}
}
// Speed/Duplex
if (strlen(speed) > 0 || strlen(duplex) > 0) {
if (use_force_mode) {
if (rtk_port_phyAutoNegoEnable_set(unit, rtk_port, DISABLED) != RT_ERR_OK ||
rtk_port_phyForceModeAbility_set(unit, rtk_port, port_speed, port_duplex, flow_ctrl) != RT_ERR_OK) {
send_error_response(client_socket, 500, "Failed to set force mode config");
return;
}
} else {
if (rtk_port_phyAutoNegoEnable_set(unit, rtk_port, ENABLED) != RT_ERR_OK) {
send_error_response(client_socket, 500, "Failed to enable auto-negotiation");
return;
}
}
}
// You can optionally store or print description here (if used)
printf("description:%s\n", description);
}
send_success_response(client_socket, "{\"message\":\"Port(s) configuration updated successfully\"}");
}
void handle_port_rate_limit_get_request(int client_socket)
{
uint32 unit = 0;
char response[BUFFER_SIZE] = "HTTP/1.1 200 OK\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Content-Type: application/json\r\n\r\n";
char json[2048] = "[";
int rtk_port;
// Get rate limit settings for ports 8-15 (mapped to ge1/1-8)
for (rtk_port = 8; rtk_port <= 15; rtk_port++)
{
int web_port = rtk_port - 7;
if (web_port > 1) strcat(json, ",");
uint32 ingressRate = 1000;
uint32 egressRate = 1000;
rtk_enable_t ingressEnable = DISABLED;
rtk_enable_t egressEnable = DISABLED;
// Get ingress rate limit using RTK APIs
rtk_rate_portIgrBwCtrlEnable_get(unit, rtk_port, &ingressEnable);
rtk_rate_portIgrBwCtrlRate_get(unit, rtk_port, &ingressRate);
// Get egress rate limit using RTK APIs
rtk_rate_portEgrBwCtrlEnable_get(unit, rtk_port, &egressEnable);
rtk_rate_portEgrBwCtrlRate_get(unit, rtk_port, &egressRate);
char portJson[256];
sprintf(portJson,
"{\"port\":\"%d\","
"\"ingressRate\":%u,"
"\"egressRate\":%u,"
"\"enabled\":%s}",
web_port, ingressRate, egressRate,
(ingressEnable == ENABLED || egressEnable == ENABLED) ? "true" : "false");
strcat(json, portJson);
}
strcat(json, "]");
strcat(response, json);
send_response(client_socket, response);
}
void handle_port_rate_limit_post_request(int client_socket, const char *body)
{
uint32 unit = 0;
int port = extract_value_int(body, "\"port\"");
int ingressRate = 0; //extract_value_int(body, "\"ingressRate\"");
int egressRate = 0; //extract_value_int(body, "\"egressRate\"");
int enabled = 1; //extract_value_int(body, "\"enabled\"");
// // Extract parameters using helper functions
// if (extract_json_int(body, "port", &port) != 0) {
// send_error_response(client_socket, 400, "Port is required");
// return;
// }
extract_json_int(body, "ingressRate", &ingressRate);
extract_json_int(body, "egressRate", &egressRate);
// extract_json_int(body, "enabled", &enabled);
// Validate and convert web port to RTK port
if (!is_valid_port(port, 1, 8)) {
send_error_response(client_socket, 400, "Port must be between 1 and 8");
return;
}
int rtk_port = port + 7;
// Validate rate parameters
if (ingressRate < 0 || ingressRate > 1000000 || egressRate < 0 || egressRate > 1000000) {
send_error_response(client_socket, 400, "Rate must be between 0 and 1000000 kbps");
return;
}
// Apply rate limit using RTK APIs
rtk_enable_t enable_val = enabled ? ENABLED : DISABLED;
int ret1 = rtk_rate_portIgrBwCtrlEnable_set(unit, rtk_port, enable_val);
int ret2 = rtk_rate_portIgrBwCtrlRate_set(unit, rtk_port, ingressRate);
int ret3 = rtk_rate_portEgrBwCtrlEnable_set(unit, rtk_port, enable_val);
int ret4 = rtk_rate_portEgrBwCtrlRate_set(unit, rtk_port, egressRate);
if (ret1 != RT_ERR_OK || ret2 != RT_ERR_OK || ret3 != RT_ERR_OK || ret4 != RT_ERR_OK) {
send_error_response(client_socket, 500, "Failed to apply rate limit configuration");
return;
}
char json[128];
snprintf(json, sizeof(json), "{\"message\":\"Rate limit for port %d updated successfully\"}", port);
send_success_response(client_socket, json);
}
void handle_learn_limit_get_request(int client_socket)
{
uint32 unit = 0;
char response[BUFFER_SIZE] = "HTTP/1.1 200 OK\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Content-Type: application/json\r\n\r\n";
char json[2048] = "[";
int rtk_port;
for (rtk_port = 8; rtk_port <= 15; rtk_port++)
{
int web_port = rtk_port - 7;
if (web_port > 1) strcat(json, ",");
uint32 maxMac = 8192;
int ret = rtk_l2_portLimitLearningCnt_get(unit, rtk_port, &maxMac);
if(ret != RT_ERR_OK)
{
send_error_response(client_socket, 500, "Failed to get learn limit");
return;
}
char portJson[128];
snprintf(portJson, sizeof(portJson),
"{\"port\":%d,\"macLimit\":%u}",
web_port, maxMac);
strcat(json, portJson);
}
strcat(json, "]");
strcat(response, json);
send_response(client_socket, response);
}
void handle_learn_limit_post_request(int client_socket, const char *body)
{
uint32 unit = 0;
int port = -1, macLimit = 0;
bool cancel = false;
if (extract_json_int(body, "port", &port) != 0) {
send_error_response(client_socket, 400, "Port is required");
return;
}
if (extract_json_int(body, "macLimit", &macLimit) != 0) {
send_error_response(client_socket, 400, "macLimit is required");
return;
}
extract_json_bool(body, "cancel", &cancel); // Optional flag
if (!is_valid_port(port, 1, 8)) {
send_error_response(client_socket, 400, "Port must be between 1 and 8");
return;
}
if (macLimit < 0 || macLimit > 8191) {
send_error_response(client_socket, 400, "macLimit must be between 0 and 8191");
return;
}
int rtk_port = port + 7;
int ret = rtk_l2_portLimitLearningCnt_set(unit, rtk_port, macLimit);
if (ret != RT_ERR_OK) {
send_error_response(client_socket, 500, "Failed to set learning limit");
return;
}
char json[128];
snprintf(json, sizeof(json),
"{\"message\":\"Learn limit for port %d %s successfully\"}",
port,
cancel ? "reset" : "updated");
send_success_response(client_socket, json);
}
void handle_download_config_request(int client_socket)
{
char response[BUFFER_SIZE] = "HTTP/1.1 200 OK\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Content-Type: application/json\r\n\r\n";
// Return current configuration as JSON
char json[1024] = "{"
"\"systemConfig\":{\"name\":\"Switch\",\"location\":\"Lab\"},"
"\"portConfig\":[{\"port\":\"1\",\"status\":\"Up\"}],"
"\"timestamp\":\"2024-01-01T00:00:00Z\""
"}";
strcat(response, json);
send_response(client_socket, response);
}
void handle_delete_config_request(int client_socket)
{
char response[BUFFER_SIZE] = "HTTP/1.1 200 OK\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Content-Type: application/json\r\n\r\n";
char json[128] = "{\"message\":\"Configuration deleted successfully\"}";
strcat(response, json);
send_response(client_socket, response);
}
// Serial configuration handler
void handle_serial_config_get_request(int client_socket)
{
char response[BUFFER_SIZE] = "HTTP/1.1 200 OK\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Content-Type: application/json\r\n\r\n";
char json[256] = "{"
"\"baudRate\":\"38400\","
"\"charSize\":\"8\","
"\"parity\":\"None\","
"\"stopBits\":\"1\","
"\"flowControl\":\"None\""
"}";
strcat(response, json);
send_response(client_socket, response);
}
// System configuration handlers
void handle_system_config_get_request(int client_socket)
{
pthread_mutex_lock(&global_data_mutex);
char json[1024];
snprintf(json, sizeof(json),
"{"
"\"description\":\"%s\","
"\"objectId\":\"%s\","
"\"version\":\"%s\","
"\"interfaces\":%d,"
"\"serialNumber\":\"%s\","
"\"macAddress\":\"%s\","
"\"ipAddress\":\"%s\","
"\"startTime\":\"0-Days 0-Hours 7-Minutes 5-Seconds\","
"\"dateTime\":\"2020/01/01 00:04:57\","
"\"systemName\":\"%s\","
"\"systemLocation\":\"%s\","
"\"systemContact\":\"%s\""
"}",
g_data.system.description,
g_data.system.objectId,
g_data.system.version,
g_data.system.interfaces,
g_data.system.serialNumber,
g_data.system.macAddress,
g_data.system.ipAddress,
g_data.system.systemName,
g_data.system.systemLocation,
g_data.system.systemContact);
pthread_mutex_unlock(&global_data_mutex);
build_json_response(client_socket, json);
}
void handle_system_config_post_request(int client_socket, const char *body)
{
char systemName[MAX_STRING_LEN] = "";
char systemLocation[MAX_STRING_LEN] = "";
char systemContact[MAX_STRING_LEN] = "";
// Use safe JSON extraction - allow optional fields
extract_json_string(body, "systemName", systemName, sizeof(systemName));
extract_json_string(body, "systemLocation", systemLocation, sizeof(systemLocation));
extract_json_string(body, "systemContact", systemContact, sizeof(systemContact));
// Validate that at least one field is provided
if (strlen(systemName) == 0 && strlen(systemLocation) == 0 && strlen(systemContact) == 0) {
send_error_response(client_socket, 400, "At least one system configuration field is required");
return;
}
pthread_mutex_lock(&global_data_mutex);
// Update global data only if values are provided
if (strlen(systemName) > 0) {
safe_strcpy(g_data.system.systemName, systemName, sizeof(g_data.system.systemName));
}
if (strlen(systemLocation) > 0) {
safe_strcpy(g_data.system.systemLocation, systemLocation, sizeof(g_data.system.systemLocation));
}
if (strlen(systemContact) > 0) {
safe_strcpy(g_data.system.systemContact, systemContact, sizeof(g_data.system.systemContact));
}
pthread_mutex_unlock(&global_data_mutex);
send_success_response(client_socket, "{\"message\":\"Config saved successfully\"}");
}
// Port stats handler
void handle_port_stats_get_request(int client_socket)
{
char response[BUFFER_SIZE] = "HTTP/1.1 200 OK\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Content-Type: application/json\r\n\r\n";
char json[256] = "{\"ports\":[\"1\",\"2\",\"3\",\"4\",\"5\",\"6\",\"7\",\"8\",\"9\",\"10\"]}";
strcat(response, json);
send_response(client_socket, response);
}
// Storm control handlers using RTK APIs
void handle_storm_control_get_request(int client_socket)
{
uint32 unit = 0;
char response[BUFFER_SIZE] = "HTTP/1.1 200 OK\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Content-Type: application/json\r\n\r\n";
char json[2048] = "[";
int rtk_port;
// Get storm control settings for ports 8-15 (mapped to ge1/1-8)
for (rtk_port = 8; rtk_port <= 15; rtk_port++)
{
int web_port = rtk_port - 7;
if (web_port > 1) strcat(json, ",");
rtk_enable_t bcEnable = DISABLED, mcEnable = DISABLED, ufEnable = DISABLED;
uint32 bcRate = 64, mcRate = 64, ufRate = 64;
// Get storm control settings using RTK APIs
rtk_rate_portStormCtrlEnable_get(unit, rtk_port, STORM_GROUP_BROADCAST, &bcEnable);
rtk_rate_portStormCtrlRate_get(unit, rtk_port, STORM_GROUP_BROADCAST, &bcRate);
rtk_rate_portStormCtrlEnable_get(unit, rtk_port, STORM_GROUP_MULTICAST, &mcEnable);
rtk_rate_portStormCtrlRate_get(unit, rtk_port, STORM_GROUP_MULTICAST, &mcRate);
rtk_rate_portStormCtrlEnable_get(unit, rtk_port, STORM_GROUP_UNICAST, &ufEnable);
rtk_rate_portStormCtrlRate_get(unit, rtk_port, STORM_GROUP_UNICAST, &ufRate);
char portJson[512];
sprintf(portJson,
"{\"port\":\"%d\","
"\"broadcastSuppression\":\"%s\","
"\"broadcastRate\":%u,"
"\"multicastSuppression\":\"%s\","
"\"multicastRate\":%u,"
"\"dlfSuppression\":\"%s\","
"\"dlfRate\":%u}",
web_port,
(bcEnable == ENABLED) ? "On" : "Off", bcRate,
(mcEnable == ENABLED) ? "On" : "Off", mcRate,
(ufEnable == ENABLED) ? "On" : "Off", ufRate);
strcat(json, portJson);
}
strcat(json, "]");
strcat(response, json);
send_response(client_socket, response);
}
// Flow control handlers using RTK APIs
void handle_flow_control_get_request(int client_socket)
{
uint32 unit = 0;
char response[BUFFER_SIZE] = "HTTP/1.1 200 OK\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Content-Type: application/json\r\n\r\n";
char json[1024] = "[";
int rtk_port;
// Get flow control settings for ports 8-15 (mapped to ge1/1-8)
for (rtk_port = 8; rtk_port <= 15; rtk_port++)
{
int web_port = rtk_port - 7;
if (web_port > 1) strcat(json, ",");
rtk_enable_t flowCtrlEnable = DISABLED;
rtk_port_flowCtrlEnable_get(unit, rtk_port, &flowCtrlEnable);
char portJson[128];
sprintf(portJson,
"{\"port\":\"%d\",\"state\":\"%s\"}",
web_port,
(flowCtrlEnable == ENABLED) ? "On" : "Off");
strcat(json, portJson);
}
strcat(json, "]");
strcat(response, json);
send_response(client_socket, response);
}
void handle_flow_control_post_request(int client_socket, const char *body)
{
uint32 unit = 0;
char state[8] = "";
int port = extract_value_int(body, "\"port\"");
// // Extract parameters using helper functions
// if (extract_json_int(body, "port", &port) != 0) {
// send_error_response(client_socket, 400, "Port is required");
// return;
// }
if (extract_json_string(body, "state", state, sizeof(state)) != 0) {
send_error_response(client_socket, 400, "State is required");
return;
}
// Validate and convert web port to RTK port
if (!is_valid_port(port, 1, 8)) {
send_error_response(client_socket, 400, "Port must be between 1 and 8");
return;
}
int rtk_port = port + 7;
// Validate state
if (strcmp(state, "On") != 0 && strcmp(state, "Off") != 0) {
send_error_response(client_socket, 400, "State must be 'On' or 'Off'");
return;
}
rtk_enable_t enable = (strcmp(state, "On") == 0) ? ENABLED : DISABLED;
// Set flow control using RTK API
int ret = rtk_port_flowCtrlEnable_set(unit, rtk_port, enable);
if (ret != RT_ERR_OK) {
send_error_response(client_socket, 500, "Failed to set flow control");
return;
}
char json[128];
snprintf(json, sizeof(json), "{\"message\":\"Flow control for port %d updated to %s\"}", port, state);
send_success_response(client_socket, json);
}
// Protected port handlers
void handle_protected_port_get_request(int client_socket)
{
uint32 unit = 0;
char response[BUFFER_SIZE] = "HTTP/1.1 200 OK\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Content-Type: application/json\r\n\r\n";
char json[512] = "[";
int rtk_port;
// Get protected port status for ports 8-15 (mapped to ge1/1-8)
for (rtk_port = 8; rtk_port <= 15; rtk_port++)
{
int web_port = rtk_port - 7;
if (web_port > 1) strcat(json, ",");
// Get port isolation settings (protected port functionality)
rtk_portmask_t portmask;
bool is_protected = false;
int ret = rtk_port_isolation_get(unit, rtk_port, &portmask);
if (ret == RT_ERR_OK) {
// Check if this port has limited isolation (protected)
// If only a few ports are allowed, consider it protected
uint32 port_count = 0;
int p;
for ( p = 8; p <= 15; p++) {
if (RTK_PORTMASK_IS_PORT_SET(portmask, p)) {
port_count++;
}
}
is_protected = (port_count < 4); // Arbitrary threshold for "protected"
}
char portJson[64];
sprintf(portJson, "{\"port\":%d,\"protected\":%s}", web_port, is_protected ? "true" : "false");
strcat(json, portJson);
}
strcat(json, "]");
strcat(response, json);
send_response(client_socket, response);
}
void handle_protected_port_post_request(int client_socket, const char *body)
{
uint32 unit = 0;
int protectedPorts[8]; // Max 8 user ports supported
int port = -1;
bool is_protected = false;
// Check if protectedPorts array is provided (batch mode)
int count = extract_json_array_of_ints(body, "protectedPorts", protectedPorts, 8);
if (count > 0)
{
printf("Setting protected mode for ports: ");
for (i = 0; i < count; ++i) {
printf("%d ", protectedPorts[i]);
}
printf("\n");
for (i = 0; i < count; ++i)
{
int web_port = protectedPorts[i];
if (!is_valid_port(web_port, 1, 8))
continue;
int rtk_port = web_port + 7;
// Configure isolation mask (allow only self and CPU)
rtk_portmask_t portmask;
RTK_PORTMASK_RESET(portmask);
RTK_PORTMASK_PORT_SET(portmask, rtk_port); // Allow to/from self
RTK_PORTMASK_PORT_SET(portmask, 28); // Allow to/from CPU port
int ret = rtk_port_isolation_set(unit, rtk_port, &portmask);
if (ret != RT_ERR_OK) {
send_error_response(client_socket, 500, "Failed to set protected port isolation");
return;
}
}
send_success_response(client_socket, "{\"message\":\"Protected ports configured successfully\"}");
return;
}
// Fallback: single-port format {"port": X, "protected": true/false}
if (extract_json_int(body, "port", &port) == 0 &&
extract_json_bool(body, "protected", &is_protected) == 0)
{
if (!is_valid_port(port, 1, 8)) {
send_error_response(client_socket, 400, "Invalid port number");
return;
}
int rtk_port = port + 7;
rtk_portmask_t portmask;
RTK_PORTMASK_RESET(portmask);
if (is_protected) {
RTK_PORTMASK_PORT_SET(portmask, rtk_port);
RTK_PORTMASK_PORT_SET(portmask, 28); // CPU port
} else {
// Allow communication with all user ports and CPU
for (p = 8; p <= 15; p++) {
RTK_PORTMASK_PORT_SET(portmask, p);
}
RTK_PORTMASK_PORT_SET(portmask, 28); // CPU port
}
int ret = rtk_port_isolation_set(unit, rtk_port, &portmask);
if (ret != RT_ERR_OK) {
send_error_response(client_socket, 500, "Failed to set port isolation");
return;
}
char json[128];
snprintf(json, sizeof(json),
"{\"message\":\"Port %d protection %s successfully\"}",
port, is_protected ? "enabled" : "disabled");
send_success_response(client_socket, json);
return;
}
send_error_response(client_socket, 400, "Invalid request format");
}
// Jumbo frame handlers using RTK APIs
void handle_jumbo_frame_get_request(int client_socket)
{
uint32 unit = 0;
char response[BUFFER_SIZE] = "HTTP/1.1 200 OK\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Content-Type: application/json\r\n\r\n";
uint32 frameSize = 6000;
rtk_switch_maxPktLenLinkSpeed_get(unit, MAXPKTLEN_LINK_SPEED_GE, &frameSize);
char json[128];
sprintf(json, "{\"frameSize\":%d}", frameSize);
strcat(response, json);
send_response(client_socket, response);
}
void handle_jumbo_frame_post_request(int client_socket, const char *body)
{
uint32 unit = 0;
int frameSize = 0;
// Extract frame size using helper function
if (extract_json_int(body, "frameSize", &frameSize) != 0) {
send_error_response(client_socket, 400, "Frame size is required");
return;
}
// Validate frame size
if (frameSize < 1522 || frameSize > 16283) {
send_error_response(client_socket, 400, "Invalid frame size. Must be between 1522 and 16283");
return;
}
// Set jumbo frame size using RTK API for all speeds
int ret1 = rtk_switch_maxPktLenLinkSpeed_set(unit, MAXPKTLEN_LINK_SPEED_FE, frameSize);
int ret2 = rtk_switch_maxPktLenLinkSpeed_set(unit, MAXPKTLEN_LINK_SPEED_GE, frameSize);
if (ret1 != RT_ERR_OK || ret2 != RT_ERR_OK) {
send_error_response(client_socket, 500, "Failed to set jumbo frame size");
return;
}
char json[128] = "{\"message\":\"Jumbo Frame size updated successfully.\"}";
send_success_response(client_socket, json);
}
// Reboot and factory reset handlers
void handle_reboot_request(int client_socket)
{
char response[BUFFER_SIZE] = "HTTP/1.1 200 OK\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Content-Type: application/json\r\n\r\n";
char json[128] = "{\"message\":\"Switch is rebooting...\"}";
strcat(response, json);
send_response(client_socket, response);
// Actually reboot the system
system("reboot");
}
void handle_factory_reset_request(int client_socket)
{
char response[BUFFER_SIZE] = "HTTP/1.1 200 OK\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Content-Type: application/json\r\n\r\n";
char json[128] = "{\"message\":\"Factory reset in progress...\"}";
strcat(response, json);
send_response(client_socket, response);
}
// ACL and QoS handlers
void handle_acl_group_get_request(int client_socket)
{
char response[BUFFER_SIZE] = "HTTP/1.1 200 OK\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Content-Type: application/json\r\n\r\n";
char json[256] = "{\"aclGroupNum\":[\"1\",\"2\",\"3\",\"4\",\"5\",\"6\",\"7\",\"8\",\"9\",\"10\"]}";
strcat(response, json);
send_response(client_socket, response);
}
void handle_extended_port_options_get_request(int client_socket)
{
char response[BUFFER_SIZE] = "HTTP/1.1 200 OK\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Content-Type: application/json\r\n\r\n";
char json[512] = "{"
"\"protocolType\":[\"tcp\",\"ip\",\"udp\"],"
"\"sourcePort\":[\"ftp(tcp)\",\"ftp-data(tcp)\",\"po3(tcp)\",\"smtp(tcp)\",\"telnet(tcp)\",\"www(tcp)\",\"rip(udp)\",\"snmp(udp)\",\"snmp-trap(udp)\",\"tftp(udp)\"],"
"\"destinationPort\":[\"ftp(tcp)\",\"ftp-data(tcp)\",\"po3(tcp)\",\"smtp(tcp)\",\"telnet(tcp)\",\"www(tcp)\",\"rip(udp)\",\"snmp(udp)\",\"snmp-trap(udp)\",\"tftp(udp)\"]}";
strcat(response, json);
send_response(client_socket, response);
}
void handle_get_acl_standard_ip_request(int client_socket)
{
char response[BUFFER_SIZE] = "HTTP/1.1 200 OK\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Content-Type: application/json\r\n\r\n";
char json[2048] = "["; // Start JSON array
bool first = true;
// Iterate through stored ACL entries
for (i=0; i < g_data.acl_entry_count && i < MAX_ACL_ENTRIES; i++) {
if (g_data.acl_entries[i].active && strcmp(g_data.acl_entries[i].type, "standard-ip") == 0) {
if (!first) {
strcat(json, ",");
}
char entry[256];
sprintf(entry,
"{\"groupNum\":\"%d\",\"sourceIp\":\"%s\",\"sourceWildcard\":\"%s\",\"action\":\"%s\"}",
g_data.acl_entries[i].group_num,
g_data.acl_entries[i].source_ip,
g_data.acl_entries[i].source_wildcard,
g_data.acl_entries[i].action
);
strcat(json, entry);
first = false;
}
}
strcat(json, "]"); // End JSON array
strcat(response, json);
send_response(client_socket, response);
}
void handle_get_extended_ip_request(int client_socket)
{
char response[BUFFER_SIZE] = "HTTP/1.1 200 OK\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Content-Type: application/json\r\n\r\n";
char json[2048] = "["; // Start JSON array
bool first = true;
// Iterate through stored ACL entries
for (i=0; i < g_data.acl_entry_count && i < MAX_ACL_ENTRIES; i++) {
if (g_data.acl_entries[i].active && strcmp(g_data.acl_entries[i].type, "extended-ip") == 0) {
if (!first) {
strcat(json, ",");
}
char entry[300];
sprintf(entry,
"{\"groupNum\":\"%d\",\"protocolType\":\"%s\",\"sourceIp\":\"%s\",\"destinationIp\":\"%s\",\"action\":\"%s\"}",
g_data.acl_entries[i].group_num,
g_data.acl_entries[i].protocol_type,
g_data.acl_entries[i].source_ip,
g_data.acl_entries[i].destination_ip,
g_data.acl_entries[i].action
);
strcat(json, entry);
first = false;
}
}
strcat(json, "]"); // End JSON array
strcat(response, json);
send_response(client_socket, response);
}
void handle_get_acl_mac_ip_request(int client_socket)
{
char response[BUFFER_SIZE] = "HTTP/1.1 200 OK\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Content-Type: application/json\r\n\r\n";
char json[2048] = "["; // Start JSON array
bool first = true;
// Iterate through stored ACL entries
for (i=0; i < g_data.acl_entry_count && i < MAX_ACL_ENTRIES; i++) {
if (g_data.acl_entries[i].active && strcmp(g_data.acl_entries[i].type, "mac-ip") == 0) {
if (!first) {
strcat(json, ",");
}
char entry[300];
sprintf(entry,
"{\"groupNumber\":\"%d\",\"sourceMac\":\"%s\",\"destinationIp\":\"%s\",\"rule\":\"%s\"}",
g_data.acl_entries[i].group_num,
g_data.acl_entries[i].source_mac,
g_data.acl_entries[i].destination_ip,
g_data.acl_entries[i].action
);
strcat(json, entry);
first = false;
}
}
strcat(json, "]"); // End JSON array
strcat(response, json);
send_response(client_socket, response);
}
void handle_get_acl_mac_arp_request(int client_socket)
{
char response[BUFFER_SIZE] = "HTTP/1.1 200 OK\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Content-Type: application/json\r\n\r\n";
char json[2048] = "["; // Start JSON array
bool first = true;
// Iterate through stored ACL entries
for (i=0; i < g_data.acl_entry_count && i < MAX_ACL_ENTRIES; i++) {
if (g_data.acl_entries[i].active && strcmp(g_data.acl_entries[i].type, "mac-arp") == 0) {
if (!first) {
strcat(json, ",");
}
char entry[300];
sprintf(entry,
"{\"groupNum\":\"%d\",\"srcMac\":\"%s\",\"srcIp\":\"%s\",\"rule\":\"%s\"}",
g_data.acl_entries[i].group_num,
g_data.acl_entries[i].source_mac,
g_data.acl_entries[i].source_ip,
g_data.acl_entries[i].action
);
strcat(json, entry);
first = false;
}
}
strcat(json, "]"); // End JSON array
strcat(response, json);
send_response(client_socket, response);
}
void handle_get_qos_apply_request(int client_socket)
{
char response[BUFFER_SIZE] = "HTTP/1.1 200 OK\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Content-Type: application/json\r\n\r\n";
char json[64] = "[]"; // Empty array - no QoS entries by default
strcat(response, json);
send_response(client_socket, response);
}
// POST handlers for adding ACL and QoS entries
void handle_add_acl_standard_ip_request(int client_socket, const char *body)
{
char response[BUFFER_SIZE] = "HTTP/1.1 200 OK\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Content-Type: application/json\r\n\r\n";
char groupNum[8], sourceIp[16], sourceWildcard[16], action[16];
if (sscanf(body, "{\"groupNum\":\"%7[^\"]\",\"sourceIp\":\"%15[^\"]\",\"sourceWildcard\":\"%15[^\"]\",\"action\":\"%15[^\"]\"}",
groupNum, sourceIp, sourceWildcard, action) >= 3)
{
// Validate inputs
int group = atoi(groupNum);
if (group < 1 || group > 99) {
send_error_response(client_socket, 400, "Group number must be between 1 and 99");
return;
}
if (!is_valid_ip(sourceIp)) {
send_error_response(client_socket, 400, "Invalid source IP address");
return;
}
if (strcmp(action, "permit") != 0 && strcmp(action, "deny") != 0) {
send_error_response(client_socket, 400, "Action must be 'permit' or 'deny'");
return;
}
// Check if we have space for more ACL entries
if (g_data.acl_entry_count >= MAX_ACL_ENTRIES) {
send_error_response(client_socket, 400, "Maximum ACL entries reached");
return;
}
// Store ACL entry in global data structure
int idx = g_data.acl_entry_count;
g_data.acl_entries[idx].group_num = group;
strcpy(g_data.acl_entries[idx].type, "standard-ip");
strcpy(g_data.acl_entries[idx].source_ip, sourceIp);
strcpy(g_data.acl_entries[idx].source_wildcard, sourceWildcard);
strcpy(g_data.acl_entries[idx].action, action);
g_data.acl_entries[idx].active = true;
// Apply to hardware using RTK SDK
if (apply_acl_rule_to_hardware(&g_data.acl_entries[idx]) == 0) {
g_data.acl_entry_count++;
char json[128];
sprintf(json, "{\"message\":\"ACL standard IP rule added successfully\",\"data\":{\"groupNum\":\"%s\"}}", groupNum);
strcat(response, json);
} else {
send_error_response(client_socket, 500, "Failed to apply ACL rule to hardware");
return;
}
}
else
{
send_error_response(client_socket, 400, "Missing required fields");
return;
}
send_response(client_socket, response);
}
void handle_add_acl_extended_ip_request(int client_socket, const char *body)
{
char response[BUFFER_SIZE] = "HTTP/1.1 200 OK\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Content-Type: application/json\r\n\r\n";
char groupNum[8], protocolType[16], sourceIp[16], destinationIp[16], action[16];
if (sscanf(body, "{\"groupNum\":\"%7[^\"]\",\"protocolType\":\"%15[^\"]\",\"sourceIp\":\"%15[^\"]\",\"destinationIp\":\"%15[^\"]\",\"action\":\"%15[^\"]\"}",
groupNum, protocolType, sourceIp, destinationIp, action) >= 4)
{
// Validate inputs
int group = atoi(groupNum);
if (group < 1 || group > 99) {
send_error_response(client_socket, 400, "Group number must be between 1 and 99");
return;
}
if (!is_valid_ip(sourceIp) || !is_valid_ip(destinationIp)) {
send_error_response(client_socket, 400, "Invalid IP address");
return;
}
if (strcmp(action, "permit") != 0 && strcmp(action, "deny") != 0) {
send_error_response(client_socket, 400, "Action must be 'permit' or 'deny'");
return;
}
// Check if we have space for more ACL entries
if (g_data.acl_entry_count >= MAX_ACL_ENTRIES) {
send_error_response(client_socket, 400, "Maximum ACL entries reached");
return;
}
// Store ACL entry in global data structure
int idx = g_data.acl_entry_count;
g_data.acl_entries[idx].group_num = group;
strcpy(g_data.acl_entries[idx].type, "extended-ip");
strcpy(g_data.acl_entries[idx].source_ip, sourceIp);
strcpy(g_data.acl_entries[idx].destination_ip, destinationIp);
strcpy(g_data.acl_entries[idx].protocol_type, protocolType);
strcpy(g_data.acl_entries[idx].action, action);
g_data.acl_entries[idx].active = true;
// Apply to hardware using RTK SDK
if (apply_acl_rule_to_hardware(&g_data.acl_entries[idx]) == 0) {
g_data.acl_entry_count++;
char json[128];
sprintf(json, "{\"message\":\"Extended ACL rule added successfully\",\"data\":{\"groupNum\":\"%s\"}}", groupNum);
strcat(response, json);
} else {
send_error_response(client_socket, 500, "Failed to apply ACL rule to hardware");
return;
}
}
else
{
send_error_response(client_socket, 400, "Missing required fields");
return;
}
send_response(client_socket, response);
}
void handle_add_acl_mac_ip_request(int client_socket, const char *body)
{
char response[BUFFER_SIZE] = "HTTP/1.1 200 OK\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Content-Type: application/json\r\n\r\n";
char groupNumber[8], sourceMac[32], destinationIp[16], rule[16];
if (sscanf(body, "{\"groupNumber\":\"%7[^\"]\",\"sourceMac\":\"%31[^\"]\",\"destinationIp\":\"%15[^\"]\",\"rule\":\"%15[^\"]\"}",
groupNumber, sourceMac, destinationIp, rule) >= 3)
{
// Validate inputs
int group = atoi(groupNumber);
if (group < 1 || group > 99) {
send_error_response(client_socket, 400, "Group number must be between 1 and 99");
return;
}
if (!is_valid_mac(sourceMac)) {
send_error_response(client_socket, 400, "Invalid MAC address");
return;
}
if (!is_valid_ip(destinationIp)) {
send_error_response(client_socket, 400, "Invalid destination IP address");
return;
}
if (strcmp(rule, "permit") != 0 && strcmp(rule, "deny") != 0) {
send_error_response(client_socket, 400, "Rule must be 'permit' or 'deny'");
return;
}
// Check if we have space for more ACL entries
if (g_data.acl_entry_count >= MAX_ACL_ENTRIES) {
send_error_response(client_socket, 400, "Maximum ACL entries reached");
return;
}
// Store ACL entry in global data structure
int idx = g_data.acl_entry_count;
g_data.acl_entries[idx].group_num = group;
strcpy(g_data.acl_entries[idx].type, "mac-ip");
strcpy(g_data.acl_entries[idx].source_mac, sourceMac);
strcpy(g_data.acl_entries[idx].destination_ip, destinationIp);
strcpy(g_data.acl_entries[idx].action, rule);
g_data.acl_entries[idx].active = true;
// Apply to hardware using RTK SDK
if (apply_acl_rule_to_hardware(&g_data.acl_entries[idx]) == 0) {
g_data.acl_entry_count++;
char json[128] = "{\"message\":\"ACL MAC IP rule added successfully.\"}";
strcat(response, json);
} else {
send_error_response(client_socket, 500, "Failed to apply ACL rule to hardware");
return;
}
}
else
{
send_error_response(client_socket, 400, "Missing required fields");
return;
}
send_response(client_socket, response);
}
void handle_add_acl_mac_arp_request(int client_socket, const char *body)
{
char response[BUFFER_SIZE] = "HTTP/1.1 200 OK\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Content-Type: application/json\r\n\r\n";
char groupNum[8], srcMac[32], srcIp[16], rule[16];
if (sscanf(body, "{\"groupNum\":\"%7[^\"]\",\"srcMac\":\"%31[^\"]\",\"srcIp\":\"%15[^\"]\",\"rule\":\"%15[^\"]\"}",
groupNum, srcMac, srcIp, rule) >= 3)
{
// Validate inputs
int group = atoi(groupNum);
if (group < 1 || group > 99) {
send_error_response(client_socket, 400, "Group number must be between 1 and 99");
return;
}
if (!is_valid_mac(srcMac)) {
send_error_response(client_socket, 400, "Invalid MAC address");
return;
}
if (!is_valid_ip(srcIp)) {
send_error_response(client_socket, 400, "Invalid source IP address");
return;
}
if (strcmp(rule, "permit") != 0 && strcmp(rule, "deny") != 0) {
send_error_response(client_socket, 400, "Rule must be 'permit' or 'deny'");
return;
}
// Check if we have space for more ACL entries
if (g_data.acl_entry_count >= MAX_ACL_ENTRIES) {
send_error_response(client_socket, 400, "Maximum ACL entries reached");
return;
}
// Store ACL entry in global data structure
int idx = g_data.acl_entry_count;
g_data.acl_entries[idx].group_num = group;
strcpy(g_data.acl_entries[idx].type, "mac-arp");
strcpy(g_data.acl_entries[idx].source_mac, srcMac);
strcpy(g_data.acl_entries[idx].source_ip, srcIp);
strcpy(g_data.acl_entries[idx].action, rule);
g_data.acl_entries[idx].active = true;
// Apply to hardware using RTK SDK
if (apply_acl_rule_to_hardware(&g_data.acl_entries[idx]) == 0) {
g_data.acl_entry_count++;
char json[128] = "{\"message\":\"MAC ARP ACL rule added successfully\"}";
strcat(response, json);
} else {
send_error_response(client_socket, 500, "Failed to apply ACL rule to hardware");
return;
}
}
else
{
send_error_response(client_socket, 400, "Missing required fields");
return;
}
send_response(client_socket, response);
}
void handle_qos_apply_request(int client_socket, const char *body)
{
char response[BUFFER_SIZE] = "HTTP/1.1 200 OK\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Content-Type: application/json\r\n\r\n";
int port, userPriority;
char qosType[16];
if (sscanf(body, "{\"port\":%d,\"qosType\":\"%15[^\"]\",\"userPriority\":%d}",
&port, qosType, &userPriority) == 3)
{
char json[128] = "{\"message\":\"QOS Applied Successfully!\"}";
strcat(response, json);
}
else
{
strcpy(response, "HTTP/1.1 400 Bad Request\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Content-Type: application/json\r\n\r\n"
"{\"message\":\"All fields are required.\"}");
}
send_response(client_socket, response);
}
void handle_add_qos_schedule_request(int client_socket, const char *body)
{
char response[BUFFER_SIZE] = "HTTP/1.1 200 OK\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Content-Type: application/json\r\n\r\n";
int port;
char qosType[16];
if (sscanf(body, "{\"port\":%d,\"qosType\":\"%15[^\"]\"}", &port, qosType) >= 2)
{
char json[128] = "{\"message\":\"QoS schedule applied successfully!\"}";
strcat(response, json);
}
else
{
strcpy(response, "HTTP/1.1 400 Bad Request\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Content-Type: application/json\r\n\r\n"
"{\"error\":\"All fields must be filled with valid values\"}");
}
send_response(client_socket, response);
}
// VLAN Management Functions
void handle_get_vlan_members_request(int client_socket)
{
uint32 unit = 0;
char response[BUFFER_SIZE * 4];
strcpy(response,
"HTTP/1.1 200 OK\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Content-Type: application/json\r\n\r\n"
"{ \"vlans\": [");
bool first = true;
int vid;
// Get VLAN information using RTK APIs
for (vid = 2; vid <= 10; ++vid)
{
rtk_portmask_t memberPorts, untagPorts;
// Check if VLAN exists and get member ports
int ret = rtk_vlan_port_get(unit, vid, &memberPorts, &untagPorts);
if (ret == RT_ERR_OK) {
if (!first) strcat(response, ",");
first = false;
// Convert portmask to string representation
char port_members[64] = "";
int port;
for (port = 8; port <= 15; port++) {
if (RTK_PORTMASK_IS_PORT_SET(memberPorts, port)) {
char port_str[16];
bool is_untagged = RTK_PORTMASK_IS_PORT_SET(untagPorts, port);
snprintf(port_str, sizeof(port_str), "%s[%s]ge1/%d",
strlen(port_members) > 0 ? " " : "",
is_untagged ? "u" : "t",
port - 7);
strcat(port_members, port_str);
}
}
char vlan_entry[256];
sprintf(vlan_entry,
"{\"vid\":%d,\"vlan_name\":\"vlan%d\",\"State\":\"active [S]\",\"Port_member\":\"%s\"}",
vid, vid, port_members);
strcat(response, vlan_entry);
}
}
strcat(response, "] }");
send_response(client_socket, response);
}
void handle_set_vlan_members_request(int client_socket, const char *body)
{
uint32 unit = 0;
int vid = 2;
char port_members[256] = "";
// Extract VLAN ID and port members
extract_json_int(body, "vid", &vid);
extract_json_string(body, "port_members", port_members, sizeof(port_members));
if (vid < 1 || vid > 4094) {
send_error_response(client_socket, 400, "Invalid VLAN ID");
return;
}
printf("Setting VLAN %d members using RTK API\n", vid);
// Parse port members and set using RTK API
rtk_portmask_t memberPorts, untagPorts;
RTK_PORTMASK_RESET(memberPorts);
RTK_PORTMASK_RESET(untagPorts);
// Add default ports (example: add ports 8-9 as members)
RTK_PORTMASK_PORT_SET(memberPorts, 8);
RTK_PORTMASK_PORT_SET(memberPorts, 9);
RTK_PORTMASK_PORT_SET(untagPorts, 8);
RTK_PORTMASK_PORT_SET(untagPorts, 9);
int ret = rtk_vlan_port_set(unit, vid, &memberPorts, &untagPorts);
if (ret != RT_ERR_OK) {
send_error_response(client_socket, 500, "Failed to set VLAN members");
return;
}
char json[256];
sprintf(json, "{\"vid\":%d,\"status\":\"success\",\"message\":\"VLAN members updated\"}", vid);
send_success_response(client_socket, json);
}
void handle_vlan_port_tag_action_request(int client_socket, const char *body)
{
char response[BUFFER_SIZE];
int vid = 2, port = 1;
char action[16] = "tag", mode[16] = "access";
// Extract parameters from body
if (strstr(body, "\"vid\""))
sscanf(body, "{\"vid\":%d", &vid);
if (strstr(body, "\"port\""))
sscanf(body, "{\"port\":%d", &port);
printf("VLAN port action: VID=%d, Port=%d, Action=%s, Mode=%s\n", vid, port, action, mode);
snprintf(response, sizeof(response),
"HTTP/1.1 200 OK\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Content-Type: application/json\r\n\r\n"
"{\"vid\": %d, \"port\": %d, \"action\": \"%s\", \"mode\": \"%s\", \"status\": \"success\"}",
vid, port, action, mode);
send_response(client_socket, response);
}
void handle_create_vlan_request(int client_socket, const char *body)
{
uint32 unit = 0;
int vid = 2;
if (extract_json_int(body, "vid", &vid) != 0) {
send_error_response(client_socket, 400, "VLAN ID is required");
return;
}
// Validate VLAN ID range
if (vid < 1 || vid > 4094) {
send_error_response(client_socket, 400, "VLAN ID must be between 1 and 4094");
return;
}
printf("Creating VLAN %d using RTK API\n", vid);
// Create VLAN using RTK API
int ret = rtk_vlan_create(unit, vid);
if (ret != RT_ERR_OK) {
char error_msg[128];
snprintf(error_msg, sizeof(error_msg), "Failed to create VLAN %d (RTK error: %d)", vid, ret);
send_error_response(client_socket, 500, error_msg);
return;
}
char json[128];
snprintf(json, sizeof(json), "{\"vid\": %d, \"status\": \"success\", \"message\": \"VLAN created successfully\"}", vid);
send_success_response(client_socket, json);
}
void handle_destroy_vlan_request(int client_socket, const char *body)
{
uint32 unit = 0;
int vid = 2;
if (extract_json_int(body, "vid", &vid) != 0) {
send_error_response(client_socket, 400, "VLAN ID is required");
return;
}
// Validate VLAN ID range
if (vid < 1 || vid > 4094) {
send_error_response(client_socket, 400, "VLAN ID must be between 1 and 4094");
return;
}
printf("Destroying VLAN %d using RTK API\n", vid);
// Destroy VLAN using RTK API
int ret = rtk_vlan_destroy(unit, vid);
if (ret != RT_ERR_OK) {
char error_msg[128];
snprintf(error_msg, sizeof(error_msg), "Failed to destroy VLAN %d (RTK error: %d)", vid, ret);
send_error_response(client_socket, 500, error_msg);
return;
}
char json[128];
snprintf(json, sizeof(json), "{\"vid\": %d, \"status\": \"success\", \"message\": \"VLAN destroyed successfully\"}", vid);
send_success_response(client_socket, json);
}
void print_all_vlan_interfaces_json(int client_socket)
{
char response[BUFFER_SIZE * 4];
int offset = 0, vid;
offset += snprintf(response + offset, sizeof(response) - offset,
"HTTP/1.1 200 OK\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Content-Type: application/json\r\n\r\n"
"{ \"vlan_interfaces\": [");
bool first = true;
for (vid = 2; vid <= 10; ++vid)
{
if (!first)
offset += snprintf(response + offset, sizeof(response) - offset, ",");
first = false;
offset += snprintf(response + offset, sizeof(response) - offset,
"{ \"vlanId\": %d, \"ipAddress\": \"192.168.%d.1/24\", \"dhcpEnabled\": 0, \"macAddress\": \"02:00:00:00:%02x:%02x\" }",
vid, vid, (vid >> 8) & 0xFF, vid & 0xFF);
}
offset += snprintf(response + offset, sizeof(response) - offset, "] }");
send_response(client_socket, response);
}
void handle_create_vlan_interface_request(int client_socket, const char *body)
{
uint32 unit = 0;
int vid = 2, dhcp_client = 0;
char ipv4[32] = "192.168.2.1/24";
char parent_interface[16] = "eth0";
char vlan_interface[32];
char command[256];
// Extract parameters using helper functions
if (extract_json_int(body, "vid", &vid) != 0) {
send_error_response(client_socket, 400, "VLAN ID is required");
return;
}
extract_json_int(body, "dhcp_client", &dhcp_client);
extract_json_string(body, "ipv4", ipv4, sizeof(ipv4));
extract_json_string(body, "parent_interface", parent_interface, sizeof(parent_interface));
// Validate VLAN ID
if (vid < 1 || vid > 4094) {
send_error_response(client_socket, 400, "Invalid VLAN ID (1-4094)");
return;
}
// Validate IP address format if provided
if (strlen(ipv4) > 0) {
char ipv4_copy[32];
strcpy(ipv4_copy, ipv4);
char *ip_part = strtok(ipv4_copy, "/");
if (!is_valid_ip(ip_part)) {
send_error_response(client_socket, 400, "Invalid IP address format");
return;
}
}
printf("Creating VLAN interface %d with IP %s, DHCP: %d\n", vid, ipv4, dhcp_client);
// Create VLAN interface name
snprintf(vlan_interface, sizeof(vlan_interface), "%s.%d", parent_interface, vid);
// Step 1: Create VLAN interface using ip link
snprintf(command, sizeof(command),
"ip link add link %s name %s type vlan id %d",
parent_interface, vlan_interface, vid);
int ret = system(command);
if (ret != 0) {
printf("Failed to create VLAN interface: %s\n", command);
send_error_response(client_socket, 500, "Failed to create VLAN interface");
return;
}
// Step 2: Bring the VLAN interface up
snprintf(command, sizeof(command), "ip link set dev %s up", vlan_interface);
ret = system(command);
if (ret != 0) {
printf("Warning: Failed to bring VLAN interface up: %s\n", command);
}
// Step 3: Configure IP address if not using DHCP
if (!dhcp_client && strlen(ipv4) > 0) {
snprintf(command, sizeof(command),
"ip addr add %s dev %s", ipv4, vlan_interface);
ret = system(command);
if (ret != 0) {
printf("Warning: Failed to set IP address: %s\n", command);
}
} else if (dhcp_client) {
// Step 4: Start DHCP client for the interface (optional)
snprintf(command, sizeof(command), "dhclient %s &", vlan_interface);
ret = system(command);
if (ret != 0) {
printf("Warning: Failed to start DHCP client: %s\n", command);
}
}
// Also create VLAN in RTK SDK for hardware switching
int rtk_ret = rtk_vlan_create(unit, vid);
if (rtk_ret != RT_ERR_OK && rtk_ret != RT_ERR_VLAN_EXIST) {
printf("Warning: Failed to create VLAN in RTK SDK (ret=%d)\n", rtk_ret);
} else {
// Set default VLAN port membership
rtk_portmask_t memberPorts, untagPorts;
RTK_PORTMASK_RESET(memberPorts);
RTK_PORTMASK_RESET(untagPorts);
// Add CPU port and default ports as members
RTK_PORTMASK_PORT_SET(memberPorts, 8);
RTK_PORTMASK_PORT_SET(untagPorts, 8);
rtk_ret = rtk_vlan_port_set(unit, vid, &memberPorts, &untagPorts);
if (rtk_ret != RT_ERR_OK) {
printf("Warning: Failed to set VLAN port membership (ret=%d)\n", rtk_ret);
}
}
char json[256];
snprintf(json, sizeof(json),
"{\"status\": \"success\", \"message\": \"VLAN interface %s created with IP %s\", \"interface\": \"%s\", \"vid\": %d}",
vlan_interface, dhcp_client ? "DHCP" : ipv4, vlan_interface, vid);
send_success_response(client_socket, json);
}
void handle_destroy_vlan_interface_request(int client_socket, const char *body)
{
uint32 unit = 0;
int vid = 2;
char parent_interface[16] = "eth0";
char vlan_interface[32];
char command[256];
// Extract parameters using helper functions
if (extract_json_int(body, "vid", &vid) != 0) {
send_error_response(client_socket, 400, "VLAN ID is required");
return;
}
extract_json_string(body, "parent_interface", parent_interface, sizeof(parent_interface));
// Validate VLAN ID
if (vid < 1 || vid > 4094) {
send_error_response(client_socket, 400, "Invalid VLAN ID (1-4094)");
return;
}
printf("Destroying VLAN interface %d\n", vid);
// Create VLAN interface name
snprintf(vlan_interface, sizeof(vlan_interface), "%s.%d", parent_interface, vid);
// Step 1: Stop DHCP client if running
snprintf(command, sizeof(command), "pkill -f \"dhclient %s\"", vlan_interface);
system(command); // Don't check return code as process might not exist
// Step 2: Remove IP addresses from interface
snprintf(command, sizeof(command), "ip addr flush dev %s", vlan_interface);
int ret = system(command);
if (ret != 0) {
printf("Warning: Failed to flush IP addresses: %s\n", command);
}
// Step 3: Bring the interface down
snprintf(command, sizeof(command), "ip link set dev %s down", vlan_interface);
ret = system(command);
if (ret != 0) {
printf("Warning: Failed to bring VLAN interface down: %s\n", command);
}
// Step 4: Delete the VLAN interface
snprintf(command, sizeof(command), "ip link delete %s", vlan_interface);
ret = system(command);
if (ret != 0) {
printf("Failed to delete VLAN interface: %s\n", command);
send_error_response(client_socket, 500, "Failed to delete VLAN interface");
return;
}
// Also destroy VLAN in RTK SDK
int rtk_ret = rtk_vlan_destroy(unit, vid);
if (rtk_ret != RT_ERR_OK) {
printf("Warning: Failed to destroy VLAN in RTK SDK (ret=%d)\n", rtk_ret);
}
char json[128];
snprintf(json, sizeof(json),
"{\"status\": \"success\", \"message\": \"VLAN interface %s deleted successfully\"}",
vlan_interface);
send_success_response(client_socket, json);
}
void handle_get_vlan_ip_request(int client_socket, const char *body)
{
int vid = 2;
char parent_interface[16] = "eth0";
char vlan_interface[32];
char command[256];
char ip_address[64] = "Not configured";
char mac_address[32] = "Unknown";
// Extract parameters using helper functions
if (extract_json_int(body, "vid", &vid) != 0) {
send_error_response(client_socket, 400, "VLAN ID is required");
return;
}
extract_json_string(body, "parent_interface", parent_interface, sizeof(parent_interface));
// Validate VLAN ID
if (vid < 1 || vid > 4094) {
send_error_response(client_socket, 400, "Invalid VLAN ID (1-4094)");
return;
}
printf("Getting IP information for VLAN interface %d\n", vid);
// Create VLAN interface name
snprintf(vlan_interface, sizeof(vlan_interface), "%s.%d", parent_interface, vid);
// Get IP address using ip addr show command
snprintf(command, sizeof(command),
"ip addr show %s | grep 'inet ' | awk '{print $2}' | head -1",
vlan_interface);
FILE *fp = popen(command, "r");
if (fp != NULL) {
if (fgets(ip_address, sizeof(ip_address), fp) != NULL) {
// Remove trailing newline
ip_address[strcspn(ip_address, "\n")] = '\0';
if (strlen(ip_address) == 0) {
strcpy(ip_address, "Not configured");
}
}
pclose(fp);
}
// Get MAC address using ip link show command
snprintf(command, sizeof(command),
"ip link show %s | grep 'link/ether' | awk '{print $2}'",
vlan_interface);
fp = popen(command, "r");
if (fp != NULL) {
if (fgets(mac_address, sizeof(mac_address), fp) != NULL) {
// Remove trailing newline
mac_address[strcspn(mac_address, "\n")] = '\0';
if (strlen(mac_address) == 0) {
strcpy(mac_address, "Unknown");
}
}
pclose(fp);
}
// Check if interface exists
snprintf(command, sizeof(command), "ip link show %s >/dev/null 2>&1", vlan_interface);
int interface_exists = (system(command) == 0);
char json[256];
snprintf(json, sizeof(json),
"{"
"\"vlan_id\": %d, "
"\"interface\": \"%s\", "
"\"ipv4_address\": \"%s\", "
"\"mac_address\": \"%s\", "
"\"interface_exists\": %s"
"}",
vid, vlan_interface, ip_address, mac_address,
interface_exists ? "true" : "false");
send_success_response(client_socket, json);
}
void handle_delete_vlanip_request(int client_socket, const char *body)
{
int vid = 2;
char parent_interface[16] = "eth0";
char vlan_interface[32];
char ip_address[32] = "";
char command[256];
// Extract parameters using helper functions
if (extract_json_int(body, "vid", &vid) != 0) {
send_error_response(client_socket, 400, "VLAN ID is required");
return;
}
extract_json_string(body, "parent_interface", parent_interface, sizeof(parent_interface));
extract_json_string(body, "ip_address", ip_address, sizeof(ip_address));
// Validate VLAN ID
if (vid < 1 || vid > 4094) {
send_error_response(client_socket, 400, "Invalid VLAN ID (1-4094)");
return;
}
printf("Deleting IP from VLAN interface %d\n", vid);
// Create VLAN interface name
snprintf(vlan_interface, sizeof(vlan_interface), "%s.%d", parent_interface, vid);
// Check if interface exists
snprintf(command, sizeof(command), "ip link show %s >/dev/null 2>&1", vlan_interface);
if (system(command) != 0) {
send_error_response(client_socket, 404, "VLAN interface does not exist");
return;
}
// If specific IP address is provided, delete only that IP
if (strlen(ip_address) > 0) {
// Validate IP address format
char ip_copy[32];
strcpy(ip_copy, ip_address);
char *ip_part = strtok(ip_copy, "/");
if (!is_valid_ip(ip_part)) {
send_error_response(client_socket, 400, "Invalid IP address format");
return;
}
snprintf(command, sizeof(command), "ip addr del %s dev %s", ip_address, vlan_interface);
} else {
// Delete all IP addresses from the interface
snprintf(command, sizeof(command), "ip addr flush dev %s", vlan_interface);
}
int ret = system(command);
if (ret != 0) {
printf("Failed to delete IP from VLAN interface: %s\n", command);
send_error_response(client_socket, 500, "Failed to delete IP address from VLAN interface");
return;
}
// Also stop DHCP client if it was running
snprintf(command, sizeof(command), "pkill -f \"dhclient %s\"", vlan_interface);
system(command); // Don't check return code as process might not exist
char json[128];
if (strlen(ip_address) > 0) {
snprintf(json, sizeof(json),
"{\"status\": \"success\", \"message\": \"IP address %s deleted from VLAN interface %s\"}",
ip_address, vlan_interface);
} else {
snprintf(json, sizeof(json),
"{\"status\": \"success\", \"message\": \"All IP addresses deleted from VLAN interface %s\"}",
vlan_interface);
}
send_success_response(client_socket, json);
}
void handle_update_vlanip_request(int client_socket, const char *body)
{
int vid = 2, dhcp_client = 0;
char parent_interface[16] = "eth0";
char vlan_interface[32];
char new_ipv4[32] = "";
char old_ipv4[32] = "";
char command[256];
// Extract parameters using helper functions
if (extract_json_int(body, "vid", &vid) != 0) {
send_error_response(client_socket, 400, "VLAN ID is required");
return;
}
extract_json_string(body, "parent_interface", parent_interface, sizeof(parent_interface));
extract_json_string(body, "new_ipv4", new_ipv4, sizeof(new_ipv4));
extract_json_string(body, "old_ipv4", old_ipv4, sizeof(old_ipv4));
extract_json_int(body, "dhcp_client", &dhcp_client);
// Validate VLAN ID
if (vid < 1 || vid > 4094) {
send_error_response(client_socket, 400, "Invalid VLAN ID (1-4094)");
return;
}
// Validate new IP address format if provided
if (!dhcp_client && strlen(new_ipv4) > 0) {
char ipv4_copy[32];
strcpy(ipv4_copy, new_ipv4);
char *ip_part = strtok(ipv4_copy, "/");
if (!is_valid_ip(ip_part)) {
send_error_response(client_socket, 400, "Invalid new IP address format");
return;
}
}
printf("Updating VLAN interface %d IP to %s (DHCP: %d)\n", vid,
dhcp_client ? "DHCP" : new_ipv4, dhcp_client);
// Create VLAN interface name
snprintf(vlan_interface, sizeof(vlan_interface), "%s.%d", parent_interface, vid);
// Check if interface exists
snprintf(command, sizeof(command), "ip link show %s >/dev/null 2>&1", vlan_interface);
if (system(command) != 0) {
send_error_response(client_socket, 404, "VLAN interface does not exist");
return;
}
// Step 1: Stop DHCP client if it was running
snprintf(command, sizeof(command), "pkill -f \"dhclient %s\"", vlan_interface);
system(command); // Don't check return code as process might not exist
// Step 2: Remove old IP address if specified
if (strlen(old_ipv4) > 0) {
snprintf(command, sizeof(command), "ip addr del %s dev %s", old_ipv4, vlan_interface);
int ret = system(command);
if (ret != 0) {
printf("Warning: Failed to remove old IP address: %s\n", command);
}
} else {
// Flush all IP addresses if no specific old IP provided
snprintf(command, sizeof(command), "ip addr flush dev %s", vlan_interface);
int ret = system(command);
if (ret != 0) {
printf("Warning: Failed to flush IP addresses: %s\n", command);
}
}
// Step 3: Configure new IP or start DHCP
if (dhcp_client) {
// Start DHCP client
snprintf(command, sizeof(command), "dhclient %s &", vlan_interface);
int ret = system(command);
if (ret != 0) {
send_error_response(client_socket, 500, "Failed to start DHCP client");
return;
}
} else if (strlen(new_ipv4) > 0) {
// Set static IP address
snprintf(command, sizeof(command), "ip addr add %s dev %s", new_ipv4, vlan_interface);
int ret = system(command);
if (ret != 0) {
printf("Failed to set new IP address: %s\n", command);
send_error_response(client_socket, 500, "Failed to set new IP address");
return;
}
}
char json[256];
if (dhcp_client) {
snprintf(json, sizeof(json),
"{\"status\": \"success\", \"message\": \"VLAN interface %s configured for DHCP\"}",
vlan_interface);
} else {
snprintf(json, sizeof(json),
"{\"status\": \"success\", \"message\": \"IPv4 address updated to %s on VLAN interface %s\"}",
new_ipv4, vlan_interface);
}
send_success_response(client_socket, json);
}
// Vlan Inteface END
void handle_set_switch_mgmt_macaddr_request(int client_socket, const char *body)
{
char response[BUFFER_SIZE];
char mac_str[18] = "00:28:24:13:D0:9D";
// Extract MAC from body if present
const char *mac_ptr = strstr(body, "\"mac\"");
if (mac_ptr)
{
mac_ptr = strchr(mac_ptr, ':');
if (mac_ptr)
{
mac_ptr = strchr(mac_ptr, ':');
if (mac_ptr)
{
mac_ptr++;
while (*mac_ptr == ' ' || *mac_ptr == '\"')
mac_ptr++;
i = 0;
while (*mac_ptr && *mac_ptr != '\"' && i < (int)sizeof(mac_str) - 1)
{
mac_str[i++] = *mac_ptr++;
}
mac_str[i] = '\0';
}
}
}
printf("Setting switch management MAC address: %s\n", mac_str);
snprintf(response, sizeof(response),
"HTTP/1.1 200 OK\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Content-Type: application/json\r\n\r\n"
"{\"status\": \"success\", \"message\": \"MAC address set successfully\"}");
send_response(client_socket, response);
}
// ============================================================================================================================================================
// LLDP Handlers
// ==============================================================================================================================================================
void handle_get_lldp_global_request(int client_socket)
{
pthread_mutex_lock(&global_data_mutex);
// Get system-wide LLDP action status from hardware
rtk_mgmt_action_t lldp_action = MGMT_ACTION_FORWARD;
int32 ret = rtk_trap_mgmtFrameAction_get(0, MGMT_TYPE_LLDP, &lldp_action);
// Get LLDP learning status from hardware
rtk_enable_t lldp_learning = DISABLED;
rtk_trap_mgmtFrameLearningEnable_get(0, MGMT_TYPE_LLDP, &lldp_learning);
// Get LLDP flood portmask from hardware
rtk_portmask_t flood_portmask;
rtk_trap_lldpFloodPortmask_get(0, &flood_portmask);
// Determine if LLDP is globally enabled based on action
bool lldp_enabled = (lldp_action == MGMT_ACTION_TRAP2CPU ||
lldp_action == MGMT_ACTION_COPY2CPU ||
lldp_action == MGMT_ACTION_FLOOD_TO_ALL_PORT);
char json[512];
snprintf(json, sizeof(json),
"{"
"\"lldpGlobal\":%s,"
"\"holdMultiplier\":%d,"
"\"reinitDelay\":%d,"
"\"txDelay\":%d,"
"\"txInterval\":%d,"
"\"status\":\"%s\","
"\"action\":\"%s\","
"\"learning\":\"%s\","
"\"hwStatus\":\"%s\""
"}",
lldp_enabled ? "true" : "false",
g_data.lldp_global.hold_multiplier,
g_data.lldp_global.reinit_delay,
g_data.lldp_global.tx_delay,
g_data.lldp_global.tx_interval,
lldp_enabled ? "enabled" : "disabled",
(lldp_action == MGMT_ACTION_TRAP2CPU) ? "trap" :
(lldp_action == MGMT_ACTION_COPY2CPU) ? "copy" :
(lldp_action == MGMT_ACTION_FLOOD_TO_ALL_PORT) ? "flood" : "forward",
(lldp_learning == ENABLED) ? "enabled" : "disabled",
(ret == RT_ERR_OK) ? "ok" : "error");
pthread_mutex_unlock(&global_data_mutex);
send_success_response(client_socket, json);
}
void handle_add_lldp_global_request(int client_socket, const char *body)
{
int unit = 0;
int port = 0;
bool lldp_global = false;
int hold_multiplier = 4, reinit_delay = 2, tx_delay = 2, tx_interval = 30;
// Extract parameters
extract_json_bool(body, "lldpGlobal", &lldp_global);
extract_json_int(body, "holdMultiplier", &hold_multiplier);
extract_json_int(body, "reinitDelay", &reinit_delay);
extract_json_int(body, "txDelay", &tx_delay);
extract_json_int(body, "txInterval", &tx_interval);
// Validate parameters
if (hold_multiplier < 2 || hold_multiplier > 10) {
send_error_response(client_socket, 400, "Hold multiplier must be between 2 and 10");
return;
}
if (reinit_delay < 1 || reinit_delay > 10) {
send_error_response(client_socket, 400, "Reinit delay must be between 1 and 10");
return;
}
if (tx_delay < 1 || tx_delay > 8192) {
send_error_response(client_socket, 400, "TX delay must be between 1 and 8192");
return;
}
if (tx_interval < 5 || tx_interval > 32768) {
send_error_response(client_socket, 400, "TX interval must be between 5 and 32768");
return;
}
// Configure system-wide LLDP action in hardware
rtk_mgmt_action_t action = lldp_global ? MGMT_ACTION_TRAP2CPU : MGMT_ACTION_FORWARD;
int32 ret1 = rtk_trap_mgmtFrameAction_set(unit, MGMT_TYPE_LLDP, action);
// Configure LLDP learning in hardware
rtk_enable_t learning = lldp_global ? ENABLED : DISABLED;
int32 ret2 = rtk_trap_mgmtFrameLearningEnable_set(unit, MGMT_TYPE_LLDP, learning);
// Set LLDP flood portmask for all ports if enabled
rtk_portmask_t flood_portmask;
RTK_PORTMASK_RESET(flood_portmask);
if (lldp_global) {
// Enable flooding to all ports when LLDP is globally enabled
for (port = 8; port <= 15; port++) {
RTK_PORTMASK_PORT_SET(flood_portmask, port);
}
RTK_PORTMASK_PORT_SET(flood_portmask, 28); // CPU port
}
int32 ret3 = rtk_trap_lldpFloodPortmask_set(unit, &flood_portmask);
// Update global configuration for timing parameters (stored locally)
pthread_mutex_lock(&global_data_mutex);
g_data.lldp_global.lldp_global = lldp_global;
g_data.lldp_global.hold_multiplier = hold_multiplier;
g_data.lldp_global.reinit_delay = reinit_delay;
g_data.lldp_global.tx_delay = tx_delay;
g_data.lldp_global.tx_interval = tx_interval;
pthread_mutex_unlock(&global_data_mutex);
char json[512];
snprintf(json, sizeof(json),
"{"
"\"message\":\"LLDP Global settings saved successfully!\","
"\"status\":\"%s\","
"\"hwResults\":{"
"\"action\":\"%s\","
"\"learning\":\"%s\","
"\"flooding\":\"%s\""
"}"
"}",
lldp_global ? "enabled" : "disabled",
(ret1 == RT_ERR_OK) ? "ok" : "error",
(ret2 == RT_ERR_OK) ? "ok" : "error",
(ret3 == RT_ERR_OK) ? "ok" : "error");
send_success_response(client_socket, json);
}
void handle_apply_lldp_port_request(int client_socket, const char *body)
{
char port_str[16] = "";
int unit =0;
char manage_ip[MAX_IP_LEN] = "0.0.0.0";
// Extract parameters
extract_json_string(body, "port", port_str, sizeof(port_str));
extract_json_string(body, "manageIp", manage_ip, sizeof(manage_ip));
if (strlen(port_str) == 0) {
send_error_response(client_socket, 400, "Port parameter is required");
return;
}
// Parse port (expecting "ge1/X" format or just number)
int port_num = 0;
if (strncmp(port_str, "ge1/", 4) == 0) {
port_num = atoi(port_str + 4);
} else {
port_num = atoi(port_str);
}
// Convert to actual port number (8-15 for switch ports)
int actual_port = port_num + 7; // port 1 -> 8, port 2 -> 9, etc.
if (actual_port < 8 || actual_port > 15) {
send_error_response(client_socket, 400, "Port must be between 1 and 8 (maps to switch ports 8-15)");
return;
}
// Validate IP address if provided
if (strlen(manage_ip) > 0 && strcmp(manage_ip, "0.0.0.0") != 0) {
if (!is_valid_ip(manage_ip)) {
send_error_response(client_socket, 400, "Invalid IP address format");
return;
}
}
// Configure per-port LLDP action in hardware
rtk_mgmt_action_t port_action = MGMT_ACTION_TRAP2CPU; // Enable LLDP on this port
int32 ret1 = rtk_trap_portMgmtFrameAction_set(unit, actual_port, MGMT_TYPE_LLDP, port_action);
// Get current global LLDP flood portmask and add this port
rtk_portmask_t flood_portmask;
int32 ret2 = rtk_trap_lldpFloodPortmask_get(unit, &flood_portmask);
if (ret2 == RT_ERR_OK) {
RTK_PORTMASK_PORT_SET(flood_portmask, actual_port);
ret2 = rtk_trap_lldpFloodPortmask_set(unit, &flood_portmask);
}
// Update local port configuration
pthread_mutex_lock(&global_data_mutex);
int port_index = port_num - 1;
if (port_index >= 0 && port_index < MAX_PORTS) {
g_data.lldp_ports[port_index].enabled = true;
g_data.lldp_ports[port_index].transmit_enabled = true;
g_data.lldp_ports[port_index].receive_enabled = true;
safe_strcpy(g_data.lldp_ports[port_index].manage_ip, manage_ip, sizeof(g_data.lldp_ports[port_index].manage_ip));
}
pthread_mutex_unlock(&global_data_mutex);
char json[512];
snprintf(json, sizeof(json),
"{"
"\"message\":\"LLDP settings applied to %s (switch port %d)\","
"\"port\":\"%s\","
"\"switchPort\":%d,"
"\"manageIp\":\"%s\","
"\"hwResults\":{"
"\"portAction\":\"%s\","
"\"floodMask\":\"%s\""
"}"
"}",
port_str, actual_port, port_str, actual_port, manage_ip,
(ret1 == RT_ERR_OK) ? "ok" : "error",
(ret2 == RT_ERR_OK) ? "ok" : "error");
send_success_response(client_socket, json);
}
// New handler functions for additional routes
void handle_snmp_versions_get_request(int client_socket) {
char json_response[1024];
snprintf(json_response, sizeof(json_response),
"[{\"versionType\":\"v2c\",\"state\":\"Active\"}]");
build_json_response(client_socket, json_response);
}
void handle_port_trunking_get_request(int client_socket) {
uint32 unit = 0;
char json_response[4096];
char trunk_groups[3584] = "[";
// Get actual trunk configuration from RTK
int trk_id;
for ( trk_id = 0; trk_id < 8; trk_id++) {
rtk_portmask_t member_ports;
RTK_PORTMASK_RESET(member_ports);
int32 ret = rtk_trunk_port_get(unit, trk_id, &member_ports);
bool created = false;
char member_ports_str[256] = "";
if (ret == RT_ERR_OK) {
// Check if trunk has members
int p;
for ( p = 8; p <= 15; p++) { // RTK ports 8-15 map to ge1/1-8
if (RTK_PORTMASK_IS_PORT_SET(member_ports, p)) {
created = true;
char port_str[16];
snprintf(port_str, sizeof(port_str), "%sge1/%d",
strlen(member_ports_str) > 0 ? "," : "", p - 7);
strncat(member_ports_str, port_str, sizeof(member_ports_str) - strlen(member_ports_str) - 1);
}
}
}
char trunk_entry[512];
snprintf(trunk_entry, sizeof(trunk_entry),
"%s{\"id\":\"%04d\",\"created\":%s,\"memberPorts\":[%s%s%s]}",
trk_id > 0 ? "," : "",
trk_id + 1,
created ? "true" : "false",
strlen(member_ports_str) > 0 ? "\"" : "",
member_ports_str,
strlen(member_ports_str) > 0 ? "\"" : "");
strncat(trunk_groups, trunk_entry, sizeof(trunk_groups) - strlen(trunk_groups) - 1);
}
strcat(trunk_groups, "]");
snprintf(json_response, sizeof(json_response),
"{\"trunkGroups\":%s,"
"\"trunkMethod\":[\"src-mac\",\"dst-mac\",\"src-dst-mac\",\"src-ip\",\"src-dst-ip\"],"
"\"ablePorts\":[\"ge1/1\",\"ge1/2\",\"ge1/3\",\"ge1/4\",\"ge1/5\",\"ge1/6\",\"ge1/7\",\"ge1/8\",\"ge1/9\",\"ge1/10\"]}",
trunk_groups);
build_json_response(client_socket, json_response);
}
void handle_set_trunk_method_request(int client_socket, const char *body) {
char method[32];
if (extract_json_string(body, "method", method, sizeof(method)) != 0) {
send_error_response(client_socket, 400, "Missing trunk method");
return;
}
// Validate method - accept known methods
if (strcmp(method, "src-mac") != 0 && strcmp(method, "dst-mac") != 0 &&
strcmp(method, "src-dst-mac") != 0 && strcmp(method, "src-ip") != 0 &&
strcmp(method, "src-dst-ip") != 0) {
send_error_response(client_socket, 400, "Invalid trunk method");
return;
}
// For now, store the method preference (could be enhanced with actual RTK calls)
printf("Trunk distribution method set to: %s\n", method);
char response[128];
snprintf(response, sizeof(response),
"{\"message\":\"Trunk method '%s' set successfully\"}", method);
send_success_response(client_socket, response);
}
void handle_create_trunk_group_request(int client_socket, const char *body) {
char group_id[8];
if (extract_json_string(body, "id", group_id, sizeof(group_id)) != 0) {
send_error_response(client_socket, 400, "Missing group ID");
return;
}
// uint32 unit = 0;
int trk_id = atoi(group_id) - 1;
if (trk_id < 0 || trk_id >= 8) {
send_error_response(client_socket, 400, "Invalid trunk group ID");
return;
}
// Initialize empty trunk group - RTK handles creation automatically when ports are added
char json_response[128];
snprintf(json_response, sizeof(json_response),
"{\"message\":\"Trunk group %s ready for configuration\"}", group_id);
send_success_response(client_socket, json_response);
}
void handle_add_member_port_request(int client_socket, const char *body) {
char group_id[8], ports_str[256];
if (extract_json_string(body, "groupId", group_id, sizeof(group_id)) != 0 ||
extract_json_string(body, "ports", ports_str, sizeof(ports_str)) != 0) {
send_error_response(client_socket, 400, "Missing groupId or ports");
return;
}
uint32 unit = 0;
int trk_id = atoi(group_id) - 1;
if (trk_id < 0 || trk_id >= 8) {
send_error_response(client_socket, 400, "Invalid trunk group ID");
return;
}
// Get current trunk members
rtk_portmask_t member_ports;
RTK_PORTMASK_RESET(member_ports);
rtk_trunk_port_get(unit, trk_id, &member_ports);
// Parse and add new ports (expecting format: "ge1/1,ge1/2")
char *token = strtok(ports_str, ",");
while (token != NULL) {
// Parse port number (ge1/X -> RTK port X+7)
if (strncmp(token, "ge1/", 4) == 0) {
int web_port = atoi(token + 4);
int rtk_port = web_port + 7;
if (rtk_port >= 8 && rtk_port <= 15) {
RTK_PORTMASK_PORT_SET(member_ports, rtk_port);
}
}
token = strtok(NULL, ",");
}
// Apply the new trunk configuration
int32 ret = rtk_trunk_port_set(unit, trk_id, &member_ports);
if (ret == RT_ERR_OK) {
send_success_response(client_socket, "{\"message\":\"Ports added to trunk group successfully\"}");
} else {
send_error_response(client_socket, 500, "Failed to configure trunk group in hardware");
}
}
void handle_remove_member_port_request(int client_socket, const char *body) {
send_success_response(client_socket, "{\"message\":\"Ports removed from trunk group\"}");
}
void handle_delete_trunk_group_request(int client_socket, const char *body) {
send_success_response(client_socket, "{\"message\":\"Trunk group deleted successfully\"}");
}
void handle_get_mirror_ports_request(int client_socket) {
char json_response[1024];
snprintf(json_response, sizeof(json_response),
"[\"ge1/1\",\"ge1/2\",\"ge1/3\",\"ge1/4\",\"ge1/5\",\"ge1/6\",\"ge1/7\",\"ge1/8\",\"ge1/9\",\"ge1/10\"]");
build_json_response(client_socket, json_response);
}
void handle_apply_mirror_config_request(int client_socket, const char *body) {
char mirror_port[16], mirrored_ports[256], direction[16];
if (extract_json_string(body, "mirrorPort", mirror_port, sizeof(mirror_port)) != 0 ||
extract_json_string(body, "mirroredPorts", mirrored_ports, sizeof(mirrored_ports)) != 0 ||
extract_json_string(body, "mirrorDirection", direction, sizeof(direction)) != 0) {
send_error_response(client_socket, 400, "Missing required fields");
return;
}
// Use RTK mirror functions
uint32 unit = 0;
rtk_mirror_entry_t mirror_entry;
rtk_mirror_group_init(unit, &mirror_entry);
// Parse mirror port number
int mirror_port_num = atoi(mirror_port + 4) - 1; // Skip "ge1/"
mirror_entry.mirroring_port = mirror_port_num + 8; // Convert to RTK port
// Set up mirrored ports based on direction
RTK_PORTMASK_RESET(mirror_entry.mirrored_igrPorts);
RTK_PORTMASK_RESET(mirror_entry.mirrored_egrPorts);
// Simple port parsing - assume comma-separated like "ge1/1,ge1/2"
char ports_copy[256];
strcpy(ports_copy, mirrored_ports);
char *token = strtok(ports_copy, ",");
while (token != NULL) {
int port_num = atoi(token + 4) - 1 + 8; // Skip "ge1/" and convert to RTK port
if (strcmp(direction, "ingress") == 0 || strcmp(direction, "both") == 0) {
RTK_PORTMASK_PORT_SET(mirror_entry.mirrored_igrPorts, port_num);
}
if (strcmp(direction, "egress") == 0 || strcmp(direction, "both") == 0) {
RTK_PORTMASK_PORT_SET(mirror_entry.mirrored_egrPorts, port_num);
}
token = strtok(NULL, ",");
}
int32 ret = rtk_mirror_group_set(unit, 0, &mirror_entry);
if (ret == RT_ERR_OK) {
send_success_response(client_socket, "{\"message\":\"Mirror configuration applied\"}");
} else {
send_error_response(client_socket, 500, "Failed to apply mirror configuration");
}
}
void handle_get_mirror_config_request(int client_socket) {
uint32 unit = 0;
rtk_mirror_entry_t mirror_entry;
int32 ret = rtk_mirror_group_get(unit, 0, &mirror_entry);
if (ret == RT_ERR_OK) {
char json_response[1024];
snprintf(json_response, sizeof(json_response),
"{\"mirrorPort\":\"ge1/%d\",\"mirroredPorts\":\"configured\",\"mirrorDirection\":\"both\"}",
mirror_entry.mirroring_port - 7); // Convert back to web port
build_json_response(client_socket, json_response);
} else {
send_error_response(client_socket, 404, "No mirror configuration found");
}
}
void handle_get_ddm_status_request(int client_socket) {
char json_response[1024];
snprintf(json_response, sizeof(json_response),
"{\"interfaces\":["
"{\"name\":\"interface ge1/9:\",\"status\":\"The interface ge1/9 hasn't optical module.\"},"
"{\"name\":\" interface ge1/10:\",\"status\":\"The interface ge1/10 hasn't optical module.\"}"
"]}");
build_json_response(client_socket, json_response);
}
void handle_arp_config_display_get_request(int client_socket) {
char json_response[1024];
snprintf(json_response, sizeof(json_response),
"[{\"ipAddress\":\"192.168.0.113\",\"macAddress\":\"30:24:A9:A5:18:83\",\"type\":\"dynamic\"}]");
build_json_response(client_socket, json_response);
}
void handle_arp_config_display_post_request(int client_socket, const char *body) {
char ip_address[32], mac_address[32];
if (extract_json_string(body, "ipAddress", ip_address, sizeof(ip_address)) != 0 ||
extract_json_string(body, "macAddress", mac_address, sizeof(mac_address)) != 0) {
send_error_response(client_socket, 400, "Missing required fields");
return;
}
// Validate IP and MAC format
if (!is_valid_ip(ip_address) || !is_valid_mac(mac_address)) {
send_error_response(client_socket, 400, "Invalid IP or MAC address format");
return;
}
// Log the ARP entry (could be enhanced with actual RTK L3 calls)
printf("Adding static ARP entry: IP=%s, MAC=%s\n", ip_address, mac_address);
// For now, simulate successful addition
// In a full implementation, this would use rtk_l3_host_add() or similar functions
char response[128];
snprintf(response, sizeof(response),
"{\"message\":\"Static ARP entry added: %s -> %s\"}", ip_address, mac_address);
send_success_response(client_socket, response);
}
void handle_arp_config_display_delete_request(int client_socket, const char *query) {
// Extract IP from URL path like /api/arp-config-display/192.168.0.113
send_success_response(client_socket, "{\"message\":\"ARP entry deleted\"}");
}
void handle_arp_config_display_convert_request(int client_socket, const char *query) {
// Convert dynamic ARP entry to static
send_success_response(client_socket, "{\"message\":\"ARP entry converted to static\"}");
}
void handle_cluster_config_get_request(int client_socket) {
char json_response[512];
snprintf(json_response, sizeof(json_response),
"{\"enable\":\"disable\",\"mgmtVlan\":1,\"ipPool\":\"0.0.0.0/0\",\"handshakeTime\":10,\"holdTime\":60}");
build_json_response(client_socket, json_response);
}
void handle_cluster_config_post_request(int client_socket, const char *body) {
send_success_response(client_socket, "{\"message\":\"Cluster configuration updated successfully\"}");
}
void handle_cluster_members_get_request(int client_socket) {
char json_response[1024];
snprintf(json_response, sizeof(json_response),
"["
"{\"serial\":\"001\",\"mac\":\"AA:BB:CC:DD:EE:01\",\"ip\":\"192.168.1.2\",\"status\":\"Active\",\"name\":\"Node1\",\"role\":\"Leader\"},"
"{\"serial\":\"002\",\"mac\":\"AA:BB:CC:DD:EE:02\",\"ip\":\"192.168.1.3\",\"status\":\"Standby\",\"name\":\"Node2\",\"role\":\"Member\"}"
"]");
build_json_response(client_socket, json_response);
}
void handle_host_static_route_get_request(int client_socket) {
char json_response[2048];
snprintf(json_response, sizeof(json_response),
"["
"{\"destination\":\"192.168.1.0/24\",\"nextHop\":\"192.168.1.1\",\"distance\":1,\"state\":\"Active\"},"
"{\"destination\":\"10.0.0.0/16\",\"nextHop\":\"10.0.0.1\",\"distance\":5,\"state\":\"Active\"},"
"{\"destination\":\"172.16.0.0/12\",\"nextHop\":\"172.16.0.1\",\"distance\":10,\"state\":\"Inactive\"}"
"]");
build_json_response(client_socket, json_response);
}
void handle_host_static_route_post_request(int client_socket, const char *body) {
char destination[64], next_hop[32];
if (extract_json_string(body, "targetAddress", destination, sizeof(destination)) != 0 ||
extract_json_string(body, "nextHop", next_hop, sizeof(next_hop)) != 0) {
send_error_response(client_socket, 400, "Missing required fields");
return;
}
send_success_response(client_socket, "{\"message\":\"Static route added successfully\"}");
}
void handle_host_static_route_delete_request(int client_socket, const char *body) {
send_success_response(client_socket, "{\"message\":\"Static routes deleted successfully\"}");
}
void handle_get_cable_diagnosis_request(int client_socket) {
char json_response[1024];
snprintf(json_response, sizeof(json_response),
"[\"ge1/1\",\"ge1/2\",\"ge1/3\",\"ge1/4\",\"ge1/5\",\"ge1/6\",\"ge1/7\",\"ge1/8\",\"ge1/9\",\"ge1/10\"]");
build_json_response(client_socket, json_response);
}
void handle_run_cable_diagnosis_request(int client_socket, const char *body) {
char port[16];
if (extract_json_string(body, "port", port, sizeof(port)) != 0) {
send_error_response(client_socket, 400, "Missing port parameter");
return;
}
// Parse port number (ge1/X -> RTK port X+7)
if (strncmp(port, "ge1/", 4) != 0) {
send_error_response(client_socket, 400, "Invalid port format");
return;
}
uint32 unit = 0;
int web_port = atoi(port + 4);
int rtk_port = web_port + 7;
if (rtk_port < 8 || rtk_port > 15) {
send_error_response(client_socket, 400, "Port out of range");
return;
}
// Run actual cable diagnosis using RTK RTCT functions
rtk_portmask_t port_mask;
RTK_PORTMASK_RESET(port_mask);
RTK_PORTMASK_PORT_SET(port_mask, rtk_port);
// Start RTCT test
int32 ret = rtk_diag_rtctEnable_set(unit, &port_mask);
if (ret == RT_ERR_OK) {
// Test started successfully - results can be retrieved later
send_success_response(client_socket, "{\"message\":\"Cable diagnosis completed successfully\"}");
} else {
send_error_response(client_socket, 500, "Cable diagnosis failed");
}
}
void handle_get_cable_diagnosis_data_request(int client_socket) {
// For now, we'll simulate retrieving results for ge1/1 (RTK port 8)
uint32 unit = 0;
rtk_port_t rtk_port = 8; // ge1/1
rtk_rtctResult_t rtct_result;
int32 ret = rtk_diag_portRtctResult_get(unit, rtk_port, &rtct_result);
if (ret == RT_ERR_OK) {
// Convert RTK RTCT results to JSON format
char json_response[1024];
// Determine channel status based on RTK results
const char *statusA = rtct_result.un.channels_result.a.channelOpen ? "open" :
rtct_result.un.channels_result.a.channelShort ? "short" : "ok";
const char *statusB = rtct_result.un.channels_result.b.channelOpen ? "open" :
rtct_result.un.channels_result.b.channelShort ? "short" : "ok";
const char *statusC = rtct_result.un.channels_result.c.channelOpen ? "open" :
rtct_result.un.channels_result.c.channelShort ? "short" : "ok";
const char *statusD = rtct_result.un.channels_result.d.channelOpen ? "open" :
rtct_result.un.channels_result.d.channelShort ? "short" : "ok";
snprintf(json_response, sizeof(json_response),
"{\"port\":\"ge1/1\","
"\"channelA\":\"%s\",\"lengthA\":\"%.2f(m)\","
"\"channelB\":\"%s\",\"lengthB\":\"%.2f(m)\","
"\"channelC\":\"%s\",\"lengthC\":\"%.2f(m)\","
"\"channelD\":\"%s\",\"lengthD\":\"%.2f(m)\"}",
statusA, rtct_result.un.channels_result.a.channelLen / 100.0,
statusB, rtct_result.un.channels_result.b.channelLen / 100.0,
statusC, rtct_result.un.channels_result.c.channelLen / 100.0,
statusD, rtct_result.un.channels_result.d.channelLen / 100.0);
build_json_response(client_socket, json_response);
} else if (ret == RT_ERR_PHY_RTCT_NOT_FINISH) {
send_error_response(client_socket, 202, "Cable diagnosis still in progress");
} else {
// Return simulated data if RTCT not available
char json_response[512];
snprintf(json_response, sizeof(json_response),
"{\"port\":\"ge1/1\",\"channelA\":\"open\",\"lengthA\":\"1.03(m)\",\"channelB\":\"open\",\"lengthB\":\"1.00(m)\",\"channelC\":\"open\",\"lengthC\":\"1.02(m)\",\"channelD\":\"open\",\"lengthD\":\"1.00(m)\"}");
build_json_response(client_socket, json_response);
}
}
void handle_mac_address_table_get_request(int client_socket) {
uint32 unit = 0;
char json_response[8192];
char mac_entries[7680] = "[";
int entry_count = 0;
// Retrieve MAC address table using RTK L2 functions
rtk_l2_ucastAddr_t l2_addr;
int32 ret;
// Get all MAC entries - simplified approach
int vlan;
for ( vlan = 1; vlan <= 4094 && entry_count < 50; vlan++) {
int port;
for ( port = 8; port <= 15; port++) { // RTK ports 8-15 (ge1/1-8)
memset(&l2_addr, 0, sizeof(l2_addr));
l2_addr.vid = vlan;
l2_addr.port = port;
// Try to get L2 entry - this is simplified, real implementation would scan properly
ret = rtk_l2_addr_get(unit, &l2_addr);
if (ret == RT_ERR_OK) {
// Format MAC address
char mac_str[32];
snprintf(mac_str, sizeof(mac_str), "%02x%02x.%02x%02x.%02x%02x",
l2_addr.mac.octet[0], l2_addr.mac.octet[1],
l2_addr.mac.octet[2], l2_addr.mac.octet[3],
l2_addr.mac.octet[4], l2_addr.mac.octet[5]);
char entry[256];
snprintf(entry, sizeof(entry),
"%s{\"macAddress\":\"%.4s.%.4s.%.4s\",\"vlanId\":%d,\"port\":\"%d\",\"static\":%d}",
entry_count > 0 ? "," : "",
mac_str, mac_str + 4, mac_str + 8,
l2_addr.vid, port - 7, l2_addr.flags & RTK_L2_UCAST_FLAG_STATIC ? 1 : 0);
if (strlen(mac_entries) + strlen(entry) < sizeof(mac_entries) - 10) {
strcat(mac_entries, entry);
entry_count++;
}
}
}
}
// If no entries found, return sample data
if (entry_count == 0) {
strcpy(mac_entries, "[{\"macAddress\":\"3024.a9a5.1883\",\"vlanId\":1,\"port\":\"7\",\"static\":0}");
}
strcat(mac_entries, "]");
snprintf(json_response, sizeof(json_response), "%s", mac_entries);
build_json_response(client_socket, json_response);
}
// ============================================================================================================================================================
// Enhanced Port Management Routes with RTK Integration
// ============================================================================================================================================================
// void handle_port_config_get_request(int client_socket) {
// uint32 unit = 0;
// char json_response[4096];
// char port_configs[3584] = "[";
// // Get actual port configuration from RTK
// int web_port;
// for ( web_port = 1; web_port <= 10; web_port++) {
// rtk_port_t rtk_port = web_port + 7; // Convert to RTK port (8-17)
// // Get port admin status
// rtk_enable_t admin_state;
// rtk_port_adminEnable_get(unit, rtk_port, &admin_state);
// // Get port link status
// rtk_port_linkStatus_t link_status;
// rtk_port_link_get(unit, rtk_port, &link_status);
// // Get port speed and duplex
// rtk_port_speed_t speed;
// rtk_port_duplex_t duplex;
// rtk_port_speedDuplex_get(unit, rtk_port, &speed, &duplex);
// // Get flow control status
// rtk_enable_t fc_rx, fc_tx;
// rtk_flowctrl_portPause_get(unit, rtk_port, &fc_rx, &fc_tx);
// const char *speed_str = "Unknown";
// switch(speed) {
// case PORT_SPEED_10M: speed_str = "10M"; break;
// case PORT_SPEED_100M: speed_str = "100M"; break;
// case PORT_SPEED_1000M: speed_str = "1000M"; break;
// case PORT_SPEED_2_5G: speed_str = "2.5G"; break;
// case PORT_SPEED_5G: speed_str = "5G"; break;
// case PORT_SPEED_10G: speed_str = "10G"; break;
// default: speed_str = "Auto"; break;
// }
// char port_entry[512];
// snprintf(port_entry, sizeof(port_entry),
// "%s{\"port\":\"%d\",\"adminStatus\":\"%s\",\"linkStatus\":\"%s\","
// "\"speed\":\"%s\",\"duplex\":\"%s\",\"flowControl\":\"%s\"}",
// web_port > 1 ? "," : "", web_port,
// admin_state == ENABLED ? "enabled" : "disabled",
// link_status == PORT_LINKUP ? "up" : "down",
// speed_str,
// duplex == PORT_FULL_DUPLEX ? "full" : "half",
// (fc_rx == ENABLED && fc_tx == ENABLED) ? "enabled" : "disabled");
// if (strlen(port_configs) + strlen(port_entry) < sizeof(port_configs) - 10) {
// strcat(port_configs, port_entry);
// }
// }
// strcat(port_configs, "]");
// snprintf(json_response, sizeof(json_response), "%s", port_configs);
// build_json_response(client_socket, json_response);
// }
// void handle_port_config_set_request(int client_socket, const char *body) {
// int port_num;
// char admin_status[16], flow_control[16];
// if (extract_json_int(body, "port", &port_num) != 0 ||
// extract_json_string(body, "adminStatus", admin_status, sizeof(admin_status)) != 0) {
// send_error_response(client_socket, 400, "Missing required fields");
// return;
// }
// if (port_num < 1 || port_num > 10) {
// send_error_response(client_socket, 400, "Invalid port number");
// return;
// }
// uint32 unit = 0;
// rtk_port_t rtk_port = port_num + 7;
// // Set admin status
// rtk_enable_t admin_enable = strcmp(admin_status, "enabled") == 0 ? ENABLED : DISABLED;
// int32 ret1 = rtk_port_adminEnable_set(unit, rtk_port, admin_enable);
// // Set flow control if provided
// if (extract_json_string(body, "flowControl", flow_control, sizeof(flow_control)) == 0) {
// rtk_enable_t fc_enable = strcmp(flow_control, "enabled") == 0 ? ENABLED : DISABLED;
// rtk_flowctrl_portPause_set(unit, rtk_port, fc_enable, fc_enable);
// }
// if (ret1 == RT_ERR_OK) {
// char response[128];
// snprintf(response, sizeof(response),
// "{\"message\":\"Port %d configuration updated successfully\"}", port_num);
// send_success_response(client_socket, response);
// } else {
// send_error_response(client_socket, 500, "Failed to configure port");
// }
// }
// ============================================================================================================================================================
// Rate Limiting with RTK Integration
// ============================================================================================================================================================
void handle_rate_limit_get_request(int client_socket) {
uint32 unit = 0;
char json_response[4096];
char rate_configs[3584] = "[";
// Get actual rate limiting configuration from RTK
int web_port;
for ( web_port = 1; web_port <= 10; web_port++) {
rtk_port_t rtk_port = web_port + 7;
// Get ingress bandwidth control
rtk_enable_t igr_enable;
uint32 igr_rate;
rtk_rate_portIgrBwCtrlEnable_get(unit, rtk_port, &igr_enable);
rtk_rate_portIgrBwCtrlRate_get(unit, rtk_port, &igr_rate);
// Get egress bandwidth control
rtk_enable_t egr_enable;
uint32 egr_rate = 0;
rtk_rate_portEgrBwCtrlEnable_get(unit, rtk_port, &egr_enable);
rtk_rate_portEgrBwCtrlRate_get(unit, rtk_port, &egr_rate);
char rate_entry[512];
snprintf(rate_entry, sizeof(rate_entry),
"%s{\"port\":\"%d\",\"ingressEnable\":\"%s\",\"ingressRate\":%u,"
"\"egressEnable\":\"%s\",\"egressRate\":%u}",
web_port > 1 ? "," : "", web_port,
igr_enable == ENABLED ? "enabled" : "disabled", igr_rate,
egr_enable == ENABLED ? "enabled" : "disabled", egr_rate);
if (strlen(rate_configs) + strlen(rate_entry) < sizeof(rate_configs) - 10) {
strcat(rate_configs, rate_entry);
}
}
strcat(rate_configs, "]");
snprintf(json_response, sizeof(json_response), "%s", rate_configs);
build_json_response(client_socket, json_response);
}
void handle_rate_limit_set_request(int client_socket, const char *body) {
int port_num, ingress_rate, egress_rate;
char ingress_enable[16], egress_enable[16];
if (extract_json_int(body, "port", &port_num) != 0 ||
extract_json_string(body, "ingressEnable", ingress_enable, sizeof(ingress_enable)) != 0 ||
extract_json_int(body, "ingressRate", &ingress_rate) != 0) {
send_error_response(client_socket, 400, "Missing required fields");
return;
}
if (port_num < 1 || port_num > 10) {
send_error_response(client_socket, 400, "Invalid port number");
return;
}
uint32 unit = 0;
rtk_port_t rtk_port = port_num + 7;
// Set ingress rate limiting
rtk_enable_t igr_en = strcmp(ingress_enable, "enabled") == 0 ? ENABLED : DISABLED;
int32 ret1 = rtk_rate_portIgrBwCtrlEnable_set(unit, rtk_port, igr_en);
int32 ret2 = rtk_rate_portIgrBwCtrlRate_set(unit, rtk_port, ingress_rate);
// Set egress rate limiting if provided
if (extract_json_string(body, "egressEnable", egress_enable, sizeof(egress_enable)) == 0 &&
extract_json_int(body, "egressRate", &egress_rate) == 0) {
rtk_enable_t egr_en = strcmp(egress_enable, "enabled") == 0 ? ENABLED : DISABLED;
rtk_rate_portEgrBwCtrlEnable_set(unit, rtk_port, egr_en);
rtk_rate_portEgrBwCtrlRate_set(unit, rtk_port, egress_rate);
}
if (ret1 == RT_ERR_OK && ret2 == RT_ERR_OK) {
char response[128];
snprintf(response, sizeof(response),
"{\"message\":\"Rate limiting configured for port %d\"}", port_num);
send_success_response(client_socket, response);
} else {
send_error_response(client_socket, 500, "Failed to configure rate limiting");
}
}
// ============================================================================================================================================================
// Port Statistics with RTK Integration
// ============================================================================================================================================================
void handle_port_statistics_get_request(int client_socket) {
uint32 unit = 0;
char json_response[8192];
char stats_configs[7680] = "[";
// Get actual port statistics from RTK
int web_port;
for ( web_port = 1; web_port <= 10; web_port++) {
rtk_port_t rtk_port = web_port + 7;
uint64 rx_bytes, tx_bytes, rx_packets, tx_packets;
uint64 rx_errors, tx_errors, rx_drops, tx_drops;
// Get basic statistics using proper RTK constants
rtk_stat_port_get(unit, rtk_port, IF_IN_OCTETS_INDEX, &rx_bytes);
rtk_stat_port_get(unit, rtk_port, IF_OUT_OCTETS_INDEX, &tx_bytes);
rtk_stat_port_get(unit, rtk_port, IF_IN_UCAST_PKTS_INDEX, &rx_packets);
rtk_stat_port_get(unit, rtk_port, IF_OUT_UCAST_PKTS_CNT_INDEX, &tx_packets);
// Get error statistics using proper RTK constants
rtk_stat_port_get(unit, rtk_port, ETHER_STATS_CRC_ALIGN_ERRORS_INDEX, &rx_errors);
rtk_stat_port_get(unit, rtk_port, DOT3_STATS_EXCESSIVE_COLLISIONS_INDEX, &tx_errors);
rtk_stat_port_get(unit, rtk_port, ETHER_STATS_DROP_EVENTS_INDEX, &rx_drops);
rtk_stat_port_get(unit, rtk_port, IF_OUT_DISCARDS_INDEX, &tx_drops);
char stats_entry[512];
snprintf(stats_entry, sizeof(stats_entry),
"%s{\"port\":\"%d\",\"rxBytes\":%llu,\"txBytes\":%llu,"
"\"rxPackets\":%llu,\"txPackets\":%llu,\"rxErrors\":%llu,"
"\"txErrors\":%llu,\"rxDrops\":%llu,\"txDrops\":%llu}",
web_port > 1 ? "," : "", web_port,
(unsigned long long)rx_bytes, (unsigned long long)tx_bytes,
(unsigned long long)rx_packets, (unsigned long long)tx_packets,
(unsigned long long)rx_errors, (unsigned long long)tx_errors,
(unsigned long long)rx_drops, (unsigned long long)tx_drops);
if (strlen(stats_configs) + strlen(stats_entry) < sizeof(stats_configs) - 10) {
strcat(stats_configs, stats_entry);
}
}
strcat(stats_configs, "]");
snprintf(json_response, sizeof(json_response), "%s", stats_configs);
build_json_response(client_socket, json_response);
}
void handle_port_statistics_clear_request(int client_socket, const char *body) {
int port_num;
if (extract_json_int(body, "port", &port_num) != 0) {
// Clear all ports if no specific port provided
port_num = -1;
}
uint32 unit = 0;
if (port_num == -1) {
// Clear all port statistics
int32 ret = rtk_stat_global_reset(unit);
if (ret == RT_ERR_OK) {
send_success_response(client_socket, "{\"message\":\"All port statistics cleared\"}");
} else {
send_error_response(client_socket, 500, "Failed to clear statistics");
}
} else {
if (port_num < 1 || port_num > 10) {
send_error_response(client_socket, 400, "Invalid port number");
return;
}
rtk_port_t rtk_port = port_num + 7;
int32 ret = rtk_stat_port_reset(unit, rtk_port);
if (ret == RT_ERR_OK) {
char response[128];
snprintf(response, sizeof(response),
"{\"message\":\"Statistics cleared for port %d\"}", port_num);
send_success_response(client_socket, response);
} else {
send_error_response(client_socket, 500, "Failed to clear port statistics");
}
}
}
// ============================================================================================================================================================
// STP Configuration with RTK Integration
// ============================================================================================================================================================
void handle_stp_config_get_request(int client_socket) {
uint32 unit = 0;
char json_response[4096];
char stp_configs[3584] = "[";
// Get STP configuration for each port
int web_port;
for ( web_port = 1; web_port <= 10; web_port++) {
rtk_port_t rtk_port = web_port + 7;
// Get STP state
rtk_stp_state_t stp_state;
rtk_stp_mstpState_get(unit, 0, rtk_port, &stp_state); // MSTI 0 (CIST)
const char *state_str = "unknown";
switch(stp_state) {
case STP_STATE_DISABLED: state_str = "disabled"; break;
case STP_STATE_BLOCKING: state_str = "blocking"; break;
case STP_STATE_LEARNING: state_str = "learning"; break;
case STP_STATE_FORWARDING: state_str = "forwarding"; break;
default: state_str = "unknown"; break;
}
char stp_entry[256];
snprintf(stp_entry, sizeof(stp_entry),
"%s{\"port\":\"%d\",\"state\":\"%s\"}",
web_port > 1 ? "," : "", web_port, state_str);
if (strlen(stp_configs) + strlen(stp_entry) < sizeof(stp_configs) - 10) {
strcat(stp_configs, stp_entry);
}
}
strcat(stp_configs, "]");
snprintf(json_response, sizeof(json_response), "%s", stp_configs);
build_json_response(client_socket, json_response);
}
void handle_stp_config_set_request(int client_socket, const char *body) {
int port_num;
char stp_state[16];
if (extract_json_int(body, "port", &port_num) != 0 ||
extract_json_string(body, "state", stp_state, sizeof(stp_state)) != 0) {
send_error_response(client_socket, 400, "Missing required fields");
return;
}
if (port_num < 1 || port_num > 10) {
send_error_response(client_socket, 400, "Invalid port number");
return;
}
uint32 unit = 0;
rtk_port_t rtk_port = port_num + 7;
rtk_stp_state_t state = STP_STATE_FORWARDING;
// Convert state string to RTK enum
if (strcmp(stp_state, "disabled") == 0) {
state = STP_STATE_DISABLED;
} else if (strcmp(stp_state, "blocking") == 0) {
state = STP_STATE_BLOCKING;
} else if (strcmp(stp_state, "learning") == 0) {
state = STP_STATE_LEARNING;
} else if (strcmp(stp_state, "forwarding") == 0) {
state = STP_STATE_FORWARDING;
}
// Set STP state using RTK
int32 ret = rtk_stp_mstpState_set(unit, 0, rtk_port, state); // MSTI 0 (CIST)
if (ret == RT_ERR_OK) {
char response[128];
snprintf(response, sizeof(response),
"{\"message\":\"STP state set to %s for port %d\"}", stp_state, port_num);
send_success_response(client_socket, response);
} else {
send_error_response(client_socket, 500, "Failed to set STP state");
}
}
// ============================================================================================================================================================
// ROUTE Handlers
// ==============================================================================================================================================================
void handle_backend_request(int client_socket)
{
char buffer[BUFFER_SIZE];
int bytes_read = read(client_socket, buffer, sizeof(buffer) - 1);
if (bytes_read <= 0)
{
close(client_socket);
return;
}
buffer[bytes_read] = '\0';
char method[16], path[256];
char *body = "";
char *query = "";
// Use helper function to parse HTTP request
if (parse_http_request(buffer, method, path, &body, &query) != 0) {
send_error_response(client_socket, 400, "Invalid HTTP request format");
close(client_socket);
return;
}
printf("Incoming request: %s %s\n", method, path);
if (strcmp(method, "OPTIONS") == 0)
{
const char *options_response = "HTTP/1.1 204 No Content\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Access-Control-Allow-Methods: GET, POST, DELETE, PATCH, OPTIONS\r\n"
"Access-Control-Allow-Headers: Content-Type\r\n\r\n";
send(client_socket, options_response, strlen(options_response), 0);
close(client_socket);
return;
}
if (strcmp(method, "GET") == 0 && strcmp(path, "/api/health_check") == 0)
{
handle_health_check_request(client_socket);
}
else if (strcmp(method, "GET") == 0 && strcmp(path, "/api/health") == 0)
{
handle_health_check_request(client_socket);
}
else if (strcmp(method, "GET") == 0 && strcmp(path, "/api/port-status") == 0)
{
handle_port_status_request(client_socket);
}
else if (strcmp(method, "GET") == 0 && strcmp(path, "/api/industrial-status") == 0)
{
handle_industrial_status_request(client_socket);
}
else if (strcmp(method, "GET") == 0 && strcmp(path, "/api/system-config") == 0)
{
handle_system_config_get_request(client_socket);
}
else if (strcmp(method, "POST") == 0 && strcmp(path, "/api/system-config") == 0)
{
handle_system_config_post_request(client_socket, body);
}
else if (strcmp(method, "POST") == 0 && strcmp(path, "/api/reboot") == 0)
{
handle_reboot_request(client_socket);
}
else if (strcmp(method, "POST") == 0 && strcmp(path, "/api/ping") == 0)
{
handle_ping_request(client_socket, body);
}
else if (strcmp(method, "POST") == 0 && strcmp(path, "/api/upload") == 0)
{
handle_upload_request(client_socket, buffer, bytes_read);
}
else if (strcmp(method, "GET") == 0 && strcmp(path, "/api/poe-config") == 0)
{
handle_poe_config_get_request(client_socket);
}
else if (strcmp(method, "GET") == 0 && strcmp(path, "/api/user-management") == 0)
{
handle_user_management_get_request(client_socket);
}
else if (strcmp(method, "POST") == 0 && strcmp(path, "/api/user-management") == 0)
{
handle_user_management_post_request(client_socket, body);
}
else if (strcmp(method, "POST") == 0 && strcmp(path, "/api/user-management") == 0)
{
handle_user_management_delete_request(client_socket, body);
}
else if (strcmp(method, "GET") == 0 && strcmp(path, "/api/user-safety") == 0)
{
handle_user_safety_get_request(client_socket);
}
else if (strcmp(method, "POST") == 0 && strcmp(path, "/api/user-safety") == 0)
{
handle_user_safety_post_request(client_socket, body);
}
else if (strcmp(method, "GET") == 0 && strcmp(path, "/api/sntp-config") == 0)
{
handle_sntp_config_get_request(client_socket);
}
else if (strcmp(method, "POST") == 0 && strcmp(path, "/api/sntp-config") == 0)
{
handle_sntp_config_post_request(client_socket, body);
}
else if (strcmp(method, "GET") == 0 && strcmp(path, "/api/jumbo-frame") == 0)
{
handle_jumbo_frame_get_request(client_socket);
}
else if (strcmp(method, "POST") == 0 && strcmp(path, "/api/jumbo-frame") == 0)
{
handle_jumbo_frame_post_request(client_socket, body);
}
else if (strcmp(method, "POST") == 0 && strcmp(path, "/api/save-config") == 0)
{
handle_save_config_request(client_socket);
}
else if (strcmp(method, "GET") == 0 && strcmp(path, "/api/download-config") == 0)
{
handle_download_config_request(client_socket);
}
else if (strcmp(method, "DELETE") == 0 && strcmp(path, "/api/delete-config") == 0)
{
handle_delete_config_request(client_socket);
}
// else if (strcmp(method, "GET") == 0 && strcmp(path, "/api/port-config") == 0)
// {
// handle_port_config_get_request(client_socket);
// }
else if (strcmp(method, "POST") == 0 && strcmp(path, "/api/port-config") == 0)
{
handle_port_config_post_request(client_socket, body);
}
else if (strcmp(method, "GET") == 0 && strcmp(path, "/api/port_stats") == 0)
{
handle_port_stats_request(client_socket);
}
else if (strcmp(method, "GET") == 0 && strcmp(path, "/api/get_port_stats") == 0)
{
handle_get_port_stats_request(client_socket, query);
}
else if (strcmp(method, "GET") == 0 && strcmp(path, "/api/storm-control") == 0)
{
handle_storm_control_get_request(client_socket);
}
else if (strcmp(method, "POST") == 0 && strcmp(path, "/api/storm-control") == 0)
{
handle_storm_control_post_request(client_socket, body);
}
else if (strcmp(method, "GET") == 0 && strcmp(path, "/api/flow-control") == 0)
{
handle_flow_control_get_request(client_socket);
}
else if (strcmp(method, "POST") == 0 && strcmp(path, "/api/flow-control") == 0)
{
handle_flow_control_post_request(client_socket, body);
}
else if (strcmp(method, "GET") == 0 && strcmp(path, "/api/port-rate-limit") == 0)
{
handle_port_rate_limit_get_request(client_socket);
}
else if (strcmp(method, "POST") == 0 && strcmp(path, "/api/port-rate-limit") == 0)
{
handle_port_rate_limit_post_request(client_socket, body);
}
else if (strcmp(method, "GET") == 0 && strcmp(path, "/api/protected-port") == 0)
{
handle_protected_port_get_request(client_socket);
}
else if (strcmp(method, "POST") == 0 && strcmp(path, "/api/protected-port") == 0)
{
handle_protected_port_post_request(client_socket, body);
}
else if (strcmp(method, "GET") == 0 && strcmp(path, "/api/learn-limit") == 0)
{
handle_learn_limit_get_request(client_socket);
}
else if (strcmp(method, "POST") == 0 && strcmp(path, "/api/learn-limit") == 0)
{
handle_learn_limit_post_request(client_socket, body);
}
else if (strcmp(method, "GET") == 0 && strcmp(path, "/api/snmp-community") == 0)
{
handle_snmp_community_get_request(client_socket);
}
else if (strcmp(method, "POST") == 0 && strcmp(path, "/api/snmp-community") == 0)
{
handle_snmp_community_post_request(client_socket, body);
}
else if (strcmp(method, "POST") == 0 && strcmp(path, "/api/snmp-community") == 0)
{
handle_snmp_community_delete_request(client_socket, body);
}
else if (strcmp(method, "POST") == 0 && strcmp(path, "/api/snmp-community") == 0)
{
handle_snmp_community_patch_request(client_socket, body);
}
else if (strcmp(method, "GET") == 0 && strcmp(path, "/api/trap-targets") == 0)
{
handle_trap_targets_get_request(client_socket);
}
else if (strcmp(method, "POST") == 0 && strcmp(path, "/api/trap-targets") == 0)
{
handle_trap_targets_post_request(client_socket, body);
}
else if (strcmp(method, "POST") == 0 && strcmp(path, "/api/trap-targets") == 0)
{
handle_trap_targets_delete_request(client_socket, body);
}
else if (strcmp(method, "GET") == 0 && strcmp(path, "/api/qos-config") == 0)
{
handle_qos_config_get_request(client_socket);
}
else if (strcmp(method, "POST") == 0 && strcmp(path, "/api/qos-config") == 0)
{
handle_qos_config_post_request(client_socket, body);
}
else if (strcmp(method, "GET") == 0 && strcmp(path, "/api/get_qos_schedule") == 0)
{
handle_get_qos_schedule_request(client_socket);
}
else if (strcmp(method, "POST") == 0 && strcmp(path, "/api/set_qos_schedule") == 0)
{
handle_set_qos_schedule_request(client_socket, body);
}
else if (strcmp(method, "POST") == 0 && strcmp(path, "/api/factory-reset") == 0)
{
handle_factory_reset_request(client_socket);
}
else if (strcmp(method, "GET") == 0 && strcmp(path, "/api/serial-config") == 0)
{
handle_serial_config_get_request(client_socket);
}
else if (strcmp(method, "GET") == 0 && strcmp(path, "/api/port_stats") == 0)
{
handle_port_stats_get_request(client_socket);
}
else if (strcmp(method, "GET") == 0 && strcmp(path, "/api/acl-group") == 0)
{
handle_acl_group_get_request(client_socket);
}
else if (strcmp(method, "GET") == 0 && strcmp(path, "/api/extended-port-options") == 0)
{
handle_extended_port_options_get_request(client_socket);
}
else if (strcmp(method, "GET") == 0 && strcmp(path, "/api/get-acl-standard-ip") == 0)
{
handle_get_acl_standard_ip_request(client_socket);
}
else if (strcmp(method, "GET") == 0 && strcmp(path, "/api/get-extended-ip") == 0)
{
handle_get_extended_ip_request(client_socket);
}
else if (strcmp(method, "GET") == 0 && strcmp(path, "/api/get-acl-mac-ip") == 0)
{
handle_get_acl_mac_ip_request(client_socket);
}
else if (strcmp(method, "GET") == 0 && strcmp(path, "/api/get-acl-mac-arp") == 0)
{
handle_get_acl_mac_arp_request(client_socket);
}
else if (strcmp(method, "GET") == 0 && strcmp(path, "/api/get-qos-apply") == 0)
{
handle_get_qos_apply_request(client_socket);
}
else if (strcmp(method, "GET") == 0 && strcmp(path, "/api/get-qos-schedule") == 0)
{
handle_get_qos_schedule_request(client_socket);
}
// MAC table routes
else if (strcmp(method, "GET") == 0 && strcmp(path, "/api/mac-bind-table") == 0)
{
handle_mac_bind_table_get_request(client_socket);
}
else if (strcmp(method, "GET") == 0 && strcmp(path, "/api/mac-auto-bind") == 0)
{
handle_mac_auto_bind_get_request(client_socket);
}
else if (strcmp(method, "GET") == 0 && strcmp(path, "/api/mac-auto-filter") == 0)
{
handle_mac_auto_filter_get_request(client_socket);
}
else if (strcmp(method, "GET") == 0 && strcmp(path, "/api/mac-filter") == 0)
{
handle_mac_filter_get_request(client_socket);
}
// RMON routes
else if (strcmp(method, "GET") == 0 && strcmp(path, "/api/rmon-statistics") == 0)
{
handle_rmon_statistics_get_request(client_socket);
}
else if (strcmp(method, "POST") == 0 && strcmp(path, "/api/rmon-statistics") == 0)
{
handle_rmon_statistics_pFost_request(client_socket, body);
}
else if (strcmp(method, "POST") == 0 && strcmp(path, "/api/rmon-statistics/delete") == 0)
{
handle_rmon_statistics_delete_request(client_socket, body);
}
else if (strcmp(method, "GET") == 0 && strcmp(path, "/api/rmon-history") == 0)
{
handle_rmon_history_get_request(client_socket);
}
else if (strcmp(method, "POST") == 0 && strcmp(path, "/api/rmon-history") == 0)
{
handle_rmon_history_post_request(client_socket, body);
}
else if (strcmp(method, "POST") == 0 && strcmp(path, "/api/rmon-history/delete") == 0)
{
handle_rmon_history_delete_request(client_socket, body);
}
else if (strcmp(method, "GET") == 0 && strcmp(path, "/api/rmon-alarm") == 0)
{
handle_rmon_alarm_get_request(client_socket);
}
else if (strcmp(method, "POST") == 0 && strcmp(path, "/api/rmon-alarm") == 0)
{
handle_rmon_alarm_post_request(client_socket, body);
}
else if (strcmp(method, "POST") == 0 && strcmp(path, "/api/rmon-alarm/delete") == 0)
{
handle_rmon_alarm_delete_request(client_socket, body);
}
else if (strcmp(method, "GET") == 0 && strcmp(path, "/api/rmon-event") == 0)
{
handle_rmon_event_get_request(client_socket);
}
else if (strcmp(method, "POST") == 0 && strcmp(path, "/api/rmon-event") == 0)
{
handle_rmon_event_post_request(client_socket, body);
}
else if (strcmp(method, "POST") == 0 && strcmp(path, "/api/rmon-event/delete") == 0)
{
handle_rmon_event_delete_request(client_socket, body);
}
// IGMP Snooping routes
else if (strcmp(method, "GET") == 0 && strcmp(path, "/api/igmp-snooping-config") == 0)
{
handle_igmp_snooping_get_request(client_socket);
}
else if (strcmp(method, "POST") == 0 && strcmp(path, "/api/igmp-snooping-config") == 0)
{
handle_igmp_snooping_post_request(client_socket, body);
}
else if (strcmp(method, "GET") == 0 && strcmp(path, "/api/multicast-group-info") == 0)
{
handle_multicast_group_get_request(client_socket);
}
else if (strcmp(method, "POST") == 0 && strcmp(path, "/api/multicast-group-info") == 0)
{
handle_multicast_group_post_request(client_socket, body);
}
else if (strcmp(method, "DELETE") == 0 && strcmp(path, "/api/multicast-group-info") == 0)
{
handle_multicast_group_delete_request(client_socket, body);
}
else if (strcmp(method, "POST") == 0 && strcmp(path, "/api/add-acl-standard-ip") == 0)
{
handle_add_acl_standard_ip_request(client_socket, body);
}
else if (strcmp(method, "POST") == 0 && strcmp(path, "/api/add-acl-extended-ip") == 0)
{
handle_add_acl_extended_ip_request(client_socket, body);
}
else if (strcmp(method, "POST") == 0 && strcmp(path, "/api/add-acl-mac-ip") == 0)
{
handle_add_acl_mac_ip_request(client_socket, body);
}
else if (strcmp(method, "POST") == 0 && strcmp(path, "/api/add-acl-mac-arp") == 0)
{
handle_add_acl_mac_arp_request(client_socket, body);
}
// MAC table POST and DELETE routes
else if (strcmp(method, "POST") == 0 && strcmp(path, "/api/mac-bind-table") == 0)
{
handle_mac_bind_table_post_request(client_socket, body);
}
else if (strcmp(method, "DELETE") == 0 && strcmp(path, "/api/mac-bind-table") == 0)
{
handle_mac_bind_table_delete_request(client_socket, body);
}
else if (strcmp(method, "POST") == 0 && strcmp(path, "/api/qos-apply") == 0)
{
handle_qos_apply_request(client_socket, body);
}
else if (strcmp(method, "POST") == 0 && strcmp(path, "/api/add-qos-schedule") == 0)
{
handle_add_qos_schedule_request(client_socket, body);
}
else if (strcmp(method, "GET") == 0 && strcmp(path, "/api/get_vlan_interfaces") == 0)
{
print_all_vlan_interfaces_json(client_socket);
}
else if (strcmp(method, "POST") == 0 && strcmp(path, "/api/set_vlan_port") == 0)
{
handle_vlan_port_tag_action_request(client_socket, body);
}
else if (strcmp(method, "GET") == 0 && strcmp(path, "/api/get_vlan_information") == 0)
{
handle_get_vlan_members_request(client_socket);
}
else if (strcmp(method, "POST") == 0 && strcmp(path, "/api/set_vlan_information") == 0)
{
handle_set_vlan_members_request(client_socket, body);
}
else if (strcmp(method, "POST") == 0 && strcmp(path, "/api/vlan_port_action") == 0)
{
handle_vlan_port_tag_action_request(client_socket, body);
}
else if (strcmp(method, "POST") == 0 && strcmp(path, "/api/destroy_vlan") == 0)
{
handle_destroy_vlan_request(client_socket, body);
}
else if (strcmp(method, "POST") == 0 && strcmp(path, "/api/create_vlan") == 0)
{
handle_create_vlan_request(client_socket, body);
}
else if (strcmp(method, "POST") == 0 && strcmp(path, "/api/add_create_vlan_interface") == 0)
{
handle_create_vlan_interface_request(client_socket, body);
}
else if (strcmp(method, "POST") == 0 && strcmp(path, "/api/delete_vlanIp") == 0)
{
handle_delete_vlanip_request(client_socket, body);
}
else if (strcmp(method, "POST") == 0 && strcmp(path, "/api/get_vlanIp") == 0)
{
handle_get_vlan_ip_request(client_socket, body);
}
else if (strcmp(method, "POST") == 0 && strcmp(path, "/api/destroy_vlan_interface") == 0)
{
handle_destroy_vlan_interface_request(client_socket, body);
}
else if (strcmp(method, "POST") == 0 && strcmp(path, "/api/update_vlanIp") == 0)
{
handle_update_vlanip_request(client_socket, body);
}
else if (strcmp(method, "POST") == 0 && strcmp(path, "/set_switch_mgmt_macaddr") == 0)
{
handle_set_switch_mgmt_macaddr_request(client_socket, body);
}
else if (strcmp(method, "POST") == 0 && strcmp(path, "/api/add-lldp-global") == 0)
{
handle_add_lldp_global_request(client_socket, body);
}
else if (strcmp(method, "POST") == 0 && strcmp(path, "/api/apply-lldp-port") == 0)
{
handle_apply_lldp_port_request(client_socket, body);
}
else if (strcmp(method, "GET") == 0 && strcmp(path, "/api/get-lldp-global") == 0)
{
handle_get_lldp_global_request(client_socket);
}
// New routes from backend.js
else if (strcmp(method, "GET") == 0 && strcmp(path, "/api/snmp-versions") == 0)
{
handle_snmp_versions_get_request(client_socket);
}
else if (strcmp(method, "GET") == 0 && strcmp(path, "/api/port-trunking") == 0)
{
handle_port_trunking_get_request(client_socket);
}
else if (strcmp(method, "POST") == 0 && strcmp(path, "/api/set-trunk-method") == 0)
{
handle_set_trunk_method_request(client_socket, body);
}
else if (strcmp(method, "POST") == 0 && strcmp(path, "/api/create-trunk-group") == 0)
{
handle_create_trunk_group_request(client_socket, body);
}
else if (strcmp(method, "POST") == 0 && strcmp(path, "/api/add-member-port") == 0)
{
handle_add_member_port_request(client_socket, body);
}
else if (strcmp(method, "POST") == 0 && strcmp(path, "/api/remove-member-port") == 0)
{
handle_remove_member_port_request(client_socket, body);
}
else if (strcmp(method, "POST") == 0 && strcmp(path, "/api/delete-trunk-group") == 0)
{
handle_delete_trunk_group_request(client_socket, body);
}
else if (strcmp(method, "GET") == 0 && strcmp(path, "/api/get-mirror-ports") == 0)
{
handle_get_mirror_ports_request(client_socket);
}
else if (strcmp(method, "POST") == 0 && strcmp(path, "/api/apply-mirror-config") == 0)
{
handle_apply_mirror_config_request(client_socket, body);
}
else if (strcmp(method, "GET") == 0 && strcmp(path, "/api/get-mirror-config") == 0)
{
handle_get_mirror_config_request(client_socket);
}
else if (strcmp(method, "GET") == 0 && strcmp(path, "/api/get-ddm-status") == 0)
{
handle_get_ddm_status_request(client_socket);
}
else if (strcmp(method, "GET") == 0 && strcmp(path, "/api/arp-config-display") == 0)
{
handle_arp_config_display_get_request(client_socket);
}
else if (strcmp(method, "POST") == 0 && strcmp(path, "/api/arp-config-display") == 0)
{
handle_arp_config_display_post_request(client_socket, body);
}
else if (strcmp(method, "DELETE") == 0 && strncmp(path, "/api/arp-config-display/", 24) == 0)
{
handle_arp_config_display_delete_request(client_socket, path + 24);
}
else if (strcmp(method, "PUT") == 0 && strstr(path, "/api/arp-config-display/convert/"))
{
handle_arp_config_display_convert_request(client_socket, query);
}
else if (strcmp(method, "GET") == 0 && strcmp(path, "/api/cluster-config") == 0)
{
handle_cluster_config_get_request(client_socket);
}
else if (strcmp(method, "POST") == 0 && strcmp(path, "/api/cluster-config") == 0)
{
handle_cluster_config_post_request(client_socket, body);
}
else if (strcmp(method, "GET") == 0 && strcmp(path, "/api/cluster-members") == 0)
{
handle_cluster_members_get_request(client_socket);
}
else if (strcmp(method, "GET") == 0 && strcmp(path, "/api/host-static-route") == 0)
{
handle_host_static_route_get_request(client_socket);
}
else if (strcmp(method, "POST") == 0 && strcmp(path, "/api/host-static-route") == 0)
{
handle_host_static_route_post_request(client_socket, body);
}
else if (strcmp(method, "DELETE") == 0 && strcmp(path, "/api/host-static-route") == 0)
{
handle_host_static_route_delete_request(client_socket, body);
}
else if (strcmp(method, "GET") == 0 && strcmp(path, "/api/get-cable-diagnosis") == 0)
{
handle_get_cable_diagnosis_request(client_socket);
}
else if (strcmp(method, "POST") == 0 && strcmp(path, "/api/run-cable-diagnosis") == 0)
{
handle_run_cable_diagnosis_request(client_socket, body);
}
else if (strcmp(method, "GET") == 0 && strcmp(path, "/api/get-cable-diagnosis-data") == 0)
{
handle_get_cable_diagnosis_data_request(client_socket);
}
// Additional routes from backend.js
else if (strcmp(method, "GET") == 0 && strcmp(path, "/set_qos_schedule") == 0)
{
handle_get_qos_schedule_request(client_socket);
}
else if (strcmp(method, "POST") == 0 && strcmp(path, "/set_qos_schedule") == 0)
{
handle_set_qos_schedule_request(client_socket, body);
}
else if (strcmp(method, "GET") == 0 && strcmp(path, "/api/mac-address-table") == 0)
{
handle_mac_address_table_get_request(client_socket);
}
// else if (strcmp(method, "GET") == 0 && strcmp(path, "/api/port-config") == 0)
// {
// handle_port_config_get_request(client_socket);
// }
// else if (strcmp(method, "POST") == 0 && strcmp(path, "/api/port-config") == 0)
// {
// handle_port_config_set_request(client_socket, body);
// }
else if (strcmp(method, "GET") == 0 && strcmp(path, "/api/rate-limit") == 0)
{
handle_rate_limit_get_request(client_socket);
}
else if (strcmp(method, "POST") == 0 && strcmp(path, "/api/rate-limit") == 0)
{
handle_rate_limit_set_request(client_socket, body);
}
else if (strcmp(method, "GET") == 0 && strcmp(path, "/api/port-statistics") == 0)
{
handle_port_statistics_get_request(client_socket);
}
else if (strcmp(method, "POST") == 0 && strcmp(path, "/api/port-statistics/clear") == 0)
{
handle_port_statistics_clear_request(client_socket, body);
}
else if (strcmp(method, "GET") == 0 && strcmp(path, "/api/stp-config") == 0)
{
handle_stp_config_get_request(client_socket);
}
else if (strcmp(method, "POST") == 0 && strcmp(path, "/api/stp-config") == 0)
{
handle_stp_config_set_request(client_socket, body);
}
else if (strcmp(method, "GET") == 0 && strcmp(path, "/api/exit") == 0)
{
extern volatile int server_running;
server_running = 0;
const char *exit_response = "HTTP/1.1 200 OK\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Content-Type: application/json\r\n\r\n"
"{\"message\": \"Server shutting down\"}";
send(client_socket, exit_response, strlen(exit_response), 0);
close(client_socket);
return;
}
else
{
handle_not_found(client_socket);
}
close(client_socket); // Close the connection after handling
}
// ============================================================================================================================================================
// HTTP BACKEND SERVER
// ==============================================================================================================================================================
void *start_backend_server(void *arg)
{
int server_fd, new_socket;
struct sockaddr_in address;
int opt = 1;
socklen_t addrlen = sizeof(address);
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0)
{
perror("Socket creation error");
return NULL;
}
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)))
{
perror("Set socket options error");
return NULL;
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(BACKENDPORT);
if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0)
{
perror("Bind failed");
return NULL;
}
if (listen(server_fd, 3) < 0)
{
perror("Listen failed");
return NULL;
}
printf("Socket server listening on port %d...\n", BACKENDPORT);
// while (1)
while (server_running)
{
if ((new_socket = accept(server_fd, (struct sockaddr *)&address, &addrlen)) < 0)
{
perror("Accept failed");
continue;
}
handle_backend_request(new_socket); // Handle HTTP requests
}
close(server_fd);
return NULL;
}
// ============================================================================================================================================================
// MAIN FUNCTION
// ==============================================================================================================================================================
/*
* Function Declaration
*/
int diag_main(int argc, char **argv)
{
pthread_t backend_thread;
cparser_t *pParser;
#ifdef CONFIG_SDK_KERNEL_LINUX
int status, result;
#endif
#ifdef CONFIG_RISE
#if RISE_IN_TURNKEY
/* no wait here */
#else
// just example: wait RISE kickoff before prompt diag-shell, please remove when you call rise_application_kickoff() in your code.
{
uint32 box_list;
rise_application_kickoff(&box_list);
// diag_util_printf("box_list=0x%08x\n",box_list);
// diag_util_printf("\n");
}
#endif /* RISE_TURNKEY_PORTING */
#endif
// Initialize global data store
initialize_global_data();
/* Process diag options */
if (argc > 1)
{
/* -d: debug option to print all chip debug informations */
if (0 == strcmp(argv[1], "-d"))
{
diag_util_mprintf_paging_lines(0);
diag_debug_dump();
return 0;
}
}
pParser = osal_alloc(sizeof(cparser_t));
if (NULL == pParser)
{
diag_util_printf("osal_alloc cparser_t structure failed!!\n");
return -1;
}
osal_memset(pParser, 0, sizeof(cparser_t));
pParser->cfg.root = &cparser_root;
pParser->cfg.ch_complete = '\t';
/*
* Instead of making sure the terminal setting of the target and
* the host are the same. ch_erase and ch_del both are treated
* as backspace.
*/
pParser->cfg.ch_erase = '\b';
pParser->cfg.ch_del = 127;
pParser->cfg.ch_help = '?';
pParser->cfg.flags = 0;
pParser->cfg.fd = STDOUT_FILENO;
strcpy(pParser->cfg.str_remark, "//");
if (dlag_initial_promt_unit_id(pParser) != RT_ERR_OK)
{
osal_free(pParser);
return -1;
}
cparser_io_config(pParser);
/* Initialization */
if (CPARSER_OK != cparser_init(&(pParser->cfg), pParser))
{
diag_util_printf("Fail to initialize parser.\n");
osal_free(pParser);
return -1;
}
#ifdef CONFIG_SDK_KERNEL_LINUX
result = fork();
if (result == 0)
{
// child process
execl("/bin/cp", "cp", "/proc/meminfo", "/tmp/mem_log_rtsdk_diag", (char *)NULL);
exit(errno);
}
if (result == -1)
{
diag_util_printf("Warning: failed to fork process\n");
}
else
{
wait(&status); // equal to waitpid(-1, &status, 0);
if (status == -1)
{
diag_util_printf("Warning: failed to log memory usage\n");
}
}
#endif
/* Main command loop */
cparser_run(pParser);
diag_util_printf("\n");
osal_free(pParser);
if (pthread_create(&backend_thread, NULL, start_backend_server, NULL) != 0)
{
perror("Error creating socket server thread");
return -1;
}
pthread_join(backend_thread, NULL);
// Cleanup mutex
pthread_mutex_destroy(&global_data_mutex);
return 0;
} /* end of diag_main */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment