Blame SOURCES/open-lldp-v1.0.1-9-VDP-Support-for-OUI-infrastructure-in-vdp22.patch

436175
From 19bdcc3fe966dc7d6fc154d7d29addfe200c6afc Mon Sep 17 00:00:00 2001
436175
From: padkrish <padkrish@cisco.com>
436175
Date: Wed, 21 Jan 2015 03:39:19 +0000
436175
Subject: [PATCH] VDP: Support for OUI infrastructure in vdp22.
436175
436175
This commit is a framework for supporting OUI fields
436175
in VDP22. This specific patch has changes for converting
436175
OUI input to vdpnl structure, vdpnl to VSI
436175
 and place-holders for calling the OUI handlers.
436175
The specific changes are:
436175
436175
vdp22.c:
436175
-------
436175
Currently, the OUI handler code is linked statically to the lldpad (vdp22).
436175
Some more enhancements are needed to support the dynamic linking of OUI
436175
handler code. This is the general flow:
436175
All the OUI handlers specify their init function in vdp22_oui_init_list. When
436175
VDP22 receives a command with the OUI fields, then based on the OUI value,
436175
it calls the appropriate init function. The OUI specific init function
436175
implemented in the OUI specific file (not in this file) then registers its
436175
handlers with VDP22. The handlers prototype is in qbg_vdp22_oui.h and it
436175
currently has:
436175
1. Handler for converting the OUI string to OUI structure which is a member of vdpnl structure.
436175
2. Handler for converting the OUI structure from vdpnl structure to a OUI structure which is a member of vsi22 structure
436175
3. Handler for creating the OUI fields for Tx.
436175
4.  handler for processing/Rx the OUI information
436175
5. Handler for freeing the OUI structure
436175
6. Handler to return the size of OUI PTLV
436175
436175
Then, accordingly the respective handlers are called.
436175
Function 'vdp22_delete_oui' calls each of the registered handlers for freeing
436175
its OUI specific fields.
436175
Function 'vdpnl_alloc_vsi_oui' calls each of the registered handlers for
436175
creating a OUI structure in vsi22 structure.
436175
Function 'oui_vdp_hndlr_init' is called by OUI specific code to register
436175
its handlers.
436175
Function 'vdp22_oui_init' calls the OUI specific init function.
436175
Comments are embedded in the other functions added.
436175
436175
vdp22sm.c:
436175
----------
436175
Function 'oui22_ptlv_sz' calls each of the handlers in its VSI structure
436175
to get the size of the OUI specific PTLV size.
436175
Function 'oui22_2tlv' calls the handler for generating the OUI data for Tx.
436175
436175
vdp22_cmds.c:
436175
-------------
436175
This file has a minor modification to get the number of OUI fields which is
436175
encoded in the input to lldpad.
436175
436175
vdp_ascii.c:
436175
------------
436175
Function 'oui_str2vdpnl' calls the respective handler to convert the OUI input
436175
string to the OUI structure stored in vdpnl structure.
436175
436175
Signed-off-by: padkrish <padkrish@cisco.com>
436175
Signed-off-by: John Fastabend <john.r.fastabend@intel.com>
436175
---
436175
 include/qbg_vdp22_oui.h |  38 ++++++++++++
436175
 qbg/vdp22.c             | 159 ++++++++++++++++++++++++++++++++++++++++++++++++
436175
 qbg/vdp22_cmds.c        |  10 ++-
436175
 qbg/vdp22sm.c           |  54 +++++++++++++++-
436175
 qbg/vdp_ascii.c         |  37 ++++++++++-
436175
 5 files changed, 293 insertions(+), 5 deletions(-)
436175
436175
diff --git a/include/qbg_vdp22_oui.h b/include/qbg_vdp22_oui.h
436175
index d31c6ad..0cce31e 100644
436175
--- a/include/qbg_vdp22_oui.h
436175
+++ b/include/qbg_vdp22_oui.h
436175
@@ -32,6 +32,7 @@
436175
  */
436175
 enum vdp22_oui {
436175
 	VDP22_OUI_TYPE_LEN = 3,          /* Size of OUI Type field */
436175
+	MAX_NUM_OUI = 10,
436175
 	VDP22_OUI_MAX_NAME = 20,
436175
 	MAX_OUI_DATA_LEN = 200
436175
 };
436175
@@ -54,4 +55,41 @@ typedef struct vdptool_oui_hndlr_tbl_s {
436175
 	bool (*oui_cli_encode_hndlr)(char *dst, char *src, size_t len);
436175
 } vdptool_oui_hndlr_tbl_t;
436175
 
436175
+struct vdpnl_oui_data_s {
436175
+	unsigned char oui_type[VDP22_OUI_TYPE_LEN];
436175
+	char oui_name[VDP22_OUI_MAX_NAME];
436175
+	int len;
436175
+	char data[MAX_OUI_DATA_LEN];
436175
+	/* If vdpnl structure is used for IPC, then this cannot be a ptr as
436175
+	 * otherwise it needs to be flattened out. If this is just used within
436175
+	 * lldpad then this can be made a ptr instead of a static array.
436175
+	 * May need to revisit later TODO
436175
+	 */
436175
+};
436175
+
436175
+struct vdp22_oui_init_s {
436175
+	unsigned char oui_type[VDP22_OUI_TYPE_LEN];
436175
+	char oui_name[VDP22_OUI_MAX_NAME];
436175
+	bool (*oui_init)();
436175
+};
436175
+
436175
+struct vdp22_oui_handler_s {
436175
+	unsigned char oui_type[VDP22_OUI_TYPE_LEN];
436175
+	char oui_name[VDP22_OUI_MAX_NAME];
436175
+	/* This handler converts the OUI string to vdpnl structure */
436175
+	bool (*str2vdpnl_hndlr)(struct vdpnl_oui_data_s *, char *);
436175
+	/* This handler converts the vdpnl structure to vsi22 structure */
436175
+	bool (*vdpnl2vsi22_hndlr)(void *, struct vdpnl_oui_data_s *,
436175
+				   struct vdp22_oui_data_s *);
436175
+	/* This handler creates the OUI fields for Tx */
436175
+	size_t (*vdp_tx_hndlr)(char unsigned *,
436175
+				struct vdp22_oui_data_s *, size_t);
436175
+	/* This handler is called for processing/Rx the OUI information */
436175
+	bool (*vdp_rx_hndlr)();
436175
+	/* This handler frees the OUI structures */
436175
+	bool (*vdp_free_oui_hndlr)(struct vdp22_oui_data_s *);
436175
+	/* This handler returns the size of OUI PTLV */
436175
+	unsigned long (*oui_ptlv_size_hndlr)(void *);
436175
+};
436175
+
436175
 #endif /* __VDP22_OUI_H__ */
436175
diff --git a/qbg/vdp22.c b/qbg/vdp22.c
436175
index d7aa648..5cae83f 100644
436175
--- a/qbg/vdp22.c
436175
+++ b/qbg/vdp22.c
436175
@@ -44,6 +44,22 @@
436175
 #include "qbg_vdp22_cmds.h"
436175
 #include "qbg_vdp22def.h"
436175
 
436175
+#define INIT_FN(name) name##_oui_init
436175
+#define EXTERN_FN(name)\
436175
+extern bool name##_oui_init()
436175
+
436175
+/* Init handlers for OUI. OUI handlers should be added in vdp22_oui_init_list.
436175
+ * First argument specifies the OUI code assigned to the Organization.
436175
+ * Second argument is the string which should match with the CLI and the third
436175
+ * argument is the init handler.
436175
+ */
436175
+
436175
+struct vdp22_oui_init_s vdp22_oui_init_list[] = {
436175
+};
436175
+
436175
+struct vdp22_oui_handler_s vdp22_oui_list[MAX_NUM_OUI];
436175
+unsigned char g_oui_index;
436175
+
436175
 /*
436175
  * VDP22 helper functions
436175
  */
436175
@@ -218,6 +234,36 @@ void vdp22_showvsi(struct vsi22 *p)
436175
 }
436175
 
436175
 /*
436175
+ * Delete the OUI structures of VSI22
436175
+ * This calls the respective OUI handlers which are responsible for freeing
436175
+ * the OUI specific 'data' element of 'vdp22_oui_data_s' structure.
436175
+ */
436175
+
436175
+static void vdp22_delete_oui(struct vsi22 *p)
436175
+{
436175
+	struct vdp22_oui_data_s *oui_str;
436175
+	struct vdp22_oui_handler_s *oui_hndlr;
436175
+	int idx;
436175
+	bool ret;
436175
+
436175
+	if ((p->no_ouidata == 0) || (!p->oui_str_data))
436175
+		return;
436175
+	for (idx = 0; idx < p->no_ouidata; idx++) {
436175
+		oui_str = &p->oui_str_data[idx];
436175
+		oui_hndlr = vdp22_get_oui_hndlr(oui_str->oui_name);
436175
+		if (!oui_hndlr)
436175
+			LLDPAD_ERR("%s: Unknown OUI %s\n",
436175
+				   __func__, oui_str->oui_name);
436175
+		else {
436175
+			ret = oui_hndlr->vdp_free_oui_hndlr(oui_str);
436175
+			LLDPAD_DBG("%s: Free handler returned %d\n", __func__,
436175
+				   ret);
436175
+		}
436175
+	}
436175
+	free(p->oui_str_data);
436175
+}
436175
+
436175
+/*
436175
  * Delete a complete VSI node not on queue.
436175
  */
436175
 void vdp22_delete_vsi(struct vsi22 *p)
436175
@@ -225,6 +271,7 @@ void vdp22_delete_vsi(struct vsi22 *p)
436175
 	LLDPAD_DBG("%s:%s vsi:%p(%02x)\n", __func__, p->vdp->ifname, p,
436175
 		   p->vsi[0]);
436175
 	free(p->fdata);
436175
+	vdp22_delete_oui(p);
436175
 	free(p);
436175
 }
436175
 
436175
@@ -475,6 +522,38 @@ static bool filter_ok(unsigned char ffmt, struct fid22 *fp,
436175
 	return rc;
436175
 }
436175
 
436175
+static void vdpnl_alloc_vsi_oui(struct vdpnl_vsi *vsi, struct vsi22 *p)
436175
+{
436175
+	struct vdp22_oui_handler_s *oui_hndlr;
436175
+	bool ret;
436175
+	int idx;
436175
+
436175
+	if (vsi->ouisz == 0)
436175
+		return;
436175
+	p->no_ouidata = vsi->ouisz;
436175
+	p->oui_str_data = calloc(vsi->ouisz, sizeof(struct vdp22_oui_data_s));
436175
+	if (!p->oui_str_data) {
436175
+		LLDPAD_ERR("%s: calloc return failure\n", __func__);
436175
+		return;
436175
+	}
436175
+	for (idx = 0; idx < vsi->ouisz; idx++) {
436175
+		struct vdpnl_oui_data_s *from = &vsi->oui_list[idx];
436175
+		struct vdp22_oui_data_s *to = &p->oui_str_data[idx];
436175
+
436175
+		oui_hndlr = vdp22_get_oui_hndlr(from->oui_name);
436175
+		if (!oui_hndlr)
436175
+			LLDPAD_ERR("%s: Unknown OUI Name %s\n",
436175
+				   __func__, from->oui_name);
436175
+		else {
436175
+			ret = oui_hndlr->vdpnl2vsi22_hndlr(p, from, to);
436175
+			if (!ret)
436175
+				LLDPAD_ERR("%s: handler return error for "
436175
+					   "oui %s\n", __func__,
436175
+					   from->oui_name);
436175
+		}
436175
+	}
436175
+}
436175
+
436175
 /*
436175
  * Allocate a VSI node with filter information data.
436175
  * Check if input data is valid.
436175
@@ -540,6 +619,7 @@ static struct vsi22 *vdp22_alloc_vsi_int(struct vdpnl_vsi *vsi,
436175
 		fp->requestor.req_pid = vsi->req_pid;
436175
 		fp->requestor.req_seq = vsi->req_seq;
436175
 	}
436175
+	vdpnl_alloc_vsi_oui(vsi, p);
436175
 	*rc = 0;
436175
 	LLDPAD_DBG("%s:%s vsi:%p(%02x)\n", __func__, vsi->ifname, p, p->vsi[0]);
436175
 	return p;
436175
@@ -1113,3 +1193,82 @@ void copy_vsi_external(struct vdpnl_vsi *vsi, struct vsi22 *p, int clif)
436175
 {
436175
 	copy_vsi(vsi, p, clif);
436175
 }
436175
+
436175
+/*
436175
+ * This is called by the ORG specific code to register its handlers.
436175
+ */
436175
+
436175
+bool oui_vdp_hndlr_init(struct vdp22_oui_handler_s *handler_ptr)
436175
+{
436175
+	if (!handler_ptr) {
436175
+		LLDPAD_DBG("%s: NULL handler\n", __func__);
436175
+		return false;
436175
+	}
436175
+	memcpy(&(vdp22_oui_list[g_oui_index]), handler_ptr,
436175
+		sizeof(vdp22_oui_list[g_oui_index]));
436175
+	g_oui_index++;
436175
+	return true;
436175
+}
436175
+
436175
+/*
436175
+ * This calls the ORG specific init function. Then the ORG specific init
436175
+ * function registers its handlers.
436175
+ */
436175
+
436175
+static void vdp22_oui_init(char *oui_name)
436175
+{
436175
+	int total;
436175
+	int idx;
436175
+
436175
+	total = sizeof(vdp22_oui_init_list) / sizeof(vdp22_oui_init_list[0]);
436175
+	for (idx = 0; idx < total; idx++) {
436175
+		if (!strncmp(vdp22_oui_init_list[idx].oui_name, oui_name,
436175
+			     sizeof(vdp22_oui_init_list[idx].oui_name))) {
436175
+			if (!vdp22_oui_init_list[idx].oui_init())
436175
+				LLDPAD_ERR("%s: oui init return error for OUI "
436175
+					   "%s\n", __func__, oui_name);
436175
+		}
436175
+	}
436175
+}
436175
+
436175
+static struct vdp22_oui_handler_s *get_oui_hndlr_internal(char *oui_name)
436175
+{
436175
+	int total;
436175
+	int idx;
436175
+
436175
+	total = g_oui_index;
436175
+	for (idx = 0; idx < total; idx++) {
436175
+		if (!strncmp(vdp22_oui_list[idx].oui_name, oui_name,
436175
+			     sizeof(vdp22_oui_list[idx].oui_name)))
436175
+			return &vdp22_oui_list[idx];
436175
+	}
436175
+	return NULL;
436175
+}
436175
+
436175
+/*
436175
+ * Return the handler structure associated with this OUI.
436175
+ * If the handler is already registered, then get_oui_hndlr_internal function
436175
+ * will return it. Otherwise, vdp22_oui_init is called so that the handler
436175
+ * init function is called which will register its handlers. This is done so
436175
+ * that the ORG specific handlers are registered only on demand.
436175
+ */
436175
+
436175
+struct vdp22_oui_handler_s *vdp22_get_oui_hndlr(char *oui_name)
436175
+{
436175
+	struct vdp22_oui_handler_s *hndlr;
436175
+
436175
+	if (oui_name == NULL) {
436175
+		LLDPAD_ERR("%s: NULL arg\n", __func__);
436175
+		return NULL;
436175
+	}
436175
+	/*
436175
+	 * First check if the handler exists.
436175
+	 * If not the OUI plugin is probably not initialized
436175
+	 * Initialize the handlers
436175
+	 */
436175
+	hndlr = get_oui_hndlr_internal(oui_name);
436175
+	if (hndlr != NULL)
436175
+		return hndlr;
436175
+	vdp22_oui_init(oui_name);
436175
+	return get_oui_hndlr_internal(oui_name);
436175
+}
436175
diff --git a/qbg/vdp22_cmds.c b/qbg/vdp22_cmds.c
436175
index 5d5ef6b..5b5788f 100644
436175
--- a/qbg/vdp22_cmds.c
436175
+++ b/qbg/vdp22_cmds.c
436175
@@ -356,20 +356,25 @@ static int get_vdp22_retval(int rc)
436175
 	}
436175
 }
436175
 
436175
-static int set_arg_vsi3(struct cmd *cmd, char *argvalue, bool test, int size)
436175
+static int set_arg_vsi3(struct cmd *cmd, char *argvalue, bool test, int size,
436175
+			int oui_size)
436175
 {
436175
 	cmd_status good_cmd = vdp22_cmdok(cmd, cmd_settlv);
436175
 	int rc;
436175
 	struct vdpnl_vsi vsi;
436175
 	struct vdpnl_mac mac[size];
436175
+	struct vdpnl_oui_data_s oui[oui_size];
436175
 
436175
 	if (good_cmd != cmd_success)
436175
 		return good_cmd;
436175
 
436175
 	memset(&vsi, 0, sizeof(vsi));
436175
 	memset(&mac, 0, sizeof(mac));
436175
+	memset(&oui, 0, sizeof(oui));
436175
 	vsi.maclist = mac;
436175
 	vsi.macsz = size;
436175
+	vsi.oui_list = (struct vdpnl_oui_data_s *)oui;
436175
+	vsi.ouisz = oui_size;
436175
 	rc = vdp_str2vdpnl(argvalue, &vsi, cmd->ifname);
436175
 	if (rc) {
436175
 		good_cmd = get_vdp22_retval(rc);
436175
@@ -392,11 +397,12 @@ out:
436175
 static int set_arg_vsi2(struct cmd *cmd, char *argvalue, bool test)
436175
 {
436175
 	int no = (cmd->ops >> OP_FID_POS) & 0xff;
436175
+	int oui_no = (cmd->ops >> OP_OUI_POS) & 0xff;
436175
 
436175
 	if (no <= 0)
436175
 		return -EINVAL;
436175
 	if ((cmd->ops & op_arg) && (cmd->ops & op_argval))
436175
-		return set_arg_vsi3(cmd, argvalue, test, no);
436175
+		return set_arg_vsi3(cmd, argvalue, test, no, oui_no);
436175
 	else /* Not supported for now */
436175
 		return cmd_failed;
436175
 }
436175
diff --git a/qbg/vdp22sm.c b/qbg/vdp22sm.c
436175
index 83a97fb..db0e413 100644
436175
--- a/qbg/vdp22sm.c
436175
+++ b/qbg/vdp22sm.c
436175
@@ -184,6 +184,33 @@ static inline size_t vsi22_ptlv_sz(struct vsi22 *vp)
436175
 }
436175
 
436175
 /*
436175
+ * This function calls the registered OUI handlers that returns the size of
436175
+ * the OUI data.
436175
+ */
436175
+
436175
+static inline size_t oui22_ptlv_sz(struct vsi22 *vp)
436175
+{
436175
+	struct vdp22_oui_handler_s *oui_hndlr;
436175
+	struct vdp22_oui_data_s *oui_str;
436175
+	size_t size = 0;
436175
+	int idx;
436175
+
436175
+	if (vp->no_ouidata == 0)
436175
+		return 0;
436175
+	for (idx = 0; idx < vp->no_ouidata; idx++) {
436175
+		oui_str = &(vp->oui_str_data[idx]);
436175
+		oui_hndlr = vdp22_get_oui_hndlr(oui_str->oui_name);
436175
+		if (!oui_hndlr) {
436175
+			LLDPAD_ERR("%s: No handler registered for OUI %s\n",
436175
+				   __func__, oui_str->oui_name);
436175
+			continue;
436175
+		}
436175
+		size += oui_hndlr->oui_ptlv_size_hndlr(oui_str->data);
436175
+	}
436175
+	return size;
436175
+}
436175
+
436175
+/*
436175
  * Extract 1, 2, 3, 4 byte integers in network byte format.
436175
  * Extract n bytes.
436175
  * Assume enough space available.
436175
@@ -309,6 +336,29 @@ static size_t vsi22_2tlv_fdata(unsigned char *cp, struct fid22 *p,
436175
 	return nbytes;
436175
 }
436175
 
436175
+static void oui22_2tlv(struct vsi22 *vp, char unsigned *cp)
436175
+{
436175
+	struct vdp22_oui_handler_s *oui_hndlr;
436175
+	struct vdp22_oui_data_s *oui_str;
436175
+	size_t offset = 0;
436175
+	size_t temp_offset = 0;
436175
+	int idx;
436175
+
436175
+	if (vp->no_ouidata == 0)
436175
+		return;
436175
+	for (idx = 0; idx < vp->no_ouidata; idx++) {
436175
+		oui_str = &(vp->oui_str_data[idx]);
436175
+		oui_hndlr = vdp22_get_oui_hndlr(oui_str->oui_name);
436175
+		if (!oui_hndlr) {
436175
+			LLDPAD_ERR("%s: No handler registered for OUI %s\n",
436175
+				   __func__, oui_str->oui_name);
436175
+			continue;
436175
+		}
436175
+		temp_offset = oui_hndlr->vdp_tx_hndlr(cp, oui_str, offset);
436175
+		offset += temp_offset;
436175
+	}
436175
+}
436175
+
436175
 static void vsi22_2tlv(struct vsi22 *vp, char unsigned *cp, unsigned char stat)
436175
 {
436175
 	size_t offset = 0, i;
436175
@@ -478,7 +528,8 @@ static void vdp22st_wait_syscmd(struct vsi22 *vsip)
436175
  */
436175
 static void vdp22st_process(struct vsi22 *vsi)
436175
 {
436175
-	unsigned short len = mgr22_ptlv_sz() + vsi22_ptlv_sz(vsi);
436175
+	unsigned short len = mgr22_ptlv_sz() + vsi22_ptlv_sz(vsi) +
436175
+			      oui22_ptlv_sz(vsi);
436175
 	unsigned char buf[len];
436175
 	struct qbg22_imm qbg;
436175
 
436175
@@ -487,6 +538,7 @@ static void vdp22st_process(struct vsi22 *vsi)
436175
 	qbg.u.c.data = buf;
436175
 	mgr22_2tlv(vsi, buf);
436175
 	vsi22_2tlv(vsi, buf + mgr22_ptlv_sz(), vsi->hints);
436175
+	oui22_2tlv(vsi, buf + mgr22_ptlv_sz() + vsi22_ptlv_sz(vsi));
436175
 	vsi->smi.txmit_error = modules_notify(LLDP_MOD_ECP22, LLDP_MOD_VDP22,
436175
 					       vsi->vdp->ifname, &qbg);
436175
 	if (!vsi->smi.txmit_error) {
436175
diff --git a/qbg/vdp_ascii.c b/qbg/vdp_ascii.c
436175
index 70ec79b..80a4419 100644
436175
--- a/qbg/vdp_ascii.c
436175
+++ b/qbg/vdp_ascii.c
436175
@@ -54,7 +54,8 @@ struct vsi_keyword_handler vsi_key_handle[] = {
436175
 /*	{VSI22_ARG_VSIIDFRMT_STR, VSI_VSIIDFRMT_ARG}, TODO*/
436175
 	{VSI22_ARG_VSIID_STR, VSI_VSIID_ARG},
436175
 	{VSI22_ARG_HINTS_STR, VSI_HINTS_ARG},
436175
-	{VSI22_ARG_FILTER_STR, VSI_FILTER_ARG} };
436175
+	{VSI22_ARG_FILTER_STR, VSI_FILTER_ARG},
436175
+	{VSI22_ARG_OUI_STR, VSI_OUI_ARG} };
436175
 
436175
 /*
436175
  * Check if it is a UUID and consists  of hexadecimal digits and dashes only.
436175
@@ -225,6 +226,33 @@ static bool gethints(struct vdpnl_vsi *p, char *s)
436175
 	return true;
436175
 }
436175
 
436175
+static bool oui_str2vdpnl(struct vdpnl_vsi *vsi, char *p, unsigned short idx)
436175
+{
436175
+	struct vdp22_oui_handler_s *oui_hndlr;
436175
+	char *temp_argval = p;
436175
+	char *oui_val;
436175
+	char oui_name[VDP22_OUI_MAX_NAME];
436175
+	u8 oui_name_len;
436175
+
436175
+	hexstr2bin(p, &oui_name_len, sizeof(oui_name_len));
436175
+	if (oui_name_len >= VDP22_OUI_MAX_NAME)
436175
+		return false;
436175
+	temp_argval = p + 2 * sizeof(oui_name_len);
436175
+	oui_val = temp_argval + oui_name_len;
436175
+	strncpy(oui_name, temp_argval, oui_name_len);
436175
+	oui_name[oui_name_len] = '\0';
436175
+	oui_hndlr = vdp22_get_oui_hndlr(oui_name);
436175
+	if (!oui_hndlr)
436175
+		return false;
436175
+	strncpy(vsi->oui_list[idx].oui_name, oui_name,
436175
+		sizeof(vsi->oui_list[idx].oui_name));
436175
+	if (oui_hndlr->str2vdpnl_hndlr)
436175
+		return oui_hndlr->str2vdpnl_hndlr(&(vsi->oui_list[idx]),
436175
+						   oui_val);
436175
+	else
436175
+		return false;
436175
+}
436175
+
436175
 /*
436175
  * Read VSI association mode. If can be followed by an error code in brackets.
436175
  * For vdp22 protocol the allowed words are assoc, preassoc, preassoc-rr and
436175
@@ -315,7 +343,7 @@ int vdp22_parse_str_vdpnl(struct vdpnl_vsi *vsi, u16 *key_flags,
436175
 	int i, ioff = 0, numargs;
436175
 	int ilen = strlen(orig_argvalue);
436175
 	unsigned int no;
436175
-	unsigned short idx = 0;
436175
+	unsigned short idx = 0, oui_idx = 0;
436175
 	u16 num_arg_keys = 0;
436175
 
436175
 	argvalue = strdup(orig_argvalue);
436175
@@ -373,6 +401,11 @@ int vdp22_parse_str_vdpnl(struct vdpnl_vsi *vsi, u16 *key_flags,
436175
 			if (!argvals[i] || !gethints(vsi, argvals[i]))
436175
 				goto out_err;
436175
 			break;
436175
+		case VSI_OUI_ARG:
436175
+			if (!oui_str2vdpnl(vsi, argvals[i], oui_idx))
436175
+				goto out_err;
436175
+			oui_idx++;
436175
+			break;
436175
 		default:
436175
 			goto out_err;
436175
 		}
436175
-- 
436175
2.1.0
436175