static u32 get_adv_instance_flags(struct hci_dev *hdev, u8 instance)
{
	u32 flags;
	struct adv_info *adv_instance;

	if (instance == 0x00) {
		/* Instance 0 always manages the "Tx Power" and "Flags"
		 * fields
		 */
		flags = MGMT_ADV_FLAG_TX_POWER | MGMT_ADV_FLAG_MANAGED_FLAGS;

		/* For instance 0, the HCI_ADVERTISING_CONNECTABLE setting
		 * corresponds to the "connectable" instance flag.
		 */
		if (hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE))
			flags |= MGMT_ADV_FLAG_CONNECTABLE;

		if (hci_dev_test_flag(hdev, HCI_LIMITED_DISCOVERABLE))
			flags |= MGMT_ADV_FLAG_LIMITED_DISCOV;
		else if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
			flags |= MGMT_ADV_FLAG_DISCOV;

		return flags;
	}

	adv_instance = hci_find_adv_instance(hdev, instance);

	/* Return 0 when we got an invalid instance identifier. */
	if (!adv_instance)
		return 0;

	return adv_instance->flags;
}


static bool adv_use_rpa(struct hci_dev *hdev, uint32_t flags)
{
	/* If privacy is not enabled don't use RPA */
	if (!hci_dev_test_flag(hdev, HCI_PRIVACY))
		return false;

	/* If basic privacy mode is enabled use RPA */
	if (!hci_dev_test_flag(hdev, HCI_LIMITED_PRIVACY))
		return true;

	/* If limited privacy mode is enabled don't use RPA if we're
	 * both discoverable and bondable.
	 */
	if ((flags & MGMT_ADV_FLAG_DISCOV) &&
	    hci_dev_test_flag(hdev, HCI_BONDABLE))
		return false;

	/* We're neither bondable nor discoverable in the limited
	 * privacy mode, therefore use RPA.
	 */
	return true;
}


static void set_random_addr(struct hci_request *req, bdaddr_t *rpa)
{
	struct hci_dev *hdev = req->hdev;

	/* If we're advertising or initiating an LE connection we can't
	 * go ahead and change the random address at this time. This is
	 * because the eventual initiator address used for the
	 * subsequently created connection will be undefined (some
	 * controllers use the new address and others the one we had
	 * when the operation started).
	 *
	 * In this kind of scenario skip the update and let the random
	 * address be updated at the next cycle.
	 */
	if (hci_dev_test_flag(hdev, HCI_LE_ADV) ||
	    hci_lookup_le_connect(hdev)) {
		bt_dev_dbg(hdev, "Deferring random address update");
		hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
		return;
	}

	hci_req_add(req, HCI_OP_LE_SET_RANDOM_ADDR, 6, rpa);
}


static bool adv_cur_instance_is_scannable(struct hci_dev *hdev)
{
	return adv_instance_is_scannable(hdev, hdev->cur_adv_instance);
}


int __hci_req_schedule_adv_instance(struct hci_request *req, u8 instance,
				    bool force)
{
	struct hci_dev *hdev = req->hdev;
	struct adv_info *adv_instance = NULL;
	u16 timeout;

	if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
	    list_empty(&hdev->adv_instances))
		return -EPERM;

	if (hdev->adv_instance_timeout)
		return -EBUSY;

	adv_instance = hci_find_adv_instance(hdev, instance);
	if (!adv_instance)
		return -ENOENT;

	/* A zero timeout means unlimited advertising. As long as there is
	 * only one instance, duration should be ignored. We still set a timeout
	 * in case further instances are being added later on.
	 *
	 * If the remaining lifetime of the instance is more than the duration
	 * then the timeout corresponds to the duration, otherwise it will be
	 * reduced to the remaining instance lifetime.
	 */
	if (adv_instance->timeout == 0 ||
	    adv_instance->duration <= adv_instance->remaining_time)
		timeout = adv_instance->duration;
	else
		timeout = adv_instance->remaining_time;

	/* The remaining time is being reduced unless the instance is being
	 * advertised without time limit.
	 */
	if (adv_instance->timeout)
		adv_instance->remaining_time =
				adv_instance->remaining_time - timeout;

	/* Only use work for scheduling instances with legacy advertising */
	if (!ext_adv_capable(hdev)) {
		hdev->adv_instance_timeout = timeout;
		queue_delayed_work(hdev->req_workqueue,
			   &hdev->adv_instance_expire,
			   msecs_to_jiffies(timeout * 1000));
	}

	/* If we're just re-scheduling the same instance again then do not
	 * execute any HCI commands. This happens when a single instance is
	 * being advertised.
	 */
	if (!force && hdev->cur_adv_instance == instance &&
	    hci_dev_test_flag(hdev, HCI_LE_ADV))
		return 0;

	hdev->cur_adv_instance = instance;
	if (ext_adv_capable(hdev)) {
		__hci_req_start_ext_adv(req, instance);
	} else {
		__hci_req_update_adv_data(req, instance);
		__hci_req_update_scan_rsp_data(req, instance);
		__hci_req_enable_advertising(req);
	}

	return 0;
}


int __hci_req_sync(struct hci_dev *hdev, int (*func)(struct hci_request *req,
						     unsigned long opt),
		   unsigned long opt, u32 timeout, u8 *hci_status)
{
	struct hci_request req;
	int err = 0;

	bt_dev_dbg(hdev, "start");

	hci_req_init(&req, hdev);

	hdev->req_status = HCI_REQ_PEND;

	err = func(&req, opt);
	if (err) {
		if (hci_status)
			*hci_status = HCI_ERROR_UNSPECIFIED;
		return err;
	}

	err = hci_req_run_skb(&req, hci_req_sync_complete);
	if (err < 0) {
		hdev->req_status = 0;

		/* ENODATA means the HCI request command queue is empty.
		 * This can happen when a request with conditionals doesn't
		 * trigger any commands to be sent. This is normal behavior
		 * and should not trigger an error return.
		 */
		if (err == -ENODATA) {
			if (hci_status)
				*hci_status = 0;
			return 0;
		}

		if (hci_status)
			*hci_status = HCI_ERROR_UNSPECIFIED;

		return err;
	}

	err = wait_event_interruptible_timeout(hdev->req_wait_q,
			hdev->req_status != HCI_REQ_PEND, timeout);

	if (err == -ERESTARTSYS)
		return -EINTR;

	switch (hdev->req_status) {
	case HCI_REQ_DONE:
		err = -bt_to_errno(hdev->req_result);
		if (hci_status)
			*hci_status = hdev->req_result;
		break;

	case HCI_REQ_CANCELED:
		err = -hdev->req_result;
		if (hci_status)
			*hci_status = HCI_ERROR_UNSPECIFIED;
		break;

	default:
		err = -ETIMEDOUT;
		if (hci_status)
			*hci_status = HCI_ERROR_UNSPECIFIED;
		break;
	}

	kfree_skb(hdev->req_skb);
	hdev->req_skb = NULL;
	hdev->req_status = hdev->req_result = 0;

	bt_dev_dbg(hdev, "end: err %d", err);

	return err;
}


static void write_iac(struct hci_request *req)
{
	struct hci_dev *hdev = req->hdev;
	struct hci_cp_write_current_iac_lap cp;

	if (!hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
		return;

	if (hci_dev_test_flag(hdev, HCI_LIMITED_DISCOVERABLE)) {
		/* Limited discoverable mode */
		cp.num_iac = min_t(u8, hdev->num_iac, 2);
		cp.iac_lap[0] = 0x00;	/* LIAC */
		cp.iac_lap[1] = 0x8b;
		cp.iac_lap[2] = 0x9e;
		cp.iac_lap[3] = 0x33;	/* GIAC */
		cp.iac_lap[4] = 0x8b;
		cp.iac_lap[5] = 0x9e;
	} else {
		/* General discoverable mode */
		cp.num_iac = 1;
		cp.iac_lap[0] = 0x33;	/* GIAC */
		cp.iac_lap[1] = 0x8b;
		cp.iac_lap[2] = 0x9e;
	}

	hci_req_add(req, HCI_OP_WRITE_CURRENT_IAC_LAP,
		    (cp.num_iac * 3) + 1, &cp);
}


static int le_scan_restart(struct hci_request *req, unsigned long opt)
{
	struct hci_dev *hdev = req->hdev;

	/* If controller is not scanning we are done. */
	if (!hci_dev_test_flag(hdev, HCI_LE_SCAN))
		return 0;

	if (hdev->scanning_paused) {
		bt_dev_dbg(hdev, "Scanning is paused for suspend");
		return 0;
	}

	hci_req_add_le_scan_disable(req, false);

	if (use_ext_scan(hdev)) {
		struct hci_cp_le_set_ext_scan_enable ext_enable_cp;

		memset(&ext_enable_cp, 0, sizeof(ext_enable_cp));
		ext_enable_cp.enable = LE_SCAN_ENABLE;
		ext_enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;

		hci_req_add(req, HCI_OP_LE_SET_EXT_SCAN_ENABLE,
			    sizeof(ext_enable_cp), &ext_enable_cp);
	} else {
		struct hci_cp_le_set_scan_enable cp;

		memset(&cp, 0, sizeof(cp));
		cp.enable = LE_SCAN_ENABLE;
		cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
		hci_req_add(req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp);
	}

	return 0;
}


static bool is_advertising_allowed(struct hci_dev *hdev, bool connectable)
{
	/* If there is no connection we are OK to advertise. */
	if (hci_conn_num(hdev, LE_LINK) == 0)
		return true;

	/* Check le_states if there is any connection in slave role. */
	if (hdev->conn_hash.le_num_slave > 0) {
		/* Slave connection state and non connectable mode bit 20. */
		if (!connectable && !(hdev->le_states[2] & 0x10))
			return false;

		/* Slave connection state and connectable mode bit 38
		 * and scannable bit 21.
		 */
		if (connectable && (!(hdev->le_states[4] & 0x40) ||
				    !(hdev->le_states[2] & 0x20)))
			return false;
	}

	/* Check le_states if there is any connection in master role. */
	if (hci_conn_num(hdev, LE_LINK) != hdev->conn_hash.le_num_slave) {
		/* Master connection state and non connectable mode bit 18. */
		if (!connectable && !(hdev->le_states[2] & 0x02))
			return false;

		/* Master connection state and connectable mode bit 35 and
		 * scannable 19.
		 */
		if (connectable && (!(hdev->le_states[4] & 0x08) ||
				    !(hdev->le_states[2] & 0x08)))
			return false;
	}

	return true;
}


bool hci_req_status_pend(struct hci_dev *hdev)
{
	return hdev->req_status == HCI_REQ_PEND;
}


int hci_req_run(struct hci_request *req, hci_req_complete_t complete)
{
	return req_run(req, complete, NULL);
}


void hci_req_reenable_advertising(struct hci_dev *hdev)
{
	struct hci_request req;

	if (!hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
	    list_empty(&hdev->adv_instances))
		return;

	hci_req_init(&req, hdev);

	if (hdev->cur_adv_instance) {
		__hci_req_schedule_adv_instance(&req, hdev->cur_adv_instance,
						true);
	} else {
		if (ext_adv_capable(hdev)) {
			__hci_req_start_ext_adv(&req, 0x00);
		} else {
			__hci_req_update_adv_data(&req, 0x00);
			__hci_req_update_scan_rsp_data(&req, 0x00);
			__hci_req_enable_advertising(&req);
		}
	}

	hci_req_run(&req, adv_enable_complete);
}


static int discoverable_update(struct hci_request *req, unsigned long opt)
{
	struct hci_dev *hdev = req->hdev;

	hci_dev_lock(hdev);

	if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
		write_iac(req);
		__hci_req_update_scan(req);
		__hci_req_update_class(req);
	}

	/* Advertising instances don't use the global discoverable setting, so
	 * only update AD if advertising was enabled using Set Advertising.
	 */
	if (hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
		__hci_req_update_adv_data(req, 0x00);

		/* Discoverable mode affects the local advertising
		 * address in limited privacy mode.
		 */
		if (hci_dev_test_flag(hdev, HCI_LIMITED_PRIVACY)) {
			if (ext_adv_capable(hdev))
				__hci_req_start_ext_adv(req, 0x00);
			else
				__hci_req_enable_advertising(req);
		}
	}

	hci_dev_unlock(hdev);

	return 0;
}


static bool is_interleave_scanning(struct hci_dev *hdev)
{
	return hdev->interleave_scan_state != INTERLEAVE_SCAN_NONE;
}


static int req_run(struct hci_request *req, hci_req_complete_t complete,
		   hci_req_complete_skb_t complete_skb)
{
	struct hci_dev *hdev = req->hdev;
	struct sk_buff *skb;
	unsigned long flags;

	bt_dev_dbg(hdev, "length %u", skb_queue_len(&req->cmd_q));

	/* If an error occurred during request building, remove all HCI
	 * commands queued on the HCI request queue.
	 */
	if (req->err) {
		skb_queue_purge(&req->cmd_q);
		return req->err;
	}

	/* Do not allow empty requests */
	if (skb_queue_empty(&req->cmd_q))
		return -ENODATA;

	skb = skb_peek_tail(&req->cmd_q);
	if (complete) {
		bt_cb(skb)->hci.req_complete = complete;
	} else if (complete_skb) {
		bt_cb(skb)->hci.req_complete_skb = complete_skb;
		bt_cb(skb)->hci.req_flags |= HCI_REQ_SKB;
	}

	spin_lock_irqsave(&hdev->cmd_q.lock, flags);
	skb_queue_splice_tail(&req->cmd_q, &hdev->cmd_q);
	spin_unlock_irqrestore(&hdev->cmd_q.lock, flags);

	queue_work(hdev->workqueue, &hdev->cmd_work);

	return 0;
}


static void le_scan_disable_work(struct work_struct *work)
{
	struct hci_dev *hdev = container_of(work, struct hci_dev,
					    le_scan_disable.work);
	u8 status;

	bt_dev_dbg(hdev, "");

	if (!hci_dev_test_flag(hdev, HCI_LE_SCAN))
		return;

	cancel_delayed_work(&hdev->le_scan_restart);

	hci_req_sync(hdev, le_scan_disable, 0, HCI_CMD_TIMEOUT, &status);
	if (status) {
		bt_dev_err(hdev, "failed to disable LE scan: status 0x%02x",
			   status);
		return;
	}

	hdev->discovery.scan_start = 0;

	/* If we were running LE only scan, change discovery state. If
	 * we were running both LE and BR/EDR inquiry simultaneously,
	 * and BR/EDR inquiry is already finished, stop discovery,
	 * otherwise BR/EDR inquiry will stop discovery when finished.
	 * If we will resolve remote device name, do not change
	 * discovery state.
	 */

	if (hdev->discovery.type == DISCOV_TYPE_LE)
		goto discov_stopped;

	if (hdev->discovery.type != DISCOV_TYPE_INTERLEAVED)
		return;

	if (test_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks)) {
		if (!test_bit(HCI_INQUIRY, &hdev->flags) &&
		    hdev->discovery.state != DISCOVERY_RESOLVING)
			goto discov_stopped;

		return;
	}

	hci_req_sync(hdev, bredr_inquiry, DISCOV_INTERLEAVED_INQUIRY_LEN,
		     HCI_CMD_TIMEOUT, &status);
	if (status) {
		bt_dev_err(hdev, "inquiry failed: status 0x%02x", status);
		goto discov_stopped;
	}

	return;

discov_stopped:
	hci_dev_lock(hdev);
	hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
	hci_dev_unlock(hdev);
}


static int update_scan(struct hci_request *req, unsigned long opt)
{
	hci_dev_lock(req->hdev);
	__hci_req_update_scan(req);
	hci_dev_unlock(req->hdev);
	return 0;
}


static void hci_req_start_scan(struct hci_request *req, u8 type, u16 interval,
			       u16 window, u8 own_addr_type, u8 filter_policy,
			       bool addr_resolv)
{
	struct hci_dev *hdev = req->hdev;

	if (hdev->scanning_paused) {
		bt_dev_dbg(hdev, "Scanning is paused for suspend");
		return;
	}

	if (use_ll_privacy(hdev) &&
	    hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY) &&
	    addr_resolv) {
		u8 enable = 0x01;

		hci_req_add(req, HCI_OP_LE_SET_ADDR_RESOLV_ENABLE, 1, &enable);
	}

	/* Use ext scanning if set ext scan param and ext scan enable is
	 * supported
	 */
	if (use_ext_scan(hdev)) {
		struct hci_cp_le_set_ext_scan_params *ext_param_cp;
		struct hci_cp_le_set_ext_scan_enable ext_enable_cp;
		struct hci_cp_le_scan_phy_params *phy_params;
		u8 data[sizeof(*ext_param_cp) + sizeof(*phy_params) * 2];
		u32 plen;

		ext_param_cp = (void *)data;
		phy_params = (void *)ext_param_cp->data;

		memset(ext_param_cp, 0, sizeof(*ext_param_cp));
		ext_param_cp->own_addr_type = own_addr_type;
		ext_param_cp->filter_policy = filter_policy;

		plen = sizeof(*ext_param_cp);

		if (scan_1m(hdev) || scan_2m(hdev)) {
			ext_param_cp->scanning_phys |= LE_SCAN_PHY_1M;

			memset(phy_params, 0, sizeof(*phy_params));
			phy_params->type = type;
			phy_params->interval = cpu_to_le16(interval);
			phy_params->window = cpu_to_le16(window);

			plen += sizeof(*phy_params);
			phy_params++;
		}

		if (scan_coded(hdev)) {
			ext_param_cp->scanning_phys |= LE_SCAN_PHY_CODED;

			memset(phy_params, 0, sizeof(*phy_params));
			phy_params->type = type;
			phy_params->interval = cpu_to_le16(interval);
			phy_params->window = cpu_to_le16(window);

			plen += sizeof(*phy_params);
			phy_params++;
		}

		hci_req_add(req, HCI_OP_LE_SET_EXT_SCAN_PARAMS,
			    plen, ext_param_cp);

		memset(&ext_enable_cp, 0, sizeof(ext_enable_cp));
		ext_enable_cp.enable = LE_SCAN_ENABLE;
		ext_enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;

		hci_req_add(req, HCI_OP_LE_SET_EXT_SCAN_ENABLE,
			    sizeof(ext_enable_cp), &ext_enable_cp);
	} else {
		struct hci_cp_le_set_scan_param param_cp;
		struct hci_cp_le_set_scan_enable enable_cp;

		memset(&param_cp, 0, sizeof(param_cp));
		param_cp.type = type;
		param_cp.interval = cpu_to_le16(interval);
		param_cp.window = cpu_to_le16(window);
		param_cp.own_address_type = own_addr_type;
		param_cp.filter_policy = filter_policy;
		hci_req_add(req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
			    &param_cp);

		memset(&enable_cp, 0, sizeof(enable_cp));
		enable_cp.enable = LE_SCAN_ENABLE;
		enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
		hci_req_add(req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
			    &enable_cp);
	}
}


int hci_update_random_address(struct hci_request *req, bool require_privacy,
			      bool use_rpa, u8 *own_addr_type)
{
	struct hci_dev *hdev = req->hdev;
	int err;

	/* If privacy is enabled use a resolvable private address. If
	 * current RPA has expired or there is something else than
	 * the current RPA in use, then generate a new one.
	 */
	if (use_rpa) {
		int to;

		/* If Controller supports LL Privacy use own address type is
		 * 0x03
		 */
		if (use_ll_privacy(hdev))
			*own_addr_type = ADDR_LE_DEV_RANDOM_RESOLVED;
		else
			*own_addr_type = ADDR_LE_DEV_RANDOM;

		if (!hci_dev_test_and_clear_flag(hdev, HCI_RPA_EXPIRED) &&
		    !bacmp(&hdev->random_addr, &hdev->rpa))
			return 0;

		err = smp_generate_rpa(hdev, hdev->irk, &hdev->rpa);
		if (err < 0) {
			bt_dev_err(hdev, "failed to generate new RPA");
			return err;
		}

		set_random_addr(req, &hdev->rpa);

		to = msecs_to_jiffies(hdev->rpa_timeout * 1000);
		queue_delayed_work(hdev->workqueue, &hdev->rpa_expired, to);

		return 0;
	}

	/* In case of required privacy without resolvable private address,
	 * use an non-resolvable private address. This is useful for active
	 * scanning and non-connectable advertising.
	 */
	if (require_privacy) {
		bdaddr_t nrpa;

		while (true) {
			/* The non-resolvable private address is generated
			 * from random six bytes with the two most significant
			 * bits cleared.
			 */
			get_random_bytes(&nrpa, 6);
			nrpa.b[5] &= 0x3f;

			/* The non-resolvable private address shall not be
			 * equal to the public address.
			 */
			if (bacmp(&hdev->bdaddr, &nrpa))
				break;
		}

		*own_addr_type = ADDR_LE_DEV_RANDOM;
		set_random_addr(req, &nrpa);
		return 0;
	}

	/* If forcing static address is in use or there is no public
	 * address use the static address as random address (but skip
	 * the HCI command if the current random address is already the
	 * static one.
	 *
	 * In case BR/EDR has been disabled on a dual-mode controller
	 * and a static address has been configured, then use that
	 * address instead of the public BR/EDR address.
	 */
	if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
	    !bacmp(&hdev->bdaddr, BDADDR_ANY) ||
	    (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
	     bacmp(&hdev->static_addr, BDADDR_ANY))) {
		*own_addr_type = ADDR_LE_DEV_RANDOM;
		if (bacmp(&hdev->static_addr, &hdev->random_addr))
			hci_req_add(req, HCI_OP_LE_SET_RANDOM_ADDR, 6,
				    &hdev->static_addr);
		return 0;
	}

	/* Neither privacy nor static address is being used so use a
	 * public address.
	 */
	*own_addr_type = ADDR_LE_DEV_PUBLIC;

	return 0;
}


struct sk_buff *__hci_cmd_sync(struct hci_dev *hdev, u16 opcode, u32 plen,
			       const void *param, u32 timeout)
{
	return __hci_cmd_sync_ev(hdev, opcode, plen, param, 0, timeout);
}


void __hci_req_update_adv_data(struct hci_request *req, u8 instance)
{
	struct hci_dev *hdev = req->hdev;
	u8 len;

	if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
		return;

	if (ext_adv_capable(hdev)) {
		struct hci_cp_le_set_ext_adv_data cp;

		memset(&cp, 0, sizeof(cp));

		len = create_instance_adv_data(hdev, instance, cp.data);

		/* There's nothing to do if the data hasn't changed */
		if (hdev->adv_data_len == len &&
		    memcmp(cp.data, hdev->adv_data, len) == 0)
			return;

		memcpy(hdev->adv_data, cp.data, sizeof(cp.data));
		hdev->adv_data_len = len;

		cp.length = len;
		cp.handle = instance;
		cp.operation = LE_SET_ADV_DATA_OP_COMPLETE;
		cp.frag_pref = LE_SET_ADV_DATA_NO_FRAG;

		hci_req_add(req, HCI_OP_LE_SET_EXT_ADV_DATA, sizeof(cp), &cp);
	} else {
		struct hci_cp_le_set_adv_data cp;

		memset(&cp, 0, sizeof(cp));

		len = create_instance_adv_data(hdev, instance, cp.data);

		/* There's nothing to do if the data hasn't changed */
		if (hdev->adv_data_len == len &&
		    memcmp(cp.data, hdev->adv_data, len) == 0)
			return;

		memcpy(hdev->adv_data, cp.data, sizeof(cp.data));
		hdev->adv_data_len = len;

		cp.length = len;

		hci_req_add(req, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp);
	}
}


static TIFFMethodType GetJPEGMethod(Image* image,TIFF *tiff,uint16 photometric,
  uint16 bits_per_sample,uint16 samples_per_pixel)
{
#define BUFFER_SIZE 2048

  MagickOffsetType
    position,
    offset;

  size_t
    i;

  TIFFMethodType
    method;

#if defined(TIFF_VERSION_BIG)
  uint64
#else
  uint32
#endif
    *value;

  unsigned char
    buffer[BUFFER_SIZE+32];

  unsigned short
    length;

  /*
    Only support 8 bit for now.
  */
  if ((photometric != PHOTOMETRIC_SEPARATED) || (bits_per_sample != 8) ||
      (samples_per_pixel != 4))
    return(ReadGenericMethod);
  /*
    Search for Adobe APP14 JPEG marker.
  */
  value=NULL;
  if (!TIFFGetField(tiff,TIFFTAG_STRIPOFFSETS,&value) || (value == NULL))
    return(ReadStripMethod);
  position=TellBlob(image);
  offset=(MagickOffsetType) (value[0]);
  if (SeekBlob(image,offset,SEEK_SET) != offset)
    return(ReadStripMethod);
  method=ReadStripMethod;
  if (ReadBlob(image,BUFFER_SIZE,buffer) == BUFFER_SIZE)
    {
      for (i=0; i < BUFFER_SIZE; i++)
      {
        while (i < BUFFER_SIZE)
        {
          if (buffer[i++] == 255)
           break;
        }
        while (i < BUFFER_SIZE)
        {
          if (buffer[++i] != 255)
           break;
        }
        if (buffer[i++] == 216) /* JPEG_MARKER_SOI */
          continue;
        length=(unsigned short) (((unsigned int) (buffer[i] << 8) |
          (unsigned int) buffer[i+1]) & 0xffff);
        if (i+(size_t) length >= BUFFER_SIZE)
          break;
        if (buffer[i-1] == 238) /* JPEG_MARKER_APP0+14 */
          {
            if (length != 14)
              break;
            /* 0 == CMYK, 1 == YCbCr, 2 = YCCK */
            if (buffer[i+13] == 2)
              method=ReadYCCKMethod;
            break;
          }
        i+=(size_t) length;
      }
    }
  (void) SeekBlob(image,position,SEEK_SET);
  return(method);
}


bool hda_codec_xfer(HDACodecDevice *dev, uint32_t stnr, bool output,
                    uint8_t *buf, uint32_t len)
{
    HDACodecBus *bus = HDA_BUS(dev->qdev.parent_bus);
    return bus->xfer(dev, stnr, output, buf, len);
}


void hda_codec_response(HDACodecDevice *dev, bool solicited, uint32_t response)
{
    HDACodecBus *bus = HDA_BUS(dev->qdev.parent_bus);
    bus->response(dev, solicited, response);
}


static uint32_t *intel_hda_reg_addr(IntelHDAState *d, const IntelHDAReg *reg)
{
    uint8_t *addr = (void*)d;

    addr += reg->offset;
    return (uint32_t*)addr;


static int intel_hda_post_load(void *opaque, int version)
{
    IntelHDAState* d = opaque;
    int i;

    dprint(d, 1, "%s\n", __func__);
    for (i = 0; i < ARRAY_SIZE(d->st); i++) {
        if (d->st[i].ctl & 0x02) {
            intel_hda_parse_bdl(d, &d->st[i]);
        }
    }
    intel_hda_update_irq(d);
    return 0;


static void hda_codec_device_class_init(ObjectClass *klass, void *data)
{
    DeviceClass *k = DEVICE_CLASS(klass);
    k->realize = hda_codec_dev_realize;
    k->unrealize = hda_codec_dev_unrealize;
    set_bit(DEVICE_CATEGORY_SOUND, k->categories);
    k->bus_type = TYPE_HDA_BUS;
    device_class_set_props(k, hda_props);


static void ucma_close_id(struct work_struct *work)
{
	struct ucma_context *ctx =  container_of(work, struct ucma_context, close_work);

	/* once all inflight tasks are finished, we close all underlying
	 * resources. The context is still alive till its explicit destryoing
	 * by its creator.
	 */
	ucma_put_ctx(ctx);
	wait_for_completion(&ctx->comp);
	/* No new events will be generated after destroying the id. */
	rdma_destroy_id(ctx->cm_id);

	/*
	 * At this point ctx->ref is zero so the only place the ctx can be is in
	 * a uevent or in __destroy_id(). Since the former doesn't touch
	 * ctx->cm_id and the latter sync cancels this, there is no races with
	 * this store.
	 */
	ctx->cm_id = NULL;
}


static struct ucma_context *ucma_get_ctx(struct ucma_file *file, int id)
{
	struct ucma_context *ctx;

	xa_lock(&ctx_table);
	ctx = _ucma_find_context(id, file);
	if (!IS_ERR(ctx))
		if (!refcount_inc_not_zero(&ctx->ref))
			ctx = ERR_PTR(-ENXIO);
	xa_unlock(&ctx_table);
	return ctx;
}


static int ucma_event_handler(struct rdma_cm_id *cm_id,
			      struct rdma_cm_event *event)
{
	struct ucma_event *uevent;
	struct ucma_context *ctx = cm_id->context;

	if (event->event == RDMA_CM_EVENT_CONNECT_REQUEST)
		return ucma_connect_event_handler(cm_id, event);

	/*
	 * We ignore events for new connections until userspace has set their
	 * context.  This can only happen if an error occurs on a new connection
	 * before the user accepts it.  This is okay, since the accept will just
	 * fail later. However, we do need to release the underlying HW
	 * resources in case of a device removal event.
	 */
	if (ctx->uid) {
		uevent = ucma_create_uevent(ctx, event);
		if (!uevent)
			return 0;

		mutex_lock(&ctx->file->mut);
		list_add_tail(&uevent->list, &ctx->file->event_list);
		mutex_unlock(&ctx->file->mut);
		wake_up_interruptible(&ctx->file->poll_wait);
	}

	if (event->event == RDMA_CM_EVENT_DEVICE_REMOVAL && !ctx->destroying)
		queue_work(system_unbound_wq, &ctx->close_work);
	return 0;
}


static void ucma_copy_ib_route(struct rdma_ucm_query_route_resp *resp,
			       struct rdma_route *route)
{
	struct rdma_dev_addr *dev_addr;

	resp->num_paths = route->num_paths;
	switch (route->num_paths) {
	case 0:
		dev_addr = &route->addr.dev_addr;
		rdma_addr_get_dgid(dev_addr,
				   (union ib_gid *) &resp->ib_route[0].dgid);
		rdma_addr_get_sgid(dev_addr,
				   (union ib_gid *) &resp->ib_route[0].sgid);
		resp->ib_route[0].pkey = cpu_to_be16(ib_addr_get_pkey(dev_addr));
		break;
	case 2:
		ib_copy_path_rec_to_user(&resp->ib_route[1],
					 &route->path_rec[1]);
		fallthrough;
	case 1:
		ib_copy_path_rec_to_user(&resp->ib_route[0],
					 &route->path_rec[0]);
		break;
	default:
		break;
	}
}


static void ucma_copy_conn_param(struct rdma_cm_id *id,
				 struct rdma_conn_param *dst,
				 struct rdma_ucm_conn_param *src)
{
	dst->private_data = src->private_data;
	dst->private_data_len = src->private_data_len;
	dst->responder_resources =src->responder_resources;
	dst->initiator_depth = src->initiator_depth;
	dst->flow_control = src->flow_control;
	dst->retry_count = src->retry_count;
	dst->rnr_retry_count = src->rnr_retry_count;
	dst->srq = src->srq;
	dst->qp_num = src->qp_num & 0xFFFFFF;
	dst->qkey = (id->route.addr.src_addr.ss_family == AF_IB) ? src->qkey : 0;
}


static int ucma_get_global_nl_info(struct ib_client_nl_info *res)
{
	res->abi = RDMA_USER_CM_ABI_VERSION;
	res->cdev = ucma_misc.this_device;
	return 0;
}


static void __exit ucma_cleanup(void)
{
	ib_unregister_client(&rdma_cma_client);
	unregister_net_sysctl_table(ucma_ctl_table_hdr);
	device_remove_file(ucma_misc.this_device, &dev_attr_abi_version);
	misc_deregister(&ucma_misc);
}


static ssize_t ucma_destroy_id(struct ucma_file *file, const char __user *inbuf,
			       int in_len, int out_len)
{
	struct rdma_ucm_destroy_id cmd;
	struct rdma_ucm_destroy_id_resp resp;
	struct ucma_context *ctx;
	int ret = 0;

	if (out_len < sizeof(resp))
		return -ENOSPC;

	if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
		return -EFAULT;

	xa_lock(&ctx_table);
	ctx = _ucma_find_context(cmd.id, file);
	if (!IS_ERR(ctx))
		__xa_erase(&ctx_table, ctx->id);
	xa_unlock(&ctx_table);

	if (IS_ERR(ctx))
		return PTR_ERR(ctx);

	resp.events_reported = __destroy_id(ctx);
	if (copy_to_user(u64_to_user_ptr(cmd.response),
			 &resp, sizeof(resp)))
		ret = -EFAULT;

	return ret;
}


static ssize_t ucma_connect(struct ucma_file *file, const char __user *inbuf,
			    int in_len, int out_len)
{
	struct rdma_conn_param conn_param;
	struct rdma_ucm_ece ece = {};
	struct rdma_ucm_connect cmd;
	struct ucma_context *ctx;
	size_t in_size;
	int ret;

	if (in_len < offsetofend(typeof(cmd), reserved))
		return -EINVAL;
	in_size = min_t(size_t, in_len, sizeof(cmd));
	if (copy_from_user(&cmd, inbuf, in_size))
		return -EFAULT;

	if (!cmd.conn_param.valid)
		return -EINVAL;

	ctx = ucma_get_ctx_dev(file, cmd.id);
	if (IS_ERR(ctx))
		return PTR_ERR(ctx);

	ucma_copy_conn_param(ctx->cm_id, &conn_param, &cmd.conn_param);
	if (offsetofend(typeof(cmd), ece) <= in_size) {
		ece.vendor_id = cmd.ece.vendor_id;
		ece.attr_mod = cmd.ece.attr_mod;
	}

	mutex_lock(&ctx->mutex);
	ret = rdma_connect_ece(ctx->cm_id, &conn_param, &ece);
	mutex_unlock(&ctx->mutex);
	ucma_put_ctx(ctx);
	return ret;
}


stonith_types(void)
{
	int i, j, cur=0, rl_size, sub_pl = 0;
	static char **	rl = NULL;
	char **		new_list, **sub_list = NULL;

	if (!init_pluginsys()) {
		return NULL;
	}

	new_list = PILListPlugins(StonithPIsys, STONITH_TYPE_S, NULL);
	if (new_list == NULL) {
		return NULL;
	}
	for (i=0; new_list[i]; ++i)
		; /* count */
	rl_size = i+1;

	rl = (char**)MALLOC(rl_size * sizeof(char *));
	if (rl == NULL) {
		LOG(PIL_CRIT, "Out of memory");
		goto types_exit;
	}

	for (i=0; new_list[i]; ++i) {
		/* look for 'external' and 'rhcs' plugins */
		if (strcmp(new_list[i], EXTPINAME_S) == 0) {
			sub_list = get_plugin_list(EXTPINAME_S);
			sub_pl = 1;
		} else if (strcmp(new_list[i], RHCSPINAME_S) == 0) {
			sub_list = get_plugin_list(RHCSPINAME_S);
			sub_pl = 1;
		}
		if (sub_pl) {
			if (sub_list) {
				for (j=0; sub_list[j]; ++j)
					; /* count */
				rl_size += j;
				rl = (char**)REALLOC(rl, rl_size*sizeof(char *));
				for (j=0; sub_list[j]; ++j) {
					rl[cur++] = sub_list[j];
				}
				FREE(sub_list);
				sub_list = NULL;
			}
			sub_pl = 0;
		} else {
			rl[cur] = STRDUP(new_list[i]);
			if (rl[cur] == NULL) {
				LOG(PIL_CRIT, "Out of memory");
				goto types_exit_mem;
			}
			cur++;
		}
	}

	rl[cur] = NULL;
	goto types_exit;

types_exit_mem:
	stonith_free_hostlist(rl);
	rl = NULL;
types_exit:
	PILFreePluginList(new_list);
	return rl;
}


Mat_VarReadInfo( mat_t *mat, const char *name )
{
    matvar_t *matvar = NULL;

    if ( (mat == NULL) || (name == NULL) )
        return NULL;

    if ( mat->version == MAT_FT_MAT73 ) {
        size_t fpos = mat->next_index;
        mat->next_index = 0;
        while ( NULL == matvar && mat->next_index < mat->num_datasets ) {
            matvar = Mat_VarReadNextInfo(mat);
            if ( matvar != NULL ) {
                if ( matvar->name == NULL || 0 != strcmp(matvar->name,name) ) {
                    Mat_VarFree(matvar);
                    matvar = NULL;
                }
            } else {
                Mat_Critical("An error occurred in reading the MAT file");
                break;
            }
        }
        mat->next_index = fpos;
    } else {
        long fpos = ftell((FILE*)mat->fp);
        if ( fpos != -1L ) {
            (void)fseek((FILE*)mat->fp,mat->bof,SEEK_SET);
            do {
                matvar = Mat_VarReadNextInfo(mat);
                if ( matvar != NULL ) {
                    if ( matvar->name == NULL || 0 != strcmp(matvar->name,name) ) {
                        Mat_VarFree(matvar);
                        matvar = NULL;
                    }
                } else if ( !feof((FILE *)mat->fp) ) {
                    Mat_Critical("An error occurred in reading the MAT file");
                    break;
                }
            } while ( NULL == matvar && !feof((FILE *)mat->fp) );
            (void)fseek((FILE*)mat->fp,fpos,SEEK_SET);
        } else {
            Mat_Critical("Couldn't determine file position");
        }
    }

    return matvar;
}


Mat_VarWriteInfo(mat_t *mat, matvar_t *matvar )
{
    Mat_Critical("Mat_VarWriteInfo/Mat_VarWriteData is not supported. "
        "Use %s instead!", mat->version == MAT_FT_MAT73 ?
        "Mat_VarWrite/Mat_VarWriteAppend" : "Mat_VarWrite");
    return 1;
}


ComplexFree(mat_complex_split_t* complex_data)
{
    free(complex_data->Re);
    free(complex_data->Im);
    free(complex_data);
}


Mat_CalcSubscripts(int rank,int *dims,int index)
{
    int i, j, *subs;
    double l;

    subs = (int*)malloc(rank*sizeof(int));
    l = index;
    for ( i = rank; i--; ) {
        int k = 1;
        for ( j = i; j--; )
            k *= dims[j];
        subs[i] = (int)floor(l / (double)k);
        l -= subs[i]*k;
        subs[i]++;
    }

    return subs;
}


Mat_VarDuplicate(const matvar_t *in, int opt)
{
    matvar_t *out;
    size_t i;

    out = Mat_VarCalloc();
    if ( out == NULL )
        return NULL;

    out->nbytes       = in->nbytes;
    out->rank         = in->rank;
    out->data_type    = in->data_type;
    out->data_size    = in->data_size;
    out->class_type   = in->class_type;
    out->isComplex    = in->isComplex;
    out->isGlobal     = in->isGlobal;
    out->isLogical    = in->isLogical;
    out->mem_conserve = in->mem_conserve;
    out->compression  = in->compression;

    if ( NULL != in->name ) {
        size_t len = strlen(in->name) + 1;
        out->name = (char*)malloc(len);
        if ( NULL != out->name )
            memcpy(out->name,in->name,len);
    }

    out->dims = (size_t*)malloc(in->rank*sizeof(*out->dims));
    if ( out->dims != NULL )
        memcpy(out->dims,in->dims,in->rank*sizeof(*out->dims));

    if ( NULL != in->internal ) {
#if defined(MAT73) && MAT73
        if ( NULL != in->internal->hdf5_name )
            out->internal->hdf5_name = strdup(in->internal->hdf5_name);

        out->internal->hdf5_ref = in->internal->hdf5_ref;
        out->internal->id       = in->internal->id;
#endif
        out->internal->datapos  = in->internal->datapos;
#if HAVE_ZLIB
        out->internal->z        = NULL;
        out->internal->data     = NULL;
#endif
        out->internal->num_fields = in->internal->num_fields;
        if ( NULL != in->internal->fieldnames && in->internal->num_fields > 0 ) {
            out->internal->fieldnames = (char**)calloc(in->internal->num_fields,
                                               sizeof(*in->internal->fieldnames));
            for ( i = 0; i < in->internal->num_fields; i++ ) {
                if ( NULL != in->internal->fieldnames[i] )
                    out->internal->fieldnames[i] =
                        strdup(in->internal->fieldnames[i]);
            }
        }

#if HAVE_ZLIB
        if ( (in->internal->z != NULL) && (NULL != (out->internal->z = (z_streamp)malloc(sizeof(z_stream)))) )
            inflateCopy(out->internal->z,in->internal->z);
        if ( in->internal->data != NULL ) {
            if ( in->class_type == MAT_C_SPARSE ) {
                out->internal->data = malloc(sizeof(mat_sparse_t));
                if ( out->internal->data != NULL ) {
                    mat_sparse_t *out_sparse = (mat_sparse_t*)out->internal->data;
                    mat_sparse_t *in_sparse  = (mat_sparse_t*)in->internal->data;
                    out_sparse->nzmax = in_sparse->nzmax;
                    out_sparse->nir = in_sparse->nir;
                    out_sparse->ir = (mat_uint32_t*)malloc(in_sparse->nir*sizeof(*out_sparse->ir));
                    if ( out_sparse->ir != NULL )
                        memcpy(out_sparse->ir, in_sparse->ir, in_sparse->nir*sizeof(*out_sparse->ir));
                    out_sparse->njc = in_sparse->njc;
                    out_sparse->jc = (mat_uint32_t*)malloc(in_sparse->njc*sizeof(*out_sparse->jc));
                    if ( out_sparse->jc != NULL )
                        memcpy(out_sparse->jc, in_sparse->jc, in_sparse->njc*sizeof(*out_sparse->jc));
                    out_sparse->ndata = in_sparse->ndata;
                    if ( out->isComplex && NULL != in_sparse->data ) {
                        out_sparse->data = malloc(sizeof(mat_complex_split_t));
                        if ( out_sparse->data != NULL ) {
                            mat_complex_split_t *out_data = (mat_complex_split_t*)out_sparse->data;
                            mat_complex_split_t *in_data  = (mat_complex_split_t*)in_sparse->data;
                            out_data->Re = malloc(
                                in_sparse->ndata*Mat_SizeOf(in->data_type));
                            if ( NULL != out_data->Re )
                                memcpy(out_data->Re,in_data->Re,
                                    in_sparse->ndata*Mat_SizeOf(in->data_type));
                            out_data->Im = malloc(
                                in_sparse->ndata*Mat_SizeOf(in->data_type));
                            if ( NULL != out_data->Im )
                                memcpy(out_data->Im,in_data->Im,
                                    in_sparse->ndata*Mat_SizeOf(in->data_type));
                        }
                    } else if ( in_sparse->data != NULL ) {
                        out_sparse->data = malloc(in_sparse->ndata*Mat_SizeOf(in->data_type));
                        if ( NULL != out_sparse->data )
                            memcpy(out_sparse->data, in_sparse->data,
                                in_sparse->ndata*Mat_SizeOf(in->data_type));
                    }
                }
            } else if ( out->isComplex ) {
                out->internal->data = malloc(sizeof(mat_complex_split_t));
                if ( out->internal->data != NULL ) {
                    mat_complex_split_t *out_data = (mat_complex_split_t*)out->internal->data;
                    mat_complex_split_t *in_data  = (mat_complex_split_t*)in->internal->data;
                    out_data->Re = malloc(out->nbytes);
                    if ( NULL != out_data->Re )
                        memcpy(out_data->Re,in_data->Re,out->nbytes);
                    out_data->Im = malloc(out->nbytes);
                    if ( NULL != out_data->Im )
                        memcpy(out_data->Im,in_data->Im,out->nbytes);
                }
            } else if ( NULL != (out->internal->data = malloc(in->nbytes)) ) {
                memcpy(out->internal->data, in->internal->data, in->nbytes);
            }
        }
#endif
    } else {
        free(out->internal);
        out->internal = NULL;
    }

    if ( !opt ) {
        out->data = in->data;
    } else if ( (in->data != NULL) && (in->class_type == MAT_C_STRUCT) ) {
        out->data = malloc(in->nbytes);
        if ( out->data != NULL && in->data_size > 0 ) {
            size_t nfields = in->nbytes / in->data_size;
            matvar_t **infields  = (matvar_t **)in->data;
            matvar_t **outfields = (matvar_t **)out->data;
            for ( i = 0; i < nfields; i++ ) {
                outfields[i] = Mat_VarDuplicate(infields[i],opt);
            }
        }
    } else if ( (in->data != NULL) && (in->class_type == MAT_C_CELL) ) {
        out->data = malloc(in->nbytes);
        if ( out->data != NULL && in->data_size > 0 ) {
            size_t nelems = in->nbytes / in->data_size;
            matvar_t **incells  = (matvar_t **)in->data;
            matvar_t **outcells = (matvar_t **)out->data;
            for ( i = 0; i < nelems; i++ ) {
                outcells[i] = Mat_VarDuplicate(incells[i],opt);
            }
        }
    } else if ( (in->data != NULL) && (in->class_type == MAT_C_SPARSE) ) {
        out->data = malloc(sizeof(mat_sparse_t));
        if ( out->data != NULL ) {
            mat_sparse_t *out_sparse = (mat_sparse_t*)out->data;
            mat_sparse_t *in_sparse  = (mat_sparse_t*)in->data;
            out_sparse->nzmax = in_sparse->nzmax;
            out_sparse->nir = in_sparse->nir;
            out_sparse->ir = (mat_uint32_t*)malloc(in_sparse->nir*sizeof(*out_sparse->ir));
            if ( out_sparse->ir != NULL )
                memcpy(out_sparse->ir, in_sparse->ir, in_sparse->nir*sizeof(*out_sparse->ir));
            out_sparse->njc = in_sparse->njc;
            out_sparse->jc = (mat_uint32_t*)malloc(in_sparse->njc*sizeof(*out_sparse->jc));
            if ( out_sparse->jc != NULL )
                memcpy(out_sparse->jc, in_sparse->jc, in_sparse->njc*sizeof(*out_sparse->jc));
            out_sparse->ndata = in_sparse->ndata;
            if ( out->isComplex && NULL != in_sparse->data ) {
                out_sparse->data = malloc(sizeof(mat_complex_split_t));
                if ( out_sparse->data != NULL ) {
                    mat_complex_split_t *out_data = (mat_complex_split_t*)out_sparse->data;
                    mat_complex_split_t *in_data  = (mat_complex_split_t*)in_sparse->data;
                    out_data->Re = malloc(in_sparse->ndata*Mat_SizeOf(in->data_type));
                    if ( NULL != out_data->Re )
                        memcpy(out_data->Re,in_data->Re,in_sparse->ndata*Mat_SizeOf(in->data_type));
                    out_data->Im = malloc(in_sparse->ndata*Mat_SizeOf(in->data_type));
                    if ( NULL != out_data->Im )
                        memcpy(out_data->Im,in_data->Im,in_sparse->ndata*Mat_SizeOf(in->data_type));
                }
            } else if ( in_sparse->data != NULL ) {
                out_sparse->data = malloc(in_sparse->ndata*Mat_SizeOf(in->data_type));
                if ( NULL != out_sparse->data )
                    memcpy(out_sparse->data, in_sparse->data, in_sparse->ndata*Mat_SizeOf(in->data_type));
            } else {
                out_sparse->data = NULL;
            }
        }
    } else if ( in->data != NULL ) {
        if ( out->isComplex ) {
            out->data = malloc(sizeof(mat_complex_split_t));
            if ( out->data != NULL ) {
                mat_complex_split_t *out_data = (mat_complex_split_t*)out->data;
                mat_complex_split_t *in_data  = (mat_complex_split_t*)in->data;
                out_data->Re = malloc(out->nbytes);
                if ( NULL != out_data->Re )
                    memcpy(out_data->Re,in_data->Re,out->nbytes);
                out_data->Im = malloc(out->nbytes);
                if ( NULL != out_data->Im )
                    memcpy(out_data->Im,in_data->Im,out->nbytes);
            }
        } else {
            out->data = malloc(in->nbytes);
            if ( out->data != NULL )
                memcpy(out->data,in->data,in->nbytes);
        }
    }

    return out;
}


errno_t sssctl_client_data_restore(struct sss_cmdline *cmdline,
                                   struct sss_tool_ctx *tool_ctx,
                                   void *pvt)
{
    struct sssctl_data_opts opts = {0};
    errno_t ret;

    /* Parse command line. */
    struct poptOption options[] = {
        {"start", 's', POPT_ARG_NONE, &opts.start, 0, _("Start SSSD if it is not running"), NULL },
        {"restart", 'r', POPT_ARG_NONE, &opts.restart, 0, _("Restart SSSD after data import"), NULL },
        POPT_TABLEEND
    };

    ret = sss_tool_popt(cmdline, options, SSS_TOOL_OPT_OPTIONAL, NULL, NULL);
    if (ret != EOK) {
        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse command arguments\n");
        return ret;
    }

    return sssctl_restore(opts.start, opts.restart);
}


static errno_t sssctl_restore(bool force_start, bool force_restart)
{
    errno_t ret;

    if (!sssctl_start_sssd(force_start)) {
        return ERR_SSSD_NOT_RUNNING;
    }

    if (sssctl_backup_file_exists(SSS_BACKUP_USER_OVERRIDES)) {
        ret = sssctl_run_command((const char *[]){"sss_override", "user-import",
                                                  SSS_BACKUP_USER_OVERRIDES, NULL});
        if (ret != EOK) {
            ERROR("Unable to import user overrides\n");
            return ret;
        }
    }

    if (sssctl_backup_file_exists(SSS_BACKUP_USER_OVERRIDES)) {
        ret = sssctl_run_command((const char *[]){"sss_override", "group-import",
                                                  SSS_BACKUP_GROUP_OVERRIDES, NULL});
        if (ret != EOK) {
            ERROR("Unable to import group overrides\n");
            return ret;
        }
    }

    sssctl_restart_sssd(force_restart);

    ret = EOK;

    return ret;
}


static bool sssctl_backup_exist(const char **files)
{
    int i;

    for (i = 0; files[i] != NULL; i++) {
        if (sssctl_backup_file_exists(files[i])) {
            return true;
        }
    }

    return false;
}


static char hex2num(char c)
{
    if (c >= '0' && c <= '9')
        return c - '0';
    if (c >= 'a' && c <= 'f')
        return c - 'a' + 10;
    if (c >= 'A' && c <= 'F')
        return c - 'A' + 10;
    return 0;
}


static void handle_reverse(srs_t *srs, FILE *fp, const char *address,
                           const char *domain __attribute__((unused)),
                           const char **excludes __attribute__((unused)))
{
    int result;
    char value[1024];
    char outputbuf[1024], *output;
    result = srs_reverse(srs, value, sizeof(value), address);
    if (result == SRS_SUCCESS)
    {
        output = url_encode(outputbuf, sizeof(outputbuf), value);
        fprintf(fp, "200 %s\n", output);
        syslog(LOG_MAIL | LOG_INFO, "srs_reverse: <%s> rewritten as <%s>",
               address, value);
    }
    else
    {
        fprintf(fp, "500 %s\n", srs_strerror(result));
        if (result != SRS_ENOTREWRITTEN && result != SRS_ENOTSRSADDRESS)
            syslog(LOG_MAIL | LOG_INFO, "srs_reverse: <%s> not rewritten: %s",
                   address, srs_strerror(result));
    }
    fflush(fp);
}


static char num2hex(char c)
{
    if (c < 10)
        return '0' + c;
    return 'a' + c - 10;
}


virSecuritySELinuxRestoreHostdevSubsysLabel(virSecurityManager *mgr,
                                            virDomainHostdevDef *dev,
                                            const char *vroot)

{
    virDomainHostdevSubsysUSB *usbsrc = &dev->source.subsys.u.usb;
    virDomainHostdevSubsysPCI *pcisrc = &dev->source.subsys.u.pci;
    virDomainHostdevSubsysSCSI *scsisrc = &dev->source.subsys.u.scsi;
    virDomainHostdevSubsysSCSIVHost *hostsrc = &dev->source.subsys.u.scsi_host;
    virDomainHostdevSubsysMediatedDev *mdevsrc = &dev->source.subsys.u.mdev;
    int ret = -1;

    /* Like virSecuritySELinuxRestoreImageLabelInt() for a networked
     * disk, do nothing for an iSCSI hostdev
     */
    if (dev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI &&
        scsisrc->protocol == VIR_DOMAIN_HOSTDEV_SCSI_PROTOCOL_TYPE_ISCSI)
        return 0;

    switch ((virDomainHostdevSubsysType)dev->source.subsys.type) {
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: {
        g_autoptr(virUSBDevice) usb = NULL;

        if (dev->missing)
            return 0;

        usb = virUSBDeviceNew(usbsrc->bus,
                              usbsrc->device,
                              vroot);
        if (!usb)
            return -1;

        ret = virUSBDeviceFileIterate(usb, virSecuritySELinuxRestoreUSBLabel, mgr);
        break;
    }

    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI: {
        g_autoptr(virPCIDevice) pci = NULL;

        if (!virPCIDeviceExists(&pcisrc->addr))
            break;

        pci = virPCIDeviceNew(&pcisrc->addr);

        if (!pci)
            return -1;

        if (pcisrc->backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO) {
            g_autofree char *vfioGroupDev = virPCIDeviceGetIOMMUGroupDev(pci);

            if (!vfioGroupDev)
                return -1;

            ret = virSecuritySELinuxRestoreFileLabel(mgr, vfioGroupDev, false);
        } else {
            ret = virPCIDeviceFileIterate(pci, virSecuritySELinuxRestorePCILabel, mgr);
        }
        break;
    }

    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI: {
        virDomainHostdevSubsysSCSIHost *scsihostsrc = &scsisrc->u.host;
        g_autoptr(virSCSIDevice) scsi =
            virSCSIDeviceNew(NULL,
                             scsihostsrc->adapter, scsihostsrc->bus,
                             scsihostsrc->target, scsihostsrc->unit,
                             dev->readonly, dev->shareable);

        if (!scsi)
            return -1;

        ret = virSCSIDeviceFileIterate(scsi, virSecuritySELinuxRestoreSCSILabel, mgr);
        break;
    }

    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI_HOST: {
        g_autoptr(virSCSIVHostDevice) host = virSCSIVHostDeviceNew(hostsrc->wwpn);

        if (!host)
            return -1;

        ret = virSCSIVHostDeviceFileIterate(host,
                                            virSecuritySELinuxRestoreHostLabel,
                                            mgr);
        break;
    }

    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_MDEV: {
        g_autofree char *vfiodev = NULL;

        if (!(vfiodev = virMediatedDeviceGetIOMMUGroupDev(mdevsrc->uuidstr)))
            return -1;

        ret = virSecuritySELinuxRestoreFileLabel(mgr, vfiodev, true);
        break;
    }

    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST:
        ret = 0;
        break;
    }

    return ret;
}


virSecuritySELinuxGetModel(virSecurityManager *mgr G_GNUC_UNUSED)
{
    return SECURITY_SELINUX_NAME;
}


virSecuritySELinuxSetImageLabel(virSecurityManager *mgr,
                                virDomainDef *def,
                                virStorageSource *src,
                                virSecurityDomainImageLabelFlags flags)
{
    return virSecuritySELinuxSetImageLabelRelative(mgr, def, src, src, flags);
}


virSecuritySELinuxGetBaseLabel(virSecurityManager *mgr, int virtType)
{
    virSecuritySELinuxData *priv = virSecurityManagerGetPrivateData(mgr);
    if (virtType == VIR_DOMAIN_VIRT_QEMU && priv->alt_domain_context)
        return priv->alt_domain_context;
    else
        return priv->domain_context;
}


virSecuritySELinuxMCSRemove(virSecurityManager *mgr,
                            const char *mcs)
{
    virSecuritySELinuxData *data = virSecurityManagerGetPrivateData(mgr);

    virHashRemoveEntry(data->mcs, mcs);
}


virSecuritySELinuxSetSecuritySmartcardCallback(virDomainDef *def,
                                               virDomainSmartcardDef *dev,
                                               void *opaque)
{
    const char *database;
    virSecurityManager *mgr = opaque;
    virSecuritySELinuxData *data = virSecurityManagerGetPrivateData(mgr);

    switch (dev->type) {
    case VIR_DOMAIN_SMARTCARD_TYPE_HOST:
        break;

    case VIR_DOMAIN_SMARTCARD_TYPE_HOST_CERTIFICATES:
        database = dev->data.cert.database;
        if (!database)
            database = VIR_DOMAIN_SMARTCARD_DEFAULT_DATABASE;
        return virSecuritySELinuxSetFilecon(mgr, database, data->content_context, true);

    case VIR_DOMAIN_SMARTCARD_TYPE_PASSTHROUGH:
        return virSecuritySELinuxSetChardevLabel(mgr, def,
                                                 dev->data.passthru, false);

    default:
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unknown smartcard type %d"),
                       dev->type);
        return -1;
    }

    return 0;
}


    long WebPImage::getHeaderOffset(byte* data, long data_size, byte* header, long header_size)
    {
        if (data_size < header_size) { return -1; }
        long pos = -1;
        for (long i=0; i < data_size - header_size; i++) {
            if (memcmp(header, &data[i], header_size) == 0) {
                pos = i;
                break;
            }
        }
        return pos;
    }


    void Jp2Image::encodeJp2Header(const DataBuf& boxBuf,DataBuf& outBuf)
    {
        DataBuf output(boxBuf.size_ + iccProfile_.size_ + 100); // allocate sufficient space
        long    outlen = sizeof(Jp2BoxHeader) ; // now many bytes have we written to output?
        long    inlen = sizeof(Jp2BoxHeader) ; // how many bytes have we read from boxBuf?
        Jp2BoxHeader* pBox   = (Jp2BoxHeader*) boxBuf.pData_;
        uint32_t      length = getLong((byte*)&pBox->length, bigEndian);
        uint32_t      count  = sizeof (Jp2BoxHeader);
        char*         p      = (char*) boxBuf.pData_;
        bool          bWroteColor = false ;

        while ( count < length || !bWroteColor ) {
            Jp2BoxHeader* pSubBox = (Jp2BoxHeader*) (p+count) ;

            // copy data.  pointer could be into a memory mapped file which we will decode!
            Jp2BoxHeader   subBox ; memcpy(&subBox,pSubBox,sizeof(subBox));
            Jp2BoxHeader   newBox =  subBox;

            if ( count < length ) {
                subBox.length = getLong((byte*)&subBox.length, bigEndian);
                subBox.type   = getLong((byte*)&subBox.type  , bigEndian);
#ifdef EXIV2_DEBUG_MESSAGES
                std::cout << "Jp2Image::encodeJp2Header subbox: "<< toAscii(subBox.type) << " length = " << subBox.length << std::endl;
#endif
                enforce(subBox.length <= length - count, Exiv2::kerCorruptedMetadata);
                count        += subBox.length;
                newBox.type   = subBox.type;
            } else {
                subBox.length=0;
                newBox.type = kJp2BoxTypeColorHeader;
                count = length;
            }

            uint32_t newlen = subBox.length;
            if ( newBox.type == kJp2BoxTypeColorHeader ) {
                bWroteColor = true ;
                if ( ! iccProfileDefined() ) {
                    const char* pad   = "\x01\x00\x00\x00\x00\x00\x10\x00\x00\x05\x1cuuid";
                    uint32_t    psize = 15;
                    newlen            = sizeof(newBox) + psize ;
                    enforce(newlen <= output.size_ - outlen, Exiv2::kerCorruptedMetadata);
                    ul2Data((byte*)&newBox.length,psize      ,bigEndian);
                    ul2Data((byte*)&newBox.type  ,newBox.type,bigEndian);
                    ::memcpy(output.pData_+outlen                     ,&newBox            ,sizeof(newBox));
                    ::memcpy(output.pData_+outlen+sizeof(newBox)      ,pad                ,psize         );
                } else {
                    const char* pad   = "\x02\x00\x00";
                    uint32_t    psize = 3;
                    newlen            = sizeof(newBox) + psize + iccProfile_.size_;
                    enforce(newlen <= output.size_ - outlen, Exiv2::kerCorruptedMetadata);
                    ul2Data((byte*)&newBox.length,newlen,bigEndian);
                    ul2Data((byte*)&newBox.type,newBox.type,bigEndian);
                    ::memcpy(output.pData_+outlen                     ,&newBox            ,sizeof(newBox)  );
                    ::memcpy(output.pData_+outlen+sizeof(newBox)      , pad               ,psize           );
                    ::memcpy(output.pData_+outlen+sizeof(newBox)+psize,iccProfile_.pData_,iccProfile_.size_);
                }
            } else {
                enforce(newlen <= output.size_ - outlen, Exiv2::kerCorruptedMetadata);
                ::memcpy(output.pData_+outlen,boxBuf.pData_+inlen,subBox.length);
            }

            outlen += newlen;
            inlen  += subBox.length;
        }

        // allocate the correct number of bytes, copy the data and update the box header
        outBuf.alloc(outlen);
        ::memcpy(outBuf.pData_,output.pData_,outlen);
        pBox   = (Jp2BoxHeader*) outBuf.pData_;
        ul2Data((byte*)&pBox->type,kJp2BoxTypeJp2Header,bigEndian);
        ul2Data((byte*)&pBox->length,outlen,bigEndian);
    } // Jp2Image::encodeJp2Header


size_t olm_pk_ciphertext_length(
    OlmPkEncryption *encryption,
    size_t plaintext_length
) {
    return olm::encode_base64_length(
        _olm_cipher_aes_sha_256_ops.encrypt_ciphertext_length(olm_pk_cipher, plaintext_length)
    );
}


size_t olm_pk_decryption_size(void) {
    return sizeof(OlmPkDecryption);
}


size_t olm_pk_encrypt(
    OlmPkEncryption *encryption,
    void const * plaintext, size_t plaintext_length,
    void * ciphertext, size_t ciphertext_length,
    void * mac, size_t mac_length,
    void * ephemeral_key, size_t ephemeral_key_size,
    const void * random, size_t random_length
) {
    if (ciphertext_length
            < olm_pk_ciphertext_length(encryption, plaintext_length)
        || mac_length
            < _olm_cipher_aes_sha_256_ops.mac_length(olm_pk_cipher)
        || ephemeral_key_size
            < olm_pk_key_length()) {
        encryption->last_error =
            OlmErrorCode::OLM_OUTPUT_BUFFER_TOO_SMALL;
        return std::size_t(-1);
    }
    if (random_length < olm_pk_encrypt_random_length(encryption)) {
        encryption->last_error =
            OlmErrorCode::OLM_NOT_ENOUGH_RANDOM;
        return std::size_t(-1);
    }

    _olm_curve25519_key_pair ephemeral_keypair;
    _olm_crypto_curve25519_generate_key((const uint8_t *) random, &ephemeral_keypair);
    olm::encode_base64(
        (const uint8_t *)ephemeral_keypair.public_key.public_key,
        CURVE25519_KEY_LENGTH,
        (uint8_t *)ephemeral_key
    );

    olm::SharedKey secret;
    _olm_crypto_curve25519_shared_secret(&ephemeral_keypair, &encryption->recipient_key, secret);
    size_t raw_ciphertext_length =
        _olm_cipher_aes_sha_256_ops.encrypt_ciphertext_length(olm_pk_cipher, plaintext_length);
    uint8_t *ciphertext_pos = (uint8_t *) ciphertext + ciphertext_length - raw_ciphertext_length;
    uint8_t raw_mac[MAC_LENGTH];
    size_t result = _olm_cipher_aes_sha_256_ops.encrypt(
        olm_pk_cipher,
        secret, sizeof(secret),
        (const uint8_t *) plaintext, plaintext_length,
        (uint8_t *) ciphertext_pos, raw_ciphertext_length,
        (uint8_t *) raw_mac, MAC_LENGTH
    );
    if (result != std::size_t(-1)) {
        olm::encode_base64(raw_mac, MAC_LENGTH, (uint8_t *)mac);
        olm::encode_base64(ciphertext_pos, raw_ciphertext_length, (uint8_t *)ciphertext);
    }
    return result;
}


size_t olm_clear_pk_encryption(
    OlmPkEncryption *encryption
) {
    /* Clear the memory backing the encryption */
    olm::unset(encryption, sizeof(OlmPkEncryption));
    /* Initialise a fresh encryption object in case someone tries to use it */
    new(encryption) OlmPkEncryption();
    return sizeof(OlmPkEncryption);
}


static int firebird_handle_closer(pdo_dbh_t *dbh) /* {{{ */
{
	pdo_firebird_db_handle *H = (pdo_firebird_db_handle *)dbh->driver_data;

	if (dbh->in_txn) {
		if (dbh->auto_commit) {
			if (isc_commit_transaction(H->isc_status, &H->tr)) {
				RECORD_ERROR(dbh);
			}
		} else {
			if (isc_rollback_transaction(H->isc_status, &H->tr)) {
				RECORD_ERROR(dbh);
			}
		}
	}

	if (isc_detach_database(H->isc_status, &H->db)) {
		RECORD_ERROR(dbh);
	}

	if (H->date_format) {
		efree(H->date_format);
	}
	if (H->time_format) {
		efree(H->time_format);
	}
	if (H->timestamp_format) {
		efree(H->timestamp_format);
	}

	pefree(H, dbh->is_persistent);

	return 0;
}


TEST_IMPL(idna_toascii) {
  /* Illegal inputs. */
  F("\xC0\x80\xC1\x80", UV_EINVAL);  /* Overlong UTF-8 sequence. */
  F("\xC0\x80\xC1\x80.com", UV_EINVAL);  /* Overlong UTF-8 sequence. */
  /* No conversion. */
  T("", "");
  T(".", ".");
  T(".com", ".com");
  T("example", "example");
  T("example-", "example-");
  T("straße.de", "xn--strae-oqa.de");
  /* Test cases adapted from punycode.js. Most are from RFC 3492. */
  T("foo.bar", "foo.bar");
  T("mañana.com", "xn--maana-pta.com");
  T("example.com.", "example.com.");
  T("bücher.com", "xn--bcher-kva.com");
  T("café.com", "xn--caf-dma.com");
  T("café.café.com", "xn--caf-dma.xn--caf-dma.com");
  T("☃-⌘.com", "xn----dqo34k.com");
  T("퐀☃-⌘.com", "xn----dqo34kn65z.com");
  T("💩.la", "xn--ls8h.la");
  T("mañana.com", "xn--maana-pta.com");
  T("mañana。com", "xn--maana-pta.com");
  T("mañana．com", "xn--maana-pta.com");
  T("mañana｡com", "xn--maana-pta.com");
  T("ü", "xn--tda");
  T(".ü", ".xn--tda");
  T("ü.ü", "xn--tda.xn--tda");
  T("ü.ü.", "xn--tda.xn--tda.");
  T("üëäö♥", "xn--4can8av2009b");
  T("Willst du die Blüthe des frühen, die Früchte des späteren Jahres",
    "xn--Willst du die Blthe des frhen, "
    "die Frchte des spteren Jahres-x9e96lkal");
  T("ليهمابتكلموشعربي؟", "xn--egbpdaj6bu4bxfgehfvwxn");
  T("他们为什么不说中文", "xn--ihqwcrb4cv8a8dqg056pqjye");
  T("他們爲什麽不說中文", "xn--ihqwctvzc91f659drss3x8bo0yb");
  T("Pročprostěnemluvíčesky", "xn--Proprostnemluvesky-uyb24dma41a");
  T("למההםפשוטלאמדבריםעברית", "xn--4dbcagdahymbxekheh6e0a7fei0b");
  T("यहलोगहिन्दीक्योंनहींबोलसकतेहैं",
    "xn--i1baa7eci9glrd9b2ae1bj0hfcgg6iyaf8o0a1dig0cd");
  T("なぜみんな日本語を話してくれないのか",
    "xn--n8jok5ay5dzabd5bym9f0cm5685rrjetr6pdxa");
  T("세계의모든사람들이한국어를이해한다면얼마나좋을까",
    "xn--989aomsvi5e83db1d2a355cv1e0vak1d"
    "wrv93d5xbh15a0dt30a5jpsd879ccm6fea98c");
  T("почемужеонинеговорятпорусски", "xn--b1abfaaepdrnnbgefbadotcwatmq2g4l");
  T("PorquénopuedensimplementehablarenEspañol",
    "xn--PorqunopuedensimplementehablarenEspaol-fmd56a");
  T("TạisaohọkhôngthểchỉnóitiếngViệt",
    "xn--TisaohkhngthchnitingVit-kjcr8268qyxafd2f1b9g");
  T("3年B組金八先生", "xn--3B-ww4c5e180e575a65lsy2b");
  T("安室奈美恵-with-SUPER-MONKEYS",
    "xn---with-SUPER-MONKEYS-pc58ag80a8qai00g7n9n");
  T("Hello-Another-Way-それぞれの場所",
    "xn--Hello-Another-Way--fc4qua05auwb3674vfr0b");
  T("ひとつ屋根の下2", "xn--2-u9tlzr9756bt3uc0v");
  T("MajiでKoiする5秒前", "xn--MajiKoi5-783gue6qz075azm5e");
  T("パフィーdeルンバ", "xn--de-jg4avhby1noc0d");
  T("そのスピードで", "xn--d9juau41awczczp");
  T("-> $1.00 <-", "-> $1.00 <-");
  /* Test cases from https://unicode.org/reports/tr46/ */
  T("faß.de", "xn--fa-hia.de");
  T("βόλος.com", "xn--nxasmm1c.com");
  T("ශ්‍රී.com", "xn--10cl1a0b660p.com");
  T("نامه‌ای.com", "xn--mgba3gch31f060k.com");
  return 0;
}


static inline void cil_reset_userrange(struct cil_userrange *userrange)
{
	if (userrange->range_str == NULL) {
		cil_reset_levelrange(userrange->range);
	}
}


static inline void cil_reset_levelrange(struct cil_levelrange *levelrange)
{
	if (levelrange->low_str == NULL) {
		cil_reset_level(levelrange->low);
	}

	if (levelrange->high_str == NULL) {
		cil_reset_level(levelrange->high);
	}
}


static void cil_reset_role(struct cil_role *role)
{
	/* reset the bounds to NULL during a re-resolve */
	role->bounds = NULL;
}


static inline void cil_reset_context(struct cil_context *context)
{
	if (context->range_str == NULL) {
		cil_reset_levelrange(context->range);
	}
}


static void cil_reset_selinuxuser(struct cil_selinuxuser *selinuxuser)
{
	if (selinuxuser->range_str == NULL) {
		cil_reset_levelrange(selinuxuser->range);
	}
}


static void cil_reset_userattributeset(struct cil_userattributeset *uas)
{
	cil_list_destroy(&uas->datum_expr, CIL_FALSE);
}


static void cil_reset_roleattributeset(struct cil_roleattributeset *ras)
{
	cil_list_destroy(&ras->datum_expr, CIL_FALSE);
}


void cil_destroy_perm(struct cil_perm *perm)
{
	if (perm == NULL) {
		return;
	}

	cil_symtab_datum_destroy(&perm->datum);
	cil_list_destroy(&perm->classperms, CIL_FALSE);

	free(perm);
}


int cil_gen_type(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
{
	enum cil_syntax syntax[] = {
		CIL_SYN_STRING,
		CIL_SYN_STRING,
		CIL_SYN_END
	};
	int syntax_len = sizeof(syntax)/sizeof(*syntax);
	char *key = NULL;
	struct cil_type *type = NULL;
	int rc = SEPOL_ERR;

	if (db == NULL || parse_current == NULL || ast_node == NULL) {
		goto exit;
	}

	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
	if (rc != SEPOL_OK) {
		goto exit;
	}

	cil_type_init(&type);

	key = parse_current->next->data;
	rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)type, (hashtab_key_t)key, CIL_SYM_TYPES, CIL_TYPE);
	if (rc != SEPOL_OK) {
		goto exit;
	}

	return SEPOL_OK;

exit:
	cil_tree_log(parse_current, CIL_ERR, "Bad type declaration");
	cil_destroy_type(type);
	cil_clear_node(ast_node);
	return rc;
}


int cil_build_ast(struct cil_db *db, struct cil_tree_node *parse_tree, struct cil_tree_node *ast)
{
	int rc = SEPOL_ERR;
	struct cil_args_build extra_args;

	if (db == NULL || parse_tree == NULL || ast == NULL) {
		goto exit;
	}

	extra_args.ast = ast;
	extra_args.db = db;
	extra_args.tunif = NULL;
	extra_args.in = NULL;
	extra_args.macro = NULL;
	extra_args.optional = NULL;
	extra_args.boolif = NULL;

	rc = cil_tree_walk(parse_tree, __cil_build_ast_node_helper, __cil_build_ast_first_child_helper, __cil_build_ast_last_child_helper, &extra_args);
	if (rc != SEPOL_OK) {
		goto exit;
	}

	return SEPOL_OK;

exit:
	return rc;
}


int cil_resolve_ioportcon(struct cil_tree_node *current, void *extra_args)
{
	struct cil_ioportcon *ioportcon = current->data;
	struct cil_symtab_datum *context_datum = NULL;
	int rc = SEPOL_ERR;

	if (ioportcon->context_str != NULL) {
		rc = cil_resolve_name(current, ioportcon->context_str, CIL_SYM_CONTEXTS, extra_args, &context_datum);
		if (rc != SEPOL_OK) {
			goto exit;
		}
		ioportcon->context = (struct cil_context*)context_datum;
	} else {
		rc = cil_resolve_context(current, ioportcon->context, extra_args);
		if (rc != SEPOL_OK) {
			goto exit;
		}
	}

	return SEPOL_OK;

exit:
	return rc;
}


void cil_destroy_userlevel(struct cil_userlevel *usrlvl)
{
	if (usrlvl == NULL) {
		return;
	}

	if (usrlvl->level_str == NULL && usrlvl->level != NULL) {
		cil_destroy_level(usrlvl->level);
	}

	free(usrlvl);
}


int cil_gen_devicetreecon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
{
	enum cil_syntax syntax[] = {
		CIL_SYN_STRING,
		CIL_SYN_STRING,
		CIL_SYN_STRING | CIL_SYN_LIST,
		CIL_SYN_END
	};
	int syntax_len = sizeof(syntax)/sizeof(*syntax);
	int rc = SEPOL_ERR;
	struct cil_devicetreecon *devicetreecon = NULL;

	if (db == NULL || parse_current == NULL || ast_node == NULL) {
		goto exit;
	}

	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
	if (rc != SEPOL_OK) {
		goto exit;
	}

	cil_devicetreecon_init(&devicetreecon);

	devicetreecon->path = parse_current->next->data;

	if (parse_current->next->next->cl_head == NULL) {
		devicetreecon->context_str = parse_current->next->next->data;
	} else {
		cil_context_init(&devicetreecon->context);

		rc = cil_fill_context(parse_current->next->next->cl_head, devicetreecon->context);
		if (rc != SEPOL_OK) {
			goto exit;
		}
	}

	ast_node->data = devicetreecon;
	ast_node->flavor = CIL_DEVICETREECON;

	return SEPOL_OK;

exit:
	cil_tree_log(parse_current, CIL_ERR, "Bad devicetreecon declaration");
	cil_destroy_devicetreecon(devicetreecon);
	return rc;
}


int cil_resolve_pirqcon(struct cil_tree_node *current, void *extra_args)
{
	struct cil_pirqcon *pirqcon = current->data;
	struct cil_symtab_datum *context_datum = NULL;
	int rc = SEPOL_ERR;

	if (pirqcon->context_str != NULL) {
		rc = cil_resolve_name(current, pirqcon->context_str, CIL_SYM_CONTEXTS, extra_args, &context_datum);
		if (rc != SEPOL_OK) {
			goto exit;
		}
		pirqcon->context = (struct cil_context*)context_datum;
	} else {
		rc = cil_resolve_context(current, pirqcon->context, extra_args);
		if (rc != SEPOL_OK) {
			goto exit;
		}
	}

	return SEPOL_OK;

exit:
	return rc;
}


int cil_resolve_sidorder(struct cil_tree_node *current, void *extra_args)
{
	struct cil_args_resolve *args = extra_args;
	struct cil_list *sidorder_list = args->sidorder_lists;
	struct cil_sidorder *sidorder = current->data;
	struct cil_list *new = NULL;
	struct cil_list_item *curr = NULL;
	struct cil_symtab_datum *datum = NULL;
	struct cil_ordered_list *ordered = NULL;
	int rc = SEPOL_ERR;

	cil_list_init(&new, CIL_SIDORDER);

	cil_list_for_each(curr, sidorder->sid_list_str) {
		rc = cil_resolve_name(current, (char *)curr->data, CIL_SYM_SIDS, extra_args, &datum);
		if (rc != SEPOL_OK) {
			cil_log(CIL_ERR, "Failed to resolve sid %s in sidorder\n", (char *)curr->data);
			goto exit;
		}
		cil_list_append(new, CIL_SID, datum);
	}

	__cil_ordered_list_init(&ordered);
	ordered->list = new;
	ordered->node = current;
	cil_list_append(sidorder_list, CIL_SIDORDER, ordered);

	return SEPOL_OK;

exit:
	cil_list_destroy(&new, CIL_FALSE);
	return rc;
}


int cil_gen_roleallow(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
{
	enum cil_syntax syntax[] = {
		CIL_SYN_STRING,
		CIL_SYN_STRING,
		CIL_SYN_STRING,
		CIL_SYN_END
	};
	int syntax_len = sizeof(syntax)/sizeof(*syntax);
	struct cil_roleallow *roleallow = NULL;
	int rc = SEPOL_ERR;

	if (db == NULL || parse_current == NULL || ast_node == NULL) {
		goto exit;
	}

	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
	if (rc != SEPOL_OK) {
		goto exit;
	}

	cil_roleallow_init(&roleallow);

	roleallow->src_str = parse_current->next->data;
	roleallow->tgt_str = parse_current->next->next->data;

	ast_node->data = roleallow;
	ast_node->flavor = CIL_ROLEALLOW;

	return SEPOL_OK;

exit:
	cil_tree_log(parse_current, CIL_ERR, "Bad roleallow rule");
	cil_destroy_roleallow(roleallow);
	return rc;
}


int cil_resolve_devicetreecon(struct cil_tree_node *current, void *extra_args)
{
	struct cil_devicetreecon *devicetreecon = current->data;
	struct cil_symtab_datum *context_datum = NULL;
	int rc = SEPOL_ERR;

	if (devicetreecon->context_str != NULL) {
		rc = cil_resolve_name(current, devicetreecon->context_str, CIL_SYM_CONTEXTS, extra_args, &context_datum);
		if (rc != SEPOL_OK) {
			goto exit;
		}
		devicetreecon->context = (struct cil_context*)context_datum;
	} else {
		rc = cil_resolve_context(current, devicetreecon->context, extra_args);
		if (rc != SEPOL_OK) {
			goto exit;
		}
	}

	return SEPOL_OK;

exit:
	return rc;
}


int cil_gen_ioportcon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
{
	enum cil_syntax syntax[] = {
		CIL_SYN_STRING,
		CIL_SYN_STRING | CIL_SYN_LIST,
		CIL_SYN_STRING | CIL_SYN_LIST,
		CIL_SYN_END
	};
	int syntax_len = sizeof(syntax)/sizeof(*syntax);
	int rc = SEPOL_ERR;
	struct cil_ioportcon *ioportcon = NULL;

	if (db == NULL || parse_current == NULL || ast_node == NULL) {
		goto exit;
	}

	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
	if (rc != SEPOL_OK) {
		goto exit;
	}

	cil_ioportcon_init(&ioportcon);

	if (parse_current->next->cl_head != NULL) {
		if (parse_current->next->cl_head->next != NULL &&
		    parse_current->next->cl_head->next->next == NULL) {
			rc = cil_fill_integer(parse_current->next->cl_head, &ioportcon->ioport_low, 0);
			if (rc != SEPOL_OK) {
				cil_log(CIL_ERR, "Improper ioport specified\n");
				goto exit;
			}
			rc = cil_fill_integer(parse_current->next->cl_head->next, &ioportcon->ioport_high, 0);
			if (rc != SEPOL_OK) {
				cil_log(CIL_ERR, "Improper ioport specified\n");
				goto exit;
			}
		} else {
			cil_log(CIL_ERR, "Improper ioport range specified\n");
			rc = SEPOL_ERR;
			goto exit;
		}
	} else {
		rc = cil_fill_integer(parse_current->next, &ioportcon->ioport_low, 0);
		if (rc != SEPOL_OK) {
			cil_log(CIL_ERR, "Improper ioport specified\n");
			goto exit;
		}
		ioportcon->ioport_high = ioportcon->ioport_low;
	}

	if (parse_current->next->next->cl_head == NULL ) {
		ioportcon->context_str = parse_current->next->next->data;
	} else {
		cil_context_init(&ioportcon->context);

		rc = cil_fill_context(parse_current->next->next->cl_head, ioportcon->context);
		if (rc != SEPOL_OK) {
			goto exit;
		}
	}

	ast_node->data = ioportcon;
	ast_node->flavor = CIL_IOPORTCON;

	return SEPOL_OK;

exit:
	cil_tree_log(parse_current, CIL_ERR, "Bad ioportcon declaration");
	cil_destroy_ioportcon(ioportcon);
	return rc;
}


int cil_resolve_default(struct cil_tree_node *current, void *extra_args)
{
	int rc = SEPOL_ERR;
	struct cil_default *def = current->data;
	struct cil_list_item *curr;
	struct cil_symtab_datum *datum;

	cil_list_init(&def->class_datums, def->flavor);

	cil_list_for_each(curr, def->class_strs) {
		rc = cil_resolve_name(current, (char *)curr->data, CIL_SYM_CLASSES, extra_args, &datum);
		if (rc != SEPOL_OK) {
			goto exit;
		}
		cil_list_append(def->class_datums, CIL_CLASS, datum);
	}

	return SEPOL_OK;

exit:
	return rc;
}


int cil_gen_senscat(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
{
	enum cil_syntax syntax[] = {
		CIL_SYN_STRING,
		CIL_SYN_STRING,
		CIL_SYN_STRING | CIL_SYN_LIST,
		CIL_SYN_END
	};
	int syntax_len = sizeof(syntax)/sizeof(*syntax);
	struct cil_senscat *senscat = NULL;
	int rc = SEPOL_ERR;

	if (db == NULL || parse_current == NULL || ast_node == NULL) {
		goto exit;
	}

	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
	if (rc != SEPOL_OK) {
		goto exit;
	}

	cil_senscat_init(&senscat);

	senscat->sens_str = parse_current->next->data;

	rc = cil_fill_cats(parse_current->next->next, &senscat->cats);
	if (rc != SEPOL_OK) {
		goto exit;
	}

	ast_node->data = senscat;
	ast_node->flavor = CIL_SENSCAT;

	return SEPOL_OK;

exit:
	cil_tree_log(parse_current, CIL_ERR, "Bad sensitivitycategory declaration");
	cil_destroy_senscat(senscat);
	return rc;
}


void cil_destroy_levelrange(struct cil_levelrange *lvlrange)
{
	if (lvlrange == NULL) {
		return;
	}

	cil_symtab_datum_destroy(&lvlrange->datum);

	if (lvlrange->low_str == NULL) {
		cil_destroy_level(lvlrange->low);
	}

	if (lvlrange->high_str == NULL) {
		cil_destroy_level(lvlrange->high);
	}

	free(lvlrange);
}


int cil_gen_netifcon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
{
	enum cil_syntax syntax[] = {
		CIL_SYN_STRING,
		CIL_SYN_STRING,
		CIL_SYN_STRING | CIL_SYN_LIST,
		CIL_SYN_STRING | CIL_SYN_LIST,
		CIL_SYN_END
	};
	int syntax_len = sizeof(syntax)/sizeof(*syntax);
	int rc = SEPOL_ERR;
	struct cil_netifcon *netifcon = NULL;

	if (db == NULL || parse_current == NULL || ast_node == NULL) {
		goto exit;
	}

	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
	if (rc != SEPOL_OK) {
		goto exit;
	}

	cil_netifcon_init(&netifcon);

	netifcon->interface_str = parse_current->next->data;

	if (parse_current->next->next->cl_head == NULL) {
		netifcon->if_context_str = parse_current->next->next->data;
	} else {
		cil_context_init(&netifcon->if_context);

		rc = cil_fill_context(parse_current->next->next->cl_head, netifcon->if_context);
		if (rc != SEPOL_OK) {
			goto exit;
		}
	}

	if (parse_current->next->next->next->cl_head == NULL) {
		netifcon->packet_context_str = parse_current->next->next->next->data;
	} else {
		cil_context_init(&netifcon->packet_context);

		rc = cil_fill_context(parse_current->next->next->next->cl_head, netifcon->packet_context);
		if (rc != SEPOL_OK) {
			goto exit;
		}
	}

	ast_node->data = netifcon;
	ast_node->flavor = CIL_NETIFCON;

	return SEPOL_OK;

exit:
	cil_tree_log(parse_current, CIL_ERR, "Bad netifcon declaration");
	cil_destroy_netifcon(netifcon);
	return SEPOL_ERR;
}


int cil_resolve_catorder(struct cil_tree_node *current, void *extra_args)
{
	struct cil_args_resolve *args = extra_args;
	struct cil_list *catorder_list = args->catorder_lists;
	struct cil_catorder *catorder = current->data;
	struct cil_list *new = NULL;
	struct cil_list_item *curr = NULL;
	struct cil_symtab_datum *cat_datum;
	struct cil_cat *cat = NULL;
	struct cil_ordered_list *ordered = NULL;
	int rc = SEPOL_ERR;

	cil_list_init(&new, CIL_CATORDER);

	cil_list_for_each(curr, catorder->cat_list_str) {
		struct cil_tree_node *node = NULL;
		rc = cil_resolve_name(current, (char *)curr->data, CIL_SYM_CATS, extra_args, &cat_datum);
		if (rc != SEPOL_OK) {
			cil_log(CIL_ERR, "Failed to resolve category %s in categoryorder\n", (char *)curr->data);
			goto exit;
		}
		node = NODE(cat_datum);
		if (node->flavor != CIL_CAT) {
			cil_log(CIL_ERR, "%s is not a category. Only categories are allowed in categoryorder statements\n", cat_datum->name);
			rc = SEPOL_ERR;
			goto exit;
		}
		cat = (struct cil_cat *)cat_datum;
		cil_list_append(new, CIL_CAT, cat);
	}

	__cil_ordered_list_init(&ordered);
	ordered->list = new;
	ordered->node = current;
	cil_list_append(catorder_list, CIL_CATORDER, ordered);

	return SEPOL_OK;

exit:
	cil_list_destroy(&new, CIL_FALSE);
	return rc;
}


int cil_gen_sensitivity(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
{
	enum cil_syntax syntax[] = {
		CIL_SYN_STRING,
		CIL_SYN_STRING,
		CIL_SYN_END
	};
	int syntax_len = sizeof(syntax)/sizeof(*syntax);
	char *key = NULL;
	struct cil_sens *sens = NULL;
	int rc = SEPOL_ERR;

	if (db == NULL || parse_current == NULL || ast_node == NULL) {
		goto exit;
	}

	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
	if (rc != SEPOL_OK) {
		goto exit;
	}

	cil_sens_init(&sens);

	key = parse_current->next->data;

	rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)sens, (hashtab_key_t)key, CIL_SYM_SENS, CIL_SENS);
	if (rc != SEPOL_OK) {
		goto exit;
	}

	return SEPOL_OK;

exit:
	cil_tree_log(parse_current, CIL_ERR, "Bad sensitivity declaration");
	cil_destroy_sensitivity(sens);
	cil_clear_node(ast_node);
	return rc;
}


int cil_gen_filecon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
{
	enum cil_syntax syntax[] = {
		CIL_SYN_STRING,
		CIL_SYN_STRING,
		CIL_SYN_STRING,
		CIL_SYN_STRING | CIL_SYN_LIST | CIL_SYN_EMPTY_LIST,
		CIL_SYN_END
	};
	int syntax_len = sizeof(syntax)/sizeof(*syntax);
	int rc = SEPOL_ERR;
	struct cil_filecon *filecon = NULL;
	char *type = NULL;

	if (db == NULL || parse_current == NULL || ast_node == NULL) {
		goto exit;
	}

	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
	if (rc != SEPOL_OK) {
		goto exit;
	}

	type = parse_current->next->next->data;
	cil_filecon_init(&filecon);

	filecon->path_str = parse_current->next->data;

	if (type == CIL_KEY_FILE) {
		filecon->type = CIL_FILECON_FILE;
	} else if (type == CIL_KEY_DIR) {
		filecon->type = CIL_FILECON_DIR;
	} else if (type == CIL_KEY_CHAR) {
		filecon->type = CIL_FILECON_CHAR;
	} else if (type == CIL_KEY_BLOCK) {
		filecon->type = CIL_FILECON_BLOCK;
	} else if (type == CIL_KEY_SOCKET) {
		filecon->type = CIL_FILECON_SOCKET;
	} else if (type == CIL_KEY_PIPE) {
		filecon->type = CIL_FILECON_PIPE;
	} else if (type == CIL_KEY_SYMLINK) {
		filecon->type = CIL_FILECON_SYMLINK;
	} else if (type == CIL_KEY_ANY) {
		filecon->type = CIL_FILECON_ANY;
	} else {
		cil_log(CIL_ERR, "Invalid file type\n");
		rc = SEPOL_ERR;
		goto exit;
	}

	if (parse_current->next->next->next->cl_head == NULL) {
		filecon->context_str = parse_current->next->next->next->data;
	} else {
		if (parse_current->next->next->next->cl_head->next == NULL) {
			filecon->context = NULL;
		} else {
			cil_context_init(&filecon->context);

			rc = cil_fill_context(parse_current->next->next->next->cl_head, filecon->context);
			if (rc != SEPOL_OK) {
				goto exit;
			}
		}
	}

	ast_node->data = filecon;
	ast_node->flavor = CIL_FILECON;

	return SEPOL_OK;

exit:
	cil_tree_log(parse_current, CIL_ERR, "Bad filecon declaration");
	cil_destroy_filecon(filecon);
	return rc;
}


int cil_gen_userprefix(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
{
	enum cil_syntax syntax[] = {
		CIL_SYN_STRING,
		CIL_SYN_STRING,
		CIL_SYN_STRING,
		CIL_SYN_END
	};
	int syntax_len = sizeof(syntax)/sizeof(*syntax);
	struct cil_userprefix *userprefix = NULL;
	int rc = SEPOL_ERR;

	if (db == NULL || parse_current == NULL || ast_node == NULL) {
		goto exit;
	}

	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
	if (rc != SEPOL_OK) {
		goto exit;
	}

	cil_userprefix_init(&userprefix);

	userprefix->user_str = parse_current->next->data;
	userprefix->prefix_str = parse_current->next->next->data;

	ast_node->data = userprefix;
	ast_node->flavor = CIL_USERPREFIX;

	return SEPOL_OK;
exit:
	cil_tree_log(parse_current, CIL_ERR, "Bad userprefix declaration");
	cil_destroy_userprefix(userprefix);
	return rc;
}


void cil_destroy_in(struct cil_in *in)
{
	if (in == NULL) {
		return;
	}

	cil_symtab_array_destroy(in->symtab);

	free(in);
}


void cil_destroy_classmapping(struct cil_classmapping *mapping)
{
	if (mapping == NULL) {
		return;
	}

	cil_destroy_classperms_list(&mapping->classperms);

	free(mapping);
}


void cil_destroy_classperms(struct cil_classperms *cp)
{
	if (cp == NULL) {
		return;
	}

	cil_list_destroy(&cp->perm_strs, CIL_TRUE);
	cil_list_destroy(&cp->perms, CIL_FALSE);

	free(cp);
}


void cil_destroy_typeattributeset(struct cil_typeattributeset *attrset)
{
	if (attrset == NULL) {
		return;
	}

	cil_list_destroy(&attrset->str_expr, CIL_TRUE);
	cil_list_destroy(&attrset->datum_expr, CIL_FALSE);

	free(attrset);
}


int cil_resolve_nodecon(struct cil_tree_node *current, void *extra_args)
{
	struct cil_nodecon *nodecon = current->data;
	struct cil_symtab_datum *addr_datum = NULL;
	struct cil_symtab_datum *mask_datum = NULL;
	struct cil_symtab_datum *context_datum = NULL;
	int rc = SEPOL_ERR;

	if (nodecon->addr_str != NULL) {
		rc = cil_resolve_name(current, nodecon->addr_str, CIL_SYM_IPADDRS, extra_args, &addr_datum);
		if (rc != SEPOL_OK) {
			goto exit;
		}
		nodecon->addr = (struct cil_ipaddr*)addr_datum;
	}

	if (nodecon->mask_str != NULL) {
		rc = cil_resolve_name(current, nodecon->mask_str, CIL_SYM_IPADDRS, extra_args, &mask_datum);
		if (rc != SEPOL_OK) {
			goto exit;
		}
		nodecon->mask = (struct cil_ipaddr*)mask_datum;
	}

	if (nodecon->context_str != NULL) {
		rc = cil_resolve_name(current, nodecon->context_str, CIL_SYM_CONTEXTS, extra_args, &context_datum);
		if (rc != SEPOL_OK) {
			goto exit;
		}
		nodecon->context = (struct cil_context*)context_datum;
	} else {
		rc = cil_resolve_context(current, nodecon->context, extra_args);
		if (rc != SEPOL_OK) {
			goto exit;
		}
	}

	if (nodecon->addr->family != nodecon->mask->family) {
		cil_log(CIL_ERR, "Nodecon ip address not in the same family\n");
		rc = SEPOL_ERR;
		goto exit;
	}

	return SEPOL_OK;

exit:
	return rc;
}


void cil_destroy_classpermissionset(struct cil_classpermissionset *cps)
{
	if (cps == NULL) {
		return;
	}

	cil_destroy_classperms_list(&cps->classperms);

	free(cps);
}


int cil_gen_src_info(struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
{
	/* No need to check syntax, because this is auto generated */
	struct cil_src_info *info = NULL;

	if (parse_current->next == NULL || parse_current->next->next == NULL) {
		cil_tree_log(parse_current, CIL_ERR, "Bad <src_info>");
		return SEPOL_ERR;
	}

	cil_src_info_init(&info);

	info->is_cil = (parse_current->next->data == CIL_KEY_SRC_CIL) ? CIL_TRUE : CIL_FALSE;
	info->path = parse_current->next->next->data;

	ast_node->data = info;
	ast_node->flavor = CIL_SRC_INFO;

	return SEPOL_OK;
}


int cil_resolve_ast(struct cil_db *db, struct cil_tree_node *current)
{
	int rc = SEPOL_ERR;
	struct cil_args_resolve extra_args;
	enum cil_pass pass = CIL_PASS_TIF;
	uint32_t changed = 0;

	if (db == NULL || current == NULL) {
		return rc;
	}

	extra_args.db = db;
	extra_args.pass = pass;
	extra_args.changed = &changed;
	extra_args.block = NULL;
	extra_args.macro = NULL;
	extra_args.optional = NULL;
	extra_args.boolif= NULL;
	extra_args.sidorder_lists = NULL;
	extra_args.classorder_lists = NULL;
	extra_args.unordered_classorder_lists = NULL;
	extra_args.catorder_lists = NULL;
	extra_args.sensitivityorder_lists = NULL;
	extra_args.in_list = NULL;

	cil_list_init(&extra_args.disabled_optionals, CIL_NODE);
	cil_list_init(&extra_args.sidorder_lists, CIL_LIST_ITEM);
	cil_list_init(&extra_args.classorder_lists, CIL_LIST_ITEM);
	cil_list_init(&extra_args.unordered_classorder_lists, CIL_LIST_ITEM);
	cil_list_init(&extra_args.catorder_lists, CIL_LIST_ITEM);
	cil_list_init(&extra_args.sensitivityorder_lists, CIL_LIST_ITEM);
	cil_list_init(&extra_args.in_list, CIL_IN);
	for (pass = CIL_PASS_TIF; pass < CIL_PASS_NUM; pass++) {
		extra_args.pass = pass;
		rc = cil_tree_walk(current, __cil_resolve_ast_node_helper, __cil_resolve_ast_first_child_helper, __cil_resolve_ast_last_child_helper, &extra_args);
		if (rc != SEPOL_OK) {
			cil_log(CIL_INFO, "Pass %i of resolution failed\n", pass);
			goto exit;
		}

		if (pass == CIL_PASS_IN) {
			rc = cil_resolve_in_list(&extra_args);
			if (rc != SEPOL_OK) {
				goto exit;
			}
			cil_list_destroy(&extra_args.in_list, CIL_FALSE);
		}

		if (pass == CIL_PASS_MISC1) {
			db->sidorder = __cil_ordered_lists_merge_all(&extra_args.sidorder_lists, NULL);
			if (db->sidorder == NULL) {
				rc = SEPOL_ERR;
				goto exit;
			}
			db->classorder = __cil_ordered_lists_merge_all(&extra_args.classorder_lists, &extra_args.unordered_classorder_lists);
			if (db->classorder == NULL) {
				rc = SEPOL_ERR;
				goto exit;
			}
			db->catorder = __cil_ordered_lists_merge_all(&extra_args.catorder_lists, NULL);
			if (db->catorder == NULL) {
				rc = SEPOL_ERR;
				goto exit;
			}
			cil_set_cat_values(db->catorder, db);
			db->sensitivityorder = __cil_ordered_lists_merge_all(&extra_args.sensitivityorder_lists, NULL);
			if (db->sensitivityorder == NULL) {
				rc = SEPOL_ERR;
				goto exit;
			}

			rc = __cil_verify_ordered(current, CIL_SID);
			if (rc != SEPOL_OK) {
				goto exit;
			}

			rc = __cil_verify_ordered(current, CIL_CLASS);
			if (rc != SEPOL_OK) {
				goto exit;
			}

			rc = __cil_verify_ordered(current, CIL_CAT);
			if (rc != SEPOL_OK) {
				goto exit;
			}

			rc = __cil_verify_ordered(current, CIL_SENS);
			if (rc != SEPOL_OK) {
				goto exit;
			}
		}

		if (changed && (pass > CIL_PASS_CALL1)) {
			struct cil_list_item *item;
			/* Need to re-resolve because an optional was disabled that contained
			 * one or more declarations. We only need to reset to the call1 pass
			 * because things done in the preceding passes aren't allowed in
			 * optionals, and thus can't be disabled.
			 * Note: set pass to CIL_PASS_CALL1 because the pass++ will increment
			 * it to CIL_PASS_CALL2
			 */
			cil_log(CIL_INFO, "Resetting declarations\n");

			if (pass >= CIL_PASS_MISC1) {
				__cil_ordered_lists_reset(&extra_args.sidorder_lists);
				__cil_ordered_lists_reset(&extra_args.classorder_lists);
				__cil_ordered_lists_reset(&extra_args.unordered_classorder_lists);
				__cil_ordered_lists_reset(&extra_args.catorder_lists);
				__cil_ordered_lists_reset(&extra_args.sensitivityorder_lists);
				cil_list_destroy(&db->sidorder, CIL_FALSE);
				cil_list_destroy(&db->classorder, CIL_FALSE);
				cil_list_destroy(&db->catorder, CIL_FALSE);
				cil_list_destroy(&db->sensitivityorder, CIL_FALSE);
			}

			pass = CIL_PASS_CALL1;

			rc = cil_reset_ast(current);
			if (rc != SEPOL_OK) {
				cil_log(CIL_ERR, "Failed to reset declarations\n");
				goto exit;
			}
			cil_list_for_each(item, extra_args.disabled_optionals) {
				cil_tree_children_destroy(item->data);
			}
			cil_list_destroy(&extra_args.disabled_optionals, CIL_FALSE);
			cil_list_init(&extra_args.disabled_optionals, CIL_NODE);
			changed = 0;
		}
	}

	rc = __cil_verify_initsids(db->sidorder);
	if (rc != SEPOL_OK) {
		goto exit;
	}

	rc = SEPOL_OK;
exit:
	__cil_ordered_lists_destroy(&extra_args.sidorder_lists);
	__cil_ordered_lists_destroy(&extra_args.classorder_lists);
	__cil_ordered_lists_destroy(&extra_args.catorder_lists);
	__cil_ordered_lists_destroy(&extra_args.sensitivityorder_lists);
	__cil_ordered_lists_destroy(&extra_args.unordered_classorder_lists);
	cil_list_destroy(&extra_args.disabled_optionals, CIL_FALSE);
	cil_list_destroy(&extra_args.in_list, CIL_FALSE);

	return rc;
}


void cil_destroy_genfscon(struct cil_genfscon *genfscon)
{
	if (genfscon == NULL) {
		return;
	}

	if (genfscon->context_str == NULL && genfscon->context != NULL) {
		cil_destroy_context(genfscon->context);
	}

	free(genfscon);
}


void cil_destroy_catorder(struct cil_catorder *catorder)
{
	if (catorder == NULL) {
		return;
	}

	if (catorder->cat_list_str != NULL) {
		cil_list_destroy(&catorder->cat_list_str, 1);
	}

	free(catorder);
}


int cil_resolve_avrule(struct cil_tree_node *current, void *extra_args)
{
	struct cil_args_resolve *args = extra_args;
	struct cil_db *db = NULL;

	struct cil_avrule *rule = current->data;
	struct cil_symtab_datum *src_datum = NULL;
	struct cil_symtab_datum *tgt_datum = NULL;
	struct cil_symtab_datum *permx_datum = NULL;
	int used;
	int rc = SEPOL_ERR;

	if (args != NULL) {
		db = args->db;
	}

	rc = cil_resolve_name(current, rule->src_str, CIL_SYM_TYPES, args, &src_datum);
	if (rc != SEPOL_OK) {
		goto exit;
	}
	rule->src = src_datum;

	if (rule->tgt_str == CIL_KEY_SELF) {
		rule->tgt = db->selftype;
	} else {
		rc = cil_resolve_name(current, rule->tgt_str, CIL_SYM_TYPES, args, &tgt_datum);
		if (rc != SEPOL_OK) {
			goto exit;
		}
		rule->tgt = tgt_datum;
		used = (rule->rule_kind == CIL_AVRULE_NEVERALLOW) ?
			CIL_ATTR_NEVERALLOW : CIL_ATTR_AVRULE;
		cil_type_used(src_datum, used); /* src not used if tgt is self */
		cil_type_used(tgt_datum, used);
	}

	if (!rule->is_extended) {
		rc = cil_resolve_classperms_list(current, rule->perms.classperms, extra_args);
		if (rc != SEPOL_OK) {
			goto exit;
		}
	} else {
		if (rule->perms.x.permx_str != NULL) {
			rc = cil_resolve_name(current, rule->perms.x.permx_str, CIL_SYM_PERMX, args, &permx_datum);
			if (rc != SEPOL_OK) {
				goto exit;
			}
			rule->perms.x.permx = (struct cil_permissionx*)permx_datum;
		} else {
			rc = cil_resolve_permissionx(current, rule->perms.x.permx, extra_args);
			if (rc != SEPOL_OK) {
				goto exit;
			}
		}
	}

	return SEPOL_OK;

exit:
	return rc;
}


int cil_resolve_catset(struct cil_tree_node *current, struct cil_catset *catset, void *extra_args)
{
	int rc = SEPOL_ERR;

	rc = cil_resolve_cats(current, catset->cats, extra_args);
	if (rc != SEPOL_OK) {
		goto exit;
	}

	rc = cil_verify_no_self_reference((struct cil_symtab_datum *)catset, catset->cats->datum_expr);
	if (rc != SEPOL_OK) {
		cil_list_destroy(&catset->cats->datum_expr, CIL_FALSE);
		goto exit;
	}

exit:
	return rc;
}


int cil_gen_roletype(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
{
	enum cil_syntax syntax[] = {
		CIL_SYN_STRING,
		CIL_SYN_STRING,
		CIL_SYN_STRING,
		CIL_SYN_END
	};
	int syntax_len = sizeof(syntax)/sizeof(*syntax);
	struct cil_roletype *roletype = NULL;
	int rc = SEPOL_ERR;

	if (db == NULL || parse_current == NULL || ast_node == NULL) {
		goto exit;
	}

	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
	if (rc != SEPOL_OK) {
		goto exit;
	}

	cil_roletype_init(&roletype);

	roletype->role_str = parse_current->next->data;
	roletype->type_str = parse_current->next->next->data;

	ast_node->data = roletype;
	ast_node->flavor = CIL_ROLETYPE;

	return SEPOL_OK;

exit:
	cil_tree_log(parse_current, CIL_ERR, "Bad roletype declaration");
	cil_destroy_roletype(roletype);
	return rc;
}


static int __cil_resolve_name_helper(struct cil_db *db, struct cil_tree_node *node, char *name, enum cil_sym_index sym_index, struct cil_symtab_datum **datum)
{
	int rc = SEPOL_ERR;

	rc = __cil_resolve_name_with_parents(node, name, sym_index, datum);
	if (rc != SEPOL_OK) {
		rc = __cil_resolve_name_with_root(db, name, sym_index, datum);
	}
	return rc;
}


int cil_gen_bool(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, int tunableif)
{
	enum cil_syntax syntax[] = {
		CIL_SYN_STRING,
		CIL_SYN_STRING,
		CIL_SYN_STRING,
		CIL_SYN_END
	};
	int syntax_len = sizeof(syntax)/sizeof(*syntax);
	char *key = NULL;
	struct cil_bool *boolean = NULL;
	int rc = SEPOL_ERR;

	if (db == NULL || parse_current == NULL || ast_node == NULL) {
		goto exit;
	}

	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
	if (rc != SEPOL_OK) {
		goto exit;
	}

	cil_bool_init(&boolean);

	key = parse_current->next->data;

	if (parse_current->next->next->data == CIL_KEY_CONDTRUE) {
		boolean->value = CIL_TRUE;
	} else if (parse_current->next->next->data == CIL_KEY_CONDFALSE) {
		boolean->value = CIL_FALSE;
	} else {
		cil_log(CIL_ERR, "Value must be either \'true\' or \'false\'");
		rc = SEPOL_ERR;
		goto exit;
	}

	rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)boolean, (hashtab_key_t)key, CIL_SYM_BOOLS, CIL_BOOL);
	if (rc != SEPOL_OK) {
		goto exit;
	}

	return SEPOL_OK;

exit:
	if (tunableif) {
		cil_tree_log(parse_current, CIL_ERR, "Bad tunable (treated as a boolean due to preserve-tunables) declaration");
	} else {
		cil_tree_log(parse_current, CIL_ERR, "Bad boolean declaration");
	}
	cil_destroy_bool(boolean);
	cil_clear_node(ast_node);
	return rc;
}


int cil_gen_typeattributeset(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
{
	enum cil_syntax syntax[] = {
		CIL_SYN_STRING,
		CIL_SYN_STRING,
		CIL_SYN_STRING | CIL_SYN_LIST,
		CIL_SYN_END
	};
	int syntax_len = sizeof(syntax)/sizeof(*syntax);
	struct cil_typeattributeset *attrset = NULL;
	int rc = SEPOL_ERR;

	if (db == NULL || parse_current == NULL || ast_node == NULL) {
		goto exit;
	}

	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
	if (rc != SEPOL_OK) {
		goto exit;
	}

	cil_typeattributeset_init(&attrset);

	attrset->attr_str = parse_current->next->data;

	rc = cil_gen_expr(parse_current->next->next, CIL_TYPE, &attrset->str_expr);
	if (rc != SEPOL_OK) {
		goto exit;
	}
	ast_node->data = attrset;
	ast_node->flavor = CIL_TYPEATTRIBUTESET;

	return SEPOL_OK;

exit:
	cil_tree_log(parse_current, CIL_ERR, "Bad typeattributeset statement");
	cil_destroy_typeattributeset(attrset);
	return rc;
}


void cil_destroy_classorder(struct cil_classorder *classorder)
{
	if (classorder == NULL) {
		return;
	}

	if (classorder->class_list_str != NULL) {
		cil_list_destroy(&classorder->class_list_str, 1);
	}

	free(classorder);
}


static int module_sig_check(struct load_info *info, int flags)
{
	int err = -ENODATA;
	const unsigned long markerlen = sizeof(MODULE_SIG_STRING) - 1;
	const char *reason;
	const void *mod = info->hdr;

	/*
	 * Require flags == 0, as a module with version information
	 * removed is no longer the module that was signed
	 */
	if (flags == 0 &&
	    info->len > markerlen &&
	    memcmp(mod + info->len - markerlen, MODULE_SIG_STRING, markerlen) == 0) {
		/* We truncate the module to discard the signature */
		info->len -= markerlen;
		err = mod_verify_sig(mod, info);
		if (!err) {
			info->sig_ok = true;
			return 0;
		}
	}

	/*
	 * We don't permit modules to be loaded into the trusted kernels
	 * without a valid signature on them, but if we're not enforcing,
	 * certain errors are non-fatal.
	 */
	switch (err) {
	case -ENODATA:
		reason = "unsigned module";
		break;
	case -ENOPKG:
		reason = "module with unsupported crypto";
		break;
	case -ENOKEY:
		reason = "module with unavailable key";
		break;

	default:
		/*
		 * All other errors are fatal, including lack of memory,
		 * unparseable signatures, and signature check failures --
		 * even if signatures aren't required.
		 */
		return err;
	}

	if (is_module_sig_enforced()) {
		pr_notice("Loading of %s is rejected\n", reason);
		return -EKEYREJECTED;
	}

	return security_locked_down(LOCKDOWN_MODULE_SIGNATURE);
}


static void module_assert_mutex_or_preempt(void)
{
#ifdef CONFIG_LOCKDEP
	if (unlikely(!debug_locks))
		return;

	WARN_ON_ONCE(!rcu_read_lock_sched_held() &&
		!lockdep_is_held(&module_mutex));
#endif
}


static inline int strong_try_module_get(struct module *mod)
{
	BUG_ON(mod && mod->state == MODULE_STATE_UNFORMED);
	if (mod && mod->state == MODULE_STATE_COMING)
		return -EBUSY;
	if (try_module_get(mod))
		return 0;
	else
		return -ENOENT;
}


static int copy_chunked_from_user(void *dst, const void __user *usrc, unsigned long len)
{
	do {
		unsigned long n = min(len, COPY_CHUNK_SIZE);

		if (copy_from_user(dst, usrc, n) != 0)
			return -EFAULT;
		cond_resched();
		dst += n;
		usrc += n;
		len -= n;
	} while (len);
	return 0;
}


static int check_modinfo_livepatch(struct module *mod, struct load_info *info)
{
	if (get_modinfo(info, "livepatch")) {
		mod->klp = true;
		add_taint_module(mod, TAINT_LIVEPATCH, LOCKDEP_STILL_OK);
		pr_notice_once("%s: tainting kernel with TAINT_LIVEPATCH\n",
			       mod->name);
	}

	return 0;
}


static void module_enable_ro(const struct module *mod, bool after_init)
{
	if (!rodata_enabled)
		return;

	set_vm_flush_reset_perms(mod->core_layout.base);
	set_vm_flush_reset_perms(mod->init_layout.base);
	frob_text(&mod->core_layout, set_memory_ro);

	frob_rodata(&mod->core_layout, set_memory_ro);
	frob_text(&mod->init_layout, set_memory_ro);
	frob_rodata(&mod->init_layout, set_memory_ro);

	if (after_init)
		frob_ro_after_init(&mod->core_layout, set_memory_ro);
}


void __symbol_put(const char *symbol)
{
	struct find_symbol_arg fsa = {
		.name	= symbol,
		.gplok	= true,
	};

	preempt_disable();
	if (!find_symbol(&fsa))
		BUG();
	module_put(fsa.owner);
	preempt_enable();
}


int lookup_module_symbol_attrs(unsigned long addr, unsigned long *size,
			unsigned long *offset, char *modname, char *name)
{
	struct module *mod;

	preempt_disable();
	list_for_each_entry_rcu(mod, &modules, list) {
		if (mod->state == MODULE_STATE_UNFORMED)
			continue;
		if (within_module(addr, mod)) {
			const char *sym;

			sym = find_kallsyms_symbol(mod, addr, size, offset);
			if (!sym)
				goto out;
			if (modname)
				strlcpy(modname, mod->name, MODULE_NAME_LEN);
			if (name)
				strlcpy(name, sym, KSYM_NAME_LEN);
			preempt_enable();
			return 0;
		}
	}
out:
	preempt_enable();
	return -ERANGE;
}


static void add_kallsyms(struct module *mod, const struct load_info *info)
{
}


static void module_enable_ro(const struct module *mod, bool after_init) {}


static int module_enforce_rwx_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
				       char *secstrings, struct module *mod)
{
	return 0;
}


static int copy_module_from_user(const void __user *umod, unsigned long len,
				  struct load_info *info)
{
	int err;

	info->len = len;
	if (info->len < sizeof(*(info->hdr)))
		return -ENOEXEC;

	err = security_kernel_load_data(LOADING_MODULE, true);
	if (err)
		return err;

	/* Suck in entire file: we'll want most of it. */
	info->hdr = __vmalloc(info->len, GFP_KERNEL | __GFP_NOWARN);
	if (!info->hdr)
		return -ENOMEM;

	if (copy_chunked_from_user(info->hdr, umod, info->len) != 0) {
		err = -EFAULT;
		goto out;
	}

	err = security_kernel_post_load_data((char *)info->hdr, info->len,
					     LOADING_MODULE, "init_module");
out:
	if (err)
		vfree(info->hdr);

	return err;
}


static void mod_update_bounds(struct module *mod)
{
	__mod_update_bounds(mod->core_layout.base, mod->core_layout.size);
	if (mod->init_layout.size)
		__mod_update_bounds(mod->init_layout.base, mod->init_layout.size);
}


void print_modules(void)
{
	struct module *mod;
	char buf[MODULE_FLAGS_BUF_SIZE];

	printk(KERN_DEFAULT "Modules linked in:");
	/* Most callers should already have preempt disabled, but make sure */
	preempt_disable();
	list_for_each_entry_rcu(mod, &modules, list) {
		if (mod->state == MODULE_STATE_UNFORMED)
			continue;
		pr_cont(" %s%s", mod->name, module_flags(mod, buf));
	}
	preempt_enable();
	if (last_unloaded_module[0])
		pr_cont(" [last unloaded: %s]", last_unloaded_module);
	pr_cont("\n");
}


static unsigned int find_sec(const struct load_info *info, const char *name)
{
	unsigned int i;

	for (i = 1; i < info->hdr->e_shnum; i++) {
		Elf_Shdr *shdr = &info->sechdrs[i];
		/* Alloc bit cleared means "ignore it." */
		if ((shdr->sh_flags & SHF_ALLOC)
		    && strcmp(info->secstrings + shdr->sh_name, name) == 0)
			return i;
	}
	return 0;
}


static int do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
{
	int ret;

	if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
		return -EPERM;

	switch (cmd) {
	case ARPT_SO_GET_INFO:
		ret = get_info(sock_net(sk), user, len);
		break;

	case ARPT_SO_GET_ENTRIES:
#ifdef CONFIG_COMPAT
		if (in_compat_syscall())
			ret = compat_get_entries(sock_net(sk), user, len);
		else
#endif
			ret = get_entries(sock_net(sk), user, len);
		break;

	case ARPT_SO_GET_REVISION_TARGET: {
		struct xt_get_revision rev;

		if (*len != sizeof(rev)) {
			ret = -EINVAL;
			break;
		}
		if (copy_from_user(&rev, user, sizeof(rev)) != 0) {
			ret = -EFAULT;
			break;
		}
		rev.name[sizeof(rev.name)-1] = 0;

		try_then_request_module(xt_find_revision(NFPROTO_ARP, rev.name,
							 rev.revision, 1, &ret),
					"arpt_%s", rev.name);
		break;
	}

	default:
		ret = -EINVAL;
	}

	return ret;
}