18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Common framework for low-level network console, dump, and debugger code
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Sep 8 2003  Matt Mackall <mpm@selenic.com>
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * based on the netconsole code from:
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * Copyright (C) 2001  Ingo Molnar <mingo@redhat.com>
108c2ecf20Sopenharmony_ci * Copyright (C) 2002  Red Hat, Inc.
118c2ecf20Sopenharmony_ci */
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#include <linux/moduleparam.h>
168c2ecf20Sopenharmony_ci#include <linux/kernel.h>
178c2ecf20Sopenharmony_ci#include <linux/netdevice.h>
188c2ecf20Sopenharmony_ci#include <linux/etherdevice.h>
198c2ecf20Sopenharmony_ci#include <linux/string.h>
208c2ecf20Sopenharmony_ci#include <linux/if_arp.h>
218c2ecf20Sopenharmony_ci#include <linux/inetdevice.h>
228c2ecf20Sopenharmony_ci#include <linux/inet.h>
238c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
248c2ecf20Sopenharmony_ci#include <linux/netpoll.h>
258c2ecf20Sopenharmony_ci#include <linux/sched.h>
268c2ecf20Sopenharmony_ci#include <linux/delay.h>
278c2ecf20Sopenharmony_ci#include <linux/rcupdate.h>
288c2ecf20Sopenharmony_ci#include <linux/workqueue.h>
298c2ecf20Sopenharmony_ci#include <linux/slab.h>
308c2ecf20Sopenharmony_ci#include <linux/export.h>
318c2ecf20Sopenharmony_ci#include <linux/if_vlan.h>
328c2ecf20Sopenharmony_ci#include <net/dsa.h>
338c2ecf20Sopenharmony_ci#include <net/tcp.h>
348c2ecf20Sopenharmony_ci#include <net/udp.h>
358c2ecf20Sopenharmony_ci#include <net/addrconf.h>
368c2ecf20Sopenharmony_ci#include <net/ndisc.h>
378c2ecf20Sopenharmony_ci#include <net/ip6_checksum.h>
388c2ecf20Sopenharmony_ci#include <asm/unaligned.h>
398c2ecf20Sopenharmony_ci#include <trace/events/napi.h>
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci/*
428c2ecf20Sopenharmony_ci * We maintain a small pool of fully-sized skbs, to make sure the
438c2ecf20Sopenharmony_ci * message gets out even in extreme OOM situations.
448c2ecf20Sopenharmony_ci */
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci#define MAX_UDP_CHUNK 1460
478c2ecf20Sopenharmony_ci#define MAX_SKBS 32
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_cistatic struct sk_buff_head skb_pool;
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ciDEFINE_STATIC_SRCU(netpoll_srcu);
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci#define USEC_PER_POLL	50
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci#define MAX_SKB_SIZE							\
568c2ecf20Sopenharmony_ci	(sizeof(struct ethhdr) +					\
578c2ecf20Sopenharmony_ci	 sizeof(struct iphdr) +						\
588c2ecf20Sopenharmony_ci	 sizeof(struct udphdr) +					\
598c2ecf20Sopenharmony_ci	 MAX_UDP_CHUNK)
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_cistatic void zap_completion_queue(void);
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_cistatic unsigned int carrier_timeout = 4;
648c2ecf20Sopenharmony_cimodule_param(carrier_timeout, uint, 0644);
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci#define np_info(np, fmt, ...)				\
678c2ecf20Sopenharmony_ci	pr_info("%s: " fmt, np->name, ##__VA_ARGS__)
688c2ecf20Sopenharmony_ci#define np_err(np, fmt, ...)				\
698c2ecf20Sopenharmony_ci	pr_err("%s: " fmt, np->name, ##__VA_ARGS__)
708c2ecf20Sopenharmony_ci#define np_notice(np, fmt, ...)				\
718c2ecf20Sopenharmony_ci	pr_notice("%s: " fmt, np->name, ##__VA_ARGS__)
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_cistatic netdev_tx_t netpoll_start_xmit(struct sk_buff *skb,
748c2ecf20Sopenharmony_ci				      struct net_device *dev,
758c2ecf20Sopenharmony_ci				      struct netdev_queue *txq)
768c2ecf20Sopenharmony_ci{
778c2ecf20Sopenharmony_ci	netdev_tx_t status = NETDEV_TX_OK;
788c2ecf20Sopenharmony_ci	netdev_features_t features;
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	features = netif_skb_features(skb);
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	if (skb_vlan_tag_present(skb) &&
838c2ecf20Sopenharmony_ci	    !vlan_hw_offload_capable(features, skb->vlan_proto)) {
848c2ecf20Sopenharmony_ci		skb = __vlan_hwaccel_push_inside(skb);
858c2ecf20Sopenharmony_ci		if (unlikely(!skb)) {
868c2ecf20Sopenharmony_ci			/* This is actually a packet drop, but we
878c2ecf20Sopenharmony_ci			 * don't want the code that calls this
888c2ecf20Sopenharmony_ci			 * function to try and operate on a NULL skb.
898c2ecf20Sopenharmony_ci			 */
908c2ecf20Sopenharmony_ci			goto out;
918c2ecf20Sopenharmony_ci		}
928c2ecf20Sopenharmony_ci	}
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	status = netdev_start_xmit(skb, dev, txq, false);
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ciout:
978c2ecf20Sopenharmony_ci	return status;
988c2ecf20Sopenharmony_ci}
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_cistatic void queue_process(struct work_struct *work)
1018c2ecf20Sopenharmony_ci{
1028c2ecf20Sopenharmony_ci	struct netpoll_info *npinfo =
1038c2ecf20Sopenharmony_ci		container_of(work, struct netpoll_info, tx_work.work);
1048c2ecf20Sopenharmony_ci	struct sk_buff *skb;
1058c2ecf20Sopenharmony_ci	unsigned long flags;
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	while ((skb = skb_dequeue(&npinfo->txq))) {
1088c2ecf20Sopenharmony_ci		struct net_device *dev = skb->dev;
1098c2ecf20Sopenharmony_ci		struct netdev_queue *txq;
1108c2ecf20Sopenharmony_ci		unsigned int q_index;
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci		if (!netif_device_present(dev) || !netif_running(dev)) {
1138c2ecf20Sopenharmony_ci			kfree_skb(skb);
1148c2ecf20Sopenharmony_ci			continue;
1158c2ecf20Sopenharmony_ci		}
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci		local_irq_save(flags);
1188c2ecf20Sopenharmony_ci		/* check if skb->queue_mapping is still valid */
1198c2ecf20Sopenharmony_ci		q_index = skb_get_queue_mapping(skb);
1208c2ecf20Sopenharmony_ci		if (unlikely(q_index >= dev->real_num_tx_queues)) {
1218c2ecf20Sopenharmony_ci			q_index = q_index % dev->real_num_tx_queues;
1228c2ecf20Sopenharmony_ci			skb_set_queue_mapping(skb, q_index);
1238c2ecf20Sopenharmony_ci		}
1248c2ecf20Sopenharmony_ci		txq = netdev_get_tx_queue(dev, q_index);
1258c2ecf20Sopenharmony_ci		HARD_TX_LOCK(dev, txq, smp_processor_id());
1268c2ecf20Sopenharmony_ci		if (netif_xmit_frozen_or_stopped(txq) ||
1278c2ecf20Sopenharmony_ci		    !dev_xmit_complete(netpoll_start_xmit(skb, dev, txq))) {
1288c2ecf20Sopenharmony_ci			skb_queue_head(&npinfo->txq, skb);
1298c2ecf20Sopenharmony_ci			HARD_TX_UNLOCK(dev, txq);
1308c2ecf20Sopenharmony_ci			local_irq_restore(flags);
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci			schedule_delayed_work(&npinfo->tx_work, HZ/10);
1338c2ecf20Sopenharmony_ci			return;
1348c2ecf20Sopenharmony_ci		}
1358c2ecf20Sopenharmony_ci		HARD_TX_UNLOCK(dev, txq);
1368c2ecf20Sopenharmony_ci		local_irq_restore(flags);
1378c2ecf20Sopenharmony_ci	}
1388c2ecf20Sopenharmony_ci}
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_cistatic int netif_local_xmit_active(struct net_device *dev)
1418c2ecf20Sopenharmony_ci{
1428c2ecf20Sopenharmony_ci	int i;
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	for (i = 0; i < dev->num_tx_queues; i++) {
1458c2ecf20Sopenharmony_ci		struct netdev_queue *txq = netdev_get_tx_queue(dev, i);
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci		if (READ_ONCE(txq->xmit_lock_owner) == smp_processor_id())
1488c2ecf20Sopenharmony_ci			return 1;
1498c2ecf20Sopenharmony_ci	}
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	return 0;
1528c2ecf20Sopenharmony_ci}
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_cistatic void poll_one_napi(struct napi_struct *napi)
1558c2ecf20Sopenharmony_ci{
1568c2ecf20Sopenharmony_ci	int work;
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	/* If we set this bit but see that it has already been set,
1598c2ecf20Sopenharmony_ci	 * that indicates that napi has been disabled and we need
1608c2ecf20Sopenharmony_ci	 * to abort this operation
1618c2ecf20Sopenharmony_ci	 */
1628c2ecf20Sopenharmony_ci	if (test_and_set_bit(NAPI_STATE_NPSVC, &napi->state))
1638c2ecf20Sopenharmony_ci		return;
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	/* We explicilty pass the polling call a budget of 0 to
1668c2ecf20Sopenharmony_ci	 * indicate that we are clearing the Tx path only.
1678c2ecf20Sopenharmony_ci	 */
1688c2ecf20Sopenharmony_ci	work = napi->poll(napi, 0);
1698c2ecf20Sopenharmony_ci	WARN_ONCE(work, "%pS exceeded budget in poll\n", napi->poll);
1708c2ecf20Sopenharmony_ci	trace_napi_poll(napi, work, 0);
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	clear_bit(NAPI_STATE_NPSVC, &napi->state);
1738c2ecf20Sopenharmony_ci}
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_cistatic void poll_napi(struct net_device *dev)
1768c2ecf20Sopenharmony_ci{
1778c2ecf20Sopenharmony_ci	struct napi_struct *napi;
1788c2ecf20Sopenharmony_ci	int cpu = smp_processor_id();
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci	list_for_each_entry_rcu(napi, &dev->napi_list, dev_list) {
1818c2ecf20Sopenharmony_ci		if (cmpxchg(&napi->poll_owner, -1, cpu) == -1) {
1828c2ecf20Sopenharmony_ci			poll_one_napi(napi);
1838c2ecf20Sopenharmony_ci			smp_store_release(&napi->poll_owner, -1);
1848c2ecf20Sopenharmony_ci		}
1858c2ecf20Sopenharmony_ci	}
1868c2ecf20Sopenharmony_ci}
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_civoid netpoll_poll_dev(struct net_device *dev)
1898c2ecf20Sopenharmony_ci{
1908c2ecf20Sopenharmony_ci	struct netpoll_info *ni = rcu_dereference_bh(dev->npinfo);
1918c2ecf20Sopenharmony_ci	const struct net_device_ops *ops;
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	/* Don't do any rx activity if the dev_lock mutex is held
1948c2ecf20Sopenharmony_ci	 * the dev_open/close paths use this to block netpoll activity
1958c2ecf20Sopenharmony_ci	 * while changing device state
1968c2ecf20Sopenharmony_ci	 */
1978c2ecf20Sopenharmony_ci	if (!ni || down_trylock(&ni->dev_lock))
1988c2ecf20Sopenharmony_ci		return;
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	/* Some drivers will take the same locks in poll and xmit,
2018c2ecf20Sopenharmony_ci	 * we can't poll if local CPU is already in xmit.
2028c2ecf20Sopenharmony_ci	 */
2038c2ecf20Sopenharmony_ci	if (!netif_running(dev) || netif_local_xmit_active(dev)) {
2048c2ecf20Sopenharmony_ci		up(&ni->dev_lock);
2058c2ecf20Sopenharmony_ci		return;
2068c2ecf20Sopenharmony_ci	}
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	ops = dev->netdev_ops;
2098c2ecf20Sopenharmony_ci	if (ops->ndo_poll_controller)
2108c2ecf20Sopenharmony_ci		ops->ndo_poll_controller(dev);
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	poll_napi(dev);
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	up(&ni->dev_lock);
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	zap_completion_queue();
2178c2ecf20Sopenharmony_ci}
2188c2ecf20Sopenharmony_ciEXPORT_SYMBOL(netpoll_poll_dev);
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_civoid netpoll_poll_disable(struct net_device *dev)
2218c2ecf20Sopenharmony_ci{
2228c2ecf20Sopenharmony_ci	struct netpoll_info *ni;
2238c2ecf20Sopenharmony_ci	int idx;
2248c2ecf20Sopenharmony_ci	might_sleep();
2258c2ecf20Sopenharmony_ci	idx = srcu_read_lock(&netpoll_srcu);
2268c2ecf20Sopenharmony_ci	ni = srcu_dereference(dev->npinfo, &netpoll_srcu);
2278c2ecf20Sopenharmony_ci	if (ni)
2288c2ecf20Sopenharmony_ci		down(&ni->dev_lock);
2298c2ecf20Sopenharmony_ci	srcu_read_unlock(&netpoll_srcu, idx);
2308c2ecf20Sopenharmony_ci}
2318c2ecf20Sopenharmony_ciEXPORT_SYMBOL(netpoll_poll_disable);
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_civoid netpoll_poll_enable(struct net_device *dev)
2348c2ecf20Sopenharmony_ci{
2358c2ecf20Sopenharmony_ci	struct netpoll_info *ni;
2368c2ecf20Sopenharmony_ci	rcu_read_lock();
2378c2ecf20Sopenharmony_ci	ni = rcu_dereference(dev->npinfo);
2388c2ecf20Sopenharmony_ci	if (ni)
2398c2ecf20Sopenharmony_ci		up(&ni->dev_lock);
2408c2ecf20Sopenharmony_ci	rcu_read_unlock();
2418c2ecf20Sopenharmony_ci}
2428c2ecf20Sopenharmony_ciEXPORT_SYMBOL(netpoll_poll_enable);
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_cistatic void refill_skbs(void)
2458c2ecf20Sopenharmony_ci{
2468c2ecf20Sopenharmony_ci	struct sk_buff *skb;
2478c2ecf20Sopenharmony_ci	unsigned long flags;
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	spin_lock_irqsave(&skb_pool.lock, flags);
2508c2ecf20Sopenharmony_ci	while (skb_pool.qlen < MAX_SKBS) {
2518c2ecf20Sopenharmony_ci		skb = alloc_skb(MAX_SKB_SIZE, GFP_ATOMIC);
2528c2ecf20Sopenharmony_ci		if (!skb)
2538c2ecf20Sopenharmony_ci			break;
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci		__skb_queue_tail(&skb_pool, skb);
2568c2ecf20Sopenharmony_ci	}
2578c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&skb_pool.lock, flags);
2588c2ecf20Sopenharmony_ci}
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_cistatic void zap_completion_queue(void)
2618c2ecf20Sopenharmony_ci{
2628c2ecf20Sopenharmony_ci	unsigned long flags;
2638c2ecf20Sopenharmony_ci	struct softnet_data *sd = &get_cpu_var(softnet_data);
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	if (sd->completion_queue) {
2668c2ecf20Sopenharmony_ci		struct sk_buff *clist;
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci		local_irq_save(flags);
2698c2ecf20Sopenharmony_ci		clist = sd->completion_queue;
2708c2ecf20Sopenharmony_ci		sd->completion_queue = NULL;
2718c2ecf20Sopenharmony_ci		local_irq_restore(flags);
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci		while (clist != NULL) {
2748c2ecf20Sopenharmony_ci			struct sk_buff *skb = clist;
2758c2ecf20Sopenharmony_ci			clist = clist->next;
2768c2ecf20Sopenharmony_ci			if (!skb_irq_freeable(skb)) {
2778c2ecf20Sopenharmony_ci				refcount_set(&skb->users, 1);
2788c2ecf20Sopenharmony_ci				dev_kfree_skb_any(skb); /* put this one back */
2798c2ecf20Sopenharmony_ci			} else {
2808c2ecf20Sopenharmony_ci				__kfree_skb(skb);
2818c2ecf20Sopenharmony_ci			}
2828c2ecf20Sopenharmony_ci		}
2838c2ecf20Sopenharmony_ci	}
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	put_cpu_var(softnet_data);
2868c2ecf20Sopenharmony_ci}
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_cistatic struct sk_buff *find_skb(struct netpoll *np, int len, int reserve)
2898c2ecf20Sopenharmony_ci{
2908c2ecf20Sopenharmony_ci	int count = 0;
2918c2ecf20Sopenharmony_ci	struct sk_buff *skb;
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	zap_completion_queue();
2948c2ecf20Sopenharmony_ci	refill_skbs();
2958c2ecf20Sopenharmony_cirepeat:
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	skb = alloc_skb(len, GFP_ATOMIC);
2988c2ecf20Sopenharmony_ci	if (!skb)
2998c2ecf20Sopenharmony_ci		skb = skb_dequeue(&skb_pool);
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	if (!skb) {
3028c2ecf20Sopenharmony_ci		if (++count < 10) {
3038c2ecf20Sopenharmony_ci			netpoll_poll_dev(np->dev);
3048c2ecf20Sopenharmony_ci			goto repeat;
3058c2ecf20Sopenharmony_ci		}
3068c2ecf20Sopenharmony_ci		return NULL;
3078c2ecf20Sopenharmony_ci	}
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci	refcount_set(&skb->users, 1);
3108c2ecf20Sopenharmony_ci	skb_reserve(skb, reserve);
3118c2ecf20Sopenharmony_ci	return skb;
3128c2ecf20Sopenharmony_ci}
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_cistatic int netpoll_owner_active(struct net_device *dev)
3158c2ecf20Sopenharmony_ci{
3168c2ecf20Sopenharmony_ci	struct napi_struct *napi;
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	list_for_each_entry_rcu(napi, &dev->napi_list, dev_list) {
3198c2ecf20Sopenharmony_ci		if (napi->poll_owner == smp_processor_id())
3208c2ecf20Sopenharmony_ci			return 1;
3218c2ecf20Sopenharmony_ci	}
3228c2ecf20Sopenharmony_ci	return 0;
3238c2ecf20Sopenharmony_ci}
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci/* call with IRQ disabled */
3268c2ecf20Sopenharmony_cistatic netdev_tx_t __netpoll_send_skb(struct netpoll *np, struct sk_buff *skb)
3278c2ecf20Sopenharmony_ci{
3288c2ecf20Sopenharmony_ci	netdev_tx_t status = NETDEV_TX_BUSY;
3298c2ecf20Sopenharmony_ci	struct net_device *dev;
3308c2ecf20Sopenharmony_ci	unsigned long tries;
3318c2ecf20Sopenharmony_ci	/* It is up to the caller to keep npinfo alive. */
3328c2ecf20Sopenharmony_ci	struct netpoll_info *npinfo;
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	lockdep_assert_irqs_disabled();
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci	dev = np->dev;
3378c2ecf20Sopenharmony_ci	npinfo = rcu_dereference_bh(dev->npinfo);
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	if (!npinfo || !netif_running(dev) || !netif_device_present(dev)) {
3408c2ecf20Sopenharmony_ci		dev_kfree_skb_irq(skb);
3418c2ecf20Sopenharmony_ci		return NET_XMIT_DROP;
3428c2ecf20Sopenharmony_ci	}
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci	/* don't get messages out of order, and no recursion */
3458c2ecf20Sopenharmony_ci	if (skb_queue_len(&npinfo->txq) == 0 && !netpoll_owner_active(dev)) {
3468c2ecf20Sopenharmony_ci		struct netdev_queue *txq;
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci		txq = netdev_core_pick_tx(dev, skb, NULL);
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci		/* try until next clock tick */
3518c2ecf20Sopenharmony_ci		for (tries = jiffies_to_usecs(1)/USEC_PER_POLL;
3528c2ecf20Sopenharmony_ci		     tries > 0; --tries) {
3538c2ecf20Sopenharmony_ci			if (HARD_TX_TRYLOCK(dev, txq)) {
3548c2ecf20Sopenharmony_ci				if (!netif_xmit_stopped(txq))
3558c2ecf20Sopenharmony_ci					status = netpoll_start_xmit(skb, dev, txq);
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci				HARD_TX_UNLOCK(dev, txq);
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci				if (dev_xmit_complete(status))
3608c2ecf20Sopenharmony_ci					break;
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci			}
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci			/* tickle device maybe there is some cleanup */
3658c2ecf20Sopenharmony_ci			netpoll_poll_dev(np->dev);
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci			udelay(USEC_PER_POLL);
3688c2ecf20Sopenharmony_ci		}
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci		WARN_ONCE(!irqs_disabled(),
3718c2ecf20Sopenharmony_ci			"netpoll_send_skb_on_dev(): %s enabled interrupts in poll (%pS)\n",
3728c2ecf20Sopenharmony_ci			dev->name, dev->netdev_ops->ndo_start_xmit);
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci	}
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci	if (!dev_xmit_complete(status)) {
3778c2ecf20Sopenharmony_ci		skb_queue_tail(&npinfo->txq, skb);
3788c2ecf20Sopenharmony_ci		schedule_delayed_work(&npinfo->tx_work,0);
3798c2ecf20Sopenharmony_ci	}
3808c2ecf20Sopenharmony_ci	return NETDEV_TX_OK;
3818c2ecf20Sopenharmony_ci}
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_cinetdev_tx_t netpoll_send_skb(struct netpoll *np, struct sk_buff *skb)
3848c2ecf20Sopenharmony_ci{
3858c2ecf20Sopenharmony_ci	unsigned long flags;
3868c2ecf20Sopenharmony_ci	netdev_tx_t ret;
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	if (unlikely(!np)) {
3898c2ecf20Sopenharmony_ci		dev_kfree_skb_irq(skb);
3908c2ecf20Sopenharmony_ci		ret = NET_XMIT_DROP;
3918c2ecf20Sopenharmony_ci	} else {
3928c2ecf20Sopenharmony_ci		local_irq_save(flags);
3938c2ecf20Sopenharmony_ci		ret = __netpoll_send_skb(np, skb);
3948c2ecf20Sopenharmony_ci		local_irq_restore(flags);
3958c2ecf20Sopenharmony_ci	}
3968c2ecf20Sopenharmony_ci	return ret;
3978c2ecf20Sopenharmony_ci}
3988c2ecf20Sopenharmony_ciEXPORT_SYMBOL(netpoll_send_skb);
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_civoid netpoll_send_udp(struct netpoll *np, const char *msg, int len)
4018c2ecf20Sopenharmony_ci{
4028c2ecf20Sopenharmony_ci	int total_len, ip_len, udp_len;
4038c2ecf20Sopenharmony_ci	struct sk_buff *skb;
4048c2ecf20Sopenharmony_ci	struct udphdr *udph;
4058c2ecf20Sopenharmony_ci	struct iphdr *iph;
4068c2ecf20Sopenharmony_ci	struct ethhdr *eth;
4078c2ecf20Sopenharmony_ci	static atomic_t ip_ident;
4088c2ecf20Sopenharmony_ci	struct ipv6hdr *ip6h;
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci	WARN_ON_ONCE(!irqs_disabled());
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	udp_len = len + sizeof(*udph);
4138c2ecf20Sopenharmony_ci	if (np->ipv6)
4148c2ecf20Sopenharmony_ci		ip_len = udp_len + sizeof(*ip6h);
4158c2ecf20Sopenharmony_ci	else
4168c2ecf20Sopenharmony_ci		ip_len = udp_len + sizeof(*iph);
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	total_len = ip_len + LL_RESERVED_SPACE(np->dev);
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci	skb = find_skb(np, total_len + np->dev->needed_tailroom,
4218c2ecf20Sopenharmony_ci		       total_len - len);
4228c2ecf20Sopenharmony_ci	if (!skb)
4238c2ecf20Sopenharmony_ci		return;
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ci	skb_copy_to_linear_data(skb, msg, len);
4268c2ecf20Sopenharmony_ci	skb_put(skb, len);
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	skb_push(skb, sizeof(*udph));
4298c2ecf20Sopenharmony_ci	skb_reset_transport_header(skb);
4308c2ecf20Sopenharmony_ci	udph = udp_hdr(skb);
4318c2ecf20Sopenharmony_ci	udph->source = htons(np->local_port);
4328c2ecf20Sopenharmony_ci	udph->dest = htons(np->remote_port);
4338c2ecf20Sopenharmony_ci	udph->len = htons(udp_len);
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci	if (np->ipv6) {
4368c2ecf20Sopenharmony_ci		udph->check = 0;
4378c2ecf20Sopenharmony_ci		udph->check = csum_ipv6_magic(&np->local_ip.in6,
4388c2ecf20Sopenharmony_ci					      &np->remote_ip.in6,
4398c2ecf20Sopenharmony_ci					      udp_len, IPPROTO_UDP,
4408c2ecf20Sopenharmony_ci					      csum_partial(udph, udp_len, 0));
4418c2ecf20Sopenharmony_ci		if (udph->check == 0)
4428c2ecf20Sopenharmony_ci			udph->check = CSUM_MANGLED_0;
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci		skb_push(skb, sizeof(*ip6h));
4458c2ecf20Sopenharmony_ci		skb_reset_network_header(skb);
4468c2ecf20Sopenharmony_ci		ip6h = ipv6_hdr(skb);
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci		/* ip6h->version = 6; ip6h->priority = 0; */
4498c2ecf20Sopenharmony_ci		put_unaligned(0x60, (unsigned char *)ip6h);
4508c2ecf20Sopenharmony_ci		ip6h->flow_lbl[0] = 0;
4518c2ecf20Sopenharmony_ci		ip6h->flow_lbl[1] = 0;
4528c2ecf20Sopenharmony_ci		ip6h->flow_lbl[2] = 0;
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci		ip6h->payload_len = htons(sizeof(struct udphdr) + len);
4558c2ecf20Sopenharmony_ci		ip6h->nexthdr = IPPROTO_UDP;
4568c2ecf20Sopenharmony_ci		ip6h->hop_limit = 32;
4578c2ecf20Sopenharmony_ci		ip6h->saddr = np->local_ip.in6;
4588c2ecf20Sopenharmony_ci		ip6h->daddr = np->remote_ip.in6;
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci		eth = skb_push(skb, ETH_HLEN);
4618c2ecf20Sopenharmony_ci		skb_reset_mac_header(skb);
4628c2ecf20Sopenharmony_ci		skb->protocol = eth->h_proto = htons(ETH_P_IPV6);
4638c2ecf20Sopenharmony_ci	} else {
4648c2ecf20Sopenharmony_ci		udph->check = 0;
4658c2ecf20Sopenharmony_ci		udph->check = csum_tcpudp_magic(np->local_ip.ip,
4668c2ecf20Sopenharmony_ci						np->remote_ip.ip,
4678c2ecf20Sopenharmony_ci						udp_len, IPPROTO_UDP,
4688c2ecf20Sopenharmony_ci						csum_partial(udph, udp_len, 0));
4698c2ecf20Sopenharmony_ci		if (udph->check == 0)
4708c2ecf20Sopenharmony_ci			udph->check = CSUM_MANGLED_0;
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci		skb_push(skb, sizeof(*iph));
4738c2ecf20Sopenharmony_ci		skb_reset_network_header(skb);
4748c2ecf20Sopenharmony_ci		iph = ip_hdr(skb);
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci		/* iph->version = 4; iph->ihl = 5; */
4778c2ecf20Sopenharmony_ci		put_unaligned(0x45, (unsigned char *)iph);
4788c2ecf20Sopenharmony_ci		iph->tos      = 0;
4798c2ecf20Sopenharmony_ci		put_unaligned(htons(ip_len), &(iph->tot_len));
4808c2ecf20Sopenharmony_ci		iph->id       = htons(atomic_inc_return(&ip_ident));
4818c2ecf20Sopenharmony_ci		iph->frag_off = 0;
4828c2ecf20Sopenharmony_ci		iph->ttl      = 64;
4838c2ecf20Sopenharmony_ci		iph->protocol = IPPROTO_UDP;
4848c2ecf20Sopenharmony_ci		iph->check    = 0;
4858c2ecf20Sopenharmony_ci		put_unaligned(np->local_ip.ip, &(iph->saddr));
4868c2ecf20Sopenharmony_ci		put_unaligned(np->remote_ip.ip, &(iph->daddr));
4878c2ecf20Sopenharmony_ci		iph->check    = ip_fast_csum((unsigned char *)iph, iph->ihl);
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci		eth = skb_push(skb, ETH_HLEN);
4908c2ecf20Sopenharmony_ci		skb_reset_mac_header(skb);
4918c2ecf20Sopenharmony_ci		skb->protocol = eth->h_proto = htons(ETH_P_IP);
4928c2ecf20Sopenharmony_ci	}
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_ci	ether_addr_copy(eth->h_source, np->dev->dev_addr);
4958c2ecf20Sopenharmony_ci	ether_addr_copy(eth->h_dest, np->remote_mac);
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci	skb->dev = np->dev;
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci	netpoll_send_skb(np, skb);
5008c2ecf20Sopenharmony_ci}
5018c2ecf20Sopenharmony_ciEXPORT_SYMBOL(netpoll_send_udp);
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_civoid netpoll_print_options(struct netpoll *np)
5048c2ecf20Sopenharmony_ci{
5058c2ecf20Sopenharmony_ci	np_info(np, "local port %d\n", np->local_port);
5068c2ecf20Sopenharmony_ci	if (np->ipv6)
5078c2ecf20Sopenharmony_ci		np_info(np, "local IPv6 address %pI6c\n", &np->local_ip.in6);
5088c2ecf20Sopenharmony_ci	else
5098c2ecf20Sopenharmony_ci		np_info(np, "local IPv4 address %pI4\n", &np->local_ip.ip);
5108c2ecf20Sopenharmony_ci	np_info(np, "interface '%s'\n", np->dev_name);
5118c2ecf20Sopenharmony_ci	np_info(np, "remote port %d\n", np->remote_port);
5128c2ecf20Sopenharmony_ci	if (np->ipv6)
5138c2ecf20Sopenharmony_ci		np_info(np, "remote IPv6 address %pI6c\n", &np->remote_ip.in6);
5148c2ecf20Sopenharmony_ci	else
5158c2ecf20Sopenharmony_ci		np_info(np, "remote IPv4 address %pI4\n", &np->remote_ip.ip);
5168c2ecf20Sopenharmony_ci	np_info(np, "remote ethernet address %pM\n", np->remote_mac);
5178c2ecf20Sopenharmony_ci}
5188c2ecf20Sopenharmony_ciEXPORT_SYMBOL(netpoll_print_options);
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_cistatic int netpoll_parse_ip_addr(const char *str, union inet_addr *addr)
5218c2ecf20Sopenharmony_ci{
5228c2ecf20Sopenharmony_ci	const char *end;
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_ci	if (!strchr(str, ':') &&
5258c2ecf20Sopenharmony_ci	    in4_pton(str, -1, (void *)addr, -1, &end) > 0) {
5268c2ecf20Sopenharmony_ci		if (!*end)
5278c2ecf20Sopenharmony_ci			return 0;
5288c2ecf20Sopenharmony_ci	}
5298c2ecf20Sopenharmony_ci	if (in6_pton(str, -1, addr->in6.s6_addr, -1, &end) > 0) {
5308c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
5318c2ecf20Sopenharmony_ci		if (!*end)
5328c2ecf20Sopenharmony_ci			return 1;
5338c2ecf20Sopenharmony_ci#else
5348c2ecf20Sopenharmony_ci		return -1;
5358c2ecf20Sopenharmony_ci#endif
5368c2ecf20Sopenharmony_ci	}
5378c2ecf20Sopenharmony_ci	return -1;
5388c2ecf20Sopenharmony_ci}
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ciint netpoll_parse_options(struct netpoll *np, char *opt)
5418c2ecf20Sopenharmony_ci{
5428c2ecf20Sopenharmony_ci	char *cur=opt, *delim;
5438c2ecf20Sopenharmony_ci	int ipv6;
5448c2ecf20Sopenharmony_ci	bool ipversion_set = false;
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci	if (*cur != '@') {
5478c2ecf20Sopenharmony_ci		if ((delim = strchr(cur, '@')) == NULL)
5488c2ecf20Sopenharmony_ci			goto parse_failed;
5498c2ecf20Sopenharmony_ci		*delim = 0;
5508c2ecf20Sopenharmony_ci		if (kstrtou16(cur, 10, &np->local_port))
5518c2ecf20Sopenharmony_ci			goto parse_failed;
5528c2ecf20Sopenharmony_ci		cur = delim;
5538c2ecf20Sopenharmony_ci	}
5548c2ecf20Sopenharmony_ci	cur++;
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ci	if (*cur != '/') {
5578c2ecf20Sopenharmony_ci		ipversion_set = true;
5588c2ecf20Sopenharmony_ci		if ((delim = strchr(cur, '/')) == NULL)
5598c2ecf20Sopenharmony_ci			goto parse_failed;
5608c2ecf20Sopenharmony_ci		*delim = 0;
5618c2ecf20Sopenharmony_ci		ipv6 = netpoll_parse_ip_addr(cur, &np->local_ip);
5628c2ecf20Sopenharmony_ci		if (ipv6 < 0)
5638c2ecf20Sopenharmony_ci			goto parse_failed;
5648c2ecf20Sopenharmony_ci		else
5658c2ecf20Sopenharmony_ci			np->ipv6 = (bool)ipv6;
5668c2ecf20Sopenharmony_ci		cur = delim;
5678c2ecf20Sopenharmony_ci	}
5688c2ecf20Sopenharmony_ci	cur++;
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci	if (*cur != ',') {
5718c2ecf20Sopenharmony_ci		/* parse out dev name */
5728c2ecf20Sopenharmony_ci		if ((delim = strchr(cur, ',')) == NULL)
5738c2ecf20Sopenharmony_ci			goto parse_failed;
5748c2ecf20Sopenharmony_ci		*delim = 0;
5758c2ecf20Sopenharmony_ci		strlcpy(np->dev_name, cur, sizeof(np->dev_name));
5768c2ecf20Sopenharmony_ci		cur = delim;
5778c2ecf20Sopenharmony_ci	}
5788c2ecf20Sopenharmony_ci	cur++;
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_ci	if (*cur != '@') {
5818c2ecf20Sopenharmony_ci		/* dst port */
5828c2ecf20Sopenharmony_ci		if ((delim = strchr(cur, '@')) == NULL)
5838c2ecf20Sopenharmony_ci			goto parse_failed;
5848c2ecf20Sopenharmony_ci		*delim = 0;
5858c2ecf20Sopenharmony_ci		if (*cur == ' ' || *cur == '\t')
5868c2ecf20Sopenharmony_ci			np_info(np, "warning: whitespace is not allowed\n");
5878c2ecf20Sopenharmony_ci		if (kstrtou16(cur, 10, &np->remote_port))
5888c2ecf20Sopenharmony_ci			goto parse_failed;
5898c2ecf20Sopenharmony_ci		cur = delim;
5908c2ecf20Sopenharmony_ci	}
5918c2ecf20Sopenharmony_ci	cur++;
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_ci	/* dst ip */
5948c2ecf20Sopenharmony_ci	if ((delim = strchr(cur, '/')) == NULL)
5958c2ecf20Sopenharmony_ci		goto parse_failed;
5968c2ecf20Sopenharmony_ci	*delim = 0;
5978c2ecf20Sopenharmony_ci	ipv6 = netpoll_parse_ip_addr(cur, &np->remote_ip);
5988c2ecf20Sopenharmony_ci	if (ipv6 < 0)
5998c2ecf20Sopenharmony_ci		goto parse_failed;
6008c2ecf20Sopenharmony_ci	else if (ipversion_set && np->ipv6 != (bool)ipv6)
6018c2ecf20Sopenharmony_ci		goto parse_failed;
6028c2ecf20Sopenharmony_ci	else
6038c2ecf20Sopenharmony_ci		np->ipv6 = (bool)ipv6;
6048c2ecf20Sopenharmony_ci	cur = delim + 1;
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci	if (*cur != 0) {
6078c2ecf20Sopenharmony_ci		/* MAC address */
6088c2ecf20Sopenharmony_ci		if (!mac_pton(cur, np->remote_mac))
6098c2ecf20Sopenharmony_ci			goto parse_failed;
6108c2ecf20Sopenharmony_ci	}
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_ci	netpoll_print_options(np);
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_ci	return 0;
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_ci parse_failed:
6178c2ecf20Sopenharmony_ci	np_info(np, "couldn't parse config at '%s'!\n", cur);
6188c2ecf20Sopenharmony_ci	return -1;
6198c2ecf20Sopenharmony_ci}
6208c2ecf20Sopenharmony_ciEXPORT_SYMBOL(netpoll_parse_options);
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ciint __netpoll_setup(struct netpoll *np, struct net_device *ndev)
6238c2ecf20Sopenharmony_ci{
6248c2ecf20Sopenharmony_ci	struct netpoll_info *npinfo;
6258c2ecf20Sopenharmony_ci	const struct net_device_ops *ops;
6268c2ecf20Sopenharmony_ci	int err;
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_ci	np->dev = ndev;
6298c2ecf20Sopenharmony_ci	strlcpy(np->dev_name, ndev->name, IFNAMSIZ);
6308c2ecf20Sopenharmony_ci
6318c2ecf20Sopenharmony_ci	if (ndev->priv_flags & IFF_DISABLE_NETPOLL) {
6328c2ecf20Sopenharmony_ci		np_err(np, "%s doesn't support polling, aborting\n",
6338c2ecf20Sopenharmony_ci		       np->dev_name);
6348c2ecf20Sopenharmony_ci		err = -ENOTSUPP;
6358c2ecf20Sopenharmony_ci		goto out;
6368c2ecf20Sopenharmony_ci	}
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci	if (!ndev->npinfo) {
6398c2ecf20Sopenharmony_ci		npinfo = kmalloc(sizeof(*npinfo), GFP_KERNEL);
6408c2ecf20Sopenharmony_ci		if (!npinfo) {
6418c2ecf20Sopenharmony_ci			err = -ENOMEM;
6428c2ecf20Sopenharmony_ci			goto out;
6438c2ecf20Sopenharmony_ci		}
6448c2ecf20Sopenharmony_ci
6458c2ecf20Sopenharmony_ci		sema_init(&npinfo->dev_lock, 1);
6468c2ecf20Sopenharmony_ci		skb_queue_head_init(&npinfo->txq);
6478c2ecf20Sopenharmony_ci		INIT_DELAYED_WORK(&npinfo->tx_work, queue_process);
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_ci		refcount_set(&npinfo->refcnt, 1);
6508c2ecf20Sopenharmony_ci
6518c2ecf20Sopenharmony_ci		ops = np->dev->netdev_ops;
6528c2ecf20Sopenharmony_ci		if (ops->ndo_netpoll_setup) {
6538c2ecf20Sopenharmony_ci			err = ops->ndo_netpoll_setup(ndev, npinfo);
6548c2ecf20Sopenharmony_ci			if (err)
6558c2ecf20Sopenharmony_ci				goto free_npinfo;
6568c2ecf20Sopenharmony_ci		}
6578c2ecf20Sopenharmony_ci	} else {
6588c2ecf20Sopenharmony_ci		npinfo = rtnl_dereference(ndev->npinfo);
6598c2ecf20Sopenharmony_ci		refcount_inc(&npinfo->refcnt);
6608c2ecf20Sopenharmony_ci	}
6618c2ecf20Sopenharmony_ci
6628c2ecf20Sopenharmony_ci	npinfo->netpoll = np;
6638c2ecf20Sopenharmony_ci
6648c2ecf20Sopenharmony_ci	/* last thing to do is link it to the net device structure */
6658c2ecf20Sopenharmony_ci	rcu_assign_pointer(ndev->npinfo, npinfo);
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_ci	return 0;
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_cifree_npinfo:
6708c2ecf20Sopenharmony_ci	kfree(npinfo);
6718c2ecf20Sopenharmony_ciout:
6728c2ecf20Sopenharmony_ci	return err;
6738c2ecf20Sopenharmony_ci}
6748c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(__netpoll_setup);
6758c2ecf20Sopenharmony_ci
6768c2ecf20Sopenharmony_ciint netpoll_setup(struct netpoll *np)
6778c2ecf20Sopenharmony_ci{
6788c2ecf20Sopenharmony_ci	struct net_device *ndev = NULL, *dev = NULL;
6798c2ecf20Sopenharmony_ci	struct net *net = current->nsproxy->net_ns;
6808c2ecf20Sopenharmony_ci	struct in_device *in_dev;
6818c2ecf20Sopenharmony_ci	int err;
6828c2ecf20Sopenharmony_ci
6838c2ecf20Sopenharmony_ci	rtnl_lock();
6848c2ecf20Sopenharmony_ci	if (np->dev_name[0])
6858c2ecf20Sopenharmony_ci		ndev = __dev_get_by_name(net, np->dev_name);
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_ci	if (!ndev) {
6888c2ecf20Sopenharmony_ci		np_err(np, "%s doesn't exist, aborting\n", np->dev_name);
6898c2ecf20Sopenharmony_ci		err = -ENODEV;
6908c2ecf20Sopenharmony_ci		goto unlock;
6918c2ecf20Sopenharmony_ci	}
6928c2ecf20Sopenharmony_ci	dev_hold(ndev);
6938c2ecf20Sopenharmony_ci
6948c2ecf20Sopenharmony_ci	/* bring up DSA management network devices up first */
6958c2ecf20Sopenharmony_ci	for_each_netdev(net, dev) {
6968c2ecf20Sopenharmony_ci		if (!netdev_uses_dsa(dev))
6978c2ecf20Sopenharmony_ci			continue;
6988c2ecf20Sopenharmony_ci
6998c2ecf20Sopenharmony_ci		err = dev_change_flags(dev, dev->flags | IFF_UP, NULL);
7008c2ecf20Sopenharmony_ci		if (err < 0) {
7018c2ecf20Sopenharmony_ci			np_err(np, "%s failed to open %s\n",
7028c2ecf20Sopenharmony_ci			       np->dev_name, dev->name);
7038c2ecf20Sopenharmony_ci			goto put;
7048c2ecf20Sopenharmony_ci		}
7058c2ecf20Sopenharmony_ci	}
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_ci	if (netdev_master_upper_dev_get(ndev)) {
7088c2ecf20Sopenharmony_ci		np_err(np, "%s is a slave device, aborting\n", np->dev_name);
7098c2ecf20Sopenharmony_ci		err = -EBUSY;
7108c2ecf20Sopenharmony_ci		goto put;
7118c2ecf20Sopenharmony_ci	}
7128c2ecf20Sopenharmony_ci
7138c2ecf20Sopenharmony_ci	if (!netif_running(ndev)) {
7148c2ecf20Sopenharmony_ci		unsigned long atmost, atleast;
7158c2ecf20Sopenharmony_ci
7168c2ecf20Sopenharmony_ci		np_info(np, "device %s not up yet, forcing it\n", np->dev_name);
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_ci		err = dev_open(ndev, NULL);
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_ci		if (err) {
7218c2ecf20Sopenharmony_ci			np_err(np, "failed to open %s\n", ndev->name);
7228c2ecf20Sopenharmony_ci			goto put;
7238c2ecf20Sopenharmony_ci		}
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ci		rtnl_unlock();
7268c2ecf20Sopenharmony_ci		atleast = jiffies + HZ/10;
7278c2ecf20Sopenharmony_ci		atmost = jiffies + carrier_timeout * HZ;
7288c2ecf20Sopenharmony_ci		while (!netif_carrier_ok(ndev)) {
7298c2ecf20Sopenharmony_ci			if (time_after(jiffies, atmost)) {
7308c2ecf20Sopenharmony_ci				np_notice(np, "timeout waiting for carrier\n");
7318c2ecf20Sopenharmony_ci				break;
7328c2ecf20Sopenharmony_ci			}
7338c2ecf20Sopenharmony_ci			msleep(1);
7348c2ecf20Sopenharmony_ci		}
7358c2ecf20Sopenharmony_ci
7368c2ecf20Sopenharmony_ci		/* If carrier appears to come up instantly, we don't
7378c2ecf20Sopenharmony_ci		 * trust it and pause so that we don't pump all our
7388c2ecf20Sopenharmony_ci		 * queued console messages into the bitbucket.
7398c2ecf20Sopenharmony_ci		 */
7408c2ecf20Sopenharmony_ci
7418c2ecf20Sopenharmony_ci		if (time_before(jiffies, atleast)) {
7428c2ecf20Sopenharmony_ci			np_notice(np, "carrier detect appears untrustworthy, waiting 4 seconds\n");
7438c2ecf20Sopenharmony_ci			msleep(4000);
7448c2ecf20Sopenharmony_ci		}
7458c2ecf20Sopenharmony_ci		rtnl_lock();
7468c2ecf20Sopenharmony_ci	}
7478c2ecf20Sopenharmony_ci
7488c2ecf20Sopenharmony_ci	if (!np->local_ip.ip) {
7498c2ecf20Sopenharmony_ci		if (!np->ipv6) {
7508c2ecf20Sopenharmony_ci			const struct in_ifaddr *ifa;
7518c2ecf20Sopenharmony_ci
7528c2ecf20Sopenharmony_ci			in_dev = __in_dev_get_rtnl(ndev);
7538c2ecf20Sopenharmony_ci			if (!in_dev)
7548c2ecf20Sopenharmony_ci				goto put_noaddr;
7558c2ecf20Sopenharmony_ci
7568c2ecf20Sopenharmony_ci			ifa = rtnl_dereference(in_dev->ifa_list);
7578c2ecf20Sopenharmony_ci			if (!ifa) {
7588c2ecf20Sopenharmony_ciput_noaddr:
7598c2ecf20Sopenharmony_ci				np_err(np, "no IP address for %s, aborting\n",
7608c2ecf20Sopenharmony_ci				       np->dev_name);
7618c2ecf20Sopenharmony_ci				err = -EDESTADDRREQ;
7628c2ecf20Sopenharmony_ci				goto put;
7638c2ecf20Sopenharmony_ci			}
7648c2ecf20Sopenharmony_ci
7658c2ecf20Sopenharmony_ci			np->local_ip.ip = ifa->ifa_local;
7668c2ecf20Sopenharmony_ci			np_info(np, "local IP %pI4\n", &np->local_ip.ip);
7678c2ecf20Sopenharmony_ci		} else {
7688c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
7698c2ecf20Sopenharmony_ci			struct inet6_dev *idev;
7708c2ecf20Sopenharmony_ci
7718c2ecf20Sopenharmony_ci			err = -EDESTADDRREQ;
7728c2ecf20Sopenharmony_ci			idev = __in6_dev_get(ndev);
7738c2ecf20Sopenharmony_ci			if (idev) {
7748c2ecf20Sopenharmony_ci				struct inet6_ifaddr *ifp;
7758c2ecf20Sopenharmony_ci
7768c2ecf20Sopenharmony_ci				read_lock_bh(&idev->lock);
7778c2ecf20Sopenharmony_ci				list_for_each_entry(ifp, &idev->addr_list, if_list) {
7788c2ecf20Sopenharmony_ci					if (!!(ipv6_addr_type(&ifp->addr) & IPV6_ADDR_LINKLOCAL) !=
7798c2ecf20Sopenharmony_ci					    !!(ipv6_addr_type(&np->remote_ip.in6) & IPV6_ADDR_LINKLOCAL))
7808c2ecf20Sopenharmony_ci						continue;
7818c2ecf20Sopenharmony_ci					np->local_ip.in6 = ifp->addr;
7828c2ecf20Sopenharmony_ci					err = 0;
7838c2ecf20Sopenharmony_ci					break;
7848c2ecf20Sopenharmony_ci				}
7858c2ecf20Sopenharmony_ci				read_unlock_bh(&idev->lock);
7868c2ecf20Sopenharmony_ci			}
7878c2ecf20Sopenharmony_ci			if (err) {
7888c2ecf20Sopenharmony_ci				np_err(np, "no IPv6 address for %s, aborting\n",
7898c2ecf20Sopenharmony_ci				       np->dev_name);
7908c2ecf20Sopenharmony_ci				goto put;
7918c2ecf20Sopenharmony_ci			} else
7928c2ecf20Sopenharmony_ci				np_info(np, "local IPv6 %pI6c\n", &np->local_ip.in6);
7938c2ecf20Sopenharmony_ci#else
7948c2ecf20Sopenharmony_ci			np_err(np, "IPv6 is not supported %s, aborting\n",
7958c2ecf20Sopenharmony_ci			       np->dev_name);
7968c2ecf20Sopenharmony_ci			err = -EINVAL;
7978c2ecf20Sopenharmony_ci			goto put;
7988c2ecf20Sopenharmony_ci#endif
7998c2ecf20Sopenharmony_ci		}
8008c2ecf20Sopenharmony_ci	}
8018c2ecf20Sopenharmony_ci
8028c2ecf20Sopenharmony_ci	/* fill up the skb queue */
8038c2ecf20Sopenharmony_ci	refill_skbs();
8048c2ecf20Sopenharmony_ci
8058c2ecf20Sopenharmony_ci	err = __netpoll_setup(np, ndev);
8068c2ecf20Sopenharmony_ci	if (err)
8078c2ecf20Sopenharmony_ci		goto put;
8088c2ecf20Sopenharmony_ci
8098c2ecf20Sopenharmony_ci	rtnl_unlock();
8108c2ecf20Sopenharmony_ci	return 0;
8118c2ecf20Sopenharmony_ci
8128c2ecf20Sopenharmony_ciput:
8138c2ecf20Sopenharmony_ci	dev_put(ndev);
8148c2ecf20Sopenharmony_ciunlock:
8158c2ecf20Sopenharmony_ci	rtnl_unlock();
8168c2ecf20Sopenharmony_ci	return err;
8178c2ecf20Sopenharmony_ci}
8188c2ecf20Sopenharmony_ciEXPORT_SYMBOL(netpoll_setup);
8198c2ecf20Sopenharmony_ci
8208c2ecf20Sopenharmony_cistatic int __init netpoll_init(void)
8218c2ecf20Sopenharmony_ci{
8228c2ecf20Sopenharmony_ci	skb_queue_head_init(&skb_pool);
8238c2ecf20Sopenharmony_ci	return 0;
8248c2ecf20Sopenharmony_ci}
8258c2ecf20Sopenharmony_cicore_initcall(netpoll_init);
8268c2ecf20Sopenharmony_ci
8278c2ecf20Sopenharmony_cistatic void rcu_cleanup_netpoll_info(struct rcu_head *rcu_head)
8288c2ecf20Sopenharmony_ci{
8298c2ecf20Sopenharmony_ci	struct netpoll_info *npinfo =
8308c2ecf20Sopenharmony_ci			container_of(rcu_head, struct netpoll_info, rcu);
8318c2ecf20Sopenharmony_ci
8328c2ecf20Sopenharmony_ci	skb_queue_purge(&npinfo->txq);
8338c2ecf20Sopenharmony_ci
8348c2ecf20Sopenharmony_ci	/* we can't call cancel_delayed_work_sync here, as we are in softirq */
8358c2ecf20Sopenharmony_ci	cancel_delayed_work(&npinfo->tx_work);
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_ci	/* clean after last, unfinished work */
8388c2ecf20Sopenharmony_ci	__skb_queue_purge(&npinfo->txq);
8398c2ecf20Sopenharmony_ci	/* now cancel it again */
8408c2ecf20Sopenharmony_ci	cancel_delayed_work(&npinfo->tx_work);
8418c2ecf20Sopenharmony_ci	kfree(npinfo);
8428c2ecf20Sopenharmony_ci}
8438c2ecf20Sopenharmony_ci
8448c2ecf20Sopenharmony_civoid __netpoll_cleanup(struct netpoll *np)
8458c2ecf20Sopenharmony_ci{
8468c2ecf20Sopenharmony_ci	struct netpoll_info *npinfo;
8478c2ecf20Sopenharmony_ci
8488c2ecf20Sopenharmony_ci	npinfo = rtnl_dereference(np->dev->npinfo);
8498c2ecf20Sopenharmony_ci	if (!npinfo)
8508c2ecf20Sopenharmony_ci		return;
8518c2ecf20Sopenharmony_ci
8528c2ecf20Sopenharmony_ci	synchronize_srcu(&netpoll_srcu);
8538c2ecf20Sopenharmony_ci
8548c2ecf20Sopenharmony_ci	if (refcount_dec_and_test(&npinfo->refcnt)) {
8558c2ecf20Sopenharmony_ci		const struct net_device_ops *ops;
8568c2ecf20Sopenharmony_ci
8578c2ecf20Sopenharmony_ci		ops = np->dev->netdev_ops;
8588c2ecf20Sopenharmony_ci		if (ops->ndo_netpoll_cleanup)
8598c2ecf20Sopenharmony_ci			ops->ndo_netpoll_cleanup(np->dev);
8608c2ecf20Sopenharmony_ci
8618c2ecf20Sopenharmony_ci		RCU_INIT_POINTER(np->dev->npinfo, NULL);
8628c2ecf20Sopenharmony_ci		call_rcu(&npinfo->rcu, rcu_cleanup_netpoll_info);
8638c2ecf20Sopenharmony_ci	} else
8648c2ecf20Sopenharmony_ci		RCU_INIT_POINTER(np->dev->npinfo, NULL);
8658c2ecf20Sopenharmony_ci}
8668c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(__netpoll_cleanup);
8678c2ecf20Sopenharmony_ci
8688c2ecf20Sopenharmony_civoid __netpoll_free(struct netpoll *np)
8698c2ecf20Sopenharmony_ci{
8708c2ecf20Sopenharmony_ci	ASSERT_RTNL();
8718c2ecf20Sopenharmony_ci
8728c2ecf20Sopenharmony_ci	/* Wait for transmitting packets to finish before freeing. */
8738c2ecf20Sopenharmony_ci	synchronize_rcu();
8748c2ecf20Sopenharmony_ci	__netpoll_cleanup(np);
8758c2ecf20Sopenharmony_ci	kfree(np);
8768c2ecf20Sopenharmony_ci}
8778c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(__netpoll_free);
8788c2ecf20Sopenharmony_ci
8798c2ecf20Sopenharmony_civoid netpoll_cleanup(struct netpoll *np)
8808c2ecf20Sopenharmony_ci{
8818c2ecf20Sopenharmony_ci	rtnl_lock();
8828c2ecf20Sopenharmony_ci	if (!np->dev)
8838c2ecf20Sopenharmony_ci		goto out;
8848c2ecf20Sopenharmony_ci	__netpoll_cleanup(np);
8858c2ecf20Sopenharmony_ci	dev_put(np->dev);
8868c2ecf20Sopenharmony_ci	np->dev = NULL;
8878c2ecf20Sopenharmony_ciout:
8888c2ecf20Sopenharmony_ci	rtnl_unlock();
8898c2ecf20Sopenharmony_ci}
8908c2ecf20Sopenharmony_ciEXPORT_SYMBOL(netpoll_cleanup);
891