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