summaryrefslogtreecommitdiffstats
path: root/drivers/net/hyperv/netvsc.c
AgeCommit message (Expand)Author
2018-09-22hv_netvsc: Add support for LRO/RSC in the vSwitchHaiyang Zhang
2018-09-17hv_netvsc: pair VF based on serial numberStephen Hemminger
2018-07-18hv_netvsc: Fix napi reschedule while receive completion is busyHaiyang Zhang
2018-06-30hv_netvsc: split sub-channel setup into async and syncStephen Hemminger
2018-06-10Merge tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsiLinus Torvalds
2018-04-27hv_netvsc: simplify receive side calling argumentsStephen Hemminger
2018-04-18hv_netvsc: Add NetVSP v6 and v6.1 into version negotiationHaiyang Zhang
2018-04-18scsi: netvsc: Use the vmbus function to calculate ring buffer percentageLong Li
2018-04-05hv_netvsc: Pass net_device parameter to revoke and teardown functionsMohammed Gamal
2018-04-05hv_netvsc: Ensure correct teardown message sequence orderMohammed Gamal
2018-04-05hv_netvsc: Split netvsc_revoke_buf() and netvsc_teardown_gpadl()Mohammed Gamal
2018-04-05hv_netvsc: Use Windows version instead of NVSP version on GPAD teardownMohammed Gamal
2018-03-25hv_netvsc: Add range checking for rx packet offset and lengthHaiyang Zhang
2018-03-25hv_netvsc: Fix the return status in RX pathHaiyang Zhang
2018-03-23Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/netDavid S. Miller
2018-03-22hv_netvsc: common detach logicStephen Hemminger
2018-03-22hv_netvsc: change GPAD teardown order on older versionsStephen Hemminger
2018-03-22hv_netvsc: use RCU to fix concurrent rx and queue changesStephen Hemminger
2018-03-22hv_netvsc: disable NAPI before channel closeStephen Hemminger
2018-03-17hv_netvsc: add trace pointsStephen Hemminger
2018-03-04hv_netvsc: use napi_schedule_irqoffStephen Hemminger
2018-03-04hv_netvsc: fix race in napi poll when reschedulingStephen Hemminger
2018-03-04hv_netvsc: fix error unwind handling if vmbus_open failsStephen Hemminger
2018-03-04hv_netvsc: avoid retry on send during shutdownStephen Hemminger
2017-12-13hv_netvsc: empty current transmit aggregation if flow blockedStephen Hemminger
2017-12-13hv_netvsc: remove open_cnt reference countStephen Hemminger
2017-12-13hv_netvsc: simplify function args in receive status pathStephen Hemminger
2017-12-13hv_netvsc: copy_to_send buf can be voidStephen Hemminger
2017-12-13hv_netvsc: Fix the receive buffer size limitHaiyang Zhang
2017-12-03hv_netvsc: use reciprocal divide to speed up percent calculationStephen Hemminger
2017-12-03hv_netvsc: replace divide with mask when computing paddingStephen Hemminger
2017-12-03hv_netvsc: don't need local xmit_moreStephen Hemminger
2017-11-08hv_netvsc: netvsc_teardown_gpadl() splitVitaly Kuznetsov
2017-10-14hv_netvsc: Add initialization of tx_table in netvsc_device_add()Haiyang Zhang
2017-10-14hv_netvsc: Rename tx_send_table to tx_tableHaiyang Zhang
2017-10-01hv_netvsc: report stop_queue and wake_queueSimon Xiao
2017-09-25hv_netvsc: make const array ver_list static, reduces object code sizeColin Ian King
2017-09-21hv_netvsc: fix send buffer failure on MTU changeAlex Ng
2017-09-11hv_netvsc: fix deadlock on hotplugStephen Hemminger
2017-08-16vmbus: remove unused vmbus_sendpacket_ctlstephen hemminger
2017-08-16vmbus: remove unused vmubs_sendpacket_pagebuffer_ctlstephen hemminger
2017-08-11netvsc: keep track of some non-fatal overload conditionsstephen hemminger
2017-08-11netvsc: allow controlling send/recv buffer sizestephen hemminger
2017-08-11netvsc: no need to allocate send/receive on numa nodestephen hemminger
2017-08-11netvsc: don't signal host twice if emptystephen hemminger
2017-08-09Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/netDavid S. Miller
2017-08-08netvsc: make sure and unregister datapathstephen hemminger
2017-08-06netvsc: fix race on sub channel creationstephen hemminger
2017-08-02hyperv: netvsc: Neaten netvsc_send_pkt by using a temporaryJoe Perches
2017-08-01netvsc: Initialize 64-bit stats seqcountFlorian Fainelli
'n402' href='#n402'>402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Crypto user configuration API.
 *
 * Copyright (C) 2011 secunet Security Networks AG
 * Copyright (C) 2011 Steffen Klassert <steffen.klassert@secunet.com>
 */

#include <linux/module.h>
#include <linux/crypto.h>
#include <linux/cryptouser.h>
#include <linux/sched.h>
#include <linux/security.h>
#include <net/netlink.h>
#include <net/net_namespace.h>
#include <net/sock.h>
#include <crypto/internal/skcipher.h>
#include <crypto/internal/rng.h>
#include <crypto/akcipher.h>
#include <crypto/kpp.h>
#include <crypto/internal/cryptouser.h>

#include "internal.h"

#define null_terminated(x)	(strnlen(x, sizeof(x)) < sizeof(x))

static DEFINE_MUTEX(crypto_cfg_mutex);

struct crypto_dump_info {
	struct sk_buff *in_skb;
	struct sk_buff *out_skb;
	u32 nlmsg_seq;
	u16 nlmsg_flags;
};

struct crypto_alg *crypto_alg_match(struct crypto_user_alg *p, int exact)
{
	struct crypto_alg *q, *alg = NULL;

	down_read(&crypto_alg_sem);

	list_for_each_entry(q, &crypto_alg_list, cra_list) {
		int match = 0;

		if (crypto_is_larval(q))
			continue;

		if ((q->cra_flags ^ p->cru_type) & p->cru_mask)
			continue;

		if (strlen(p->cru_driver_name))
			match = !strcmp(q->cra_driver_name,
					p->cru_driver_name);
		else if (!exact)
			match = !strcmp(q->cra_name, p->cru_name);

		if (!match)
			continue;

		if (unlikely(!crypto_mod_get(q)))
			continue;

		alg = q;
		break;
	}

	up_read(&crypto_alg_sem);

	return alg;
}

static int crypto_report_cipher(struct sk_buff *skb, struct crypto_alg *alg)
{
	struct crypto_report_cipher rcipher;

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

	strscpy(rcipher.type, "cipher", sizeof(rcipher.type));

	rcipher.blocksize = alg->cra_blocksize;
	rcipher.min_keysize = alg->cra_cipher.cia_min_keysize;
	rcipher.max_keysize = alg->cra_cipher.cia_max_keysize;

	return nla_put(skb, CRYPTOCFGA_REPORT_CIPHER,
		       sizeof(rcipher), &rcipher);
}

static int crypto_report_comp(struct sk_buff *skb, struct crypto_alg *alg)
{
	struct crypto_report_comp rcomp;

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

	strscpy(rcomp.type, "compression", sizeof(rcomp.type));

	return nla_put(skb, CRYPTOCFGA_REPORT_COMPRESS, sizeof(rcomp), &rcomp);
}

static int crypto_report_one(struct crypto_alg *alg,
			     struct crypto_user_alg *ualg, struct sk_buff *skb)
{
	memset(ualg, 0, sizeof(*ualg));

	strscpy(ualg->cru_name, alg->cra_name, sizeof(ualg->cru_name));
	strscpy(ualg->cru_driver_name, alg->cra_driver_name,
		sizeof(ualg->cru_driver_name));
	strscpy(ualg->cru_module_name, module_name(alg->cra_module),
		sizeof(ualg->cru_module_name));

	ualg->cru_type = 0;
	ualg->cru_mask = 0;
	ualg->cru_flags = alg->cra_flags;
	ualg->cru_refcnt = refcount_read(&alg->cra_refcnt);

	if (nla_put_u32(skb, CRYPTOCFGA_PRIORITY_VAL, alg->cra_priority))
		goto nla_put_failure;
	if (alg->cra_flags & CRYPTO_ALG_LARVAL) {
		struct crypto_report_larval rl;

		memset(&rl, 0, sizeof(rl));
		strscpy(rl.type, "larval", sizeof(rl.type));
		if (nla_put(skb, CRYPTOCFGA_REPORT_LARVAL, sizeof(rl), &rl))
			goto nla_put_failure;
		goto out;
	}

	if (alg->cra_type && alg->cra_type->report) {
		if (alg->cra_type->report(skb, alg))
			goto nla_put_failure;

		goto out;
	}

	switch (alg->cra_flags & (CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_LARVAL)) {
	case CRYPTO_ALG_TYPE_CIPHER:
		if (crypto_report_cipher(skb, alg))
			goto nla_put_failure;

		break;
	case CRYPTO_ALG_TYPE_COMPRESS:
		if (crypto_report_comp(skb, alg))
			goto nla_put_failure;

		break;
	}

out:
	return 0;

nla_put_failure:
	return -EMSGSIZE;
}

static int crypto_report_alg(struct crypto_alg *alg,
			     struct crypto_dump_info *info)
{
	struct sk_buff *in_skb = info->in_skb;
	struct sk_buff *skb = info->out_skb;
	struct nlmsghdr *nlh;
	struct crypto_user_alg *ualg;
	int err = 0;

	nlh = nlmsg_put(skb, NETLINK_CB(in_skb).portid, info->nlmsg_seq,
			CRYPTO_MSG_GETALG, sizeof(*ualg), info->nlmsg_flags);
	if (!nlh) {
		err = -EMSGSIZE;
		goto out;
	}

	ualg = nlmsg_data(nlh);

	err = crypto_report_one(alg, ualg, skb);
	if (err) {
		nlmsg_cancel(skb, nlh);
		goto out;
	}

	nlmsg_end(skb, nlh);

out:
	return err;
}

static int crypto_report(struct sk_buff *in_skb, struct nlmsghdr *in_nlh,
			 struct nlattr **attrs)
{
	struct net *net = sock_net(in_skb->sk);
	struct crypto_user_alg *p = nlmsg_data(in_nlh);
	struct crypto_alg *alg;
	struct sk_buff *skb;
	struct crypto_dump_info info;
	int err;

	if (!null_terminated(p->cru_name) || !null_terminated(p->cru_driver_name))
		return -EINVAL;

	alg = crypto_alg_match(p, 0);
	if (!alg)
		return -ENOENT;

	err = -ENOMEM;
	skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
	if (!skb)
		goto drop_alg;

	info.in_skb = in_skb;
	info.out_skb = skb;
	info.nlmsg_seq = in_nlh->nlmsg_seq;
	info.nlmsg_flags = 0;

	err = crypto_report_alg(alg, &info);

drop_alg:
	crypto_mod_put(alg);

	if (err) {
		kfree_skb(skb);
		return err;
	}

	return nlmsg_unicast(net->crypto_nlsk, skb, NETLINK_CB(in_skb).portid);
}

static int crypto_dump_report(struct sk_buff *skb, struct netlink_callback *cb)
{
	const size_t start_pos = cb->args[0];
	size_t pos = 0;
	struct crypto_dump_info info;
	struct crypto_alg *alg;
	int res;

	info.in_skb = cb->skb;
	info.out_skb = skb;
	info.nlmsg_seq = cb->nlh->nlmsg_seq;
	info.nlmsg_flags = NLM_F_MULTI;

	down_read(&crypto_alg_sem);
	list_for_each_entry(alg, &crypto_alg_list