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

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