Blame lldp_8021qaz.c

Packit 597cd4
/******************************************************************************
Packit 597cd4
Packit 597cd4
  LLDP Agent Daemon (LLDPAD) Software
Packit 597cd4
  Copyright(c) 2007-2012 Intel Corporation.
Packit 597cd4
Packit 597cd4
  This program is free software; you can redistribute it and/or modify it
Packit 597cd4
  under the terms and conditions of the GNU General Public License,
Packit 597cd4
  version 2, as published by the Free Software Foundation.
Packit 597cd4
Packit 597cd4
  This program is distributed in the hope it will be useful, but WITHOUT
Packit 597cd4
  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
Packit 597cd4
  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
Packit 597cd4
  more details.
Packit 597cd4
Packit 597cd4
  You should have received a copy of the GNU General Public License along with
Packit 597cd4
  this program; if not, write to the Free Software Foundation, Inc.,
Packit 597cd4
  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
Packit 597cd4
Packit 597cd4
  The full GNU General Public License is included in this distribution in
Packit 597cd4
  the file called "COPYING".
Packit 597cd4
Packit 597cd4
  Contact Information:
Packit 597cd4
  open-lldp Mailing List <lldp-devel@open-lldp.org>
Packit 597cd4
Packit 597cd4
******************************************************************************/
Packit 597cd4
Packit 597cd4
#include <stdlib.h>
Packit 597cd4
#include <assert.h>
Packit 597cd4
#include <errno.h>
Packit 597cd4
#include <netlink/attr.h>
Packit 597cd4
#include <netlink/msg.h>
Packit 597cd4
#include "lldp.h"
Packit 597cd4
#include "lldp_8021qaz.h"
Packit 597cd4
#include "messages.h"
Packit 597cd4
#include "lldp_util.h"
Packit 597cd4
#include "dcb_driver_interface.h"
Packit 597cd4
#include "config.h"
Packit 597cd4
#include "lldp_mand_clif.h"
Packit 597cd4
#include "lldp_dcbx_nl.h"
Packit 597cd4
#include "lldp/l2_packet.h"
Packit 597cd4
#include "lldp/ports.h"
Packit 597cd4
#include "lldpad_status.h"
Packit 597cd4
#include "lldp_8021qaz_cmds.h"
Packit 597cd4
#include "lldp_mand_clif.h"
Packit 597cd4
#include "include/linux/dcbnl.h"
Packit 597cd4
#include "include/linux/rtnetlink.h"
Packit 597cd4
#include "include/linux/netlink.h"
Packit 597cd4
#include "lldp_dcbx.h"
Packit 597cd4
Packit 597cd4
Packit 597cd4
struct lldp_head lldp_head;
Packit 597cd4
struct config_t lldpad_cfg;
Packit 597cd4
Packit 597cd4
static int ieee8021qaz_check_pending(struct port *port, struct lldp_agent *);
Packit 597cd4
static void run_all_sm(struct port *port, struct lldp_agent *agent);
Packit 597cd4
static void ieee8021qaz_mibUpdateObjects(struct port *port);
Packit 597cd4
static void ieee8021qaz_app_reset(struct app_tlv_head *head);
Packit 597cd4
static int get_ieee_hw(const char *ifname, struct ieee_ets **ets,
Packit 597cd4
		       struct ieee_pfc **pfc, struct app_prio **app,
Packit 597cd4
		       int *cnt);
Packit 597cd4
Packit 597cd4
static const struct lldp_mod_ops ieee8021qaz_ops = {
Packit 597cd4
	.lldp_mod_register	= ieee8021qaz_register,
Packit 597cd4
	.lldp_mod_unregister	= ieee8021qaz_unregister,
Packit 597cd4
	.lldp_mod_gettlv	= ieee8021qaz_gettlv,
Packit 597cd4
	.lldp_mod_rchange	= ieee8021qaz_rchange,
Packit 597cd4
	.lldp_mod_ifup		= ieee8021qaz_ifup,
Packit 597cd4
	.lldp_mod_ifdown	= ieee8021qaz_ifdown,
Packit 597cd4
	.lldp_mod_mibdelete	= ieee8021qaz_mibDeleteObject,
Packit 597cd4
	.get_arg_handler	= ieee8021qaz_get_arg_handlers,
Packit 597cd4
	.timer			= ieee8021qaz_check_pending,
Packit 597cd4
};
Packit 597cd4
Packit 597cd4
static int ieee8021qaz_check_pending(struct port *port,
Packit 597cd4
				     struct lldp_agent *agent)
Packit 597cd4
{
Packit 597cd4
	struct ieee8021qaz_user_data *iud;
Packit 597cd4
	struct ieee8021qaz_tlvs *tlv = NULL;
Packit 597cd4
Packit 597cd4
	if (agent->type != NEAREST_BRIDGE)
Packit 597cd4
		return 0;
Packit 597cd4
Packit 597cd4
	if (!port->portEnabled)
Packit 597cd4
		return 0;
Packit 597cd4
Packit 597cd4
	iud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_8021QAZ);
Packit 597cd4
	if (iud) {
Packit 597cd4
		LIST_FOREACH(tlv, &iud->head, entry) {
Packit 597cd4
			if (!strncmp(port->ifname, tlv->ifname, IFNAMSIZ)) {
Packit 597cd4
				if (tlv->active && tlv->pending &&
Packit 597cd4
				    port->dormantDelay == 1) {
Packit 597cd4
					tlv->pending = false;
Packit 597cd4
					ieee8021qaz_app_reset(&tlv->app_head);
Packit 597cd4
					run_all_sm(port, agent);
Packit 597cd4
					somethingChangedLocal(port->ifname,
Packit 597cd4
							      agent->type);
Packit 597cd4
				}
Packit 597cd4
				break;
Packit 597cd4
			}
Packit 597cd4
		}
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
	return 0;
Packit 597cd4
}
Packit 597cd4
Packit 597cd4
/* LLDP_8021QAZ_MOD_OPS - REGISTER */
Packit 597cd4
struct lldp_module *ieee8021qaz_register(void)
Packit 597cd4
{
Packit 597cd4
	struct lldp_module *mod;
Packit 597cd4
	struct ieee8021qaz_user_data *iud;
Packit 597cd4
Packit 597cd4
	mod = malloc(sizeof(*mod));
Packit 597cd4
	if (!mod) {
Packit 597cd4
		LLDPAD_ERR("Failed to malloc LLDP-8021QAZ module data");
Packit 597cd4
		goto out_err;
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
	iud = malloc(sizeof(*iud));
Packit 597cd4
	if (!iud) {
Packit 597cd4
		free(mod);
Packit 597cd4
		LLDPAD_ERR("Failed to malloc LLDP-8021QAZ module user data");
Packit 597cd4
		goto out_err;
Packit 597cd4
	}
Packit 597cd4
	memset((void *) iud, 0, sizeof(struct ieee8021qaz_user_data));
Packit 597cd4
Packit 597cd4
	LIST_INIT(&iud->head);
Packit 597cd4
Packit 597cd4
	mod->id	  = LLDP_MOD_8021QAZ;
Packit 597cd4
	mod->ops  = &ieee8021qaz_ops;
Packit 597cd4
	mod->data = iud;
Packit 597cd4
Packit 597cd4
	LLDPAD_DBG("%s: ieee8021qaz_register SUCCESS\n", __func__);
Packit 597cd4
	return mod;
Packit 597cd4
Packit 597cd4
out_err:
Packit 597cd4
	LLDPAD_DBG("%s: ieee8021qaz_register FAILED\n", __func__);
Packit 597cd4
	return NULL;
Packit 597cd4
}
Packit 597cd4
Packit 597cd4
struct ieee8021qaz_tlvs *ieee8021qaz_data(const char *ifname)
Packit 597cd4
{
Packit 597cd4
	struct ieee8021qaz_user_data *iud;
Packit 597cd4
	struct ieee8021qaz_tlvs *tlv = NULL;
Packit 597cd4
Packit 597cd4
	iud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_8021QAZ);
Packit 597cd4
	if (iud) {
Packit 597cd4
		LIST_FOREACH(tlv, &iud->head, entry) {
Packit 597cd4
			if (!strncmp(tlv->ifname, ifname, IFNAMSIZ))
Packit 597cd4
				return tlv;
Packit 597cd4
		}
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
	return NULL;
Packit 597cd4
}
Packit 597cd4
Packit 597cd4
static void set_ets_prio_map(const char *arg, u32 *prio_map)
Packit 597cd4
{
Packit 597cd4
		char *argcpy = strdup(arg);
Packit 597cd4
		char *tokens;
Packit 597cd4
		int tc, prio;
Packit 597cd4
Packit 597cd4
		if (!argcpy)
Packit 597cd4
			return;
Packit 597cd4
Packit 597cd4
		tokens = strtok(argcpy, ",");
Packit 597cd4
Packit 597cd4
		while (tokens) {
Packit 597cd4
			prio = 0x7 & atoi(tokens);
Packit 597cd4
			tc = 0x7 & atoi(&tokens[2]);
Packit 597cd4
			*prio_map |= tc << (4 * (7-prio));
Packit 597cd4
			tokens = strtok(NULL, ",");
Packit 597cd4
		}
Packit 597cd4
		free(argcpy);
Packit 597cd4
}
Packit 597cd4
Packit 597cd4
static void set_ets_tsa_map(const char *arg, u8 *tsa_map)
Packit 597cd4
{
Packit 597cd4
	int i, type, tc;
Packit 597cd4
	char *argcpy = strdup(arg);
Packit 597cd4
	char *tokens;
Packit 597cd4
Packit 597cd4
	if (!argcpy)
Packit 597cd4
		return;
Packit 597cd4
Packit 597cd4
	tokens = strtok(argcpy, ",");
Packit 597cd4
Packit 597cd4
	for (i = 0; tokens; i++) {
Packit 597cd4
		tc = atoi(tokens);
Packit 597cd4
		if ((strcmp(&tokens[2], "strict")) == 0)
Packit 597cd4
			type = IEEE8021Q_TSA_STRICT;
Packit 597cd4
		else if ((strcmp(&tokens[2], "cb_shaper")) == 0)
Packit 597cd4
			type = IEEE8021Q_TSA_CBSHAPER;
Packit 597cd4
		else if ((strcmp(&tokens[2], "ets")) == 0)
Packit 597cd4
			type = IEEE8021Q_TSA_ETS;
Packit 597cd4
		else if ((strcmp(&tokens[2], "vendor")) == 0)
Packit 597cd4
			type = IEEE8021Q_TSA_VENDOR;
Packit 597cd4
		else
Packit 597cd4
			type = IEEE8021Q_TSA_STRICT;
Packit 597cd4
Packit 597cd4
		tsa_map[tc] = type;
Packit 597cd4
		tokens = strtok(NULL, ",");
Packit 597cd4
	}
Packit 597cd4
	free(argcpy);
Packit 597cd4
}
Packit 597cd4
Packit 597cd4
static int read_cfg_file(char *ifname, struct lldp_agent *agent,
Packit 597cd4
			 struct ieee8021qaz_tlvs *tlvs)
Packit 597cd4
{
Packit 597cd4
	const char *arg = NULL;
Packit 597cd4
	char arg_path[256];
Packit 597cd4
	int res = 0, i;
Packit 597cd4
	int willing, pfc_mask, delay;
Packit 597cd4
Packit 597cd4
	if (agent->type != NEAREST_BRIDGE)
Packit 597cd4
		return 0;
Packit 597cd4
Packit 597cd4
	/* Read ETS-CFG willing bit -- default willing enabled */
Packit 597cd4
	snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", TLVID_PREFIX,
Packit 597cd4
		 TLVID_8021(LLDP_8021QAZ_ETSCFG), ARG_WILLING);
Packit 597cd4
	res = get_config_setting(ifname, agent->type, arg_path, &willing,
Packit 597cd4
				 CONFIG_TYPE_INT);
Packit 597cd4
	if (!res)
Packit 597cd4
		tlvs->ets->cfgl->willing = !!willing;
Packit 597cd4
	else
Packit 597cd4
		tlvs->ets->cfgl->willing = 1;
Packit 597cd4
Packit 597cd4
	/* Read PFC willing bit -- default willing enabled */
Packit 597cd4
	snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", TLVID_PREFIX,
Packit 597cd4
		 TLVID_8021(LLDP_8021QAZ_PFC), ARG_WILLING);
Packit 597cd4
	res = get_config_setting(ifname, agent->type, arg_path, &willing,
Packit 597cd4
				 CONFIG_TYPE_INT);
Packit 597cd4
	if (!res)
Packit 597cd4
		tlvs->pfc->local.willing = !!willing;
Packit 597cd4
	else
Packit 597cd4
		tlvs->pfc->local.willing = 1;
Packit 597cd4
Packit 597cd4
	/* Read and parse ETS-CFG priority map --
Packit 597cd4
	 * default all priorities TC0
Packit 597cd4
	 */
Packit 597cd4
	snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", TLVID_PREFIX,
Packit 597cd4
		 TLVID_8021(LLDP_8021QAZ_ETSCFG), ARG_ETS_UP2TC);
Packit 597cd4
	res = get_config_setting(ifname, agent->type, arg_path, &arg,
Packit 597cd4
				 CONFIG_TYPE_STRING);
Packit 597cd4
	if (!res)
Packit 597cd4
		set_ets_prio_map(arg, &tlvs->ets->cfgl->prio_map);
Packit 597cd4
	else
Packit 597cd4
		tlvs->ets->cfgl->prio_map = 0x00000000;
Packit 597cd4
Packit 597cd4
	/* Default ETS-CFG num_tc to MAX */
Packit 597cd4
	tlvs->ets->cfgl->max_tcs = MAX_TCS;
Packit 597cd4
Packit 597cd4
	/* Read and parse ETS-REC priority map --
Packit 597cd4
	 * default all priorities TC0
Packit 597cd4
	 */
Packit 597cd4
	snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", TLVID_PREFIX,
Packit 597cd4
		 TLVID_8021(LLDP_8021QAZ_ETSREC), ARG_ETS_UP2TC);
Packit 597cd4
	res = get_config_setting(ifname, agent->type, arg_path, &arg,
Packit 597cd4
				 CONFIG_TYPE_STRING);
Packit 597cd4
	if (!res)
Packit 597cd4
		set_ets_prio_map(arg, &tlvs->ets->recl->prio_map);
Packit 597cd4
	else
Packit 597cd4
		tlvs->ets->recl->prio_map = 0x00000000;
Packit 597cd4
Packit 597cd4
	/* Read and parse ETS-CFG tc bandwidth map --
Packit 597cd4
	 * default percentage mapping 0,0,0,0,0,0,0,0 (strict priority)
Packit 597cd4
	 */
Packit 597cd4
	snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", TLVID_PREFIX,
Packit 597cd4
		 TLVID_8021(LLDP_8021QAZ_ETSCFG), ARG_ETS_TCBW);
Packit 597cd4
	res = get_config_setting(ifname, agent->type, arg_path, &arg,
Packit 597cd4
				 CONFIG_TYPE_STRING);
Packit 597cd4
	if (!res) {
Packit 597cd4
		char *argcpy = strdup(arg);
Packit 597cd4
		char *tokens;
Packit 597cd4
Packit 597cd4
		if (argcpy) {
Packit 597cd4
			tokens = strtok(argcpy, ",");
Packit 597cd4
Packit 597cd4
			for (i = 0; tokens; i++) {
Packit 597cd4
				tlvs->ets->cfgl->tc_bw[i] = atoi(tokens);
Packit 597cd4
				tokens = strtok(NULL, ",");
Packit 597cd4
			}
Packit 597cd4
			free(argcpy);
Packit 597cd4
		}
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
	/* Read and parse ETS-REC tc bandwidth map --
Packit 597cd4
	 * default percentage mapping 0,0,0,0,0,0,0,0 (strict priority)
Packit 597cd4
	 */
Packit 597cd4
	snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", TLVID_PREFIX,
Packit 597cd4
		 TLVID_8021(LLDP_8021QAZ_ETSREC), ARG_ETS_TCBW);
Packit 597cd4
	res = get_config_setting(ifname, agent->type, arg_path, &arg,
Packit 597cd4
				 CONFIG_TYPE_STRING);
Packit 597cd4
	if (!res) {
Packit 597cd4
		char *argcpy = strdup(arg);
Packit 597cd4
		char *tokens;
Packit 597cd4
Packit 597cd4
		if (argcpy) {
Packit 597cd4
			tokens = strtok(argcpy, ",");
Packit 597cd4
Packit 597cd4
			for (i = 0; tokens; i++) {
Packit 597cd4
				tlvs->ets->recl->tc_bw[i] = atoi(tokens);
Packit 597cd4
				tokens = strtok(NULL, ",");
Packit 597cd4
			}
Packit 597cd4
			free(argcpy);
Packit 597cd4
		}
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
	/* Read and parse ETS-CFG tc transmission selction algorithm map
Packit 597cd4
	 * This defaults to all traffic classes using strict priority
Packit 597cd4
	 */
Packit 597cd4
	snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", TLVID_PREFIX,
Packit 597cd4
		 TLVID_8021(LLDP_8021QAZ_ETSCFG), ARG_ETS_TSA);
Packit 597cd4
	res = get_config_setting(ifname, agent->type, arg_path, &arg,
Packit 597cd4
				 CONFIG_TYPE_STRING);
Packit 597cd4
	if (!res) {
Packit 597cd4
		set_ets_tsa_map(arg, tlvs->ets->cfgl->tsa_map);
Packit 597cd4
	} else {
Packit 597cd4
		for (i = 0; i < MAX_TCS; i++)
Packit 597cd4
			tlvs->ets->cfgl->tsa_map[i] = IEEE8021Q_TSA_STRICT;
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
	/* Read and parse ETS-REC tc transmission selction algorithm map
Packit 597cd4
	 * This defaults to all traffic classes using strict priority
Packit 597cd4
	 */
Packit 597cd4
	snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", TLVID_PREFIX,
Packit 597cd4
		 TLVID_8021(LLDP_8021QAZ_ETSREC), ARG_ETS_TSA);
Packit 597cd4
	res = get_config_setting(ifname, agent->type, arg_path, &arg,
Packit 597cd4
				 CONFIG_TYPE_STRING);
Packit 597cd4
	if (!res) {
Packit 597cd4
		set_ets_tsa_map(arg, tlvs->ets->recl->tsa_map);
Packit 597cd4
	} else {
Packit 597cd4
		for (i = 0; i < MAX_TCS; i++)
Packit 597cd4
			tlvs->ets->recl->tsa_map[i] = IEEE8021Q_TSA_STRICT;
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
	/* Read and parse PFC enable bitmask -- default 0x00 */
Packit 597cd4
	snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", TLVID_PREFIX,
Packit 597cd4
		 TLVID_8021(LLDP_8021QAZ_PFC), ARG_PFC_ENABLED);
Packit 597cd4
	res = get_config_setting(ifname, agent->type, arg_path, &pfc_mask,
Packit 597cd4
				 CONFIG_TYPE_INT);
Packit 597cd4
	if (!res)
Packit 597cd4
		tlvs->pfc->local.pfc_enable = pfc_mask;
Packit 597cd4
Packit 597cd4
	/* Read and parse PFC delay -- default 0x00 */
Packit 597cd4
	snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", TLVID_PREFIX,
Packit 597cd4
		 TLVID_8021(LLDP_8021QAZ_PFC), ARG_PFC_DELAY);
Packit 597cd4
	res = get_config_setting(ifname, agent->type, arg_path, &delay,
Packit 597cd4
				 CONFIG_TYPE_INT);
Packit 597cd4
	if (!res)
Packit 597cd4
		tlvs->pfc->local.delay = delay;
Packit 597cd4
Packit 597cd4
	/* Default PFC capabilities to MAX */
Packit 597cd4
	tlvs->pfc->local.pfc_cap = MAX_TCS;
Packit 597cd4
Packit 597cd4
	/* Read and add APP data to internal lldpad APP ring */
Packit 597cd4
	for (i = 0; i < MAX_APP_ENTRIES; i++) {
Packit 597cd4
		char *parse;
Packit 597cd4
		char *app_tuple;
Packit 597cd4
		u8 prio, sel;
Packit 597cd4
		long pid;
Packit 597cd4
Packit 597cd4
		snprintf(arg_path, sizeof(arg_path), "%s%08x.%s%i", TLVID_PREFIX,
Packit 597cd4
			 TLVID_8021(LLDP_8021QAZ_APP), ARG_APP, i);
Packit 597cd4
		res = get_config_setting(ifname, agent->type, arg_path, &arg,
Packit 597cd4
					 CONFIG_TYPE_STRING);
Packit 597cd4
Packit 597cd4
		if (res)
Packit 597cd4
			continue;
Packit 597cd4
Packit 597cd4
		/* Parse cfg file input, bounds checking done on set app cmd */
Packit 597cd4
		parse = strdup(arg);
Packit 597cd4
		if (!parse)
Packit 597cd4
			break;
Packit 597cd4
		app_tuple = strtok(parse, ",");
Packit 597cd4
		if (!app_tuple)
Packit 597cd4
			break;
Packit 597cd4
		prio = atoi(app_tuple);
Packit 597cd4
		app_tuple = strtok(NULL, ",");
Packit 597cd4
		if (!app_tuple)
Packit 597cd4
			break;
Packit 597cd4
		sel = atoi(app_tuple);
Packit 597cd4
Packit 597cd4
		app_tuple = strtok(NULL, ",");
Packit 597cd4
		if (!app_tuple)
Packit 597cd4
			break;
Packit 597cd4
Packit 597cd4
		/* APP Data can be in hex or integer form */
Packit 597cd4
		errno = 0;
Packit 597cd4
		pid = strtol(app_tuple, NULL, 0);
Packit 597cd4
		if (!errno)
Packit 597cd4
			ieee8021qaz_mod_app(&tlvs->app_head, 0,
Packit 597cd4
					    prio, sel, (u16) pid, 0);
Packit 597cd4
		free(parse);
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
	return 0;
Packit 597cd4
}
Packit 597cd4
Packit 597cd4
inline int get_prio_map(u32 prio_map, int prio)
Packit 597cd4
{
Packit 597cd4
	if (prio > 7)
Packit 597cd4
		return 0;
Packit 597cd4
Packit 597cd4
	return (prio_map >> (4 * (7-prio))) & 0xF;
Packit 597cd4
}
Packit 597cd4
Packit 597cd4
inline void set_prio_map(u32 *prio_map, u8 prio, int tc)
Packit 597cd4
{
Packit 597cd4
	u32 mask = ~(0xffffffff & (0xF << (4 * (7-prio))));
Packit 597cd4
	*prio_map &= mask;
Packit 597cd4
	*prio_map |= tc << (4 * (7-prio));
Packit 597cd4
}
Packit 597cd4
Packit 597cd4
/*
Packit 597cd4
 * get_dcbx_hw - Get bitmask of hardware DCBX version and firmware status
Packit 597cd4
 *
Packit 597cd4
 * @ifname: interface name to query
Packit 597cd4
 * @dcbx: bitmask to store DCBX capabilities
Packit 597cd4
 *
Packit 597cd4
 * Returns 0 on success, error value otherwise.
Packit 597cd4
 */
Packit 597cd4
int get_dcbx_hw(const char *ifname, __u8 *dcbx)
Packit 597cd4
{
Packit 597cd4
	int err = 0;
Packit 597cd4
	struct nlattr *attr;
Packit 597cd4
	struct sockaddr_nl dest_addr;
Packit 597cd4
	static struct nl_sock *nlsocket;
Packit 597cd4
	struct nl_msg *nlm = NULL;
Packit 597cd4
	unsigned char *msg = NULL;
Packit 597cd4
	struct nlmsghdr *hdr;
Packit 597cd4
	struct dcbmsg d = {
Packit 597cd4
			   .dcb_family = AF_UNSPEC,
Packit 597cd4
			   .cmd = DCB_CMD_GDCBX,
Packit 597cd4
			   .dcb_pad = 0
Packit 597cd4
			  };
Packit 597cd4
Packit 597cd4
	if (!nlsocket) {
Packit 597cd4
		nlsocket = nl_socket_alloc();
Packit 597cd4
		if (!nlsocket) {
Packit 597cd4
			LLDPAD_WARN("%s: %s: nl_socket_alloc failed\n",
Packit 597cd4
				    __func__, ifname);
Packit 597cd4
			err = -ENOMEM;
Packit 597cd4
			goto out;
Packit 597cd4
		}
Packit 597cd4
		nl_socket_set_local_port(nlsocket, 0);
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
	err = nl_connect(nlsocket, NETLINK_ROUTE);
Packit 597cd4
	if (err < 0) {
Packit 597cd4
		LLDPAD_WARN("%s: %s nlconnect failed abort get ieee, %s\n",
Packit 597cd4
			    __func__, ifname, nl_geterror(err));
Packit 597cd4
		goto out;
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
	nlm = nlmsg_alloc_simple(RTM_GETDCB, NLM_F_REQUEST);
Packit 597cd4
	if (!nlm) {
Packit 597cd4
		LLDPAD_WARN("%s: %s nlmsg_alloc failed abort get ieee\n",
Packit 597cd4
			    __func__, ifname);
Packit 597cd4
		err = -ENOMEM;
Packit 597cd4
		goto out;
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
	memset(&dest_addr, 0, sizeof(dest_addr));
Packit 597cd4
	dest_addr.nl_family = AF_NETLINK;
Packit 597cd4
	nlmsg_set_dst(nlm, &dest_addr);
Packit 597cd4
Packit 597cd4
	err = nlmsg_append(nlm, &d, sizeof(d), NLMSG_ALIGNTO);
Packit 597cd4
	if (err < 0)
Packit 597cd4
		goto out;
Packit 597cd4
Packit 597cd4
	err = nla_put(nlm, DCB_ATTR_IFNAME, strlen(ifname)+1, ifname);
Packit 597cd4
	if (err < 0)
Packit 597cd4
		goto out;
Packit 597cd4
Packit 597cd4
	err = nl_send_auto_complete(nlsocket, nlm);
Packit 597cd4
	if (err <= 0) {
Packit 597cd4
		LLDPAD_WARN("%s: %s 802.1Qaz get app attributes failed\n",
Packit 597cd4
			    __func__, ifname);
Packit 597cd4
		goto out;
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
	err = nl_recv(nlsocket, &dest_addr, &msg, NULL);
Packit 597cd4
	if (err <= 0) {
Packit 597cd4
		LLDPAD_WARN("%s: %s: nl_recv returned %d\n", __func__, ifname,
Packit 597cd4
			    err);
Packit 597cd4
		goto out;
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
	hdr = (struct nlmsghdr *) msg;
Packit 597cd4
Packit 597cd4
	attr = nlmsg_find_attr(hdr, sizeof(d), DCB_ATTR_DCBX);
Packit 597cd4
	if (!attr) {
Packit 597cd4
		LLDPAD_DBG("%s: %s: nlmsg_find_attr failed, no GDCBX support\n",
Packit 597cd4
			    __func__, ifname);
Packit 597cd4
		err = -EOPNOTSUPP;
Packit 597cd4
		goto out;
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
	*dcbx = nla_get_u8(attr);
Packit 597cd4
out:
Packit 597cd4
	nlmsg_free(nlm);
Packit 597cd4
	free(msg);
Packit 597cd4
	if (nlsocket)
Packit 597cd4
		nl_close(nlsocket);
Packit 597cd4
	return err;
Packit 597cd4
}
Packit 597cd4
Packit 597cd4
/*
Packit 597cd4
 * LLDP_8021QAZ_MOD_OPS - IFUP
Packit 597cd4
 *
Packit 597cd4
 * Load TLV values (either from config file, command prompt or defaults),
Packit 597cd4
 * set up adapter, initialize FSMs and build tlvs
Packit 597cd4
 *
Packit 597cd4
 * Check if a 'config' file exists (to load tlv values). If YES, load save them
Packit 597cd4
 * as new defaults. If NO, load defaults. Also, check for TLV values via cmd
Packit 597cd4
 * prompt. Then initialize FSMs for each tlv and finally build the tlvs
Packit 597cd4
 */
Packit 597cd4
void ieee8021qaz_ifup(char *ifname, struct lldp_agent *agent)
Packit 597cd4
{
Packit 597cd4
	struct port *port = NULL;
Packit 597cd4
	struct ieee8021qaz_tlvs *tlvs;
Packit 597cd4
	struct ieee8021qaz_user_data *iud;
Packit 597cd4
	int adminstatus, cnt, len;
Packit 597cd4
	__u8 dcbx = 0;
Packit 597cd4
	struct ieee_ets *ets = NULL;
Packit 597cd4
	struct ieee_pfc *pfc = NULL;
Packit 597cd4
	struct app_prio *data = NULL;
Packit 597cd4
	int err, no_set_status;
Packit 597cd4
Packit 597cd4
	if (agent->type != NEAREST_BRIDGE)
Packit 597cd4
		return;
Packit 597cd4
Packit 597cd4
	/* 802.1Qaz does not support bonded or vlan devices */
Packit 597cd4
	if (is_bond(ifname) || is_vlan(ifname))
Packit 597cd4
		return;
Packit 597cd4
Packit 597cd4
	err = get_dcbx_hw(ifname, &dcbx);
Packit 597cd4
	if (err < 0)
Packit 597cd4
		return;
Packit 597cd4
Packit 597cd4
	/* If admin has explicitly enabled Rx/Tx, don't override it */
Packit 597cd4
	no_set_status = get_config_setting(ifname, agent->type, ARG_ADMINSTATUS,
Packit 597cd4
						&adminstatus, CONFIG_TYPE_INT);
Packit 597cd4
Packit 597cd4
	/* If hardware is not DCBX IEEE compliant or it is managed
Packit 597cd4
	 * by an LLD agent most likely a firmware agent abort
Packit 597cd4
	 */
Packit 597cd4
	if (dcbx & DCB_CAP_DCBX_LLD_MANAGED) {
Packit 597cd4
		if (no_set_status)
Packit 597cd4
			set_lldp_agent_admin(ifname, agent->type,
Packit 597cd4
					     (adminstatus & enabledRxOnly));
Packit 597cd4
		return;
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
	/* If 802.1Qaz is already configured no need to continue */
Packit 597cd4
	tlvs = ieee8021qaz_data(ifname);
Packit 597cd4
	if (tlvs)
Packit 597cd4
		goto initialized;
Packit 597cd4
Packit 597cd4
	/* if there is no persistent adminStatus setting then set to enabledRx
Packit 597cd4
	 * but do not persist that as a setting.
Packit 597cd4
	 */
Packit 597cd4
	if (no_set_status)
Packit 597cd4
		set_lldp_agent_admin(ifname, agent->type, enabledRxOnly);
Packit 597cd4
Packit 597cd4
	/* lookup port data */
Packit 597cd4
	port = port_find_by_ifindex(get_ifidx(ifname));
Packit 597cd4
Packit 597cd4
	/*
Packit 597cd4
	 * Check if link down and/or tlvs exist for current port.
Packit 597cd4
	 * If true, then return without any further work
Packit 597cd4
	 */
Packit 597cd4
	if (!port)
Packit 597cd4
		return;
Packit 597cd4
Packit 597cd4
	/* Initializing TLV structs */
Packit 597cd4
	tlvs = malloc(sizeof(*tlvs));
Packit 597cd4
	if (!tlvs) {
Packit 597cd4
		LLDPAD_DBG("%s: ifname %s malloc failed.\n", __func__, ifname);
Packit 597cd4
		return;
Packit 597cd4
	}
Packit 597cd4
	memset(tlvs, 0, sizeof(*tlvs));
Packit 597cd4
Packit 597cd4
	tlvs->rx = malloc(sizeof(*tlvs->rx));
Packit 597cd4
	if (!tlvs->rx) {
Packit 597cd4
		free(tlvs);
Packit 597cd4
		LLDPAD_DBG("%s: %s malloc failed.\n", __func__, ifname);
Packit 597cd4
		return;
Packit 597cd4
	}
Packit 597cd4
	memset(tlvs->rx, 0, sizeof(*tlvs->rx));
Packit 597cd4
Packit 597cd4
	/* Initializing the ieee8021qaz_tlvs struct */
Packit 597cd4
	strncpy(tlvs->ifname, ifname, IFNAMSIZ);
Packit 597cd4
	tlvs->port = port;
Packit 597cd4
	tlvs->ieee8021qazdu = 0;
Packit 597cd4
	l2_packet_get_own_src_addr(port->l2, tlvs->local_mac);
Packit 597cd4
	memset(tlvs->remote_mac, 0, ETH_ALEN);
Packit 597cd4
Packit 597cd4
	/* Initialize all TLVs */
Packit 597cd4
	tlvs->ets = malloc(sizeof(*tlvs->ets));
Packit 597cd4
	if (!tlvs->ets)
Packit 597cd4
		goto err;
Packit 597cd4
	memset(tlvs->ets, 0, sizeof(*tlvs->ets));
Packit 597cd4
Packit 597cd4
	tlvs->ets->cfgl = malloc(sizeof(*tlvs->ets->cfgl));
Packit 597cd4
	if (!tlvs->ets->cfgl)
Packit 597cd4
		goto err;
Packit 597cd4
Packit 597cd4
	tlvs->ets->recl = malloc(sizeof(*tlvs->ets->recl));
Packit 597cd4
	if (!tlvs->ets->recl)
Packit 597cd4
		goto err_recl;
Packit 597cd4
Packit 597cd4
	tlvs->pfc = malloc(sizeof(*tlvs->pfc));
Packit 597cd4
	if (!tlvs->pfc)
Packit 597cd4
		goto err_pfc;
Packit 597cd4
Packit 597cd4
	memset(tlvs->ets->cfgl, 0, sizeof(*tlvs->ets->cfgl));
Packit 597cd4
	memset(tlvs->ets->recl, 0, sizeof(*tlvs->ets->recl));
Packit 597cd4
	memset(tlvs->pfc, 0, sizeof(*tlvs->pfc));
Packit 597cd4
Packit 597cd4
	tlvs->ets->pending = 1;
Packit 597cd4
	tlvs->ets->current_state = 0;
Packit 597cd4
Packit 597cd4
	tlvs->pfc->pending = 1;
Packit 597cd4
	tlvs->pfc->current_state = 0;
Packit 597cd4
	tlvs->pfc->remote_param = 0;
Packit 597cd4
Packit 597cd4
	LIST_INIT(&tlvs->app_head);
Packit 597cd4
	read_cfg_file(port->ifname, agent, tlvs);
Packit 597cd4
Packit 597cd4
	iud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_8021QAZ);
Packit 597cd4
	LIST_INSERT_HEAD(&iud->head, tlvs, entry);
Packit 597cd4
Packit 597cd4
initialized:
Packit 597cd4
	/* Query hardware and set maximum number of TCs with hardware values */
Packit 597cd4
	len = get_ieee_hw(ifname, &ets, &pfc, &data, &cnt);
Packit 597cd4
	if (len > 0) {
Packit 597cd4
		if (ets)
Packit 597cd4
			tlvs->ets->cfgl->max_tcs = ets->ets_cap;
Packit 597cd4
		if (pfc)
Packit 597cd4
			tlvs->pfc->local.pfc_cap = pfc->pfc_cap;
Packit 597cd4
Packit 597cd4
		free(ets);
Packit 597cd4
		free(pfc);
Packit 597cd4
		free(data);
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
	/* if the dcbx field is filled in by the dcbx query then the
Packit 597cd4
	 * kernel is supports IEEE mode, so make IEEE DCBX active by default.
Packit 597cd4
	 */
Packit 597cd4
	if (dcbx_get_legacy_version(ifname) & ~MASK_DCBX_FORCE) {
Packit 597cd4
		tlvs->active = false;
Packit 597cd4
	} else {
Packit 597cd4
		tlvs->active = true;
Packit 597cd4
		tlvs->pending = true;
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
	return;
Packit 597cd4
err_pfc:
Packit 597cd4
	free(tlvs->ets->recl);
Packit 597cd4
err_recl:
Packit 597cd4
	free(tlvs->ets->cfgl);
Packit 597cd4
err:
Packit 597cd4
	free(tlvs->ets);
Packit 597cd4
	free(tlvs->rx);
Packit 597cd4
	free(tlvs);
Packit 597cd4
	LLDPAD_WARN("%s: %s malloc failed.\n", __func__, ifname);
Packit 597cd4
	return;
Packit 597cd4
}
Packit 597cd4
Packit 597cd4
/*
Packit 597cd4
 * ets_sm - Asymmetric State Machine for the ETS tlv
Packit 597cd4
 */
Packit 597cd4
static void ets_sm(struct etscfg_obj *localAdminParam,
Packit 597cd4
		   struct etsrec_obj *remoteParam,
Packit 597cd4
		   bool *state)
Packit 597cd4
{
Packit 597cd4
	int willing = localAdminParam->willing;
Packit 597cd4
Packit 597cd4
	if (willing && remoteParam)
Packit 597cd4
		*state = RX_RECOMMEND;
Packit 597cd4
	else if (!willing || !remoteParam)
Packit 597cd4
		*state = INIT;
Packit 597cd4
}
Packit 597cd4
Packit 597cd4
/*
Packit 597cd4
 * cmp_mac_addrs - Compares 2 MAC addresses.
Packit 597cd4
 * returns 1, if first_mac > second_mac; else 0
Packit 597cd4
 */
Packit 597cd4
static bool cmp_mac_addrs(u8 first_mac[], u8 second_mac[])
Packit 597cd4
{
Packit 597cd4
	int i;
Packit 597cd4
Packit 597cd4
	for (i = 0; i < ETH_ALEN; i++) {
Packit 597cd4
		if (first_mac[i] == second_mac[i])
Packit 597cd4
			continue;
Packit 597cd4
		if (first_mac[i] < second_mac[i])
Packit 597cd4
			return 0;
Packit 597cd4
		return 1;
Packit 597cd4
	}
Packit 597cd4
	return 0;
Packit 597cd4
}
Packit 597cd4
Packit 597cd4
/*
Packit 597cd4
 * pfc_sm - Symmetric State Machine for the PFC tlv
Packit 597cd4
 */
Packit 597cd4
static void pfc_sm(struct ieee8021qaz_tlvs *tlvs)
Packit 597cd4
{
Packit 597cd4
	bool local_willing, remote_willing;
Packit 597cd4
	bool remote_param, cmp_mac;
Packit 597cd4
Packit 597cd4
	local_willing = tlvs->pfc->local.willing;
Packit 597cd4
	remote_willing = tlvs->pfc->remote.willing;
Packit 597cd4
	remote_param = tlvs->pfc->remote_param;
Packit 597cd4
	cmp_mac = cmp_mac_addrs(tlvs->local_mac, tlvs->remote_mac);
Packit 597cd4
Packit 597cd4
	if ((local_willing && !remote_willing && remote_param) ||
Packit 597cd4
	    (local_willing && remote_willing && !cmp_mac))
Packit 597cd4
		tlvs->pfc->current_state = RX_RECOMMEND;
Packit 597cd4
	else if (!local_willing || !remote_param ||
Packit 597cd4
		 (local_willing && remote_willing && cmp_mac))
Packit 597cd4
		tlvs->pfc->current_state = INIT;
Packit 597cd4
}
Packit 597cd4
Packit 597cd4
#ifdef LLDPAD_8021QAZ_DEBUG
Packit 597cd4
void print_ets(struct ieee_ets *ets)
Packit 597cd4
{
Packit 597cd4
	int i;
Packit 597cd4
Packit 597cd4
	printf("ETS:\n");
Packit 597cd4
	printf("\tcap %2x cbs %2x\n", ets->ets_cap, ets->cbs);
Packit 597cd4
Packit 597cd4
	printf("\tets tc_tx_bw: ");
Packit 597cd4
	for (i = 0; i < 8; i++)
Packit 597cd4
		printf("%i ", ets->tc_tx_bw[i]);
Packit 597cd4
	printf("\n");
Packit 597cd4
Packit 597cd4
	printf("\tets tc_rx_bw: ");
Packit 597cd4
	for (i = 0; i < 8; i++)
Packit 597cd4
		printf("%i ", ets->tc_rx_bw[i]);
Packit 597cd4
	printf("\n");
Packit 597cd4
Packit 597cd4
	printf("\tets tc_tsa: ");
Packit 597cd4
	for (i = 0; i < 8; i++)
Packit 597cd4
		printf("%i ", ets->tc_tsa[i]);
Packit 597cd4
	printf("\n");
Packit 597cd4
Packit 597cd4
	printf("\tets prio_tc: ");
Packit 597cd4
	for (i = 0; i < 8; i++)
Packit 597cd4
		printf("%i ", ets->prio_tc[i]);
Packit 597cd4
	printf("\n");
Packit 597cd4
}
Packit 597cd4
Packit 597cd4
void print_pfc(struct ieee_pfc *pfc)
Packit 597cd4
{
Packit 597cd4
	int i;
Packit 597cd4
Packit 597cd4
	printf("PFC:\n");
Packit 597cd4
	printf("\t cap %2x en %2x\n", pfc->pfc_cap, pfc->pfc_en);
Packit 597cd4
	printf("\t mbc %2x delay %i\n", pfc->mbc, pfc->delay);
Packit 597cd4
Packit 597cd4
	printf("\t requests: ");
Packit 597cd4
	for (i = 0; i < 8; i++)
Packit 597cd4
		printf("%llu ", pfc->requests[i]);
Packit 597cd4
	printf("\n");
Packit 597cd4
Packit 597cd4
	printf("\t indications: ");
Packit 597cd4
	for (i = 0; i < 8; i++)
Packit 597cd4
		printf("%llu ", pfc->indications[i]);
Packit 597cd4
	printf("\n");
Packit 597cd4
}
Packit 597cd4
#endif
Packit 597cd4
Packit 597cd4
/*
Packit 597cd4
 * get_ieee_hw - Populates IEEE data structures with hardware DCB attributes.
Packit 597cd4
 *
Packit 597cd4
 * @ifname: interface name to query
Packit 597cd4
 * @ets: pointer to copy returned ETS struct
Packit 597cd4
 * @pfc: pointer to copy returned PFC struct
Packit 597cd4
 * @app: pointer to copy concatenated APP entries
Packit 597cd4
 * @cnt: number of app entries returned
Packit 597cd4
 *
Packit 597cd4
 * Returns nlmsg bytes size on success otherwise negative error code.
Packit 597cd4
 */
Packit 597cd4
static int get_ieee_hw(const char *ifname, struct ieee_ets **ets,
Packit 597cd4
			struct ieee_pfc **pfc, struct app_prio **app,
Packit 597cd4
			int *cnt)
Packit 597cd4
{
Packit 597cd4
	int err = 0;
Packit 597cd4
	int rem;
Packit 597cd4
	int itr = 0;
Packit 597cd4
	struct sockaddr_nl dest_addr;
Packit 597cd4
	struct nl_sock *nlsocket = NULL;
Packit 597cd4
	struct nl_msg *nlm;
Packit 597cd4
	unsigned char *msg = NULL;
Packit 597cd4
	struct nlmsghdr *hdr;
Packit 597cd4
	struct nlattr *app_attr, *attr, *nattr;
Packit 597cd4
	struct dcbmsg d = {
Packit 597cd4
			   .dcb_family = AF_UNSPEC,
Packit 597cd4
			   .cmd = DCB_CMD_IEEE_GET,
Packit 597cd4
			   .dcb_pad = 0
Packit 597cd4
			  };
Packit 597cd4
Packit 597cd4
	nlsocket = nl_socket_alloc();
Packit 597cd4
	if (!nlsocket) {
Packit 597cd4
		LLDPAD_WARN("%s: %s: nl_handle_alloc failed\n",
Packit 597cd4
			    __func__, ifname);
Packit 597cd4
		*cnt = 0;
Packit 597cd4
		return -ENOMEM;
Packit 597cd4
	}
Packit 597cd4
	nl_socket_set_local_port(nlsocket, 0);
Packit 597cd4
Packit 597cd4
	err = nl_connect(nlsocket, NETLINK_ROUTE);
Packit 597cd4
	if (err < 0) {
Packit 597cd4
		LLDPAD_WARN("%s: %s nlconnect failed abort get ieee, %s\n",
Packit 597cd4
			    __func__, ifname, nl_geterror(err));
Packit 597cd4
		goto out1;
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
	nlm = nlmsg_alloc_simple(RTM_GETDCB, NLM_F_REQUEST);
Packit 597cd4
	if (!nlm) {
Packit 597cd4
		err = -ENOMEM;
Packit 597cd4
		goto out1;
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
	memset(&dest_addr, 0, sizeof(dest_addr));
Packit 597cd4
	dest_addr.nl_family = AF_NETLINK;
Packit 597cd4
	nlmsg_set_dst(nlm, &dest_addr);
Packit 597cd4
Packit 597cd4
	err = nlmsg_append(nlm, &d, sizeof(d), NLMSG_ALIGNTO);
Packit 597cd4
	if (err < 0)
Packit 597cd4
		goto out;
Packit 597cd4
Packit 597cd4
	err = nla_put(nlm, DCB_ATTR_IFNAME, strlen(ifname)+1, ifname);
Packit 597cd4
	if (err < 0)
Packit 597cd4
		goto out;
Packit 597cd4
Packit 597cd4
	err = nl_send_auto_complete(nlsocket, nlm);
Packit 597cd4
	if (err <= 0) {
Packit 597cd4
		LLDPAD_WARN("%s: %s 802.1Qaz get app attributes failed\n",
Packit 597cd4
			    __func__, ifname);
Packit 597cd4
		goto out;
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
	err = nl_recv(nlsocket, &dest_addr, &msg, NULL);
Packit 597cd4
	if (err <= 0) {
Packit 597cd4
		LLDPAD_WARN("%s: %s: nl_recv returned %d\n", __func__, ifname,
Packit 597cd4
			    err);
Packit 597cd4
		goto out;
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
	hdr = (struct nlmsghdr *) msg;
Packit 597cd4
Packit 597cd4
	attr = nlmsg_find_attr(hdr, sizeof(d), DCB_ATTR_IEEE);
Packit 597cd4
	if (!attr) {
Packit 597cd4
		LLDPAD_WARN("%s: %s: nlmsg_find_attr failed\n",
Packit 597cd4
			    __func__, ifname);
Packit 597cd4
		goto out;
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
	*app = malloc(sizeof(struct app_prio));
Packit 597cd4
	if (*app == NULL) {
Packit 597cd4
		err = -ENOMEM;
Packit 597cd4
		goto out;
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
	*ets = malloc(sizeof(struct ieee_ets));
Packit 597cd4
	if (*ets == NULL) {
Packit 597cd4
		err = -ENOMEM;
Packit 597cd4
		free(*app);
Packit 597cd4
		goto out;
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
	*pfc = malloc(sizeof(struct ieee_pfc));
Packit 597cd4
	if (*pfc == NULL) {
Packit 597cd4
		err = -ENOMEM;
Packit 597cd4
		free(*app);
Packit 597cd4
		free(*ets);
Packit 597cd4
		goto out;
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
	memset(*pfc, 0, sizeof(struct ieee_pfc));
Packit 597cd4
	memset(*ets, 0, sizeof(struct ieee_ets));
Packit 597cd4
	memset(*app, 0, sizeof(struct app_prio));
Packit 597cd4
Packit 597cd4
	nla_for_each_nested(nattr, attr, rem) {
Packit 597cd4
		if (nla_type(nattr) == DCB_ATTR_IEEE_APP_TABLE) {
Packit 597cd4
			struct app_prio *this_app = *app;
Packit 597cd4
Packit 597cd4
			nla_for_each_nested(app_attr, nattr, rem) {
Packit 597cd4
				struct dcb_app *data = nla_data(app_attr);
Packit 597cd4
Packit 597cd4
				LLDPAD_DBG("app %i %i %i\n",
Packit 597cd4
					   data->selector,
Packit 597cd4
					   data->protocol,
Packit 597cd4
					   data->priority);
Packit 597cd4
Packit 597cd4
				this_app = realloc(this_app,
Packit 597cd4
					      sizeof(struct app_prio) * itr +
Packit 597cd4
					      sizeof(struct app_prio));
Packit 597cd4
				if (!this_app) {
Packit 597cd4
					free(this_app);
Packit 597cd4
					free(*ets);
Packit 597cd4
					free(*pfc);
Packit 597cd4
					err = -ENOMEM;
Packit 597cd4
					LLDPAD_WARN("%s: %s: realloc failed\n",
Packit 597cd4
						    __func__, ifname);
Packit 597cd4
					goto out;
Packit 597cd4
				}
Packit 597cd4
				this_app[itr].prs =
Packit 597cd4
					(data->priority << 5) | data->selector;
Packit 597cd4
				this_app[itr].pid = htons(data->protocol);
Packit 597cd4
				itr++;
Packit 597cd4
			}
Packit 597cd4
Packit 597cd4
			/* realloc may have moved app so reset it */
Packit 597cd4
			*app = this_app;
Packit 597cd4
		}
Packit 597cd4
Packit 597cd4
		if (nla_type(nattr) == DCB_ATTR_IEEE_ETS) {
Packit 597cd4
			struct ieee_ets *nl_ets = nla_data(nattr);
Packit 597cd4
Packit 597cd4
			memcpy(*ets, nl_ets, sizeof(struct ieee_ets));
Packit 597cd4
#ifdef LLDPAD_8021QAZ_DEBUG
Packit 597cd4
			print_ets(nl_ets);
Packit 597cd4
#endif
Packit 597cd4
		}
Packit 597cd4
Packit 597cd4
		if (nla_type(nattr) == DCB_ATTR_IEEE_PFC) {
Packit 597cd4
			struct ieee_pfc *nl_pfc = nla_data(nattr);
Packit 597cd4
Packit 597cd4
			memcpy(*pfc, nl_pfc, sizeof(struct ieee_pfc));
Packit 597cd4
#ifdef LLDPAD_8021QAZ_DEBUG
Packit 597cd4
			print_pfc(nl_pfc);
Packit 597cd4
#endif
Packit 597cd4
		}
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
out:
Packit 597cd4
	nlmsg_free(nlm);
Packit 597cd4
	free(msg);
Packit 597cd4
	nl_close(nlsocket);
Packit 597cd4
	nl_socket_free(nlsocket);
Packit 597cd4
out1:
Packit 597cd4
	*cnt = itr;
Packit 597cd4
	return err;
Packit 597cd4
}
Packit 597cd4
Packit 597cd4
static int del_ieee_hw(const char *ifname, struct dcb_app *app_data)
Packit 597cd4
{
Packit 597cd4
	int err = 0;
Packit 597cd4
	struct nlattr *ieee, *app;
Packit 597cd4
	struct sockaddr_nl dest_addr;
Packit 597cd4
	struct nl_sock *nlsocket;
Packit 597cd4
	struct nl_msg *nlm;
Packit 597cd4
	struct dcbmsg d = {
Packit 597cd4
			   .dcb_family = AF_UNSPEC,
Packit 597cd4
			   .cmd = DCB_CMD_IEEE_DEL,
Packit 597cd4
			   .dcb_pad = 0
Packit 597cd4
			  };
Packit 597cd4
Packit 597cd4
	nlsocket = nl_socket_alloc();
Packit 597cd4
	if (!nlsocket) {
Packit 597cd4
		LLDPAD_WARN("%s: %s: nl_handle_alloc failed\n",
Packit 597cd4
			    __func__, ifname);
Packit 597cd4
		return -ENOMEM;
Packit 597cd4
	}
Packit 597cd4
	nl_socket_set_local_port(nlsocket, 0);
Packit 597cd4
Packit 597cd4
	err = nl_connect(nlsocket, NETLINK_ROUTE);
Packit 597cd4
	if (err < 0) {
Packit 597cd4
		LLDPAD_WARN("%s: %s nlconnect failed abort hardware set, %s\n",
Packit 597cd4
			    __func__, ifname, nl_geterror(err));
Packit 597cd4
		err = -EIO;
Packit 597cd4
		goto out1;
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
	nlm = nlmsg_alloc_simple(RTM_SETDCB, NLM_F_REQUEST);
Packit 597cd4
	if (!nlm) {
Packit 597cd4
		err = -ENOMEM;
Packit 597cd4
		goto out2;
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
	memset(&dest_addr, 0, sizeof(dest_addr));
Packit 597cd4
	dest_addr.nl_family = AF_NETLINK;
Packit 597cd4
	nlmsg_set_dst(nlm, &dest_addr);
Packit 597cd4
Packit 597cd4
	err = nlmsg_append(nlm, &d, sizeof(d), NLMSG_ALIGNTO);
Packit 597cd4
	if (err < 0)
Packit 597cd4
		goto out;
Packit 597cd4
Packit 597cd4
	err = nla_put(nlm, DCB_ATTR_IFNAME, strlen(ifname)+1, ifname);
Packit 597cd4
	if (err < 0)
Packit 597cd4
		goto out;
Packit 597cd4
Packit 597cd4
	ieee = nla_nest_start(nlm, DCB_ATTR_IEEE);
Packit 597cd4
	if (!ieee) {
Packit 597cd4
		err = -ENOMEM;
Packit 597cd4
		goto out;
Packit 597cd4
	}
Packit 597cd4
	if (app_data) {
Packit 597cd4
		app = nla_nest_start(nlm, DCB_ATTR_IEEE_APP_TABLE);
Packit 597cd4
		if (!app) {
Packit 597cd4
			err = -ENOMEM;
Packit 597cd4
			goto out;
Packit 597cd4
		}
Packit 597cd4
Packit 597cd4
		err = nla_put(nlm, DCB_ATTR_IEEE_APP,
Packit 597cd4
			      sizeof(*app_data), app_data);
Packit 597cd4
		if (err < 0)
Packit 597cd4
			goto out;
Packit 597cd4
		nla_nest_end(nlm, app);
Packit 597cd4
	}
Packit 597cd4
	nla_nest_end(nlm, ieee);
Packit 597cd4
	err = nl_send_auto_complete(nlsocket, nlm);
Packit 597cd4
	if (err <= 0)
Packit 597cd4
		LLDPAD_WARN("%s: %s 802.1Qaz set attributes failed\n",
Packit 597cd4
			    __func__, ifname);
Packit 597cd4
Packit 597cd4
out:
Packit 597cd4
	nlmsg_free(nlm);
Packit 597cd4
out2:
Packit 597cd4
	nl_close(nlsocket);
Packit 597cd4
	nl_socket_free(nlsocket);
Packit 597cd4
out1:
Packit 597cd4
	return err;
Packit 597cd4
Packit 597cd4
Packit 597cd4
}
Packit 597cd4
Packit 597cd4
static int set_ieee_hw(const char *ifname, struct ieee_ets *ets_data,
Packit 597cd4
		       struct ieee_pfc *pfc_data, struct dcb_app *app_data)
Packit 597cd4
{
Packit 597cd4
	int err = 0;
Packit 597cd4
	struct nlattr *ieee, *app;
Packit 597cd4
	struct sockaddr_nl dest_addr;
Packit 597cd4
	struct nl_sock *nlsocket;
Packit 597cd4
	struct nl_msg *nlm;
Packit 597cd4
	struct dcbmsg d = {
Packit 597cd4
			   .dcb_family = AF_UNSPEC,
Packit 597cd4
			   .cmd = DCB_CMD_IEEE_SET,
Packit 597cd4
			   .dcb_pad = 0
Packit 597cd4
			  };
Packit 597cd4
Packit 597cd4
	nlsocket = nl_socket_alloc();
Packit 597cd4
	if (!nlsocket) {
Packit 597cd4
		LLDPAD_WARN("%s: %s: nl_handle_alloc failed\n",
Packit 597cd4
			    __func__, ifname);
Packit 597cd4
		return -ENOMEM;
Packit 597cd4
	}
Packit 597cd4
	nl_socket_set_local_port(nlsocket, 0);
Packit 597cd4
Packit 597cd4
	if (!ets_data && !pfc_data && !app_data) {
Packit 597cd4
		err = 0;
Packit 597cd4
		goto out1;
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
#ifdef LLDPAD_8021QAZ_DEBUG
Packit 597cd4
	if (ets_data)
Packit 597cd4
		print_ets(ets_data);
Packit 597cd4
	if (pfc_data)
Packit 597cd4
		print_pfc(pfc_data);
Packit 597cd4
#endif
Packit 597cd4
Packit 597cd4
	err = nl_connect(nlsocket, NETLINK_ROUTE);
Packit 597cd4
	if (err < 0) {
Packit 597cd4
		LLDPAD_WARN("%s: %s nlconnect failed abort hardware set, %s\n",
Packit 597cd4
			    __func__, ifname, nl_geterror(err));
Packit 597cd4
		err = -EIO;
Packit 597cd4
		goto out1;
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
	nlm = nlmsg_alloc_simple(RTM_SETDCB, NLM_F_REQUEST);
Packit 597cd4
	if (!nlm) {
Packit 597cd4
		err = -ENOMEM;
Packit 597cd4
		goto out2;
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
	memset(&dest_addr, 0, sizeof(dest_addr));
Packit 597cd4
	dest_addr.nl_family = AF_NETLINK;
Packit 597cd4
	nlmsg_set_dst(nlm, &dest_addr);
Packit 597cd4
Packit 597cd4
	err = nlmsg_append(nlm, &d, sizeof(d), NLMSG_ALIGNTO);
Packit 597cd4
	if (err < 0)
Packit 597cd4
		goto out;
Packit 597cd4
Packit 597cd4
	err = nla_put(nlm, DCB_ATTR_IFNAME, strlen(ifname)+1, ifname);
Packit 597cd4
	if (err < 0)
Packit 597cd4
		goto out;
Packit 597cd4
Packit 597cd4
	ieee = nla_nest_start(nlm, DCB_ATTR_IEEE);
Packit 597cd4
	if (!ieee) {
Packit 597cd4
		err = -ENOMEM;
Packit 597cd4
		goto out;
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
	if (ets_data) {
Packit 597cd4
		err = nla_put(nlm, DCB_ATTR_IEEE_ETS,
Packit 597cd4
			      sizeof(*ets_data), ets_data);
Packit 597cd4
		if (err < 0)
Packit 597cd4
			goto out;
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
	if (pfc_data) {
Packit 597cd4
		err = nla_put(nlm, DCB_ATTR_IEEE_PFC,
Packit 597cd4
			      sizeof(*pfc_data), pfc_data);
Packit 597cd4
		if (err < 0)
Packit 597cd4
			goto out;
Packit 597cd4
	}
Packit 597cd4
	if (app_data) {
Packit 597cd4
		app = nla_nest_start(nlm, DCB_ATTR_IEEE_APP_TABLE);
Packit 597cd4
		if (!app) {
Packit 597cd4
			err = -ENOMEM;
Packit 597cd4
			goto out;
Packit 597cd4
		}
Packit 597cd4
Packit 597cd4
		err = nla_put(nlm, DCB_ATTR_IEEE_APP,
Packit 597cd4
			      sizeof(*app_data), app_data);
Packit 597cd4
		if (err < 0)
Packit 597cd4
			goto out;
Packit 597cd4
		nla_nest_end(nlm, app);
Packit 597cd4
	}
Packit 597cd4
	nla_nest_end(nlm, ieee);
Packit 597cd4
	err = nl_send_auto_complete(nlsocket, nlm);
Packit 597cd4
	if (err <= 0)
Packit 597cd4
		LLDPAD_WARN("%s: %s 802.1Qaz set attributes failed\n",
Packit 597cd4
			    __func__, ifname);
Packit 597cd4
Packit 597cd4
out:
Packit 597cd4
	nlmsg_free(nlm);
Packit 597cd4
out2:
Packit 597cd4
	nl_close(nlsocket);
Packit 597cd4
	nl_socket_free(nlsocket);
Packit 597cd4
out1:
Packit 597cd4
	return err;
Packit 597cd4
}
Packit 597cd4
Packit 597cd4
static void ets_cfg_to_ieee(struct ieee_ets *ieee, struct etscfg_obj *cfg)
Packit 597cd4
{
Packit 597cd4
	int i;
Packit 597cd4
Packit 597cd4
	memcpy(ieee->tc_tx_bw, cfg->tc_bw, MAX_TCS);
Packit 597cd4
	memcpy(ieee->tc_rx_bw, cfg->tc_bw, MAX_TCS);
Packit 597cd4
	memcpy(ieee->tc_tsa, cfg->tsa_map, MAX_TCS);
Packit 597cd4
Packit 597cd4
	for (i = 0; i < MAX_USER_PRIORITIES; i++)
Packit 597cd4
		ieee->prio_tc[i] = get_prio_map(cfg->prio_map, i);
Packit 597cd4
Packit 597cd4
	memcpy(ieee->tc_reco_bw, cfg->tc_bw, MAX_TCS);
Packit 597cd4
	memcpy(ieee->tc_reco_tsa, cfg->tsa_map, MAX_TCS);
Packit 597cd4
Packit 597cd4
	for (i = 0; i < MAX_USER_PRIORITIES; i++)
Packit 597cd4
		ieee->reco_prio_tc[i] = get_prio_map(cfg->prio_map, i);
Packit 597cd4
Packit 597cd4
	return;
Packit 597cd4
}
Packit 597cd4
Packit 597cd4
static void ets_rec_to_ieee(struct ieee_ets *ieee, struct etsrec_obj *rec)
Packit 597cd4
{
Packit 597cd4
	int i;
Packit 597cd4
Packit 597cd4
	memcpy(ieee->tc_tx_bw, rec->tc_bw, MAX_TCS);
Packit 597cd4
	memcpy(ieee->tc_rx_bw, rec->tc_bw, MAX_TCS);
Packit 597cd4
	memcpy(ieee->tc_tsa, rec->tsa_map, MAX_TCS);
Packit 597cd4
Packit 597cd4
	for (i = 0; i < MAX_TCS; i++)
Packit 597cd4
		ieee->prio_tc[i] = get_prio_map(rec->prio_map, i);
Packit 597cd4
Packit 597cd4
	memcpy(ieee->tc_reco_bw, rec->tc_bw, MAX_TCS);
Packit 597cd4
	memcpy(ieee->tc_reco_tsa, rec->tsa_map, MAX_TCS);
Packit 597cd4
Packit 597cd4
	for (i = 0; i < MAX_TCS; i++)
Packit 597cd4
		ieee->reco_prio_tc[i] = get_prio_map(rec->prio_map, i);
Packit 597cd4
Packit 597cd4
	return;
Packit 597cd4
}
Packit 597cd4
Packit 597cd4
void run_all_sm(struct port *port, struct lldp_agent *agent)
Packit 597cd4
{
Packit 597cd4
	struct ieee8021qaz_tlvs *tlvs;
Packit 597cd4
	struct ieee_ets *ets;
Packit 597cd4
	struct ieee_pfc *pfc;
Packit 597cd4
	struct pfc_obj *pfc_obj;
Packit 597cd4
Packit 597cd4
	if (agent->type != NEAREST_BRIDGE)
Packit 597cd4
		return;
Packit 597cd4
Packit 597cd4
	tlvs = ieee8021qaz_data(port->ifname);
Packit 597cd4
	if (!tlvs)
Packit 597cd4
		return;
Packit 597cd4
Packit 597cd4
	ets_sm(tlvs->ets->cfgl, tlvs->ets->recr, &tlvs->ets->current_state);
Packit 597cd4
Packit 597cd4
	ets = malloc(sizeof(*ets));
Packit 597cd4
	if (!ets) {
Packit 597cd4
		LLDPAD_WARN("%s: %s: ets malloc failed\n",
Packit 597cd4
			    __func__, port->ifname);
Packit 597cd4
		return;
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
	memset(ets, 0, sizeof(*ets));
Packit 597cd4
Packit 597cd4
	if (tlvs->ets->current_state == RX_RECOMMEND)
Packit 597cd4
		ets_rec_to_ieee(ets, tlvs->ets->recr);
Packit 597cd4
	else
Packit 597cd4
		ets_cfg_to_ieee(ets, tlvs->ets->cfgl);
Packit 597cd4
Packit 597cd4
	pfc_sm(tlvs);
Packit 597cd4
Packit 597cd4
	if (tlvs->pfc->current_state == RX_RECOMMEND)
Packit 597cd4
		pfc_obj = &tlvs->pfc->remote;
Packit 597cd4
	else
Packit 597cd4
		pfc_obj = &tlvs->pfc->local;
Packit 597cd4
Packit 597cd4
	pfc = malloc(sizeof(*pfc));
Packit 597cd4
	if (!pfc) {
Packit 597cd4
		LLDPAD_WARN("%s: %s: pfc malloc failed\n",
Packit 597cd4
			    __func__, port->ifname);
Packit 597cd4
		goto out;
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
	memset(pfc, 0, sizeof(*pfc));
Packit 597cd4
Packit 597cd4
	pfc->pfc_en = pfc_obj->pfc_enable;
Packit 597cd4
	pfc->mbc = pfc_obj->mbc;
Packit 597cd4
	pfc->delay = pfc_obj->delay;
Packit 597cd4
Packit 597cd4
	if (ieee8021qaz_check_active(port->ifname)) {
Packit 597cd4
		set_dcbx_mode(port->ifname,
Packit 597cd4
			      DCB_CAP_DCBX_VER_IEEE | DCB_CAP_DCBX_HOST);
Packit 597cd4
		set_ieee_hw(port->ifname, ets, pfc, NULL);
Packit 597cd4
		ieee8021qaz_app_sethw(port->ifname, &tlvs->app_head);
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
out:
Packit 597cd4
	free(pfc);
Packit 597cd4
	free(ets);
Packit 597cd4
}
Packit 597cd4
Packit 597cd4
/*
Packit 597cd4
 * bld_ieee8021qaz_etscfg_tlv - builds the ETS Configuration TLV
Packit 597cd4
 * Returns 1 on success, NULL if the TLV fail to build correctly.
Packit 597cd4
 */
Packit 597cd4
static struct unpacked_tlv *
Packit 597cd4
bld_ieee8021qaz_etscfg_tlv(struct ieee8021qaz_tlvs *tlvs)
Packit 597cd4
{
Packit 597cd4
	struct ieee8021qaz_tlv_etscfg *etscfg;
Packit 597cd4
	struct unpacked_tlv *tlv = create_tlv();
Packit 597cd4
	int i = 0;
Packit 597cd4
Packit 597cd4
	if (!tlv)
Packit 597cd4
		return NULL;
Packit 597cd4
Packit 597cd4
	etscfg = (struct ieee8021qaz_tlv_etscfg *)malloc(sizeof(*etscfg));
Packit 597cd4
	if (!etscfg) {
Packit 597cd4
		LLDPAD_WARN("%s: Failed to malloc etscfg\n", __func__);
Packit 597cd4
		free(tlv);
Packit 597cd4
		return NULL;
Packit 597cd4
	}
Packit 597cd4
	memset(etscfg, 0, sizeof(*etscfg));
Packit 597cd4
Packit 597cd4
	hton24(etscfg->oui, OUI_IEEE_8021);
Packit 597cd4
	etscfg->subtype = LLDP_8021QAZ_ETSCFG;
Packit 597cd4
	etscfg->wcrt = tlvs->ets->cfgl->willing << 7 |
Packit 597cd4
		       tlvs->ets->cfgl->cbs << 6 |
Packit 597cd4
		       (tlvs->ets->cfgl->max_tcs & 0x7);
Packit 597cd4
Packit 597cd4
	if (tlvs->ets->current_state == INIT) {
Packit 597cd4
		etscfg->prio_map = htonl(tlvs->ets->cfgl->prio_map);
Packit 597cd4
		for (i = 0; i < MAX_TCS; i++) {
Packit 597cd4
			etscfg->tc_bw[i] = tlvs->ets->cfgl->tc_bw[i];
Packit 597cd4
			etscfg->tsa_map[i] = tlvs->ets->cfgl->tsa_map[i];
Packit 597cd4
		}
Packit 597cd4
	} else {
Packit 597cd4
		etscfg->prio_map = htonl(tlvs->ets->recr->prio_map);
Packit 597cd4
		for (i = 0; i < MAX_TCS; i++) {
Packit 597cd4
			etscfg->tc_bw[i] = tlvs->ets->recr->tc_bw[i];
Packit 597cd4
			etscfg->tsa_map[i] = tlvs->ets->recr->tsa_map[i];
Packit 597cd4
		}
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
	tlv->type = ORG_SPECIFIC_TLV;
Packit 597cd4
	tlv->length = sizeof(struct ieee8021qaz_tlv_etscfg);
Packit 597cd4
	tlv->info = (u8 *)etscfg;
Packit 597cd4
Packit 597cd4
	if (OUI_SUB_SIZE > tlv->length)
Packit 597cd4
		goto error;
Packit 597cd4
Packit 597cd4
	return tlv;
Packit 597cd4
Packit 597cd4
error:
Packit 597cd4
	if (tlv) {
Packit 597cd4
		if (tlv->info)
Packit 597cd4
			free(tlv->info);
Packit 597cd4
		free(tlv);
Packit 597cd4
	}
Packit 597cd4
	LLDPAD_WARN("%s: Failed\n", __func__);
Packit 597cd4
	return NULL;
Packit 597cd4
}
Packit 597cd4
Packit 597cd4
/*
Packit 597cd4
 * bld_ieee8021qaz_etsrec_tlv - builds the ETS Recommendation TLV
Packit 597cd4
 * Returns 1 on success, NULL if the TLV fail to build correctly.
Packit 597cd4
 */
Packit 597cd4
struct unpacked_tlv *
Packit 597cd4
bld_ieee8021qaz_etsrec_tlv(struct ieee8021qaz_tlvs *tlvs)
Packit 597cd4
{
Packit 597cd4
	struct ieee8021qaz_tlv_etsrec *etsrec;
Packit 597cd4
	struct unpacked_tlv *tlv = create_tlv();
Packit 597cd4
	int i = 0;
Packit 597cd4
Packit 597cd4
	if (!tlv)
Packit 597cd4
		return NULL;
Packit 597cd4
Packit 597cd4
	etsrec = (struct ieee8021qaz_tlv_etsrec *)malloc(sizeof(*etsrec));
Packit 597cd4
	if (!etsrec) {
Packit 597cd4
		LLDPAD_WARN("%s: Failed to malloc etscfg\n", __func__);
Packit 597cd4
		free(tlv);
Packit 597cd4
		return NULL;
Packit 597cd4
	}
Packit 597cd4
	memset(etsrec, 0, sizeof(*etsrec));
Packit 597cd4
Packit 597cd4
	hton24(etsrec->oui, OUI_IEEE_8021);
Packit 597cd4
	etsrec->subtype = LLDP_8021QAZ_ETSREC;
Packit 597cd4
	etsrec->prio_map = htonl(tlvs->ets->recl->prio_map);
Packit 597cd4
Packit 597cd4
	for (i = 0; i < MAX_TCS; i++) {
Packit 597cd4
		etsrec->tc_bw[i] = tlvs->ets->recl->tc_bw[i];
Packit 597cd4
		etsrec->tsa_map[i] = tlvs->ets->recl->tsa_map[i];
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
	tlv->type = ORG_SPECIFIC_TLV;
Packit 597cd4
	tlv->length = sizeof(struct ieee8021qaz_tlv_etsrec);
Packit 597cd4
	tlv->info = (u8 *)etsrec;
Packit 597cd4
Packit 597cd4
	if (OUI_SUB_SIZE > tlv->length)
Packit 597cd4
		goto error;
Packit 597cd4
Packit 597cd4
	return tlv;
Packit 597cd4
Packit 597cd4
error:
Packit 597cd4
	if (tlv) {
Packit 597cd4
		if (tlv->info)
Packit 597cd4
			free(tlv->info);
Packit 597cd4
		free(tlv);
Packit 597cd4
	}
Packit 597cd4
	LLDPAD_WARN("%s: Failed\n", __func__);
Packit 597cd4
	return NULL;
Packit 597cd4
}
Packit 597cd4
Packit 597cd4
/*
Packit 597cd4
 * bld_ieee8021qaz_pfc_tlv - builds the PFC Control Configuration TLV
Packit 597cd4
 * Returns unpacket tlv or NULL if the TLV fails to build correctly.
Packit 597cd4
 */
Packit 597cd4
static struct unpacked_tlv *
Packit 597cd4
bld_ieee8021qaz_pfc_tlv(struct ieee8021qaz_tlvs *tlvs)
Packit 597cd4
{
Packit 597cd4
	struct ieee8021qaz_tlv_pfc *pfc;
Packit 597cd4
	struct unpacked_tlv *tlv = create_tlv();
Packit 597cd4
Packit 597cd4
	if (!tlv)
Packit 597cd4
		return NULL;
Packit 597cd4
Packit 597cd4
	pfc = (struct ieee8021qaz_tlv_pfc *)malloc(sizeof(*pfc));
Packit 597cd4
	if (!pfc) {
Packit 597cd4
		LLDPAD_WARN("%s: Failed to malloc pfc\n", __func__);
Packit 597cd4
		free(tlv);
Packit 597cd4
		return NULL;
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
	memset(pfc, 0, sizeof(*pfc));
Packit 597cd4
Packit 597cd4
	hton24(pfc->oui, OUI_IEEE_8021);
Packit 597cd4
	pfc->subtype = LLDP_8021QAZ_PFC;
Packit 597cd4
Packit 597cd4
	pfc->wmrc = tlvs->pfc->local.willing << 7 |
Packit 597cd4
		    tlvs->pfc->local.mbc << 6 |
Packit 597cd4
		    tlvs->pfc->local.pfc_cap;
Packit 597cd4
Packit 597cd4
	if (tlvs->pfc->current_state == INIT)
Packit 597cd4
		pfc->pfc_enable = tlvs->pfc->local.pfc_enable;
Packit 597cd4
	else
Packit 597cd4
		pfc->pfc_enable = tlvs->pfc->remote.pfc_enable;
Packit 597cd4
Packit 597cd4
	tlv->type = ORG_SPECIFIC_TLV;
Packit 597cd4
	tlv->length = sizeof(struct ieee8021qaz_tlv_pfc);
Packit 597cd4
	tlv->info = (u8 *)pfc;
Packit 597cd4
Packit 597cd4
	if (OUI_SUB_SIZE > tlv->length)
Packit 597cd4
		goto error;
Packit 597cd4
Packit 597cd4
	return tlv;
Packit 597cd4
error:
Packit 597cd4
	if (tlv) {
Packit 597cd4
		if (tlv->info)
Packit 597cd4
			free(tlv->info);
Packit 597cd4
		free(tlv);
Packit 597cd4
	}
Packit 597cd4
	LLDPAD_WARN("%s: Failed\n", __func__);
Packit 597cd4
	return NULL;
Packit 597cd4
}
Packit 597cd4
Packit 597cd4
/*
Packit 597cd4
 * bld_ieee8021qaz_app_tlv - builds the APP TLV
Packit 597cd4
 * Returns unacked tlv or NULL if the TLV fails to build correctly.
Packit 597cd4
 */
Packit 597cd4
static struct unpacked_tlv *
Packit 597cd4
bld_ieee8021qaz_app_tlv(char *ifname)
Packit 597cd4
{
Packit 597cd4
	struct ieee8021qaz_tlv_app *app = NULL;
Packit 597cd4
	struct unpacked_tlv *tlv;
Packit 597cd4
	struct ieee_ets *ets = NULL;
Packit 597cd4
	struct ieee_pfc *pfc = NULL;
Packit 597cd4
	struct app_prio *data = NULL;
Packit 597cd4
	__u8 *ptr;
Packit 597cd4
	int cnt, err;
Packit 597cd4
Packit 597cd4
	tlv = create_tlv();
Packit 597cd4
	if (!tlv)
Packit 597cd4
		return NULL;
Packit 597cd4
Packit 597cd4
	err = get_ieee_hw(ifname, &ets, &pfc, &data, &cnt);
Packit 597cd4
	if (!err) {
Packit 597cd4
		LLDPAD_WARN("%s: %s: get_ieee_hw failed\n", __func__, ifname);
Packit 597cd4
		goto error;
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
	app = malloc(sizeof(*app) + (sizeof(*data) * cnt));
Packit 597cd4
	if (!app) {
Packit 597cd4
		LLDPAD_WARN("%s: Failed to malloc app\n", __func__);
Packit 597cd4
		goto error;
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
	memset(app, 0, sizeof(*app));
Packit 597cd4
	hton24(app->oui, OUI_IEEE_8021);
Packit 597cd4
	app->subtype = LLDP_8021QAZ_APP;
Packit 597cd4
Packit 597cd4
	ptr = (u8 *) app + sizeof(*app);
Packit 597cd4
	memcpy(ptr, data, sizeof(*data) * cnt);
Packit 597cd4
Packit 597cd4
	tlv->type = ORG_SPECIFIC_TLV;
Packit 597cd4
	tlv->length = sizeof(struct ieee8021qaz_tlv_app) + (cnt * 3);
Packit 597cd4
	tlv->info = (u8 *)app;
Packit 597cd4
Packit 597cd4
	if (OUI_SUB_SIZE > tlv->length) {
Packit 597cd4
		LLDPAD_WARN("%s: %s: tlv->length = %d, cnt=%d\n", __func__,
Packit 597cd4
			    ifname, tlv->length, cnt);
Packit 597cd4
		goto error;
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
	free(ets);
Packit 597cd4
	free(pfc);
Packit 597cd4
	free(data);
Packit 597cd4
Packit 597cd4
	return tlv;
Packit 597cd4
Packit 597cd4
error:
Packit 597cd4
	free(tlv);
Packit 597cd4
	free(ets);
Packit 597cd4
	free(pfc);
Packit 597cd4
	free(app);
Packit 597cd4
	free(data);
Packit 597cd4
	LLDPAD_WARN("%s: Failed\n", __func__);
Packit 597cd4
	return NULL;
Packit 597cd4
}
Packit 597cd4
Packit 597cd4
/*
Packit 597cd4
 * ieee8021qaz_bld_tlv - builds all IEEE8021QAZ TLVs
Packit 597cd4
 * Returns 1 on success, NULL if any of the TLVs fail to build correctly.
Packit 597cd4
 */
Packit 597cd4
static struct packed_tlv *ieee8021qaz_bld_tlv(struct port *port,
Packit 597cd4
					      struct lldp_agent *agent)
Packit 597cd4
{
Packit 597cd4
	struct ieee8021qaz_tlvs *data;
Packit 597cd4
	struct packed_tlv *ptlv = NULL;
Packit 597cd4
	struct unpacked_tlv *etscfg_tlv, *etsrec_tlv, *pfc_tlv, *app_tlv;
Packit 597cd4
	size_t size;
Packit 597cd4
Packit 597cd4
	if (agent->type != NEAREST_BRIDGE)
Packit 597cd4
		return NULL;
Packit 597cd4
Packit 597cd4
	data = ieee8021qaz_data(port->ifname);
Packit 597cd4
	if (!data)
Packit 597cd4
		return ptlv;
Packit 597cd4
Packit 597cd4
	etscfg_tlv = etsrec_tlv = pfc_tlv = app_tlv = NULL;
Packit 597cd4
Packit 597cd4
	if (!data->active)
Packit 597cd4
		return ptlv;
Packit 597cd4
Packit 597cd4
	if (!is_tlv_txdisabled(port->ifname, agent->type, TLVID_8021(LLDP_8021QAZ_ETSCFG)))
Packit 597cd4
		etscfg_tlv = bld_ieee8021qaz_etscfg_tlv(data);
Packit 597cd4
	if (is_tlv_txenabled(port->ifname, agent->type, TLVID_8021(LLDP_8021QAZ_ETSREC)))
Packit 597cd4
		etsrec_tlv = bld_ieee8021qaz_etsrec_tlv(data);
Packit 597cd4
	if (!is_tlv_txdisabled(port->ifname, agent->type, TLVID_8021(LLDP_8021QAZ_PFC)))
Packit 597cd4
		pfc_tlv = bld_ieee8021qaz_pfc_tlv(data);
Packit 597cd4
	if (is_tlv_txenabled(port->ifname, agent->type, TLVID_8021(LLDP_8021QAZ_APP)))
Packit 597cd4
		app_tlv = bld_ieee8021qaz_app_tlv(port->ifname);
Packit 597cd4
Packit 597cd4
	size = TLVSIZE(etscfg_tlv)
Packit 597cd4
		+ TLVSIZE(etsrec_tlv)
Packit 597cd4
		+ TLVSIZE(pfc_tlv)
Packit 597cd4
		+ TLVSIZE(app_tlv);
Packit 597cd4
Packit 597cd4
	ptlv = create_ptlv();
Packit 597cd4
	if (!ptlv)
Packit 597cd4
		goto err;
Packit 597cd4
Packit 597cd4
	ptlv->tlv = malloc(size);
Packit 597cd4
	if (!ptlv->tlv)
Packit 597cd4
		goto err;
Packit 597cd4
Packit 597cd4
	ptlv->size = 0;
Packit 597cd4
	PACK_TLV_AFTER(etscfg_tlv, ptlv, size, err);
Packit 597cd4
	PACK_TLV_AFTER(etsrec_tlv, ptlv, size, err);
Packit 597cd4
	PACK_TLV_AFTER(pfc_tlv, ptlv, size, err);
Packit 597cd4
	PACK_TLV_AFTER(app_tlv, ptlv, size, err);
Packit 597cd4
err:
Packit 597cd4
	free_unpkd_tlv(etscfg_tlv);
Packit 597cd4
	free_unpkd_tlv(etsrec_tlv);
Packit 597cd4
	free_unpkd_tlv(pfc_tlv);
Packit 597cd4
	free_unpkd_tlv(app_tlv);
Packit 597cd4
	return ptlv;
Packit 597cd4
}
Packit 597cd4
Packit 597cd4
/* LLDP_8021QAZ_MOD_OPS - GETTLV */
Packit 597cd4
struct packed_tlv *ieee8021qaz_gettlv(struct port *port,
Packit 597cd4
				      struct lldp_agent *agent)
Packit 597cd4
{
Packit 597cd4
	struct packed_tlv *ptlv = NULL;
Packit 597cd4
Packit 597cd4
	if (agent->type != NEAREST_BRIDGE)
Packit 597cd4
		return NULL;
Packit 597cd4
Packit 597cd4
	/* Update TLV State Machines */
Packit 597cd4
	run_all_sm(port, agent);
Packit 597cd4
	/* Build TLVs */
Packit 597cd4
	ptlv = ieee8021qaz_bld_tlv(port, agent);
Packit 597cd4
	return ptlv;
Packit 597cd4
}
Packit 597cd4
Packit 597cd4
static bool unpack_ieee8021qaz_tlvs(struct port *port,
Packit 597cd4
				    struct lldp_agent *agent,
Packit 597cd4
				    struct unpacked_tlv *tlv)
Packit 597cd4
{
Packit 597cd4
	/* Unpack tlvs and store in rx */
Packit 597cd4
	struct ieee8021qaz_tlvs *tlvs;
Packit 597cd4
Packit 597cd4
	if (agent->type != NEAREST_BRIDGE) {
Packit 597cd4
		LLDPAD_INFO("%s: %s: ignoring tlv from remote bridge\n",
Packit 597cd4
			    __func__, port->ifname);
Packit 597cd4
		return false;
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
	tlvs = ieee8021qaz_data(port->ifname);
Packit 597cd4
Packit 597cd4
	/* Process */
Packit 597cd4
	switch (tlv->info[OUI_SIZE]) {
Packit 597cd4
	case IEEE8021QAZ_ETSCFG_TLV:
Packit 597cd4
		if (tlvs->rx->etscfg == NULL) {
Packit 597cd4
			tlvs->ieee8021qazdu |= RCVD_IEEE8021QAZ_TLV_ETSCFG;
Packit 597cd4
			tlvs->rx->etscfg = tlv;
Packit 597cd4
		} else {
Packit 597cd4
			LLDPAD_WARN("%s: %s: 802.1Qaz Duplicate ETSCFG TLV\n",
Packit 597cd4
				__func__, port->ifname);
Packit 597cd4
			agent->rx.dupTlvs |= DUP_IEEE8021QAZ_TLV_ETSCFG;
Packit 597cd4
			return false;
Packit 597cd4
		}
Packit 597cd4
		break;
Packit 597cd4
	case IEEE8021QAZ_ETSREC_TLV:
Packit 597cd4
		if (tlvs->rx->etsrec == NULL) {
Packit 597cd4
			tlvs->ieee8021qazdu |= RCVD_IEEE8021QAZ_TLV_ETSREC;
Packit 597cd4
			tlvs->rx->etsrec = tlv;
Packit 597cd4
		} else {
Packit 597cd4
			LLDPAD_WARN("%s: %s: 802.1Qaz Duplicate ETSREC TLV\n",
Packit 597cd4
				__func__, port->ifname);
Packit 597cd4
			agent->rx.dupTlvs |= DUP_IEEE8021QAZ_TLV_ETSREC;
Packit 597cd4
			return false;
Packit 597cd4
		}
Packit 597cd4
		break;
Packit 597cd4
Packit 597cd4
	case IEEE8021QAZ_PFC_TLV:
Packit 597cd4
		if (tlvs->rx->pfc == NULL) {
Packit 597cd4
			tlvs->ieee8021qazdu |= RCVD_IEEE8021QAZ_TLV_PFC;
Packit 597cd4
			tlvs->rx->pfc = tlv;
Packit 597cd4
		} else {
Packit 597cd4
			LLDPAD_WARN("%s: %s: 802.1Qaz Duplicate PFC TLV\n",
Packit 597cd4
				__func__, port->ifname);
Packit 597cd4
			agent->rx.dupTlvs |= DUP_IEEE8021QAZ_TLV_PFC;
Packit 597cd4
			return false;
Packit 597cd4
		}
Packit 597cd4
		break;
Packit 597cd4
	case IEEE8021QAZ_APP_TLV:
Packit 597cd4
		if (tlvs->rx->app == NULL) {
Packit 597cd4
			tlvs->ieee8021qazdu |= RCVD_IEEE8021QAZ_TLV_APP;
Packit 597cd4
			tlvs->rx->app = tlv;
Packit 597cd4
		} else {
Packit 597cd4
			LLDPAD_WARN("%s: %s: 802.1Qaz Duplicate APP TLV\n",
Packit 597cd4
				    __func__, port->ifname);
Packit 597cd4
			agent->rx.dupTlvs |= DUP_IEEE8021QAZ_TLV_APP;
Packit 597cd4
			return false;
Packit 597cd4
		}
Packit 597cd4
		break;
Packit 597cd4
	default:
Packit 597cd4
		LLDPAD_INFO("%s: %s: Unknown TLV 0x%04x\n", __func__,
Packit 597cd4
			    port->ifname, tlv->info[OUI_SIZE]);
Packit 597cd4
		return false;
Packit 597cd4
	}
Packit 597cd4
	return true;
Packit 597cd4
}
Packit 597cd4
Packit 597cd4
static void clear_ieee8021qaz_rx(struct ieee8021qaz_tlvs *tlvs)
Packit 597cd4
{
Packit 597cd4
	if (!tlvs)
Packit 597cd4
		return;
Packit 597cd4
Packit 597cd4
	if (!tlvs->rx)
Packit 597cd4
		return;
Packit 597cd4
Packit 597cd4
	if (tlvs->rx->ieee8021qaz)
Packit 597cd4
		tlvs->rx->ieee8021qaz = free_unpkd_tlv(tlvs->rx->ieee8021qaz);
Packit 597cd4
	if (tlvs->rx->etscfg)
Packit 597cd4
		tlvs->rx->etscfg = free_unpkd_tlv(tlvs->rx->etscfg);
Packit 597cd4
	if (tlvs->rx->etsrec)
Packit 597cd4
		tlvs->rx->etsrec = free_unpkd_tlv(tlvs->rx->etsrec);
Packit 597cd4
	if (tlvs->rx->pfc)
Packit 597cd4
		tlvs->rx->pfc = free_unpkd_tlv(tlvs->rx->pfc);
Packit 597cd4
	if (tlvs->rx->app)
Packit 597cd4
		tlvs->rx->app =	free_unpkd_tlv(tlvs->rx->app);
Packit 597cd4
Packit 597cd4
	free(tlvs->rx);
Packit 597cd4
	tlvs->rx = NULL;
Packit 597cd4
}
Packit 597cd4
Packit 597cd4
static void process_ieee8021qaz_etscfg_tlv(struct port *port)
Packit 597cd4
{
Packit 597cd4
	struct ieee8021qaz_tlvs *tlvs;
Packit 597cd4
	u8 offset = 0;
Packit 597cd4
	int i = 0;
Packit 597cd4
Packit 597cd4
	tlvs = ieee8021qaz_data(port->ifname);
Packit 597cd4
	offset = OUI_SUB_SIZE;
Packit 597cd4
Packit 597cd4
	if (tlvs->ets->cfgr)
Packit 597cd4
		free(tlvs->ets->cfgr);
Packit 597cd4
	tlvs->ets->cfgr = malloc(sizeof(*tlvs->ets->cfgr));
Packit 597cd4
	if (!tlvs->ets->cfgr) {
Packit 597cd4
		LLDPAD_WARN("%s: %s: cfgr malloc failed\n",
Packit 597cd4
			    __func__, port->ifname);
Packit 597cd4
		return;
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
	if (tlvs->rx->etscfg->info[offset] & BIT7)
Packit 597cd4
		tlvs->ets->cfgr->willing = true;
Packit 597cd4
	else
Packit 597cd4
		tlvs->ets->cfgr->willing = false;
Packit 597cd4
Packit 597cd4
	if (tlvs->rx->etscfg->info[offset] & BIT6)
Packit 597cd4
		tlvs->ets->cfgr->cbs = true;
Packit 597cd4
	else
Packit 597cd4
		tlvs->ets->cfgr->cbs = false;
Packit 597cd4
Packit 597cd4
	tlvs->ets->cfgr->max_tcs = tlvs->rx->etscfg->info[offset] & 0x07;
Packit 597cd4
Packit 597cd4
	/*Moving offset to PRIO_MAP */
Packit 597cd4
	offset += 1;
Packit 597cd4
	tlvs->ets->cfgr->prio_map = 0;
Packit 597cd4
	for (i = 0; i < 4; i++) {
Packit 597cd4
		u8 temp1 = 0, temp2 = 0;
Packit 597cd4
Packit 597cd4
		temp1 = (tlvs->rx->etscfg->info[offset] >> 4) & 0x0F;
Packit 597cd4
		temp2 = tlvs->rx->etscfg->info[offset] & 0x0F;
Packit 597cd4
		set_prio_map(&tlvs->ets->cfgr->prio_map, (2*i), temp1);
Packit 597cd4
		set_prio_map(&tlvs->ets->cfgr->prio_map, ((2*i)+1), temp2);
Packit 597cd4
Packit 597cd4
		offset += 1;
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
	for (i = 0; i < MAX_TCS; i++) {
Packit 597cd4
		tlvs->ets->cfgr->tc_bw[i] = tlvs->rx->etscfg->info[offset];
Packit 597cd4
		offset += 1;
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
	for (i = 0; i < MAX_TCS; i++) {
Packit 597cd4
		tlvs->ets->cfgr->tsa_map[i] = tlvs->rx->etscfg->info[offset];
Packit 597cd4
		offset += 1;
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
}
Packit 597cd4
Packit 597cd4
static void process_ieee8021qaz_etsrec_tlv(struct port *port)
Packit 597cd4
{
Packit 597cd4
	struct ieee8021qaz_tlvs *tlvs;
Packit 597cd4
	u8 offset = 0;
Packit 597cd4
	int i = 0;
Packit 597cd4
Packit 597cd4
	tlvs = ieee8021qaz_data(port->ifname);
Packit 597cd4
Packit 597cd4
	/* Bypassing OUI, SUBTYPE fields */
Packit 597cd4
	offset = OUI_SUB_SIZE + 1;
Packit 597cd4
Packit 597cd4
	if (tlvs->ets->recr)
Packit 597cd4
		memset(tlvs->ets->recr, 0, sizeof(*tlvs->ets->recr));
Packit 597cd4
	else
Packit 597cd4
		tlvs->ets->recr = malloc(sizeof(*tlvs->ets->recr));
Packit 597cd4
Packit 597cd4
	if (!tlvs->ets->recr)
Packit 597cd4
		return;
Packit 597cd4
Packit 597cd4
	tlvs->ets->recr->prio_map = 0;
Packit 597cd4
	for (i = 0; i < 4; i++) {
Packit 597cd4
		u8 temp1 = 0, temp2 = 0;
Packit 597cd4
Packit 597cd4
		temp1 = (tlvs->rx->etsrec->info[offset] >> 4) & 0x0F;
Packit 597cd4
		temp2 = tlvs->rx->etsrec->info[offset] & 0x0F;
Packit 597cd4
		set_prio_map(&tlvs->ets->recr->prio_map, (2*i), temp1);
Packit 597cd4
		set_prio_map(&tlvs->ets->recr->prio_map, ((2*i)+1), temp2);
Packit 597cd4
Packit 597cd4
		offset += 1;
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
	for (i = 0; i < MAX_TCS; i++) {
Packit 597cd4
		tlvs->ets->recr->tc_bw[i] = tlvs->rx->etsrec->info[offset];
Packit 597cd4
		offset += 1;
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
	for (i = 0; i < MAX_TCS; i++) {
Packit 597cd4
		tlvs->ets->recr->tsa_map[i] = tlvs->rx->etsrec->info[offset];
Packit 597cd4
		offset += 1;
Packit 597cd4
	}
Packit 597cd4
}
Packit 597cd4
Packit 597cd4
static void process_ieee8021qaz_pfc_tlv(struct port *port)
Packit 597cd4
{
Packit 597cd4
	struct ieee8021qaz_tlvs *tlvs;
Packit 597cd4
	u8 offset = 0;
Packit 597cd4
Packit 597cd4
	tlvs = ieee8021qaz_data(port->ifname);
Packit 597cd4
Packit 597cd4
	/* Bypassing OUI, SUBTYPE fields */
Packit 597cd4
	offset = OUI_SUB_SIZE;
Packit 597cd4
	if (tlvs->rx->pfc->info[offset] & BIT7)
Packit 597cd4
		tlvs->pfc->remote.willing = true;
Packit 597cd4
	else
Packit 597cd4
		tlvs->pfc->remote.willing = false;
Packit 597cd4
Packit 597cd4
	if (tlvs->rx->pfc->info[offset] & BIT6)
Packit 597cd4
		tlvs->pfc->remote.mbc = true;
Packit 597cd4
	else
Packit 597cd4
		tlvs->pfc->remote.mbc = false;
Packit 597cd4
Packit 597cd4
	tlvs->pfc->remote.pfc_cap = tlvs->rx->pfc->info[offset] & 0x0F;
Packit 597cd4
Packit 597cd4
	offset += 1;
Packit 597cd4
	tlvs->pfc->remote.pfc_enable = tlvs->rx->pfc->info[offset];
Packit 597cd4
Packit 597cd4
	tlvs->pfc->remote_param = true;
Packit 597cd4
}
Packit 597cd4
Packit 597cd4
int ieee8021qaz_mod_app(struct app_tlv_head *head, int peer,
Packit 597cd4
			u8 prio, u8 sel, u16 proto, u32 ops)
Packit 597cd4
{
Packit 597cd4
	struct app_obj *np;
Packit 597cd4
Packit 597cd4
	/* Search list for existing match and abort
Packit 597cd4
	 * Mark entry for deletion if delete option supplied
Packit 597cd4
	 */
Packit 597cd4
	LIST_FOREACH(np, head, entry) {
Packit 597cd4
		if (np->app.selector == sel &&
Packit 597cd4
		    np->app.protocol == proto &&
Packit 597cd4
		    np->app.priority == prio) {
Packit 597cd4
			if (ops & op_delete)
Packit 597cd4
				np->hw = IEEE_APP_DEL;
Packit 597cd4
			return 1;
Packit 597cd4
		}
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
	if (ops & op_delete)
Packit 597cd4
		return 1;
Packit 597cd4
Packit 597cd4
	/* Add new entry for APP data */
Packit 597cd4
	np = calloc(1, sizeof(*np));
Packit 597cd4
	if (!np) {
Packit 597cd4
		LLDPAD_WARN("%s: memory alloc failure.\n", __func__);
Packit 597cd4
		return -1;
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
	np->peer = peer;
Packit 597cd4
	np->hw = IEEE_APP_SET;
Packit 597cd4
	np->app.priority = prio;
Packit 597cd4
	np->app.selector = sel;
Packit 597cd4
	np->app.protocol = proto;
Packit 597cd4
Packit 597cd4
	LIST_INSERT_HEAD(head, np, entry);
Packit 597cd4
	return 0;
Packit 597cd4
}
Packit 597cd4
Packit 597cd4
static void ieee8021qaz_app_reset(struct app_tlv_head *head)
Packit 597cd4
{
Packit 597cd4
	struct app_obj *np;
Packit 597cd4
Packit 597cd4
	LIST_FOREACH(np, head, entry) {
Packit 597cd4
		if (np->peer)
Packit 597cd4
			np->hw = IEEE_APP_DEL;
Packit 597cd4
	}
Packit 597cd4
}
Packit 597cd4
Packit 597cd4
static int __ieee8021qaz_app_sethw(char *ifname, struct app_tlv_head *head)
Packit 597cd4
{
Packit 597cd4
	struct app_obj *np, *np_tmp;
Packit 597cd4
	int set = 0;
Packit 597cd4
Packit 597cd4
	LIST_FOREACH(np, head, entry) {
Packit 597cd4
		if (np->hw != IEEE_APP_SET)
Packit 597cd4
			continue;
Packit 597cd4
		set = set_ieee_hw(ifname, NULL, NULL, &np->app);
Packit 597cd4
		np->hw = IEEE_APP_DONE;
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
	np = LIST_FIRST(head);
Packit 597cd4
	while (np) {
Packit 597cd4
		if (np->hw == IEEE_APP_DEL) {
Packit 597cd4
			np_tmp = np;
Packit 597cd4
			np = LIST_NEXT(np, entry);
Packit 597cd4
			LIST_REMOVE(np_tmp, entry);
Packit 597cd4
			set = del_ieee_hw(ifname, &np_tmp->app);
Packit 597cd4
			free(np_tmp);
Packit 597cd4
		} else {
Packit 597cd4
			np = LIST_NEXT(np, entry);
Packit 597cd4
		}
Packit 597cd4
	}
Packit 597cd4
	return set;
Packit 597cd4
}
Packit 597cd4
Packit 597cd4
int ieee8021qaz_app_sethw(char *ifname, struct app_tlv_head *head)
Packit 597cd4
{
Packit 597cd4
	if (ieee8021qaz_check_active(ifname)) {
Packit 597cd4
		set_dcbx_mode(ifname,
Packit 597cd4
			      DCB_CAP_DCBX_VER_IEEE | DCB_CAP_DCBX_HOST);
Packit 597cd4
		return __ieee8021qaz_app_sethw(ifname, head);
Packit 597cd4
	}
Packit 597cd4
	return 0;
Packit 597cd4
}
Packit 597cd4
Packit 597cd4
static void process_ieee8021qaz_app_tlv(struct port *port)
Packit 597cd4
{
Packit 597cd4
	struct ieee8021qaz_tlvs *tlvs;
Packit 597cd4
	int offset = OUI_SUB_SIZE + 1;
Packit 597cd4
Packit 597cd4
	tlvs = ieee8021qaz_data(port->ifname);
Packit 597cd4
Packit 597cd4
	/* clear app priorities so old data is flushed */
Packit 597cd4
	ieee8021qaz_app_reset(&tlvs->app_head);
Packit 597cd4
Packit 597cd4
	while (offset < tlvs->rx->app->length) {
Packit 597cd4
		struct app_obj *np;
Packit 597cd4
		int set = 0;
Packit 597cd4
		u8 prio  = (tlvs->rx->app->info[offset] & 0xE0) >> 5;
Packit 597cd4
		u8 sel = (tlvs->rx->app->info[offset] & 0x07);
Packit 597cd4
		u16 proto = (tlvs->rx->app->info[offset + 1] << 8) |
Packit 597cd4
			     tlvs->rx->app->info[offset + 2];
Packit 597cd4
Packit 597cd4
		/* Search list for existing match and mark set */
Packit 597cd4
		LIST_FOREACH(np, &tlvs->app_head, entry) {
Packit 597cd4
			if (np->app.selector == sel &&
Packit 597cd4
			    np->app.protocol == proto &&
Packit 597cd4
			    np->app.priority == prio) {
Packit 597cd4
				np->hw = IEEE_APP_SET;
Packit 597cd4
				set = 1;
Packit 597cd4
				break;
Packit 597cd4
			}
Packit 597cd4
		}
Packit 597cd4
Packit 597cd4
		/* If APP data not found in LIST add APP entry */
Packit 597cd4
		if (!set)
Packit 597cd4
			ieee8021qaz_mod_app(&tlvs->app_head, 1,
Packit 597cd4
					    prio, sel, proto, 0);
Packit 597cd4
		offset += 3;
Packit 597cd4
	}
Packit 597cd4
}
Packit 597cd4
Packit 597cd4
static void ieee8021qaz_mibUpdateObjects(struct port *port)
Packit 597cd4
{
Packit 597cd4
	struct ieee8021qaz_tlvs *tlvs;
Packit 597cd4
Packit 597cd4
	tlvs = ieee8021qaz_data(port->ifname);
Packit 597cd4
Packit 597cd4
	if (tlvs->rx->etscfg) {
Packit 597cd4
		process_ieee8021qaz_etscfg_tlv(port);
Packit 597cd4
	} else if (tlvs->ets->cfgr) {
Packit 597cd4
		free(tlvs->ets->cfgr);
Packit 597cd4
		tlvs->ets->cfgr = NULL;
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
	if (tlvs->rx->etsrec) {
Packit 597cd4
		process_ieee8021qaz_etsrec_tlv(port);
Packit 597cd4
	} else if (tlvs->ets->recr) {
Packit 597cd4
		free(tlvs->ets->recr);
Packit 597cd4
		tlvs->ets->recr = NULL;
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
	if (tlvs->rx->pfc)
Packit 597cd4
		process_ieee8021qaz_pfc_tlv(port);
Packit 597cd4
	else if (tlvs->pfc)
Packit 597cd4
		tlvs->pfc->remote_param = false;
Packit 597cd4
Packit 597cd4
	if (tlvs->rx->app)
Packit 597cd4
		process_ieee8021qaz_app_tlv(port);
Packit 597cd4
	else
Packit 597cd4
		ieee8021qaz_app_reset(&tlvs->app_head);
Packit 597cd4
}
Packit 597cd4
Packit 597cd4
/*
Packit 597cd4
 * LLDP_8021_QAZ_MOD_OPS - RCHANGE
Packit 597cd4
 *
Packit 597cd4
 * TLVs not consumed on error otherwise it is either free'd or stored
Packit 597cd4
 * internally in the module.
Packit 597cd4
 */
Packit 597cd4
int ieee8021qaz_rchange(struct port *port, struct lldp_agent *agent,
Packit 597cd4
			struct unpacked_tlv *tlv)
Packit 597cd4
{
Packit 597cd4
	u8 oui[OUI_SIZE] = INIT_IEEE8021QAZ_OUI;
Packit 597cd4
	struct ieee8021qaz_tlvs *qaz_tlvs;
Packit 597cd4
	struct ieee8021qaz_unpkd_tlvs *rx;
Packit 597cd4
Packit 597cd4
	if (agent->type != NEAREST_BRIDGE)
Packit 597cd4
		return 0;
Packit 597cd4
Packit 597cd4
	qaz_tlvs = ieee8021qaz_data(port->ifname);
Packit 597cd4
	if (!qaz_tlvs)
Packit 597cd4
		return SUBTYPE_INVALID;
Packit 597cd4
Packit 597cd4
	/*
Packit 597cd4
	 * TYPE_1 mandatory and always before IEEE8021QAZ tlvs so
Packit 597cd4
	 * we can use it to make the beginning of a IEEE8021QAZ PDU.
Packit 597cd4
	 * Verifies that only a single IEEE8021QAZ tlv is present.
Packit 597cd4
	 */
Packit 597cd4
	if (tlv->type == TYPE_1) {
Packit 597cd4
		clear_ieee8021qaz_rx(qaz_tlvs);
Packit 597cd4
		rx = malloc(sizeof(*rx));
Packit 597cd4
		memset(rx, 0, sizeof(*rx));
Packit 597cd4
		qaz_tlvs->rx = rx;
Packit 597cd4
		qaz_tlvs->ieee8021qazdu = 0;
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
	/*
Packit 597cd4
	 * TYPE_127 is for the Organizationally Specific TLVS
Packit 597cd4
	 * More than 1 of this type is allowed.
Packit 597cd4
	 */
Packit 597cd4
	if (tlv->type == TYPE_127) {
Packit 597cd4
		if (tlv->length < (OUI_SUB_SIZE))
Packit 597cd4
			return TLV_ERR;
Packit 597cd4
Packit 597cd4
		if ((memcmp(tlv->info, &oui, OUI_SIZE) != 0))
Packit 597cd4
			return SUBTYPE_INVALID;
Packit 597cd4
Packit 597cd4
		l2_packet_get_remote_addr(port->l2, qaz_tlvs->remote_mac);
Packit 597cd4
		if (unpack_ieee8021qaz_tlvs(port, agent, tlv))
Packit 597cd4
			return TLV_OK;
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
	if (tlv->type == TYPE_0) {
Packit 597cd4
		if (qaz_tlvs->active &&
Packit 597cd4
		    dcbx_tlvs_rxed(qaz_tlvs->ifname, agent) &&
Packit 597cd4
		   !qaz_tlvs->ieee8021qazdu) {
Packit 597cd4
			qaz_tlvs->active = false;
Packit 597cd4
			LLDPAD_INFO("IEEE DCBX on %s going INACTIVE\n",
Packit 597cd4
				    qaz_tlvs->ifname);
Packit 597cd4
		}
Packit 597cd4
Packit 597cd4
		if (qaz_tlvs->active) {
Packit 597cd4
			/* If peer is DCBX, then go into RXTX mode
Packit 597cd4
			 * if current configuration is RXOnly and
Packit 597cd4
			 * not persistant (i.e. default)
Packit 597cd4
			 */
Packit 597cd4
			int adminstatus;
Packit 597cd4
			if (qaz_tlvs->ieee8021qazdu &&
Packit 597cd4
				get_config_setting(qaz_tlvs->ifname,
Packit 597cd4
						   agent->type,
Packit 597cd4
						   ARG_ADMINSTATUS,
Packit 597cd4
						   &adminstatus,
Packit 597cd4
						   CONFIG_TYPE_INT) &&
Packit 597cd4
				get_lldp_agent_admin(qaz_tlvs->ifname,
Packit 597cd4
						     agent->type) ==
Packit 597cd4
						    enabledRxOnly) {
Packit 597cd4
				adminstatus = enabledRxTx;
Packit 597cd4
				if (set_config_setting(qaz_tlvs->ifname,
Packit 597cd4
						       agent->type,
Packit 597cd4
						       ARG_ADMINSTATUS,
Packit 597cd4
						       &adminstatus,
Packit 597cd4
						       CONFIG_TYPE_INT) ==
Packit 597cd4
						       cmd_success)
Packit 597cd4
					set_lldp_agent_admin(qaz_tlvs->ifname,
Packit 597cd4
							     agent->type,
Packit 597cd4
							     adminstatus);
Packit 597cd4
			}
Packit 597cd4
			if (qaz_tlvs->ieee8021qazdu)
Packit 597cd4
				qaz_tlvs->pending = false;
Packit 597cd4
Packit 597cd4
			/* Update TLV State Machines */
Packit 597cd4
			ieee8021qaz_mibUpdateObjects(port);
Packit 597cd4
			run_all_sm(port, agent);
Packit 597cd4
			clear_ieee8021qaz_rx(qaz_tlvs);
Packit 597cd4
			somethingChangedLocal(port->ifname, agent->type);
Packit 597cd4
		}
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
	return TLV_OK;
Packit 597cd4
}
Packit 597cd4
Packit 597cd4
static void ieee8021qaz_free_rx(struct ieee8021qaz_unpkd_tlvs *rx)
Packit 597cd4
{
Packit 597cd4
	if (!rx)
Packit 597cd4
		return;
Packit 597cd4
Packit 597cd4
	if (rx->etscfg)
Packit 597cd4
		rx->etscfg = free_unpkd_tlv(rx->etscfg);
Packit 597cd4
	if (rx->etsrec)
Packit 597cd4
		rx->etsrec = free_unpkd_tlv(rx->etsrec);
Packit 597cd4
	if (rx->pfc)
Packit 597cd4
		rx->pfc = free_unpkd_tlv(rx->pfc);
Packit 597cd4
	if (rx->app)
Packit 597cd4
		rx->app = free_unpkd_tlv(rx->app);
Packit 597cd4
Packit 597cd4
	return;
Packit 597cd4
}
Packit 597cd4
Packit 597cd4
/*
Packit 597cd4
 * LLDP_8021QAZ_MOD_OPS - MIBDELETEOBJECT
Packit 597cd4
 *
Packit 597cd4
 * ieee8021qaz_mibDeleteObject - deletes MIBs
Packit 597cd4
 * Check if peer has ETS enabled
Packit 597cd4
 *   - If yes, check if ETS TLV is present
Packit 597cd4
 *     - If yes, set it as absent (delete it?)
Packit 597cd4
 * Same for PFC and APP.
Packit 597cd4
 */
Packit 597cd4
u8 ieee8021qaz_mibDeleteObject(struct port *port, struct lldp_agent *agent)
Packit 597cd4
{
Packit 597cd4
	struct ieee8021qaz_tlvs *tlvs;
Packit 597cd4
Packit 597cd4
	if (agent->type != NEAREST_BRIDGE)
Packit 597cd4
		return 0;
Packit 597cd4
Packit 597cd4
	tlvs = ieee8021qaz_data(port->ifname);
Packit 597cd4
	if (!tlvs)
Packit 597cd4
		return 0;
Packit 597cd4
	ieee8021qaz_free_rx(tlvs->rx);
Packit 597cd4
Packit 597cd4
	/* Reseting ETS Remote params */
Packit 597cd4
	if (tlvs->ets) {
Packit 597cd4
		if (tlvs->ets->recr) {
Packit 597cd4
			free(tlvs->ets->recr);
Packit 597cd4
			tlvs->ets->recr = NULL;
Packit 597cd4
		}
Packit 597cd4
Packit 597cd4
		if (tlvs->ets->cfgr) {
Packit 597cd4
			free(tlvs->ets->cfgr);
Packit 597cd4
			tlvs->ets->cfgr = NULL;
Packit 597cd4
		}
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
	/* Reseting PFC Remote params */
Packit 597cd4
	tlvs->pfc->remote_param = 0;
Packit 597cd4
	tlvs->pfc->remote.willing = NULL;
Packit 597cd4
	tlvs->pfc->remote.mbc = NULL;
Packit 597cd4
	tlvs->pfc->remote.pfc_cap = 0;
Packit 597cd4
	tlvs->pfc->remote.pfc_enable = 0;
Packit 597cd4
Packit 597cd4
	/* Clear peer Application data */
Packit 597cd4
	ieee8021qaz_app_reset(&tlvs->app_head);
Packit 597cd4
Packit 597cd4
	/* Kick Tx State Machine */
Packit 597cd4
	somethingChangedLocal(port->ifname, agent->type);
Packit 597cd4
	return 0;
Packit 597cd4
}
Packit 597cd4
Packit 597cd4
static struct ets_attrib *free_ets_tlv(struct ets_attrib *ets)
Packit 597cd4
{
Packit 597cd4
	if (ets) {
Packit 597cd4
		free(ets->cfgl);
Packit 597cd4
		free(ets->recl);
Packit 597cd4
		free(ets->cfgr);
Packit 597cd4
		free(ets->recr);
Packit 597cd4
		free(ets);
Packit 597cd4
		ets = NULL;
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
	return NULL;
Packit 597cd4
}
Packit 597cd4
Packit 597cd4
static struct pfc_attrib *free_pfc_tlv(struct pfc_attrib *pfc)
Packit 597cd4
{
Packit 597cd4
	if (pfc) {
Packit 597cd4
		free(pfc);
Packit 597cd4
		pfc = NULL;
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
	return NULL;
Packit 597cd4
}
Packit 597cd4
Packit 597cd4
static void ieee8021qaz_free_tlv(struct ieee8021qaz_tlvs *tlvs)
Packit 597cd4
{
Packit 597cd4
	struct app_obj *np;
Packit 597cd4
Packit 597cd4
	if (!tlvs)
Packit 597cd4
		return;
Packit 597cd4
Packit 597cd4
	if (tlvs->ets)
Packit 597cd4
		tlvs->ets = free_ets_tlv(tlvs->ets);
Packit 597cd4
	if (tlvs->pfc)
Packit 597cd4
		tlvs->pfc = free_pfc_tlv(tlvs->pfc);
Packit 597cd4
Packit 597cd4
	/* Remove _all_ existing application data */
Packit 597cd4
	LIST_FOREACH(np, &tlvs->app_head, entry)
Packit 597cd4
		np->hw = IEEE_APP_DEL;
Packit 597cd4
Packit 597cd4
	__ieee8021qaz_app_sethw(tlvs->ifname, &tlvs->app_head);
Packit 597cd4
Packit 597cd4
	return;
Packit 597cd4
}
Packit 597cd4
Packit 597cd4
static void ieee8021qaz_free_data(struct ieee8021qaz_user_data *iud)
Packit 597cd4
{
Packit 597cd4
	struct ieee8021qaz_tlvs *id;
Packit 597cd4
	if (iud) {
Packit 597cd4
		while (!LIST_EMPTY(&iud->head)) {
Packit 597cd4
			id = LIST_FIRST(&iud->head);
Packit 597cd4
			LIST_REMOVE(id, entry);
Packit 597cd4
			ieee8021qaz_free_tlv(id);
Packit 597cd4
			ieee8021qaz_free_rx(id->rx);
Packit 597cd4
			free(id->rx);
Packit 597cd4
			free(id);
Packit 597cd4
		}
Packit 597cd4
	}
Packit 597cd4
}
Packit 597cd4
Packit 597cd4
/* LLDP_8021QAZ_MOD_OPS - UNREGISTER */
Packit 597cd4
void ieee8021qaz_unregister(struct lldp_module *mod)
Packit 597cd4
{
Packit 597cd4
	if (mod->data) {
Packit 597cd4
		ieee8021qaz_free_data(mod->data);
Packit 597cd4
		free(mod->data);
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
	free(mod);
Packit 597cd4
}
Packit 597cd4
Packit 597cd4
/*
Packit 597cd4
 * LLDP_8021QAZ_MOD_OPS - IFDOWN
Packit 597cd4
 */
Packit 597cd4
void ieee8021qaz_ifdown(char *device_name, struct lldp_agent *agent)
Packit 597cd4
{
Packit 597cd4
	struct ieee8021qaz_tlvs *tlvs;
Packit 597cd4
Packit 597cd4
	if (agent->type != NEAREST_BRIDGE)
Packit 597cd4
		return;
Packit 597cd4
Packit 597cd4
	tlvs = ieee8021qaz_data(device_name);
Packit 597cd4
	if (!tlvs)
Packit 597cd4
		return;
Packit 597cd4
Packit 597cd4
	ieee8021qaz_free_rx(tlvs->rx);
Packit 597cd4
	free(tlvs->rx);
Packit 597cd4
	tlvs->rx = NULL;
Packit 597cd4
}
Packit 597cd4
Packit 597cd4
/*
Packit 597cd4
 * LLDP_8021QAZ_MOD_OPS - TLVS_RXED
Packit 597cd4
 */
Packit 597cd4
int ieee8021qaz_tlvs_rxed(const char *ifname)
Packit 597cd4
{
Packit 597cd4
	struct ieee8021qaz_user_data *iud;
Packit 597cd4
	struct ieee8021qaz_tlvs *tlv = NULL;
Packit 597cd4
Packit 597cd4
	iud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_8021QAZ);
Packit 597cd4
	if (iud) {
Packit 597cd4
		LIST_FOREACH(tlv, &iud->head, entry) {
Packit 597cd4
			if (!strncmp(tlv->ifname, ifname, IFNAMSIZ))
Packit 597cd4
				return !!tlv->ieee8021qazdu;
Packit 597cd4
		}
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
	return 0;
Packit 597cd4
}
Packit 597cd4
Packit 597cd4
/*
Packit 597cd4
 * LLDP_8021QAZ_MOD_OPS - CHECK_ACTIVE
Packit 597cd4
 */
Packit 597cd4
int ieee8021qaz_check_active(const char *ifname)
Packit 597cd4
{
Packit 597cd4
	struct ieee8021qaz_user_data *iud;
Packit 597cd4
	struct ieee8021qaz_tlvs *tlv = NULL;
Packit 597cd4
Packit 597cd4
	iud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_8021QAZ);
Packit 597cd4
	if (iud) {
Packit 597cd4
		LIST_FOREACH(tlv, &iud->head, entry) {
Packit 597cd4
			if (!strncmp(tlv->ifname, ifname, IFNAMSIZ))
Packit 597cd4
				return tlv->active && !tlv->pending;
Packit 597cd4
		}
Packit 597cd4
	}
Packit 597cd4
Packit 597cd4
	return 0;
Packit 597cd4
}