/*	$OpenBSD: if_umb.h,v 1.10 2021/07/04 19:22:32 sthen Exp $ */

/*
 * Copyright (c) 2016 genua mbH
 * All rights reserved.
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

/*
 * Mobile Broadband Interface Model
 * https://www.usb.org/sites/default/files/MBIM-Compliance-1.0.pdf
 */

struct umb_valdescr {
	int	 val;
	char	*descr;
};

static const char *
umb_val2descr(const struct umb_valdescr *vdp, int val)
{
	static char sval[32];

	while (vdp->descr != NULL) {
		if (vdp->val == val)
			return vdp->descr;
		vdp++;
	}
	snprintf(sval, sizeof (sval), "#%d", val);
	return sval;
}

#define MBIM_REGSTATE_DESCRIPTIONS {				\
	{ MBIM_REGSTATE_UNKNOWN,	"unknown" },		\
	{ MBIM_REGSTATE_DEREGISTERED,	"not registered" },	\
	{ MBIM_REGSTATE_SEARCHING,	"searching" },		\
	{ MBIM_REGSTATE_HOME,		"home network" },	\
	{ MBIM_REGSTATE_ROAMING,	"roaming network" },	\
	{ MBIM_REGSTATE_PARTNER,	"partner network" },	\
	{ MBIM_REGSTATE_DENIED,		"access denied" },	\
	{ 0, NULL } }

#define MBIM_DATACLASS_DESCRIPTIONS {					\
	{ MBIM_DATACLASS_NONE,				"none" },	\
	{ MBIM_DATACLASS_GPRS,				"GPRS" },	\
	{ MBIM_DATACLASS_EDGE,				"EDGE" },	\
	{ MBIM_DATACLASS_UMTS,				"UMTS" },	\
	{ MBIM_DATACLASS_HSDPA,				"HSDPA" },	\
	{ MBIM_DATACLASS_HSUPA,				"HSUPA" },	\
	{ MBIM_DATACLASS_HSDPA|MBIM_DATACLASS_HSUPA,	"HSPA" },	\
	{ MBIM_DATACLASS_LTE,				"LTE" },	\
	{ MBIM_DATACLASS_1XRTT,				"CDMA2000" },	\
	{ MBIM_DATACLASS_1XEVDO,			"CDMA2000" },	\
	{ MBIM_DATACLASS_1XEVDO_REV_A,			"CDMA2000" },	\
	{ MBIM_DATACLASS_1XEVDV,			"CDMA2000" },	\
	{ MBIM_DATACLASS_3XRTT,				"CDMA2000" },	\
	{ MBIM_DATACLASS_1XEVDO_REV_B,			"CDMA2000" },	\
	{ MBIM_DATACLASS_UMB,				"CDMA2000" },	\
	{ MBIM_DATACLASS_CUSTOM,			"custom" },	\
	{ 0, NULL } }

#define MBIM_1TO1_DESCRIPTION(m)	{ (m), #m }
#define MBIM_MESSAGES_DESCRIPTIONS {				\
	MBIM_1TO1_DESCRIPTION(MBIM_OPEN_MSG),			\
	MBIM_1TO1_DESCRIPTION(MBIM_CLOSE_MSG),			\
	MBIM_1TO1_DESCRIPTION(MBIM_COMMAND_MSG),		\
	MBIM_1TO1_DESCRIPTION(MBIM_HOST_ERROR_MSG),		\
	MBIM_1TO1_DESCRIPTION(MBIM_OPEN_DONE),			\
	MBIM_1TO1_DESCRIPTION(MBIM_CLOSE_DONE),			\
	MBIM_1TO1_DESCRIPTION(MBIM_COMMAND_DONE),		\
	MBIM_1TO1_DESCRIPTION(MBIM_FUNCTION_ERROR_MSG),		\
	MBIM_1TO1_DESCRIPTION(MBIM_INDICATE_STATUS_MSG),	\
	{ 0, NULL } }

#define MBIM_STATUS_DESCRIPTION(m)	{ MBIM_STATUS_ ## m, #m }
#define MBIM_STATUS_DESCRIPTIONS {					\
	MBIM_STATUS_DESCRIPTION(SUCCESS),				\
	MBIM_STATUS_DESCRIPTION(BUSY),					\
	MBIM_STATUS_DESCRIPTION(FAILURE),				\
	MBIM_STATUS_DESCRIPTION(SIM_NOT_INSERTED),			\
	MBIM_STATUS_DESCRIPTION(BAD_SIM),				\
	MBIM_STATUS_DESCRIPTION(PIN_REQUIRED),				\
	MBIM_STATUS_DESCRIPTION(PIN_DISABLED),				\
	MBIM_STATUS_DESCRIPTION(NOT_REGISTERED),			\
	MBIM_STATUS_DESCRIPTION(PROVIDERS_NOT_FOUND),			\
	MBIM_STATUS_DESCRIPTION(NO_DEVICE_SUPPORT),			\
	MBIM_STATUS_DESCRIPTION(PROVIDER_NOT_VISIBLE),			\
	MBIM_STATUS_DESCRIPTION(DATA_CLASS_NOT_AVAILABLE),		\
	MBIM_STATUS_DESCRIPTION(PACKET_SERVICE_DETACHED),		\
	MBIM_STATUS_DESCRIPTION(MAX_ACTIVATED_CONTEXTS),		\
	MBIM_STATUS_DESCRIPTION(NOT_INITIALIZED),			\
	MBIM_STATUS_DESCRIPTION(VOICE_CALL_IN_PROGRESS),		\
	MBIM_STATUS_DESCRIPTION(CONTEXT_NOT_ACTIVATED),			\
	MBIM_STATUS_DESCRIPTION(SERVICE_NOT_ACTIVATED),			\
	MBIM_STATUS_DESCRIPTION(INVALID_ACCESS_STRING),			\
	MBIM_STATUS_DESCRIPTION(INVALID_USER_NAME_PWD),			\
	MBIM_STATUS_DESCRIPTION(RADIO_POWER_OFF),			\
	MBIM_STATUS_DESCRIPTION(INVALID_PARAMETERS),			\
	MBIM_STATUS_DESCRIPTION(READ_FAILURE),				\
	MBIM_STATUS_DESCRIPTION(WRITE_FAILURE),				\
	MBIM_STATUS_DESCRIPTION(NO_PHONEBOOK),				\
	MBIM_STATUS_DESCRIPTION(PARAMETER_TOO_LONG),			\
	MBIM_STATUS_DESCRIPTION(STK_BUSY),				\
	MBIM_STATUS_DESCRIPTION(OPERATION_NOT_ALLOWED),			\
	MBIM_STATUS_DESCRIPTION(MEMORY_FAILURE),			\
	MBIM_STATUS_DESCRIPTION(INVALID_MEMORY_INDEX),			\
	MBIM_STATUS_DESCRIPTION(MEMORY_FULL),				\
	MBIM_STATUS_DESCRIPTION(FILTER_NOT_SUPPORTED),			\
	MBIM_STATUS_DESCRIPTION(DSS_INSTANCE_LIMIT),			\
	MBIM_STATUS_DESCRIPTION(INVALID_DEVICE_SERVICE_OPERATION),	\
	MBIM_STATUS_DESCRIPTION(AUTH_INCORRECT_AUTN),			\
	MBIM_STATUS_DESCRIPTION(AUTH_SYNC_FAILURE),			\
	MBIM_STATUS_DESCRIPTION(AUTH_AMF_NOT_SET),			\
	MBIM_STATUS_DESCRIPTION(CONTEXT_NOT_SUPPORTED),			\
	MBIM_STATUS_DESCRIPTION(SMS_UNKNOWN_SMSC_ADDRESS),		\
	MBIM_STATUS_DESCRIPTION(SMS_NETWORK_TIMEOUT),			\
	MBIM_STATUS_DESCRIPTION(SMS_LANG_NOT_SUPPORTED),		\
	MBIM_STATUS_DESCRIPTION(SMS_ENCODING_NOT_SUPPORTED),		\
	MBIM_STATUS_DESCRIPTION(SMS_FORMAT_NOT_SUPPORTED),		\
	{ 0, NULL } }

#define MBIM_ERROR_DESCRIPTION(m)	{ MBIM_ERROR_ ## m, #m }
#define MBIM_ERROR_DESCRIPTIONS {					\
	MBIM_ERROR_DESCRIPTION(TIMEOUT_FRAGMENT),			\
	MBIM_ERROR_DESCRIPTION(FRAGMENT_OUT_OF_SEQUENCE),		\
	MBIM_ERROR_DESCRIPTION(LENGTH_MISMATCH),			\
	MBIM_ERROR_DESCRIPTION(DUPLICATED_TID),				\
	MBIM_ERROR_DESCRIPTION(NOT_OPENED),				\
	MBIM_ERROR_DESCRIPTION(UNKNOWN),				\
	MBIM_ERROR_DESCRIPTION(CANCEL),					\
	MBIM_ERROR_DESCRIPTION(MAX_TRANSFER),				\
	{ 0, NULL } }

#define MBIM_CID_DESCRIPTIONS {						\
	MBIM_1TO1_DESCRIPTION(MBIM_CID_DEVICE_CAPS),			\
	MBIM_1TO1_DESCRIPTION(MBIM_CID_SUBSCRIBER_READY_STATUS),	\
	MBIM_1TO1_DESCRIPTION(MBIM_CID_RADIO_STATE),			\
	MBIM_1TO1_DESCRIPTION(MBIM_CID_PIN),				\
	MBIM_1TO1_DESCRIPTION(MBIM_CID_PIN_LIST),			\
	MBIM_1TO1_DESCRIPTION(MBIM_CID_HOME_PROVIDER),			\
	MBIM_1TO1_DESCRIPTION(MBIM_CID_PREFERRED_PROVIDERS),		\
	MBIM_1TO1_DESCRIPTION(MBIM_CID_VISIBLE_PROVIDERS),		\
	MBIM_1TO1_DESCRIPTION(MBIM_CID_REGISTER_STATE),			\
	MBIM_1TO1_DESCRIPTION(MBIM_CID_PACKET_SERVICE),			\
	MBIM_1TO1_DESCRIPTION(MBIM_CID_SIGNAL_STATE),			\
	MBIM_1TO1_DESCRIPTION(MBIM_CID_CONNECT),			\
	MBIM_1TO1_DESCRIPTION(MBIM_CID_PROVISIONED_CONTEXTS),		\
	MBIM_1TO1_DESCRIPTION(MBIM_CID_SERVICE_ACTIVATION),		\
	MBIM_1TO1_DESCRIPTION(MBIM_CID_IP_CONFIGURATION),		\
	MBIM_1TO1_DESCRIPTION(MBIM_CID_DEVICE_SERVICES),		\
	MBIM_1TO1_DESCRIPTION(MBIM_CID_DEVICE_SERVICE_SUBSCRIBE_LIST),	\
	MBIM_1TO1_DESCRIPTION(MBIM_CID_PACKET_STATISTICS),		\
	MBIM_1TO1_DESCRIPTION(MBIM_CID_NETWORK_IDLE_HINT),		\
	MBIM_1TO1_DESCRIPTION(MBIM_CID_EMERGENCY_MODE),			\
	MBIM_1TO1_DESCRIPTION(MBIM_CID_IP_PACKET_FILTERS),		\
	MBIM_1TO1_DESCRIPTION(MBIM_CID_MULTICARRIER_PROVIDERS),		\
	{ 0, NULL } }

#define MBIM_SIMSTATE_DESCRIPTIONS {					\
	{ MBIM_SIMSTATE_NOTINITIALIZED, "not initialized" },		\
	{ MBIM_SIMSTATE_INITIALIZED, "initialized" },			\
	{ MBIM_SIMSTATE_NOTINSERTED, "not inserted" },			\
	{ MBIM_SIMSTATE_BADSIM, "bad type" },				\
	{ MBIM_SIMSTATE_FAILURE, "failed" },				\
	{ MBIM_SIMSTATE_NOTACTIVATED, "not activated" },		\
	{ MBIM_SIMSTATE_LOCKED, "locked" },				\
	{ 0, NULL } }

#define MBIM_PINTYPE_DESCRIPTIONS {					\
	{ MBIM_PIN_TYPE_NONE, "none" },					\
	{ MBIM_PIN_TYPE_CUSTOM, "custom" },				\
	{ MBIM_PIN_TYPE_PIN1, "PIN1" },					\
	{ MBIM_PIN_TYPE_PIN2, "PIN2" },					\
	{ MBIM_PIN_TYPE_DEV_SIM_PIN, "device PIN" },			\
	{ MBIM_PIN_TYPE_DEV_FIRST_SIM_PIN, "device 1st PIN" },		\
	{ MBIM_PIN_TYPE_NETWORK_PIN, "network PIN" },			\
	{ MBIM_PIN_TYPE_NETWORK_SUBSET_PIN, "network subset PIN" },	\
	{ MBIM_PIN_TYPE_SERVICE_PROVIDER_PIN, "provider PIN" },		\
	{ MBIM_PIN_TYPE_CORPORATE_PIN, "corporate PIN" },		\
	{ MBIM_PIN_TYPE_SUBSIDY_LOCK, "subsidy lock" },			\
	{ MBIM_PIN_TYPE_PUK1, "PUK" },					\
	{ MBIM_PIN_TYPE_PUK2, "PUK2" },					\
	{ MBIM_PIN_TYPE_DEV_FIRST_SIM_PUK, "device 1st PUK" },		\
	{ MBIM_PIN_TYPE_NETWORK_PUK, "network PUK" },			\
	{ MBIM_PIN_TYPE_NETWORK_SUBSET_PUK, "network subset PUK" },	\
	{ MBIM_PIN_TYPE_SERVICE_PROVIDER_PUK, "provider PUK" },		\
	{ MBIM_PIN_TYPE_CORPORATE_PUK, "corporate PUK" },		\
	{ 0, NULL } }

#define MBIM_PKTSRV_STATE_DESCRIPTIONS {				\
	{ MBIM_PKTSERVICE_STATE_UNKNOWN, "unknown" },			\
	{ MBIM_PKTSERVICE_STATE_ATTACHING, "attaching" },		\
	{ MBIM_PKTSERVICE_STATE_ATTACHED, "attached" },			\
	{ MBIM_PKTSERVICE_STATE_DETACHING, "detaching" },		\
	{ MBIM_PKTSERVICE_STATE_DETACHED, "detached" },			\
	{ 0, NULL } }

#define MBIM_ACTIVATION_STATE_DESCRIPTIONS {				\
	{ MBIM_ACTIVATION_STATE_UNKNOWN, "unknown" },			\
	{ MBIM_ACTIVATION_STATE_ACTIVATED, "activated" },		\
	{ MBIM_ACTIVATION_STATE_ACTIVATING, "activating" },		\
	{ MBIM_ACTIVATION_STATE_DEACTIVATED, "deactivated" },		\
	{ MBIM_ACTIVATION_STATE_DEACTIVATING, "deactivating" },		\
	{ 0, NULL } }

/*
 * Driver internal state
 */
enum umb_state {
	UMB_S_DOWN = 0,		/* interface down */
	UMB_S_OPEN,		/* MBIM device has been opened */
	UMB_S_CID,		/* QMI client id allocated */
	UMB_S_RADIO,		/* radio is on */
	UMB_S_SIMREADY,		/* SIM is ready */
	UMB_S_ATTACHED,		/* packet service is attached */
	UMB_S_CONNECTED,	/* connected to provider */
	UMB_S_UP,		/* have IP configuration */
};

#define UMB_INTERNAL_STATE_DESCRIPTIONS {	\
	{ UMB_S_DOWN, "down" },			\
	{ UMB_S_OPEN, "open" },			\
	{ UMB_S_CID, "CID allocated" },		\
	{ UMB_S_RADIO, "radio on" },		\
	{ UMB_S_SIMREADY, "SIM is ready" },	\
	{ UMB_S_ATTACHED, "attached" },		\
	{ UMB_S_CONNECTED, "connected" },	\
	{ UMB_S_UP, "up" },			\
	{ 0, NULL } }

/*
 * UMB parameters (SIOC[GS]UMBPARAM ioctls)
 */
struct umb_parameter {
	int			op;
	int			is_puk;
	char			pin[MBIM_PIN_MAXLEN];
	int			pinlen;

	char			newpin[MBIM_PIN_MAXLEN];
	int			newpinlen;

#define UMB_APN_MAXLEN		100
	uint16_t		apn[UMB_APN_MAXLEN];
	int			apnlen;

	int			roaming;
	uint32_t		preferredclasses;
};

/*
 * UMB device status info (SIOCGUMBINFO ioctl)
 */
struct umb_info {
	enum umb_state		state;
	int			enable_roaming;
#define UMB_PIN_REQUIRED	0
#define UMB_PIN_UNLOCKED	1
#define UMB_PUK_REQUIRED	2
	int			pin_state;
	int			pin_attempts_left;
	int			activation;
	int			sim_state;
	int			regstate;
	int			regmode;
	int			nwerror;
	int			packetstate;
	uint32_t		supportedclasses; /* what the hw supports */
	uint32_t		preferredclasses; /* what the user prefers */
	uint32_t		highestclass;	/* what the network offers */
	uint32_t		cellclass;
#define UMB_PROVIDERNAME_MAXLEN		20
	uint16_t		provider[UMB_PROVIDERNAME_MAXLEN];
#define UMB_PROVIDERID_MAXLEN		20
	uint16_t		providerid[UMB_PROVIDERID_MAXLEN];
#define UMB_PHONENR_MAXLEN		22
	uint16_t		pn[UMB_PHONENR_MAXLEN];
#define UMB_SUBSCRIBERID_MAXLEN		15
	uint16_t		sid[UMB_SUBSCRIBERID_MAXLEN];
#define UMB_ICCID_MAXLEN		20
	uint16_t		iccid[UMB_ICCID_MAXLEN];
#define UMB_ROAMINGTEXT_MAXLEN		63
	uint16_t		roamingtxt[UMB_ROAMINGTEXT_MAXLEN];

#define UMB_DEVID_MAXLEN		18
	uint16_t		devid[UMB_DEVID_MAXLEN];
#define UMB_FWINFO_MAXLEN		30
	uint16_t		fwinfo[UMB_FWINFO_MAXLEN];
#define UMB_HWINFO_MAXLEN		30
	uint16_t		hwinfo[UMB_HWINFO_MAXLEN];

	uint16_t		apn[UMB_APN_MAXLEN];
	int			apnlen;

#define UMB_VALUE_UNKNOWN	-999
	int			rssi;
#define UMB_BER_EXCELLENT	0
#define UMB_BER_VERYGOOD	1
#define UMB_BER_GOOD		2
#define UMB_BER_OK		3
#define UMB_BER_MEDIUM		4
#define UMB_BER_BAD		5
#define UMB_BER_VERYBAD		6
#define UMB_BER_EXTREMELYBAD	7
	int			ber;

	int			hw_radio_on;
	int			sw_radio_on;

	uint64_t		uplink_speed;
	uint64_t		downlink_speed;

#define UMB_MAX_DNSSRV			2
	struct in_addr		ipv4dns[UMB_MAX_DNSSRV];
	struct in6_addr		ipv6dns[UMB_MAX_DNSSRV];
};

#ifdef _KERNEL
/*
 * UMB device
 */
struct umb_softc {
	struct device		 sc_dev;
	struct ifnet		 sc_if;
#define GET_IFP(sc)	(&(sc)->sc_if)
	struct usbd_device	*sc_udev;

	int			 sc_ver_maj;
	int			 sc_ver_min;
	int			 sc_ctrl_len;
	int			 sc_maxpktlen;
	int			 sc_maxsessions;
	unsigned int		 sc_ncm_supported_formats;
	int			 sc_ncm_format;

	int			 sc_maxdgram;
	int			 sc_align;
	int			 sc_ndp_div;
	int			 sc_ndp_remainder;

#define UMBFLG_FCC_AUTH_REQUIRED	0x0001
#define UMBFLG_NO_INET6			0x0002
#define UMBFLG_NDP_AT_END		0x0004
	uint32_t		 sc_flags;
	int			 sc_cid;

	struct usb_task		 sc_umb_task;
	struct usb_task		 sc_get_response_task;
	int			 sc_nresp;
	struct timeout		 sc_statechg_timer;

	uint8_t			 sc_ctrl_ifaceno;
	struct usbd_pipe	*sc_ctrl_pipe;
	struct usb_cdc_notification sc_intr_msg;
	struct usbd_interface	*sc_data_iface;

	void			*sc_resp_buf;
	void			*sc_ctrl_msg;

	int			 sc_rx_ep;
	struct usbd_xfer	*sc_rx_xfer;
	void			*sc_rx_buf;
	int			 sc_rx_bufsz;
	struct usbd_pipe	*sc_rx_pipe;
	unsigned		 sc_rx_nerr;

	int			 sc_tx_ep;
	struct usbd_xfer	*sc_tx_xfer;
	void			*sc_tx_buf;
	int			 sc_tx_bufsz;
	struct usbd_pipe	*sc_tx_pipe;
	struct mbuf_list	 sc_tx_ml;
	uint32_t		 sc_tx_seq;

	uint32_t		 sc_tid;

#define sc_state		sc_info.state
#define sc_roaming		sc_info.enable_roaming
	struct umb_info		 sc_info;
};
#endif /* _KERNEL */
