Newer
Older
* Copyright (C) 2023 IOPSYS Software Solutions AB. All rights reserved.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <net/if_arp.h>
#include <linux/if_bridge.h>
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <json-c/json.h>
#include <libubox/blobmsg.h>
#include <libubox/blobmsg_json.h>
#include <libubox/uloop.h>
#include <libubox/ustream.h>
#include <libubox/utils.h>
#include <libubus.h>
#if (EASYMESH_VERSION >2)
#include <openssl/err.h>
#include <openssl/bn.h>
#include <openssl/evp.h>
#include <openssl/x509.h>
#include <openssl/ec.h>
#endif
#include <cmdu.h>
#include <easymesh.h>
#include <i1905_wsc.h>
#include <map_module.h>
#include <uci.h>
#include "timer.h"
#include "utils/1905_ubus.h"
#include "utils/utils.h"
#if (EASYMESH_VERSION > 2)
#include "dpp.h"
#endif
#include "config.h"
#include "nl.h"
#include "agent.h"
#include "qos.h"
#include "qos_internal.h"
#if (EASYMESH_VERSION > 2)
free(rule);
}
void qos_rule_free_all(struct list_head *list_head)
{
struct temp_rule *p, *tmp;
list_for_each_entry_safe(p, tmp, list_head, list) {
qos_rule_free(p);
}
}
int qos_add_dscp_rule(void *agent,
struct tlv_spr *spr,
struct ieee1905_dscp_pcp_usr *dscp_pcp)
dbg("%s: adding DSCP rule...\n", __func__);
list_for_each_entry(r, &a->qos_rules, list) {
return -1;
}
}
r = calloc(1, sizeof(struct temp_rule));
if (r == NULL) {
return -1;
}
r->type = QOS_RULE_TYPE_DSCP_PCP;
memcpy(&r->spr, spr, sizeof(struct tlv_spr));
memcpy(&r->dscp, dscp_pcp, sizeof(struct ieee1905_dscp_pcp_usr));
dbg("%s: DSCP rule added\n", __func__);
list_add_tail(&r->list, &a->qos_rules);
return 0;
}
int qos_del_dscp_rule(void *agent,
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
{
struct agent *a = (struct agent *)agent;
struct temp_rule *r;
dbg("%s: removing DSCP rule...\n", __func__);
list_for_each_entry(r, &a->qos_rules, list) {
if (r->spr.rule_id == spr->rule_id) {
list_del(&r->list);
dbg("%s: DSCP rule removed\n", __func__);
return 0;
}
}
err("%s: rule is not found\n", __func__);
return -1;
}
dscp_pcp_conv_result dscp_pcp2qosmap(uint8_t dscp_pcp[64],
char *qos_map,
size_t qos_map_len)
{
/* Internal constants */
#define PCP_COUNT (8)
#define DSCP_PCP_MAX (64)
#define DSCP_UP_EXC_MAX (21)
#define RANGE_MIN (0)
#define RANGE_MAX (1)
#define RANGE_TOTAL (2)
#define TMP_BUF_LEN (50)
#define DSCP_NEUTRAL (255)
dscp_pcp_conv_result rc = DSCP_PCP_CONV_RESULT_OK;
uint8_t pcp_dscp_min[PCP_COUNT] = { DSCP_NEUTRAL };
uint8_t pcp_dscp_max[PCP_COUNT] = { DSCP_NEUTRAL };
uint8_t dscp_up[DSCP_UP_EXC_MAX][2];
size_t total_du = 0;
size_t i, j;
size_t final_len;
memset(pcp_dscp, 0, sizeof(pcp_dscp));
uint8_t pcp = dscp_pcp[i];
uint8_t dscp = i;
pcp_dscp[pcp][dscp] = 1;
}
/* Find the biggest ranges of used DSCPs for PCPs */
uint8_t ranges[64][3];
uint8_t total_ranges = 0;
int inside = 0;
uint8_t range_biggest_val;
int range_biggest_index = -1;
memset(ranges, 0, sizeof(ranges));
for (j = 0; j < DSCP_PCP_MAX; ++j) {
if (pcp_dscp[i][j]) {
if (inside == 0) {
inside = 1;
ranges[total_ranges][RANGE_MIN] = j;
ranges[total_ranges][RANGE_MAX] = j;
ranges[total_ranges][RANGE_TOTAL] = 1;
range_biggest_index = total_ranges;
range_biggest_val = 1;
}
total_ranges++;
ranges[total_ranges - 1][RANGE_MAX] = j;
ranges[total_ranges - 1][RANGE_TOTAL]++;
if (range_biggest_val <
range_biggest_index = total_ranges - 1;
range_biggest_val++;
}
}
pcp_dscp_min[i] = ranges[range_biggest_index][RANGE_MIN];
pcp_dscp_max[i] = ranges[range_biggest_index][RANGE_MAX];
pcp_dscp_min[i] = DSCP_NEUTRAL;
pcp_dscp_max[i] = DSCP_NEUTRAL;
}
}
/* Find exceptions that don't belong to [DSCP_min, DSCP_max] range */
uint8_t pcp = dscp_pcp[i];
uint8_t dscp = i;
if (dscp < pcp_dscp_min[pcp] ||
dscp_up[total_du][0] = dscp;
dscp_up[total_du][1] = pcp;
total_du++;
rc = DSCP_PCP_CONV_RESULT_OK_TOO_MANY_EXC;
break;
}
}
}
/* Write out pcp_X_dscp_min,pcp_X_dscp_max */
final_len = 0;
/*
* No need for bounds check - result length can't exceed the buffer
* length
*/
sprintf(pair, "%d,%d,", dscp_up[i][0], dscp_up[i][1]);
final_len += strlen(pair);
rc = DSCP_PCP_CONV_RESULT_TOO_LONG;
break;
}
strcat(qos_map, pair);
}
if (rc != DSCP_PCP_CONV_RESULT_OK &&
rc != DSCP_PCP_CONV_RESULT_OK_TOO_MANY_EXC)
return rc;
/*
* No need for bounds check - result length can't exceed the buffer
* length
*/
(i != 0 || total_du != 0) ? "," : "",
pcp_dscp_min[i],
pcp_dscp_max[i]);
rc = DSCP_PCP_CONV_RESULT_TOO_LONG;
break;
}
strcat(qos_map, pair);
}
#undef PCP_COUNT
#undef DSCP_PCP_MAX
#undef DSCP_UP_EXC_MAX
#undef RANGE_MIN
#undef RANGE_MAX
#undef RANGE_TOTAL
#undef TMP_BUF_LEN
return rc;
}
dscp_pcp_conv_result dscp_pcp2qosmap_simple(int pcp, char *str, size_t len)
{
size_t i;
char s[50];
/*
* Map DSCP [0, 63] to PCP passed as argument,
* all other PCP->DSCP ranges are mapped to [255, 255] (unused)
*/
(pcp == i) ? 0 : 255,
(pcp == i) ? 63 : 255);
if ((strlen(str) + strlen(s)) >= len)
return DSCP_PCP_CONV_RESULT_TOO_LONG;
strcat(str, s);
}
return DSCP_PCP_CONV_RESULT_OK;
}
int qos_apply_dscp_rules(void *agent)
{
dscp_pcp_conv_result rc;
struct agent *a = (struct agent *)agent;
struct temp_rule *r;
int biggest_precedence_idx = -1;
int biggest_precedence = -1;
size_t i;
dbg("%s: finding DSCP rule with the highest precedence\n", __func__);
i = 0;
list_for_each_entry(r, &a->qos_rules, list) {
biggest_precedence = r->spr.precedence;
biggest_precedence_idx = i;
}
++i;
}
dbg("%s: applying DSCP rules...\n", __func__);
list_for_each_entry(r, &a->qos_rules, list) {
char str[512] = { '\0' };
if ((i++) != biggest_precedence_idx) {
dbg("%s: ignore rule with smaller precedence\n", __func__);
continue;
}
if (r->spr.always_match == 0) {
dbg("%s: don't install not always-match rule\n", __func__);
continue;
}
if (r->spr.output < 0x08) {
rc = dscp_pcp2qosmap_simple(r->spr.output, str, sizeof(str) - 1);
} else if (r->spr.output == 0x08) {
rc = dscp_pcp2qosmap(r->dscp.dscp_pcp, str, sizeof(str) - 1);
} else {
err("%s: unsupported SPR output value\n", __func__);
rc = DSCP_PCP_CONV_RESULT_FAIL;
}
if (rc != DSCP_PCP_CONV_RESULT_OK &&
rc != DSCP_PCP_CONV_RESULT_OK_TOO_MANY_EXC) {
err("%s: wrong QoS map\n", __func__);
continue;
}
list_for_each_entry(fcfg, &a->cfg.aplist, list) {
runCmd("/lib/wifi/multiap set_qos_map %s %s", fcfg->name, str);
}
dbg("%s: DSCP rule applied: %s\n", __func__, str);
}
qos_sync_rules_to_nodes(agent);
dbg("%s: done with DSCP rules\n", __func__);
return 0;
}
int qos_sync_rules_to_nodes(void *agent)
{
struct agent *a = (struct agent *)agent;
struct node *n = NULL;
list_for_each_entry(n, &a->nodelist, list) {
char mac[50];
hwaddr_ntoa(n->alid, mac);
list_for_each_entry(fcfg, &a->cfg.aplist, list) {
runCmd("/lib/wifi/multiap set_qos_map %s %s", fcfg->name, mac);
struct temp_rule *r;
int nr = 0;
info("Registered QoS rules:\n");
list_for_each_entry(r, &a->qos_rules, list) {
info("[%d] add %d prec %doutput %d always %d\n",
r->spr.rule_id,
r->spr.add_remove,
r->spr.precedence,
r->spr.output,
r->spr.always_match);