Merge d04b231c96e87d4db7d7995c63f75d02c87ac710 on remote branch

Change-Id: Ida3b4259d618d1099699e10cf523f8ec4f20ef43
diff --git a/cld80211-lib/cld80211_lib.c b/cld80211-lib/cld80211_lib.c
index 1ca085a..e92d822 100644
--- a/cld80211-lib/cld80211_lib.c
+++ b/cld80211-lib/cld80211_lib.c
@@ -31,6 +31,9 @@
  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
  *
+ * Changes from Qualcomm Innovation Center are provided under the following license:
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * SPDX-License-Identifier: BSD-3-Clause-Clear
  */
 
 #include <errno.h>
@@ -112,8 +115,10 @@
 }
 
 
-void exit_cld80211_recv(struct cld80211_ctx *ctx)
+void exit_cld80211_recv(void *cldctx)
 {
+	struct cld80211_ctx *ctx = (struct cld80211_ctx *) cldctx;
+
 	if (!ctx) {
 		ALOGE("%s: ctx is NULL: %s", getprogname(), __func__);
 		return;
@@ -257,8 +262,10 @@
 }
 
 
-int cld80211_add_mcast_group(struct cld80211_ctx *ctx, const char* mcgroup)
+int cld80211_add_mcast_group(void *cldctx, const char* mcgroup)
 {
+	struct cld80211_ctx *ctx = (struct cld80211_ctx *) cldctx;
+
 	if (!ctx || !mcgroup) {
 		ALOGE("%s: ctx/mcgroup is NULL: %s", getprogname(), __func__);
 		return 0;
@@ -280,7 +287,7 @@
 }
 
 
-int cld80211_remove_mcast_group(struct cld80211_ctx *ctx, const char* mcgroup)
+int cld80211_remove_mcast_group(void *cldctx, const char* mcgroup)
 {
 	// Drop membership is not a necessary cleanup action so comment it out.
 #if 0
@@ -306,10 +313,11 @@
 }
 
 
-struct nl_msg *cld80211_msg_alloc(struct cld80211_ctx *ctx, int cmd,
-				  struct nlattr **nla_data, int pid)
+struct nl_msg *cld80211_msg_alloc(void *cldctx, int cmd, struct nlattr **nla_data,
+				  int pid)
 {
 	struct nl_msg *nlmsg;
+	struct cld80211_ctx *ctx = (struct cld80211_ctx *) cldctx;
 
 	if (!ctx || !nla_data) {
 		ALOGE("%s: ctx is null: %s", getprogname(), __func__);
@@ -338,9 +346,10 @@
 }
 
 
-int cld80211_send_msg(struct cld80211_ctx *ctx, struct nl_msg *nlmsg)
+int cld80211_send_msg(void *cldctx, struct nl_msg *nlmsg)
 {
 	int err;
+	struct cld80211_ctx *ctx = (struct cld80211_ctx *) cldctx;
 
 	if (!ctx || !ctx->sock || !nlmsg) {
 		ALOGE("%s: Invalid data from client", getprogname());
@@ -357,11 +366,12 @@
 }
 
 
-int cld80211_send_recv_msg(struct cld80211_ctx *ctx, struct nl_msg *nlmsg,
+int cld80211_send_recv_msg(void *cldctx, struct nl_msg *nlmsg,
 			   int (*valid_handler)(struct nl_msg *, void *),
 			   void *valid_data)
 {
 	int err;
+	struct cld80211_ctx *ctx = (struct cld80211_ctx *) cldctx;
 
 	if (!ctx || !ctx->sock || !nlmsg) {
 		ALOGE("%s: Invalid data from client", getprogname());
@@ -403,13 +413,14 @@
 }
 
 
-int cld80211_recv(struct cld80211_ctx *ctx, int timeout, bool recv_multi_msg,
+int cld80211_recv(void *cldctx, int timeout, bool recv_multi_msg,
 		  int (*valid_handler)(struct nl_msg *, void *),
 		  void *cbctx)
 {
 	struct pollfd pfd[2];
 	struct nl_cb *cb;
 	int err;
+	struct cld80211_ctx *ctx = (struct cld80211_ctx *) cldctx;
 
 	if (!ctx || !ctx->sock || !valid_handler) {
 		ALOGE("%s: Invalid data from client", getprogname());
@@ -516,8 +527,10 @@
 }
 
 
-void cld80211_deinit(struct cld80211_ctx *ctx)
+void cld80211_deinit(void *cldctx)
 {
+	struct cld80211_ctx *ctx = (struct cld80211_ctx *) cldctx;
+
 	if (!ctx || !ctx->sock) {
 		ALOGE("%s: ctx/sock is NULL", getprogname());
 		return;
@@ -527,8 +540,10 @@
 	free (ctx);
 }
 
-void cld80211_stop_recv(struct cld80211_ctx *ctx, bool is_terminating)
+void cld80211_stop_recv(void *cldctx, bool is_terminating)
 {
+	struct cld80211_ctx *ctx = (struct cld80211_ctx *) cldctx;
+
 	if (!ctx || !ctx->sock) {
 		ALOGE("%s: ctx/sock is NULL", getprogname());
 		return;
@@ -536,3 +551,25 @@
 	ALOGE("%s: Program is terminating:%d", getprogname(), is_terminating);
 	ctx->is_terminating = is_terminating;
 }
+
+struct nl_sock *cld80211_get_nl_socket_ctx(void *cldctx)
+{
+	struct cld80211_ctx *ctx = (struct cld80211_ctx *) cldctx;
+
+	if (!ctx || !ctx->sock) {
+		ALOGE("%s: ctx/sock is NULL", getprogname());
+		return NULL;
+	}
+	return ctx->sock;
+}
+
+int *cld80211_get_exit_socket_pair(void *cldctx)
+{
+	struct cld80211_ctx *ctx = (struct cld80211_ctx *) cldctx;
+
+	if (!ctx || !ctx->sock) {
+		ALOGE("%s: ctx/sock is NULL", getprogname());
+		return NULL;
+	}
+	return ctx->exit_sockets;
+}
diff --git a/cld80211-lib/cld80211_lib.h b/cld80211-lib/cld80211_lib.h
index c786361..ab5ba48 100644
--- a/cld80211-lib/cld80211_lib.h
+++ b/cld80211-lib/cld80211_lib.h
@@ -25,6 +25,9 @@
  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
+ * Changes from Qualcomm Innovation Center are provided under the following license:
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * SPDX-License-Identifier: BSD-3-Clause-Clear
  */
 
 #ifndef CLD80211_LIB_H
@@ -87,37 +90,37 @@
 /**
  * free the socket created in cld80211_init()
  */
-void cld80211_deinit(struct cld80211_ctx *ctx);
+void cld80211_deinit(void *cldctx);
 
 /**
  * Allocate nl_msg and populate family and genl header details
  */
-struct nl_msg *cld80211_msg_alloc(struct cld80211_ctx *ctx, int cmd,
-				  struct nlattr **nla_data, int pid);
+struct nl_msg *cld80211_msg_alloc(void *cldctx, int cmd, struct nlattr **nla_data,
+				  int pid);
 
 /**
  * Send nlmsg to driver and return; It doesn't wait for response
  */
-int cld80211_send_msg(struct cld80211_ctx *ctx, struct nl_msg *nlmsg);
+int cld80211_send_msg(void *cldctx, struct nl_msg *nlmsg);
 
 /**
  * Send nlmsg to driver and get response, if any
  */
-int cld80211_send_recv_msg(struct cld80211_ctx *ctx, struct nl_msg *nlmsg,
-		      int (*valid_handler)(struct nl_msg *, void *),
-		      void *valid_data);
+int cld80211_send_recv_msg(void *cldctx, struct nl_msg *nlmsg,
+			   int (*valid_handler)(struct nl_msg *, void *),
+			   void *valid_data);
 
 /**
  * Add membership for multicast group "mcgroup" to receive the messages
  * sent to this group from driver
  */
-int cld80211_add_mcast_group(struct cld80211_ctx *ctx, const char* mcgroup);
+int cld80211_add_mcast_group(void *cldctx, const char* mcgroup);
 
 /**
  * Remove membership of multicast group "mcgroup" to stop receiving messages
  * sent to this group from driver
  */
-int cld80211_remove_mcast_group(struct cld80211_ctx *ctx, const char* mcgroup);
+int cld80211_remove_mcast_group(void *cldctx, const char* mcgroup);
 
 /**
  * Receive messages from driver on cld80211 family. Client can do
@@ -142,7 +145,7 @@
  *        nlmsg is received
  * Returns corresponding errno when a failure happens while receiving nl msg
  */
-int cld80211_recv(struct cld80211_ctx *ctx, int timeout, bool recv_multi_msg,
+int cld80211_recv(void *cldctx, int timeout, bool recv_multi_msg,
 		  int (*valid_handler)(struct nl_msg *, void *),
 		  void *cbctx);
 
@@ -150,13 +153,23 @@
  * poll() is a blocking call on sock. Client has to unblock the poll()
  * first to exit gracefully.
  */
-void exit_cld80211_recv(struct cld80211_ctx *ctx);
+void exit_cld80211_recv(void *cldctx);
 
 /**
  * Client has to inform to exit gracefully during polling and reset the flag
  * accordingly.
  */
-void cld80211_stop_recv(struct cld80211_ctx *ctx, bool is_terminating);
+void cld80211_stop_recv(void *cldctx, bool is_terminating);
+
+/**
+ * Get the nl socket context to listen to driver events.
+ */
+struct nl_sock *cld80211_get_nl_socket_ctx(void *cldctx);
+
+/**
+ * Get the exit socket pair for clients to stop listening to driver events.
+ */
+int *cld80211_get_exit_socket_pair(void *cldctx);
 #ifdef __cplusplus
 }
 #endif
diff --git a/qcwcn/wpa_supplicant_8_lib/driver_cmd_nl80211.c b/qcwcn/wpa_supplicant_8_lib/driver_cmd_nl80211.c
index f95a8fb..f93e64f 100644
--- a/qcwcn/wpa_supplicant_8_lib/driver_cmd_nl80211.c
+++ b/qcwcn/wpa_supplicant_8_lib/driver_cmd_nl80211.c
@@ -268,7 +268,7 @@
 };
 
 
-static char *get_next_arg(char *cmd)
+char *get_next_arg(char *cmd)
 {
 	char *pos = cmd;
 
@@ -2724,7 +2724,7 @@
 	return (u32)val;
 }
 
-static s32 get_s32_from_string(char *cmd_string, int *ret)
+s32 get_s32_from_string(char *cmd_string, int *ret)
 {
 	s64 val64 = 0;
 	s32 val = 0;
diff --git a/qcwcn/wpa_supplicant_8_lib/driver_cmd_nl80211_common.h b/qcwcn/wpa_supplicant_8_lib/driver_cmd_nl80211_common.h
index 1fe2743..25b5f60 100644
--- a/qcwcn/wpa_supplicant_8_lib/driver_cmd_nl80211_common.h
+++ b/qcwcn/wpa_supplicant_8_lib/driver_cmd_nl80211_common.h
@@ -49,6 +49,9 @@
 #include <netlink/object-api.h>
 #include <linux/pkt_sched.h>
 
+#define OBSS_PD_THRESHOLD_MIN -82
+#define OBSS_PD_THRESHOLD_MAX -62
+
 struct wpa_driver_nl80211_data *drv;
 struct i802_bss *bss;
 struct nl_msg *prepare_vendor_nlmsg(struct wpa_driver_nl80211_data *drv,
@@ -64,3 +67,5 @@
 int wpa_driver_sr_event(struct wpa_driver_nl80211_data *drv,
 		        u32 vendor_id, u32 subcmd, u8 *data, size_t len);
 char *skip_white_space(char *cmd);
+char *get_next_arg(char *cmd);
+s32 get_s32_from_string(char *cmd_string, int *ret);
diff --git a/qcwcn/wpa_supplicant_8_lib/driver_cmd_nl80211_sr.c b/qcwcn/wpa_supplicant_8_lib/driver_cmd_nl80211_sr.c
index 8d8acd6..d0cb989 100644
--- a/qcwcn/wpa_supplicant_8_lib/driver_cmd_nl80211_sr.c
+++ b/qcwcn/wpa_supplicant_8_lib/driver_cmd_nl80211_sr.c
@@ -80,7 +80,14 @@
 		*sr_cmd = QCA_WLAN_SR_OPERATION_GET_STATS;
 	else if (os_strncasecmp(cmd, "clearstats", 10) == 0)
 		*sr_cmd = QCA_WLAN_SR_OPERATION_CLEAR_STATS;
-	else {
+	else if (os_strncasecmp(cmd, "getparams", 9) == 0) {
+		cmd += 9;
+		cmd = skip_white_space(cmd);
+		if (*cmd != '\0')
+			return -EINVAL;
+		else
+			*sr_cmd = QCA_WLAN_SR_OPERATION_GET_PARAMS;
+	} else {
 		wpa_printf(MSG_ERROR, "Unknown SR command:%s\n", cmd);
 		return -EINVAL;
 	}
@@ -159,6 +166,65 @@
 	return 0;
 }
 
+static int parse_sr_get_params_response(struct resp_info *info,
+					struct nlattr *vendata, int datalen)
+{
+	int cmd_id, ret;
+	u8 srg_pd_offset_min = 0, srg_pd_offset_max = 0,
+	non_srg_pd_offset_max = 0, hesiga_val15_enable = 1,
+	non_srg_pd_disallow = 1;
+	struct nlattr *sr_attr[QCA_WLAN_VENDOR_ATTR_SR_PARAMS_MAX + 1];
+
+	ret = nla_parse_nested(sr_attr, QCA_WLAN_VENDOR_ATTR_SR_PARAMS_MAX,
+			       vendata, NULL);
+	if (ret) {
+		wpa_printf(MSG_ERROR, "SR params: nla_parse fail, error: %d", ret);
+		return ret;
+	}
+
+	cmd_id = QCA_WLAN_VENDOR_ATTR_SR_PARAMS_SRG_OBSS_PD_MIN_OFFSET;
+	if (sr_attr[cmd_id])
+		srg_pd_offset_min = nla_get_u8(sr_attr[cmd_id]);
+	else
+		wpa_printf(MSG_INFO, "SR params: SRG PD min offset not found");
+
+	cmd_id = QCA_WLAN_VENDOR_ATTR_SR_PARAMS_SRG_OBSS_PD_MAX_OFFSET;
+	if (sr_attr[cmd_id])
+		srg_pd_offset_max = nla_get_u8(sr_attr[cmd_id]);
+	else
+		wpa_printf(MSG_INFO, "SR params: SRG PD max offset not found");
+
+	cmd_id = QCA_WLAN_VENDOR_ATTR_SR_PARAMS_NON_SRG_OBSS_PD_MAX_OFFSET;
+	if (sr_attr[cmd_id])
+		non_srg_pd_offset_max = nla_get_u8(sr_attr[cmd_id]);
+	else
+		wpa_printf(MSG_INFO, "SR params: Non SRG PD max offset not found");
+
+	cmd_id = QCA_WLAN_VENDOR_ATTR_SR_PARAMS_HESIGA_VAL15_ENABLE;
+	if (!sr_attr[cmd_id]) {
+		wpa_printf(MSG_INFO, "SR params: Hesiga Val15 is not enabled by AP");
+		hesiga_val15_enable = 0;
+	}
+
+	cmd_id = QCA_WLAN_VENDOR_ATTR_SR_PARAMS_NON_SRG_OBSS_PD_DISALLOW;
+	if (!sr_attr[cmd_id]) {
+		wpa_printf(MSG_INFO, "SR params: non SRG PD is not allowed by AP");
+		non_srg_pd_disallow = 0;
+	}
+
+	ret = os_snprintf(info->reply_buf, info->reply_buf_len,
+			"srg_obss_pd_min_offset: %u\nsrg_obss_pd_max_offset: %u\n"
+			"non_srg_obss_pd_max_offset: %u\nhesiga_val15_enable: %u\n"
+			"non_srg_pd_disallow: %u", srg_pd_offset_min,
+			srg_pd_offset_max, non_srg_pd_offset_max,
+			hesiga_val15_enable, non_srg_pd_disallow);
+	if (os_snprintf_error(info->reply_buf_len, ret)) {
+		wpa_printf(MSG_ERROR, "SR params: Failed to put in buffer, error: %d", ret);
+		return ret;
+	}
+	return 0;
+}
+
 /**
  * sr_response_unpack() - unpack the spatial reuse command response received from driver
  *
@@ -179,16 +245,19 @@
 	switch (info->cmd_oper) {
 	case QCA_WLAN_SR_OPERATION_GET_STATS:
 		ret = parse_sr_get_stats_response(info, vendata, datalen);
-		if (ret) {
-			wpa_printf(MSG_ERROR, "Unpacking SR stats failed, error:%d\n",ret);
-			return ret;
-		}
+		if (ret)
+			wpa_printf(MSG_ERROR, "Unpacking SR stats failed, error:%d", ret);
+		break;
+	case QCA_WLAN_SR_OPERATION_GET_PARAMS:
+		ret = parse_sr_get_params_response(info, vendata, datalen);
+		if (ret)
+			wpa_printf(MSG_ERROR, "Unpacking SR params failed, error:%d", ret);
 		break;
 	default:
 		ret = -EINVAL;
-		wpa_printf(MSG_ERROR, "Unsupported SR command:%d, error:%d\n",
+		wpa_printf(MSG_ERROR, "Unsupported SR command:%d, error:%d",
 			   info->cmd_oper, ret);
-		return ret;
+		break;
 	}
 	return ret;
 }
@@ -216,15 +285,94 @@
 	drv = info->drv;
 
 	ret = sr_response_unpack(info, vendata, datalen);
-	if (!ret)
-		wpa_msg(drv->ctx, MSG_INFO, "CTRL-EVENT-SR STATS RESPONSE\n" "%s", info->reply_buf);
-	else
-		wpa_msg(drv->ctx, MSG_INFO, "CTRL-EVENT-SR STATS RESPONSE\n" " %s : Error = %d",
-			info->reply_buf, ret);
-
+	switch (info->cmd_oper) {
+	case QCA_WLAN_SR_OPERATION_GET_STATS:
+		if (!ret)
+			wpa_msg(drv->ctx, MSG_INFO, "CTRL-EVENT-SR STATS RESPONSE\n"
+				"%s", info->reply_buf);
+		else
+			wpa_msg(drv->ctx, MSG_ERROR, "CTRL-EVENT-SR STATS RESPONSE\n"
+				" %s : Error = %d", info->reply_buf, ret);
+		break;
+	case QCA_WLAN_SR_OPERATION_GET_PARAMS:
+		if (!ret)
+			wpa_msg(drv->ctx, MSG_INFO, "CTRL-EVENT-SR PARAMS RESPONSE\n"
+				"%s", info->reply_buf);
+		else
+			wpa_msg(drv->ctx, MSG_ERROR, "CTRL-EVENT-SR PARAMS RESPONSE\n"
+				" %s : Error = %d", info->reply_buf, ret);
+		break;
+	}
 	return ret;
 }
 
+static int pack_sr_enable_nlmsg(struct nl_msg *nlmsg, char *cmd)
+{
+
+	struct nlattr *sr_attr;
+	s8 is_srg_pd_cmd = 0, is_non_srg_pd_cmd = 0;
+	s32 pd_thres = 0, cmd_id;
+	int ret;
+
+	cmd += 6;
+	cmd = skip_white_space(cmd);
+	if (*cmd == '\0')
+		return 0;
+
+	sr_attr = nla_nest_start(nlmsg, QCA_WLAN_VENDOR_ATTR_SR_PARAMS);
+	if (!sr_attr)
+		return -ENOMEM;
+
+	for (int i = 0; i < 2; i++) {
+		if (os_strncasecmp(cmd, "srg_pd_threshold ", 17) == 0) {
+			cmd += 17;
+			cmd = skip_white_space(cmd);
+			pd_thres = get_s32_from_string(cmd, &ret);
+			if (ret < 0 || pd_thres < OBSS_PD_THRESHOLD_MIN ||
+			    pd_thres > OBSS_PD_THRESHOLD_MAX) {
+				wpa_printf(MSG_ERROR, "Invalid SRG PD threshold: %d", pd_thres);
+				return -EINVAL;
+			}
+			cmd_id = QCA_WLAN_VENDOR_ATTR_SR_PARAMS_SRG_PD_THRESHOLD;
+			if (nla_put_s32(nlmsg, cmd_id, pd_thres)) {
+				wpa_printf(MSG_ERROR, "Failed to put SRG PD threshold");
+				return -ENOMEM;
+			}
+			is_srg_pd_cmd++;
+		} else if (os_strncasecmp(cmd, "non_srg_pd_threshold ", 21) == 0) {
+			cmd += 21;
+			cmd = skip_white_space(cmd);
+			pd_thres = get_s32_from_string(cmd, &ret);
+			/**
+			 * For non-SRG OBSS, allowed range for PD threshold
+			 * is -62 to -81 as -82 is fixed as min offset.
+			 **/
+			if (ret < 0 || pd_thres <= OBSS_PD_THRESHOLD_MIN ||
+			    pd_thres > OBSS_PD_THRESHOLD_MAX) {
+				wpa_printf(MSG_ERROR, "Invalid Non-SRG PD threshold: %d", pd_thres);
+				return -EINVAL;
+			}
+			cmd_id = QCA_WLAN_VENDOR_ATTR_SR_PARAMS_NON_SRG_PD_THRESHOLD;
+			if (nla_put_s32(nlmsg, cmd_id, pd_thres)) {
+				wpa_printf(MSG_ERROR, "Failed to put Non-SRG PD threshold");
+				return -ENOMEM;
+			}
+			is_non_srg_pd_cmd++;
+		} else if (*cmd == '\0')
+			break;
+		else
+			return -EINVAL;
+
+		if (is_srg_pd_cmd > 1 || is_non_srg_pd_cmd > 1)
+			return -EINVAL;
+
+		cmd = get_next_arg(cmd);
+		cmd = skip_white_space(cmd);
+	}
+	nla_nest_end(nlmsg, sr_attr);
+	return 0;
+}
+
 /**
  * wpa_driver_sr_cmd() - handle the spatial reuse commands
  *
@@ -288,11 +436,18 @@
 	}
 	switch (sr_cmd) {
 		case QCA_WLAN_SR_OPERATION_SR_ENABLE:
+			status = pack_sr_enable_nlmsg(nlmsg, cmd);
+			if (status < 0) {
+				wpa_printf(MSG_ERROR, "SR enable command failed: %d,"
+					   "error:%d", sr_cmd, status);
+				goto nlmsg_fail;
+			}
 		case QCA_WLAN_SR_OPERATION_SR_DISABLE:
 		case QCA_WLAN_SR_OPERATION_PSR_AND_NON_SRG_OBSS_PD_PROHIBIT:
 		case QCA_WLAN_SR_OPERATION_PSR_AND_NON_SRG_OBSS_PD_ALLOW:
 		case QCA_WLAN_SR_OPERATION_GET_STATS:
 		case QCA_WLAN_SR_OPERATION_CLEAR_STATS:
+		case QCA_WLAN_SR_OPERATION_GET_PARAMS:
 			status = nla_put_u8(nlmsg, QCA_WLAN_VENDOR_ATTR_SR_OPERATION, sr_cmd);
 			if (status) {
 				wpa_printf(MSG_ERROR, "Fail to put SR command:%d, error:%d\n",
@@ -307,9 +462,14 @@
 				   sr_cmd, status);
 			goto nlmsg_fail;
 	}
-	status = send_nlmsg((struct nl_sock *)drv->global->nl, nlmsg,
-			    (sr_cmd == QCA_WLAN_SR_OPERATION_GET_STATS) ? response_handler : NULL,
-			    (sr_cmd == QCA_WLAN_SR_OPERATION_GET_STATS) ? &info : NULL);
+	if (sr_cmd == QCA_WLAN_SR_OPERATION_GET_STATS ||
+	    sr_cmd == QCA_WLAN_SR_OPERATION_GET_PARAMS)
+		status = send_nlmsg((struct nl_sock *)drv->global->nl,
+				    nlmsg, response_handler, &info);
+	else
+		status = send_nlmsg((struct nl_sock *)drv->global->nl,
+				    nlmsg, NULL, NULL);
+
 	if (status) {
 		wpa_printf(MSG_ERROR, "Fail to send nlmsg SR command:%d to driver, error:%d\n",
 			   sr_cmd, status);