162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Common framework for low-level network console, dump, and debugger code
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Sep 8 2003  Matt Mackall <mpm@selenic.com>
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * based on the netconsole code from:
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * Copyright (C) 2001  Ingo Molnar <mingo@redhat.com>
1062306a36Sopenharmony_ci * Copyright (C) 2002  Red Hat, Inc.
1162306a36Sopenharmony_ci */
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include <linux/moduleparam.h>
1662306a36Sopenharmony_ci#include <linux/kernel.h>
1762306a36Sopenharmony_ci#include <linux/netdevice.h>
1862306a36Sopenharmony_ci#include <linux/etherdevice.h>
1962306a36Sopenharmony_ci#include <linux/string.h>
2062306a36Sopenharmony_ci#include <linux/if_arp.h>
2162306a36Sopenharmony_ci#include <linux/inetdevice.h>
2262306a36Sopenharmony_ci#include <linux/inet.h>
2362306a36Sopenharmony_ci#include <linux/interrupt.h>
2462306a36Sopenharmony_ci#include <linux/netpoll.h>
2562306a36Sopenharmony_ci#include <linux/sched.h>
2662306a36Sopenharmony_ci#include <linux/delay.h>
2762306a36Sopenharmony_ci#include <linux/rcupdate.h>
2862306a36Sopenharmony_ci#include <linux/workqueue.h>
2962306a36Sopenharmony_ci#include <linux/slab.h>
3062306a36Sopenharmony_ci#include <linux/export.h>
3162306a36Sopenharmony_ci#include <linux/if_vlan.h>
3262306a36Sopenharmony_ci#include <net/tcp.h>
3362306a36Sopenharmony_ci#include <net/udp.h>
3462306a36Sopenharmony_ci#include <net/addrconf.h>
3562306a36Sopenharmony_ci#include <net/ndisc.h>
3662306a36Sopenharmony_ci#include <net/ip6_checksum.h>
3762306a36Sopenharmony_ci#include <asm/unaligned.h>
3862306a36Sopenharmony_ci#include <trace/events/napi.h>
3962306a36Sopenharmony_ci#include <linux/kconfig.h>
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci/*
4262306a36Sopenharmony_ci * We maintain a small pool of fully-sized skbs, to make sure the
4362306a36Sopenharmony_ci * message gets out even in extreme OOM situations.
4462306a36Sopenharmony_ci */
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci#define MAX_UDP_CHUNK 1460
4762306a36Sopenharmony_ci#define MAX_SKBS 32
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_cistatic struct sk_buff_head skb_pool;
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ciDEFINE_STATIC_SRCU(netpoll_srcu);
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci#define USEC_PER_POLL	50
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci#define MAX_SKB_SIZE							\
5662306a36Sopenharmony_ci	(sizeof(struct ethhdr) +					\
5762306a36Sopenharmony_ci	 sizeof(struct iphdr) +						\
5862306a36Sopenharmony_ci	 sizeof(struct udphdr) +					\
5962306a36Sopenharmony_ci	 MAX_UDP_CHUNK)
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_cistatic void zap_completion_queue(void);
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_cistatic unsigned int carrier_timeout = 4;
6462306a36Sopenharmony_cimodule_param(carrier_timeout, uint, 0644);
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci#define np_info(np, fmt, ...)				\
6762306a36Sopenharmony_ci	pr_info("%s: " fmt, np->name, ##__VA_ARGS__)
6862306a36Sopenharmony_ci#define np_err(np, fmt, ...)				\
6962306a36Sopenharmony_ci	pr_err("%s: " fmt, np->name, ##__VA_ARGS__)
7062306a36Sopenharmony_ci#define np_notice(np, fmt, ...)				\
7162306a36Sopenharmony_ci	pr_notice("%s: " fmt, np->name, ##__VA_ARGS__)
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_cistatic netdev_tx_t netpoll_start_xmit(struct sk_buff *skb,
7462306a36Sopenharmony_ci				      struct net_device *dev,
7562306a36Sopenharmony_ci				      struct netdev_queue *txq)
7662306a36Sopenharmony_ci{
7762306a36Sopenharmony_ci	netdev_tx_t status = NETDEV_TX_OK;
7862306a36Sopenharmony_ci	netdev_features_t features;
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	features = netif_skb_features(skb);
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	if (skb_vlan_tag_present(skb) &&
8362306a36Sopenharmony_ci	    !vlan_hw_offload_capable(features, skb->vlan_proto)) {
8462306a36Sopenharmony_ci		skb = __vlan_hwaccel_push_inside(skb);
8562306a36Sopenharmony_ci		if (unlikely(!skb)) {
8662306a36Sopenharmony_ci			/* This is actually a packet drop, but we
8762306a36Sopenharmony_ci			 * don't want the code that calls this
8862306a36Sopenharmony_ci			 * function to try and operate on a NULL skb.
8962306a36Sopenharmony_ci			 */
9062306a36Sopenharmony_ci			goto out;
9162306a36Sopenharmony_ci		}
9262306a36Sopenharmony_ci	}
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	status = netdev_start_xmit(skb, dev, txq, false);
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ciout:
9762306a36Sopenharmony_ci	return status;
9862306a36Sopenharmony_ci}
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_cistatic void queue_process(struct work_struct *work)
10162306a36Sopenharmony_ci{
10262306a36Sopenharmony_ci	struct netpoll_info *npinfo =
10362306a36Sopenharmony_ci		container_of(work, struct netpoll_info, tx_work.work);
10462306a36Sopenharmony_ci	struct sk_buff *skb;
10562306a36Sopenharmony_ci	unsigned long flags;
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	while ((skb = skb_dequeue(&npinfo->txq))) {
10862306a36Sopenharmony_ci		struct net_device *dev = skb->dev;
10962306a36Sopenharmony_ci		struct netdev_queue *txq;
11062306a36Sopenharmony_ci		unsigned int q_index;
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci		if (!netif_device_present(dev) || !netif_running(dev)) {
11362306a36Sopenharmony_ci			kfree_skb(skb);
11462306a36Sopenharmony_ci			continue;
11562306a36Sopenharmony_ci		}
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci		local_irq_save(flags);
11862306a36Sopenharmony_ci		/* check if skb->queue_mapping is still valid */
11962306a36Sopenharmony_ci		q_index = skb_get_queue_mapping(skb);
12062306a36Sopenharmony_ci		if (unlikely(q_index >= dev->real_num_tx_queues)) {
12162306a36Sopenharmony_ci			q_index = q_index % dev->real_num_tx_queues;
12262306a36Sopenharmony_ci			skb_set_queue_mapping(skb, q_index);
12362306a36Sopenharmony_ci		}
12462306a36Sopenharmony_ci		txq = netdev_get_tx_queue(dev, q_index);
12562306a36Sopenharmony_ci		HARD_TX_LOCK(dev, txq, smp_processor_id());
12662306a36Sopenharmony_ci		if (netif_xmit_frozen_or_stopped(txq) ||
12762306a36Sopenharmony_ci		    !dev_xmit_complete(netpoll_start_xmit(skb, dev, txq))) {
12862306a36Sopenharmony_ci			skb_queue_head(&npinfo->txq, skb);
12962306a36Sopenharmony_ci			HARD_TX_UNLOCK(dev, txq);
13062306a36Sopenharmony_ci			local_irq_restore(flags);
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci			schedule_delayed_work(&npinfo->tx_work, HZ/10);
13362306a36Sopenharmony_ci			return;
13462306a36Sopenharmony_ci		}
13562306a36Sopenharmony_ci		HARD_TX_UNLOCK(dev, txq);
13662306a36Sopenharmony_ci		local_irq_restore(flags);
13762306a36Sopenharmony_ci	}
13862306a36Sopenharmony_ci}
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_cistatic int netif_local_xmit_active(struct net_device *dev)
14162306a36Sopenharmony_ci{
14262306a36Sopenharmony_ci	int i;
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	for (i = 0; i < dev->num_tx_queues; i++) {
14562306a36Sopenharmony_ci		struct netdev_queue *txq = netdev_get_tx_queue(dev, i);
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci		if (READ_ONCE(txq->xmit_lock_owner) == smp_processor_id())
14862306a36Sopenharmony_ci			return 1;
14962306a36Sopenharmony_ci	}
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	return 0;
15262306a36Sopenharmony_ci}
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_cistatic void poll_one_napi(struct napi_struct *napi)
15562306a36Sopenharmony_ci{
15662306a36Sopenharmony_ci	int work;
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	/* If we set this bit but see that it has already been set,
15962306a36Sopenharmony_ci	 * that indicates that napi has been disabled and we need
16062306a36Sopenharmony_ci	 * to abort this operation
16162306a36Sopenharmony_ci	 */
16262306a36Sopenharmony_ci	if (test_and_set_bit(NAPI_STATE_NPSVC, &napi->state))
16362306a36Sopenharmony_ci		return;
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	/* We explicilty pass the polling call a budget of 0 to
16662306a36Sopenharmony_ci	 * indicate that we are clearing the Tx path only.
16762306a36Sopenharmony_ci	 */
16862306a36Sopenharmony_ci	work = napi->poll(napi, 0);
16962306a36Sopenharmony_ci	WARN_ONCE(work, "%pS exceeded budget in poll\n", napi->poll);
17062306a36Sopenharmony_ci	trace_napi_poll(napi, work, 0);
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	clear_bit(NAPI_STATE_NPSVC, &napi->state);
17362306a36Sopenharmony_ci}
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_cistatic void poll_napi(struct net_device *dev)
17662306a36Sopenharmony_ci{
17762306a36Sopenharmony_ci	struct napi_struct *napi;
17862306a36Sopenharmony_ci	int cpu = smp_processor_id();
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	list_for_each_entry_rcu(napi, &dev->napi_list, dev_list) {
18162306a36Sopenharmony_ci		if (cmpxchg(&napi->poll_owner, -1, cpu) == -1) {
18262306a36Sopenharmony_ci			poll_one_napi(napi);
18362306a36Sopenharmony_ci			smp_store_release(&napi->poll_owner, -1);
18462306a36Sopenharmony_ci		}
18562306a36Sopenharmony_ci	}
18662306a36Sopenharmony_ci}
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_civoid netpoll_poll_dev(struct net_device *dev)
18962306a36Sopenharmony_ci{
19062306a36Sopenharmony_ci	struct netpoll_info *ni = rcu_dereference_bh(dev->npinfo);
19162306a36Sopenharmony_ci	const struct net_device_ops *ops;
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	/* Don't do any rx activity if the dev_lock mutex is held
19462306a36Sopenharmony_ci	 * the dev_open/close paths use this to block netpoll activity
19562306a36Sopenharmony_ci	 * while changing device state
19662306a36Sopenharmony_ci	 */
19762306a36Sopenharmony_ci	if (!ni || down_trylock(&ni->dev_lock))
19862306a36Sopenharmony_ci		return;
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	/* Some drivers will take the same locks in poll and xmit,
20162306a36Sopenharmony_ci	 * we can't poll if local CPU is already in xmit.
20262306a36Sopenharmony_ci	 */
20362306a36Sopenharmony_ci	if (!netif_running(dev) || netif_local_xmit_active(dev)) {
20462306a36Sopenharmony_ci		up(&ni->dev_lock);
20562306a36Sopenharmony_ci		return;
20662306a36Sopenharmony_ci	}
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	ops = dev->netdev_ops;
20962306a36Sopenharmony_ci	if (ops->ndo_poll_controller)
21062306a36Sopenharmony_ci		ops->ndo_poll_controller(dev);
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	poll_napi(dev);
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	up(&ni->dev_lock);
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	zap_completion_queue();
21762306a36Sopenharmony_ci}
21862306a36Sopenharmony_ciEXPORT_SYMBOL(netpoll_poll_dev);
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_civoid netpoll_poll_disable(struct net_device *dev)
22162306a36Sopenharmony_ci{
22262306a36Sopenharmony_ci	struct netpoll_info *ni;
22362306a36Sopenharmony_ci	int idx;
22462306a36Sopenharmony_ci	might_sleep();
22562306a36Sopenharmony_ci	idx = srcu_read_lock(&netpoll_srcu);
22662306a36Sopenharmony_ci	ni = srcu_dereference(dev->npinfo, &netpoll_srcu);
22762306a36Sopenharmony_ci	if (ni)
22862306a36Sopenharmony_ci		down(&ni->dev_lock);
22962306a36Sopenharmony_ci	srcu_read_unlock(&netpoll_srcu, idx);
23062306a36Sopenharmony_ci}
23162306a36Sopenharmony_ciEXPORT_SYMBOL(netpoll_poll_disable);
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_civoid netpoll_poll_enable(struct net_device *dev)
23462306a36Sopenharmony_ci{
23562306a36Sopenharmony_ci	struct netpoll_info *ni;
23662306a36Sopenharmony_ci	rcu_read_lock();
23762306a36Sopenharmony_ci	ni = rcu_dereference(dev->npinfo);
23862306a36Sopenharmony_ci	if (ni)
23962306a36Sopenharmony_ci		up(&ni->dev_lock);
24062306a36Sopenharmony_ci	rcu_read_unlock();
24162306a36Sopenharmony_ci}
24262306a36Sopenharmony_ciEXPORT_SYMBOL(netpoll_poll_enable);
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_cistatic void refill_skbs(void)
24562306a36Sopenharmony_ci{
24662306a36Sopenharmony_ci	struct sk_buff *skb;
24762306a36Sopenharmony_ci	unsigned long flags;
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	spin_lock_irqsave(&skb_pool.lock, flags);
25062306a36Sopenharmony_ci	while (skb_pool.qlen < MAX_SKBS) {
25162306a36Sopenharmony_ci		skb = alloc_skb(MAX_SKB_SIZE, GFP_ATOMIC);
25262306a36Sopenharmony_ci		if (!skb)
25362306a36Sopenharmony_ci			break;
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci		__skb_queue_tail(&skb_pool, skb);
25662306a36Sopenharmony_ci	}
25762306a36Sopenharmony_ci	spin_unlock_irqrestore(&skb_pool.lock, flags);
25862306a36Sopenharmony_ci}
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_cistatic void zap_completion_queue(void)
26162306a36Sopenharmony_ci{
26262306a36Sopenharmony_ci	unsigned long flags;
26362306a36Sopenharmony_ci	struct softnet_data *sd = &get_cpu_var(softnet_data);
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	if (sd->completion_queue) {
26662306a36Sopenharmony_ci		struct sk_buff *clist;
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci		local_irq_save(flags);
26962306a36Sopenharmony_ci		clist = sd->completion_queue;
27062306a36Sopenharmony_ci		sd->completion_queue = NULL;
27162306a36Sopenharmony_ci		local_irq_restore(flags);
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci		while (clist != NULL) {
27462306a36Sopenharmony_ci			struct sk_buff *skb = clist;
27562306a36Sopenharmony_ci			clist = clist->next;
27662306a36Sopenharmony_ci			if (!skb_irq_freeable(skb)) {
27762306a36Sopenharmony_ci				refcount_set(&skb->users, 1);
27862306a36Sopenharmony_ci				dev_kfree_skb_any(skb); /* put this one back */
27962306a36Sopenharmony_ci			} else {
28062306a36Sopenharmony_ci				__kfree_skb(skb);
28162306a36Sopenharmony_ci			}
28262306a36Sopenharmony_ci		}
28362306a36Sopenharmony_ci	}
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	put_cpu_var(softnet_data);
28662306a36Sopenharmony_ci}
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_cistatic struct sk_buff *find_skb(struct netpoll *np, int len, int reserve)
28962306a36Sopenharmony_ci{
29062306a36Sopenharmony_ci	int count = 0;
29162306a36Sopenharmony_ci	struct sk_buff *skb;
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	zap_completion_queue();
29462306a36Sopenharmony_ci	refill_skbs();
29562306a36Sopenharmony_cirepeat:
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	skb = alloc_skb(len, GFP_ATOMIC);
29862306a36Sopenharmony_ci	if (!skb)
29962306a36Sopenharmony_ci		skb = skb_dequeue(&skb_pool);
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	if (!skb) {
30262306a36Sopenharmony_ci		if (++count < 10) {
30362306a36Sopenharmony_ci			netpoll_poll_dev(np->dev);
30462306a36Sopenharmony_ci			goto repeat;
30562306a36Sopenharmony_ci		}
30662306a36Sopenharmony_ci		return NULL;
30762306a36Sopenharmony_ci	}
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	refcount_set(&skb->users, 1);
31062306a36Sopenharmony_ci	skb_reserve(skb, reserve);
31162306a36Sopenharmony_ci	return skb;
31262306a36Sopenharmony_ci}
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_cistatic int netpoll_owner_active(struct net_device *dev)
31562306a36Sopenharmony_ci{
31662306a36Sopenharmony_ci	struct napi_struct *napi;
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	list_for_each_entry_rcu(napi, &dev->napi_list, dev_list) {
31962306a36Sopenharmony_ci		if (napi->poll_owner == smp_processor_id())
32062306a36Sopenharmony_ci			return 1;
32162306a36Sopenharmony_ci	}
32262306a36Sopenharmony_ci	return 0;
32362306a36Sopenharmony_ci}
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci/* call with IRQ disabled */
32662306a36Sopenharmony_cistatic netdev_tx_t __netpoll_send_skb(struct netpoll *np, struct sk_buff *skb)
32762306a36Sopenharmony_ci{
32862306a36Sopenharmony_ci	netdev_tx_t status = NETDEV_TX_BUSY;
32962306a36Sopenharmony_ci	struct net_device *dev;
33062306a36Sopenharmony_ci	unsigned long tries;
33162306a36Sopenharmony_ci	/* It is up to the caller to keep npinfo alive. */
33262306a36Sopenharmony_ci	struct netpoll_info *npinfo;
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	lockdep_assert_irqs_disabled();
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	dev = np->dev;
33762306a36Sopenharmony_ci	npinfo = rcu_dereference_bh(dev->npinfo);
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	if (!npinfo || !netif_running(dev) || !netif_device_present(dev)) {
34062306a36Sopenharmony_ci		dev_kfree_skb_irq(skb);
34162306a36Sopenharmony_ci		return NET_XMIT_DROP;
34262306a36Sopenharmony_ci	}
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	/* don't get messages out of order, and no recursion */
34562306a36Sopenharmony_ci	if (skb_queue_len(&npinfo->txq) == 0 && !netpoll_owner_active(dev)) {
34662306a36Sopenharmony_ci		struct netdev_queue *txq;
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci		txq = netdev_core_pick_tx(dev, skb, NULL);
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci		/* try until next clock tick */
35162306a36Sopenharmony_ci		for (tries = jiffies_to_usecs(1)/USEC_PER_POLL;
35262306a36Sopenharmony_ci		     tries > 0; --tries) {
35362306a36Sopenharmony_ci			if (HARD_TX_TRYLOCK(dev, txq)) {
35462306a36Sopenharmony_ci				if (!netif_xmit_stopped(txq))
35562306a36Sopenharmony_ci					status = netpoll_start_xmit(skb, dev, txq);
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci				HARD_TX_UNLOCK(dev, txq);
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci				if (dev_xmit_complete(status))
36062306a36Sopenharmony_ci					break;
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci			}
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci			/* tickle device maybe there is some cleanup */
36562306a36Sopenharmony_ci			netpoll_poll_dev(np->dev);
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci			udelay(USEC_PER_POLL);
36862306a36Sopenharmony_ci		}
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci		WARN_ONCE(!irqs_disabled(),
37162306a36Sopenharmony_ci			"netpoll_send_skb_on_dev(): %s enabled interrupts in poll (%pS)\n",
37262306a36Sopenharmony_ci			dev->name, dev->netdev_ops->ndo_start_xmit);
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	}
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	if (!dev_xmit_complete(status)) {
37762306a36Sopenharmony_ci		skb_queue_tail(&npinfo->txq, skb);
37862306a36Sopenharmony_ci		schedule_delayed_work(&npinfo->tx_work,0);
37962306a36Sopenharmony_ci	}
38062306a36Sopenharmony_ci	return NETDEV_TX_OK;
38162306a36Sopenharmony_ci}
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_cinetdev_tx_t netpoll_send_skb(struct netpoll *np, struct sk_buff *skb)
38462306a36Sopenharmony_ci{
38562306a36Sopenharmony_ci	unsigned long flags;
38662306a36Sopenharmony_ci	netdev_tx_t ret;
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	if (unlikely(!np)) {
38962306a36Sopenharmony_ci		dev_kfree_skb_irq(skb);
39062306a36Sopenharmony_ci		ret = NET_XMIT_DROP;
39162306a36Sopenharmony_ci	} else {
39262306a36Sopenharmony_ci		local_irq_save(flags);
39362306a36Sopenharmony_ci		ret = __netpoll_send_skb(np, skb);
39462306a36Sopenharmony_ci		local_irq_restore(flags);
39562306a36Sopenharmony_ci	}
39662306a36Sopenharmony_ci	return ret;
39762306a36Sopenharmony_ci}
39862306a36Sopenharmony_ciEXPORT_SYMBOL(netpoll_send_skb);
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_civoid netpoll_send_udp(struct netpoll *np, const char *msg, int len)
40162306a36Sopenharmony_ci{
40262306a36Sopenharmony_ci	int total_len, ip_len, udp_len;
40362306a36Sopenharmony_ci	struct sk_buff *skb;
40462306a36Sopenharmony_ci	struct udphdr *udph;
40562306a36Sopenharmony_ci	struct iphdr *iph;
40662306a36Sopenharmony_ci	struct ethhdr *eth;
40762306a36Sopenharmony_ci	static atomic_t ip_ident;
40862306a36Sopenharmony_ci	struct ipv6hdr *ip6h;
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	if (!IS_ENABLED(CONFIG_PREEMPT_RT))
41162306a36Sopenharmony_ci		WARN_ON_ONCE(!irqs_disabled());
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	udp_len = len + sizeof(*udph);
41462306a36Sopenharmony_ci	if (np->ipv6)
41562306a36Sopenharmony_ci		ip_len = udp_len + sizeof(*ip6h);
41662306a36Sopenharmony_ci	else
41762306a36Sopenharmony_ci		ip_len = udp_len + sizeof(*iph);
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	total_len = ip_len + LL_RESERVED_SPACE(np->dev);
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	skb = find_skb(np, total_len + np->dev->needed_tailroom,
42262306a36Sopenharmony_ci		       total_len - len);
42362306a36Sopenharmony_ci	if (!skb)
42462306a36Sopenharmony_ci		return;
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	skb_copy_to_linear_data(skb, msg, len);
42762306a36Sopenharmony_ci	skb_put(skb, len);
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	skb_push(skb, sizeof(*udph));
43062306a36Sopenharmony_ci	skb_reset_transport_header(skb);
43162306a36Sopenharmony_ci	udph = udp_hdr(skb);
43262306a36Sopenharmony_ci	udph->source = htons(np->local_port);
43362306a36Sopenharmony_ci	udph->dest = htons(np->remote_port);
43462306a36Sopenharmony_ci	udph->len = htons(udp_len);
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	if (np->ipv6) {
43762306a36Sopenharmony_ci		udph->check = 0;
43862306a36Sopenharmony_ci		udph->check = csum_ipv6_magic(&np->local_ip.in6,
43962306a36Sopenharmony_ci					      &np->remote_ip.in6,
44062306a36Sopenharmony_ci					      udp_len, IPPROTO_UDP,
44162306a36Sopenharmony_ci					      csum_partial(udph, udp_len, 0));
44262306a36Sopenharmony_ci		if (udph->check == 0)
44362306a36Sopenharmony_ci			udph->check = CSUM_MANGLED_0;
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci		skb_push(skb, sizeof(*ip6h));
44662306a36Sopenharmony_ci		skb_reset_network_header(skb);
44762306a36Sopenharmony_ci		ip6h = ipv6_hdr(skb);
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci		/* ip6h->version = 6; ip6h->priority = 0; */
45062306a36Sopenharmony_ci		*(unsigned char *)ip6h = 0x60;
45162306a36Sopenharmony_ci		ip6h->flow_lbl[0] = 0;
45262306a36Sopenharmony_ci		ip6h->flow_lbl[1] = 0;
45362306a36Sopenharmony_ci		ip6h->flow_lbl[2] = 0;
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci		ip6h->payload_len = htons(sizeof(struct udphdr) + len);
45662306a36Sopenharmony_ci		ip6h->nexthdr = IPPROTO_UDP;
45762306a36Sopenharmony_ci		ip6h->hop_limit = 32;
45862306a36Sopenharmony_ci		ip6h->saddr = np->local_ip.in6;
45962306a36Sopenharmony_ci		ip6h->daddr = np->remote_ip.in6;
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci		eth = skb_push(skb, ETH_HLEN);
46262306a36Sopenharmony_ci		skb_reset_mac_header(skb);
46362306a36Sopenharmony_ci		skb->protocol = eth->h_proto = htons(ETH_P_IPV6);
46462306a36Sopenharmony_ci	} else {
46562306a36Sopenharmony_ci		udph->check = 0;
46662306a36Sopenharmony_ci		udph->check = csum_tcpudp_magic(np->local_ip.ip,
46762306a36Sopenharmony_ci						np->remote_ip.ip,
46862306a36Sopenharmony_ci						udp_len, IPPROTO_UDP,
46962306a36Sopenharmony_ci						csum_partial(udph, udp_len, 0));
47062306a36Sopenharmony_ci		if (udph->check == 0)
47162306a36Sopenharmony_ci			udph->check = CSUM_MANGLED_0;
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci		skb_push(skb, sizeof(*iph));
47462306a36Sopenharmony_ci		skb_reset_network_header(skb);
47562306a36Sopenharmony_ci		iph = ip_hdr(skb);
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci		/* iph->version = 4; iph->ihl = 5; */
47862306a36Sopenharmony_ci		*(unsigned char *)iph = 0x45;
47962306a36Sopenharmony_ci		iph->tos      = 0;
48062306a36Sopenharmony_ci		put_unaligned(htons(ip_len), &(iph->tot_len));
48162306a36Sopenharmony_ci		iph->id       = htons(atomic_inc_return(&ip_ident));
48262306a36Sopenharmony_ci		iph->frag_off = 0;
48362306a36Sopenharmony_ci		iph->ttl      = 64;
48462306a36Sopenharmony_ci		iph->protocol = IPPROTO_UDP;
48562306a36Sopenharmony_ci		iph->check    = 0;
48662306a36Sopenharmony_ci		put_unaligned(np->local_ip.ip, &(iph->saddr));
48762306a36Sopenharmony_ci		put_unaligned(np->remote_ip.ip, &(iph->daddr));
48862306a36Sopenharmony_ci		iph->check    = ip_fast_csum((unsigned char *)iph, iph->ihl);
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci		eth = skb_push(skb, ETH_HLEN);
49162306a36Sopenharmony_ci		skb_reset_mac_header(skb);
49262306a36Sopenharmony_ci		skb->protocol = eth->h_proto = htons(ETH_P_IP);
49362306a36Sopenharmony_ci	}
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci	ether_addr_copy(eth->h_source, np->dev->dev_addr);
49662306a36Sopenharmony_ci	ether_addr_copy(eth->h_dest, np->remote_mac);
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	skb->dev = np->dev;
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci	netpoll_send_skb(np, skb);
50162306a36Sopenharmony_ci}
50262306a36Sopenharmony_ciEXPORT_SYMBOL(netpoll_send_udp);
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_civoid netpoll_print_options(struct netpoll *np)
50562306a36Sopenharmony_ci{
50662306a36Sopenharmony_ci	np_info(np, "local port %d\n", np->local_port);
50762306a36Sopenharmony_ci	if (np->ipv6)
50862306a36Sopenharmony_ci		np_info(np, "local IPv6 address %pI6c\n", &np->local_ip.in6);
50962306a36Sopenharmony_ci	else
51062306a36Sopenharmony_ci		np_info(np, "local IPv4 address %pI4\n", &np->local_ip.ip);
51162306a36Sopenharmony_ci	np_info(np, "interface '%s'\n", np->dev_name);
51262306a36Sopenharmony_ci	np_info(np, "remote port %d\n", np->remote_port);
51362306a36Sopenharmony_ci	if (np->ipv6)
51462306a36Sopenharmony_ci		np_info(np, "remote IPv6 address %pI6c\n", &np->remote_ip.in6);
51562306a36Sopenharmony_ci	else
51662306a36Sopenharmony_ci		np_info(np, "remote IPv4 address %pI4\n", &np->remote_ip.ip);
51762306a36Sopenharmony_ci	np_info(np, "remote ethernet address %pM\n", np->remote_mac);
51862306a36Sopenharmony_ci}
51962306a36Sopenharmony_ciEXPORT_SYMBOL(netpoll_print_options);
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_cistatic int netpoll_parse_ip_addr(const char *str, union inet_addr *addr)
52262306a36Sopenharmony_ci{
52362306a36Sopenharmony_ci	const char *end;
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	if (!strchr(str, ':') &&
52662306a36Sopenharmony_ci	    in4_pton(str, -1, (void *)addr, -1, &end) > 0) {
52762306a36Sopenharmony_ci		if (!*end)
52862306a36Sopenharmony_ci			return 0;
52962306a36Sopenharmony_ci	}
53062306a36Sopenharmony_ci	if (in6_pton(str, -1, addr->in6.s6_addr, -1, &end) > 0) {
53162306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
53262306a36Sopenharmony_ci		if (!*end)
53362306a36Sopenharmony_ci			return 1;
53462306a36Sopenharmony_ci#else
53562306a36Sopenharmony_ci		return -1;
53662306a36Sopenharmony_ci#endif
53762306a36Sopenharmony_ci	}
53862306a36Sopenharmony_ci	return -1;
53962306a36Sopenharmony_ci}
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ciint netpoll_parse_options(struct netpoll *np, char *opt)
54262306a36Sopenharmony_ci{
54362306a36Sopenharmony_ci	char *cur=opt, *delim;
54462306a36Sopenharmony_ci	int ipv6;
54562306a36Sopenharmony_ci	bool ipversion_set = false;
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci	if (*cur != '@') {
54862306a36Sopenharmony_ci		if ((delim = strchr(cur, '@')) == NULL)
54962306a36Sopenharmony_ci			goto parse_failed;
55062306a36Sopenharmony_ci		*delim = 0;
55162306a36Sopenharmony_ci		if (kstrtou16(cur, 10, &np->local_port))
55262306a36Sopenharmony_ci			goto parse_failed;
55362306a36Sopenharmony_ci		cur = delim;
55462306a36Sopenharmony_ci	}
55562306a36Sopenharmony_ci	cur++;
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci	if (*cur != '/') {
55862306a36Sopenharmony_ci		ipversion_set = true;
55962306a36Sopenharmony_ci		if ((delim = strchr(cur, '/')) == NULL)
56062306a36Sopenharmony_ci			goto parse_failed;
56162306a36Sopenharmony_ci		*delim = 0;
56262306a36Sopenharmony_ci		ipv6 = netpoll_parse_ip_addr(cur, &np->local_ip);
56362306a36Sopenharmony_ci		if (ipv6 < 0)
56462306a36Sopenharmony_ci			goto parse_failed;
56562306a36Sopenharmony_ci		else
56662306a36Sopenharmony_ci			np->ipv6 = (bool)ipv6;
56762306a36Sopenharmony_ci		cur = delim;
56862306a36Sopenharmony_ci	}
56962306a36Sopenharmony_ci	cur++;
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci	if (*cur != ',') {
57262306a36Sopenharmony_ci		/* parse out dev name */
57362306a36Sopenharmony_ci		if ((delim = strchr(cur, ',')) == NULL)
57462306a36Sopenharmony_ci			goto parse_failed;
57562306a36Sopenharmony_ci		*delim = 0;
57662306a36Sopenharmony_ci		strscpy(np->dev_name, cur, sizeof(np->dev_name));
57762306a36Sopenharmony_ci		cur = delim;
57862306a36Sopenharmony_ci	}
57962306a36Sopenharmony_ci	cur++;
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci	if (*cur != '@') {
58262306a36Sopenharmony_ci		/* dst port */
58362306a36Sopenharmony_ci		if ((delim = strchr(cur, '@')) == NULL)
58462306a36Sopenharmony_ci			goto parse_failed;
58562306a36Sopenharmony_ci		*delim = 0;
58662306a36Sopenharmony_ci		if (*cur == ' ' || *cur == '\t')
58762306a36Sopenharmony_ci			np_info(np, "warning: whitespace is not allowed\n");
58862306a36Sopenharmony_ci		if (kstrtou16(cur, 10, &np->remote_port))
58962306a36Sopenharmony_ci			goto parse_failed;
59062306a36Sopenharmony_ci		cur = delim;
59162306a36Sopenharmony_ci	}
59262306a36Sopenharmony_ci	cur++;
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci	/* dst ip */
59562306a36Sopenharmony_ci	if ((delim = strchr(cur, '/')) == NULL)
59662306a36Sopenharmony_ci		goto parse_failed;
59762306a36Sopenharmony_ci	*delim = 0;
59862306a36Sopenharmony_ci	ipv6 = netpoll_parse_ip_addr(cur, &np->remote_ip);
59962306a36Sopenharmony_ci	if (ipv6 < 0)
60062306a36Sopenharmony_ci		goto parse_failed;
60162306a36Sopenharmony_ci	else if (ipversion_set && np->ipv6 != (bool)ipv6)
60262306a36Sopenharmony_ci		goto parse_failed;
60362306a36Sopenharmony_ci	else
60462306a36Sopenharmony_ci		np->ipv6 = (bool)ipv6;
60562306a36Sopenharmony_ci	cur = delim + 1;
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci	if (*cur != 0) {
60862306a36Sopenharmony_ci		/* MAC address */
60962306a36Sopenharmony_ci		if (!mac_pton(cur, np->remote_mac))
61062306a36Sopenharmony_ci			goto parse_failed;
61162306a36Sopenharmony_ci	}
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci	netpoll_print_options(np);
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci	return 0;
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci parse_failed:
61862306a36Sopenharmony_ci	np_info(np, "couldn't parse config at '%s'!\n", cur);
61962306a36Sopenharmony_ci	return -1;
62062306a36Sopenharmony_ci}
62162306a36Sopenharmony_ciEXPORT_SYMBOL(netpoll_parse_options);
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ciint __netpoll_setup(struct netpoll *np, struct net_device *ndev)
62462306a36Sopenharmony_ci{
62562306a36Sopenharmony_ci	struct netpoll_info *npinfo;
62662306a36Sopenharmony_ci	const struct net_device_ops *ops;
62762306a36Sopenharmony_ci	int err;
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci	np->dev = ndev;
63062306a36Sopenharmony_ci	strscpy(np->dev_name, ndev->name, IFNAMSIZ);
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci	if (ndev->priv_flags & IFF_DISABLE_NETPOLL) {
63362306a36Sopenharmony_ci		np_err(np, "%s doesn't support polling, aborting\n",
63462306a36Sopenharmony_ci		       np->dev_name);
63562306a36Sopenharmony_ci		err = -ENOTSUPP;
63662306a36Sopenharmony_ci		goto out;
63762306a36Sopenharmony_ci	}
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci	if (!ndev->npinfo) {
64062306a36Sopenharmony_ci		npinfo = kmalloc(sizeof(*npinfo), GFP_KERNEL);
64162306a36Sopenharmony_ci		if (!npinfo) {
64262306a36Sopenharmony_ci			err = -ENOMEM;
64362306a36Sopenharmony_ci			goto out;
64462306a36Sopenharmony_ci		}
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci		sema_init(&npinfo->dev_lock, 1);
64762306a36Sopenharmony_ci		skb_queue_head_init(&npinfo->txq);
64862306a36Sopenharmony_ci		INIT_DELAYED_WORK(&npinfo->tx_work, queue_process);
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci		refcount_set(&npinfo->refcnt, 1);
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci		ops = np->dev->netdev_ops;
65362306a36Sopenharmony_ci		if (ops->ndo_netpoll_setup) {
65462306a36Sopenharmony_ci			err = ops->ndo_netpoll_setup(ndev, npinfo);
65562306a36Sopenharmony_ci			if (err)
65662306a36Sopenharmony_ci				goto free_npinfo;
65762306a36Sopenharmony_ci		}
65862306a36Sopenharmony_ci	} else {
65962306a36Sopenharmony_ci		npinfo = rtnl_dereference(ndev->npinfo);
66062306a36Sopenharmony_ci		refcount_inc(&npinfo->refcnt);
66162306a36Sopenharmony_ci	}
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ci	npinfo->netpoll = np;
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci	/* last thing to do is link it to the net device structure */
66662306a36Sopenharmony_ci	rcu_assign_pointer(ndev->npinfo, npinfo);
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci	return 0;
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_cifree_npinfo:
67162306a36Sopenharmony_ci	kfree(npinfo);
67262306a36Sopenharmony_ciout:
67362306a36Sopenharmony_ci	return err;
67462306a36Sopenharmony_ci}
67562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(__netpoll_setup);
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ciint netpoll_setup(struct netpoll *np)
67862306a36Sopenharmony_ci{
67962306a36Sopenharmony_ci	struct net_device *ndev = NULL;
68062306a36Sopenharmony_ci	struct in_device *in_dev;
68162306a36Sopenharmony_ci	int err;
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_ci	rtnl_lock();
68462306a36Sopenharmony_ci	if (np->dev_name[0]) {
68562306a36Sopenharmony_ci		struct net *net = current->nsproxy->net_ns;
68662306a36Sopenharmony_ci		ndev = __dev_get_by_name(net, np->dev_name);
68762306a36Sopenharmony_ci	}
68862306a36Sopenharmony_ci	if (!ndev) {
68962306a36Sopenharmony_ci		np_err(np, "%s doesn't exist, aborting\n", np->dev_name);
69062306a36Sopenharmony_ci		err = -ENODEV;
69162306a36Sopenharmony_ci		goto unlock;
69262306a36Sopenharmony_ci	}
69362306a36Sopenharmony_ci	netdev_hold(ndev, &np->dev_tracker, GFP_KERNEL);
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci	if (netdev_master_upper_dev_get(ndev)) {
69662306a36Sopenharmony_ci		np_err(np, "%s is a slave device, aborting\n", np->dev_name);
69762306a36Sopenharmony_ci		err = -EBUSY;
69862306a36Sopenharmony_ci		goto put;
69962306a36Sopenharmony_ci	}
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_ci	if (!netif_running(ndev)) {
70262306a36Sopenharmony_ci		unsigned long atmost;
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci		np_info(np, "device %s not up yet, forcing it\n", np->dev_name);
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci		err = dev_open(ndev, NULL);
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_ci		if (err) {
70962306a36Sopenharmony_ci			np_err(np, "failed to open %s\n", ndev->name);
71062306a36Sopenharmony_ci			goto put;
71162306a36Sopenharmony_ci		}
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci		rtnl_unlock();
71462306a36Sopenharmony_ci		atmost = jiffies + carrier_timeout * HZ;
71562306a36Sopenharmony_ci		while (!netif_carrier_ok(ndev)) {
71662306a36Sopenharmony_ci			if (time_after(jiffies, atmost)) {
71762306a36Sopenharmony_ci				np_notice(np, "timeout waiting for carrier\n");
71862306a36Sopenharmony_ci				break;
71962306a36Sopenharmony_ci			}
72062306a36Sopenharmony_ci			msleep(1);
72162306a36Sopenharmony_ci		}
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci		rtnl_lock();
72462306a36Sopenharmony_ci	}
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci	if (!np->local_ip.ip) {
72762306a36Sopenharmony_ci		if (!np->ipv6) {
72862306a36Sopenharmony_ci			const struct in_ifaddr *ifa;
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci			in_dev = __in_dev_get_rtnl(ndev);
73162306a36Sopenharmony_ci			if (!in_dev)
73262306a36Sopenharmony_ci				goto put_noaddr;
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_ci			ifa = rtnl_dereference(in_dev->ifa_list);
73562306a36Sopenharmony_ci			if (!ifa) {
73662306a36Sopenharmony_ciput_noaddr:
73762306a36Sopenharmony_ci				np_err(np, "no IP address for %s, aborting\n",
73862306a36Sopenharmony_ci				       np->dev_name);
73962306a36Sopenharmony_ci				err = -EDESTADDRREQ;
74062306a36Sopenharmony_ci				goto put;
74162306a36Sopenharmony_ci			}
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ci			np->local_ip.ip = ifa->ifa_local;
74462306a36Sopenharmony_ci			np_info(np, "local IP %pI4\n", &np->local_ip.ip);
74562306a36Sopenharmony_ci		} else {
74662306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
74762306a36Sopenharmony_ci			struct inet6_dev *idev;
74862306a36Sopenharmony_ci
74962306a36Sopenharmony_ci			err = -EDESTADDRREQ;
75062306a36Sopenharmony_ci			idev = __in6_dev_get(ndev);
75162306a36Sopenharmony_ci			if (idev) {
75262306a36Sopenharmony_ci				struct inet6_ifaddr *ifp;
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci				read_lock_bh(&idev->lock);
75562306a36Sopenharmony_ci				list_for_each_entry(ifp, &idev->addr_list, if_list) {
75662306a36Sopenharmony_ci					if (!!(ipv6_addr_type(&ifp->addr) & IPV6_ADDR_LINKLOCAL) !=
75762306a36Sopenharmony_ci					    !!(ipv6_addr_type(&np->remote_ip.in6) & IPV6_ADDR_LINKLOCAL))
75862306a36Sopenharmony_ci						continue;
75962306a36Sopenharmony_ci					np->local_ip.in6 = ifp->addr;
76062306a36Sopenharmony_ci					err = 0;
76162306a36Sopenharmony_ci					break;
76262306a36Sopenharmony_ci				}
76362306a36Sopenharmony_ci				read_unlock_bh(&idev->lock);
76462306a36Sopenharmony_ci			}
76562306a36Sopenharmony_ci			if (err) {
76662306a36Sopenharmony_ci				np_err(np, "no IPv6 address for %s, aborting\n",
76762306a36Sopenharmony_ci				       np->dev_name);
76862306a36Sopenharmony_ci				goto put;
76962306a36Sopenharmony_ci			} else
77062306a36Sopenharmony_ci				np_info(np, "local IPv6 %pI6c\n", &np->local_ip.in6);
77162306a36Sopenharmony_ci#else
77262306a36Sopenharmony_ci			np_err(np, "IPv6 is not supported %s, aborting\n",
77362306a36Sopenharmony_ci			       np->dev_name);
77462306a36Sopenharmony_ci			err = -EINVAL;
77562306a36Sopenharmony_ci			goto put;
77662306a36Sopenharmony_ci#endif
77762306a36Sopenharmony_ci		}
77862306a36Sopenharmony_ci	}
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_ci	/* fill up the skb queue */
78162306a36Sopenharmony_ci	refill_skbs();
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_ci	err = __netpoll_setup(np, ndev);
78462306a36Sopenharmony_ci	if (err)
78562306a36Sopenharmony_ci		goto put;
78662306a36Sopenharmony_ci	rtnl_unlock();
78762306a36Sopenharmony_ci	return 0;
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ciput:
79062306a36Sopenharmony_ci	netdev_put(ndev, &np->dev_tracker);
79162306a36Sopenharmony_ciunlock:
79262306a36Sopenharmony_ci	rtnl_unlock();
79362306a36Sopenharmony_ci	return err;
79462306a36Sopenharmony_ci}
79562306a36Sopenharmony_ciEXPORT_SYMBOL(netpoll_setup);
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_cistatic int __init netpoll_init(void)
79862306a36Sopenharmony_ci{
79962306a36Sopenharmony_ci	skb_queue_head_init(&skb_pool);
80062306a36Sopenharmony_ci	return 0;
80162306a36Sopenharmony_ci}
80262306a36Sopenharmony_cicore_initcall(netpoll_init);
80362306a36Sopenharmony_ci
80462306a36Sopenharmony_cistatic void rcu_cleanup_netpoll_info(struct rcu_head *rcu_head)
80562306a36Sopenharmony_ci{
80662306a36Sopenharmony_ci	struct netpoll_info *npinfo =
80762306a36Sopenharmony_ci			container_of(rcu_head, struct netpoll_info, rcu);
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci	skb_queue_purge(&npinfo->txq);
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ci	/* we can't call cancel_delayed_work_sync here, as we are in softirq */
81262306a36Sopenharmony_ci	cancel_delayed_work(&npinfo->tx_work);
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci	/* clean after last, unfinished work */
81562306a36Sopenharmony_ci	__skb_queue_purge(&npinfo->txq);
81662306a36Sopenharmony_ci	/* now cancel it again */
81762306a36Sopenharmony_ci	cancel_delayed_work(&npinfo->tx_work);
81862306a36Sopenharmony_ci	kfree(npinfo);
81962306a36Sopenharmony_ci}
82062306a36Sopenharmony_ci
82162306a36Sopenharmony_civoid __netpoll_cleanup(struct netpoll *np)
82262306a36Sopenharmony_ci{
82362306a36Sopenharmony_ci	struct netpoll_info *npinfo;
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_ci	npinfo = rtnl_dereference(np->dev->npinfo);
82662306a36Sopenharmony_ci	if (!npinfo)
82762306a36Sopenharmony_ci		return;
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci	synchronize_srcu(&netpoll_srcu);
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci	if (refcount_dec_and_test(&npinfo->refcnt)) {
83262306a36Sopenharmony_ci		const struct net_device_ops *ops;
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ci		ops = np->dev->netdev_ops;
83562306a36Sopenharmony_ci		if (ops->ndo_netpoll_cleanup)
83662306a36Sopenharmony_ci			ops->ndo_netpoll_cleanup(np->dev);
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_ci		RCU_INIT_POINTER(np->dev->npinfo, NULL);
83962306a36Sopenharmony_ci		call_rcu(&npinfo->rcu, rcu_cleanup_netpoll_info);
84062306a36Sopenharmony_ci	} else
84162306a36Sopenharmony_ci		RCU_INIT_POINTER(np->dev->npinfo, NULL);
84262306a36Sopenharmony_ci}
84362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(__netpoll_cleanup);
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_civoid __netpoll_free(struct netpoll *np)
84662306a36Sopenharmony_ci{
84762306a36Sopenharmony_ci	ASSERT_RTNL();
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_ci	/* Wait for transmitting packets to finish before freeing. */
85062306a36Sopenharmony_ci	synchronize_rcu();
85162306a36Sopenharmony_ci	__netpoll_cleanup(np);
85262306a36Sopenharmony_ci	kfree(np);
85362306a36Sopenharmony_ci}
85462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(__netpoll_free);
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_civoid netpoll_cleanup(struct netpoll *np)
85762306a36Sopenharmony_ci{
85862306a36Sopenharmony_ci	rtnl_lock();
85962306a36Sopenharmony_ci	if (!np->dev)
86062306a36Sopenharmony_ci		goto out;
86162306a36Sopenharmony_ci	__netpoll_cleanup(np);
86262306a36Sopenharmony_ci	netdev_put(np->dev, &np->dev_tracker);
86362306a36Sopenharmony_ci	np->dev = NULL;
86462306a36Sopenharmony_ciout:
86562306a36Sopenharmony_ci	rtnl_unlock();
86662306a36Sopenharmony_ci}
86762306a36Sopenharmony_ciEXPORT_SYMBOL(netpoll_cleanup);
868