162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* linux/net/ipv4/arp.c 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) 1994 by Florian La Roche 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * This module implements the Address Resolution Protocol ARP (RFC 826), 762306a36Sopenharmony_ci * which is used to convert IP addresses (or in the future maybe other 862306a36Sopenharmony_ci * high-level addresses) into a low-level hardware address (like an Ethernet 962306a36Sopenharmony_ci * address). 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * Fixes: 1262306a36Sopenharmony_ci * Alan Cox : Removed the Ethernet assumptions in 1362306a36Sopenharmony_ci * Florian's code 1462306a36Sopenharmony_ci * Alan Cox : Fixed some small errors in the ARP 1562306a36Sopenharmony_ci * logic 1662306a36Sopenharmony_ci * Alan Cox : Allow >4K in /proc 1762306a36Sopenharmony_ci * Alan Cox : Make ARP add its own protocol entry 1862306a36Sopenharmony_ci * Ross Martin : Rewrote arp_rcv() and arp_get_info() 1962306a36Sopenharmony_ci * Stephen Henson : Add AX25 support to arp_get_info() 2062306a36Sopenharmony_ci * Alan Cox : Drop data when a device is downed. 2162306a36Sopenharmony_ci * Alan Cox : Use init_timer(). 2262306a36Sopenharmony_ci * Alan Cox : Double lock fixes. 2362306a36Sopenharmony_ci * Martin Seine : Move the arphdr structure 2462306a36Sopenharmony_ci * to if_arp.h for compatibility. 2562306a36Sopenharmony_ci * with BSD based programs. 2662306a36Sopenharmony_ci * Andrew Tridgell : Added ARP netmask code and 2762306a36Sopenharmony_ci * re-arranged proxy handling. 2862306a36Sopenharmony_ci * Alan Cox : Changed to use notifiers. 2962306a36Sopenharmony_ci * Niibe Yutaka : Reply for this device or proxies only. 3062306a36Sopenharmony_ci * Alan Cox : Don't proxy across hardware types! 3162306a36Sopenharmony_ci * Jonathan Naylor : Added support for NET/ROM. 3262306a36Sopenharmony_ci * Mike Shaver : RFC1122 checks. 3362306a36Sopenharmony_ci * Jonathan Naylor : Only lookup the hardware address for 3462306a36Sopenharmony_ci * the correct hardware type. 3562306a36Sopenharmony_ci * Germano Caronni : Assorted subtle races. 3662306a36Sopenharmony_ci * Craig Schlenter : Don't modify permanent entry 3762306a36Sopenharmony_ci * during arp_rcv. 3862306a36Sopenharmony_ci * Russ Nelson : Tidied up a few bits. 3962306a36Sopenharmony_ci * Alexey Kuznetsov: Major changes to caching and behaviour, 4062306a36Sopenharmony_ci * eg intelligent arp probing and 4162306a36Sopenharmony_ci * generation 4262306a36Sopenharmony_ci * of host down events. 4362306a36Sopenharmony_ci * Alan Cox : Missing unlock in device events. 4462306a36Sopenharmony_ci * Eckes : ARP ioctl control errors. 4562306a36Sopenharmony_ci * Alexey Kuznetsov: Arp free fix. 4662306a36Sopenharmony_ci * Manuel Rodriguez: Gratuitous ARP. 4762306a36Sopenharmony_ci * Jonathan Layes : Added arpd support through kerneld 4862306a36Sopenharmony_ci * message queue (960314) 4962306a36Sopenharmony_ci * Mike Shaver : /proc/sys/net/ipv4/arp_* support 5062306a36Sopenharmony_ci * Mike McLagan : Routing by source 5162306a36Sopenharmony_ci * Stuart Cheshire : Metricom and grat arp fixes 5262306a36Sopenharmony_ci * *** FOR 2.1 clean this up *** 5362306a36Sopenharmony_ci * Lawrence V. Stefani: (08/12/96) Added FDDI support. 5462306a36Sopenharmony_ci * Alan Cox : Took the AP1000 nasty FDDI hack and 5562306a36Sopenharmony_ci * folded into the mainstream FDDI code. 5662306a36Sopenharmony_ci * Ack spit, Linus how did you allow that 5762306a36Sopenharmony_ci * one in... 5862306a36Sopenharmony_ci * Jes Sorensen : Make FDDI work again in 2.1.x and 5962306a36Sopenharmony_ci * clean up the APFDDI & gen. FDDI bits. 6062306a36Sopenharmony_ci * Alexey Kuznetsov: new arp state machine; 6162306a36Sopenharmony_ci * now it is in net/core/neighbour.c. 6262306a36Sopenharmony_ci * Krzysztof Halasa: Added Frame Relay ARP support. 6362306a36Sopenharmony_ci * Arnaldo C. Melo : convert /proc/net/arp to seq_file 6462306a36Sopenharmony_ci * Shmulik Hen: Split arp_send to arp_create and 6562306a36Sopenharmony_ci * arp_xmit so intermediate drivers like 6662306a36Sopenharmony_ci * bonding can change the skb before 6762306a36Sopenharmony_ci * sending (e.g. insert 8021q tag). 6862306a36Sopenharmony_ci * Harald Welte : convert to make use of jenkins hash 6962306a36Sopenharmony_ci * Jesper D. Brouer: Proxy ARP PVLAN RFC 3069 support. 7062306a36Sopenharmony_ci */ 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci#include <linux/module.h> 7562306a36Sopenharmony_ci#include <linux/types.h> 7662306a36Sopenharmony_ci#include <linux/string.h> 7762306a36Sopenharmony_ci#include <linux/kernel.h> 7862306a36Sopenharmony_ci#include <linux/capability.h> 7962306a36Sopenharmony_ci#include <linux/socket.h> 8062306a36Sopenharmony_ci#include <linux/sockios.h> 8162306a36Sopenharmony_ci#include <linux/errno.h> 8262306a36Sopenharmony_ci#include <linux/in.h> 8362306a36Sopenharmony_ci#include <linux/mm.h> 8462306a36Sopenharmony_ci#include <linux/inet.h> 8562306a36Sopenharmony_ci#include <linux/inetdevice.h> 8662306a36Sopenharmony_ci#include <linux/netdevice.h> 8762306a36Sopenharmony_ci#include <linux/etherdevice.h> 8862306a36Sopenharmony_ci#include <linux/fddidevice.h> 8962306a36Sopenharmony_ci#include <linux/if_arp.h> 9062306a36Sopenharmony_ci#include <linux/skbuff.h> 9162306a36Sopenharmony_ci#include <linux/proc_fs.h> 9262306a36Sopenharmony_ci#include <linux/seq_file.h> 9362306a36Sopenharmony_ci#include <linux/stat.h> 9462306a36Sopenharmony_ci#include <linux/init.h> 9562306a36Sopenharmony_ci#include <linux/net.h> 9662306a36Sopenharmony_ci#include <linux/rcupdate.h> 9762306a36Sopenharmony_ci#include <linux/slab.h> 9862306a36Sopenharmony_ci#ifdef CONFIG_SYSCTL 9962306a36Sopenharmony_ci#include <linux/sysctl.h> 10062306a36Sopenharmony_ci#endif 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci#include <net/net_namespace.h> 10362306a36Sopenharmony_ci#include <net/ip.h> 10462306a36Sopenharmony_ci#include <net/icmp.h> 10562306a36Sopenharmony_ci#include <net/route.h> 10662306a36Sopenharmony_ci#include <net/protocol.h> 10762306a36Sopenharmony_ci#include <net/tcp.h> 10862306a36Sopenharmony_ci#include <net/sock.h> 10962306a36Sopenharmony_ci#include <net/arp.h> 11062306a36Sopenharmony_ci#include <net/ax25.h> 11162306a36Sopenharmony_ci#include <net/netrom.h> 11262306a36Sopenharmony_ci#include <net/dst_metadata.h> 11362306a36Sopenharmony_ci#include <net/ip_tunnels.h> 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci#include <linux/uaccess.h> 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci#include <linux/netfilter_arp.h> 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci/* 12062306a36Sopenharmony_ci * Interface to generic neighbour cache. 12162306a36Sopenharmony_ci */ 12262306a36Sopenharmony_cistatic u32 arp_hash(const void *pkey, const struct net_device *dev, __u32 *hash_rnd); 12362306a36Sopenharmony_cistatic bool arp_key_eq(const struct neighbour *n, const void *pkey); 12462306a36Sopenharmony_cistatic int arp_constructor(struct neighbour *neigh); 12562306a36Sopenharmony_cistatic void arp_solicit(struct neighbour *neigh, struct sk_buff *skb); 12662306a36Sopenharmony_cistatic void arp_error_report(struct neighbour *neigh, struct sk_buff *skb); 12762306a36Sopenharmony_cistatic void parp_redo(struct sk_buff *skb); 12862306a36Sopenharmony_cistatic int arp_is_multicast(const void *pkey); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_cistatic const struct neigh_ops arp_generic_ops = { 13162306a36Sopenharmony_ci .family = AF_INET, 13262306a36Sopenharmony_ci .solicit = arp_solicit, 13362306a36Sopenharmony_ci .error_report = arp_error_report, 13462306a36Sopenharmony_ci .output = neigh_resolve_output, 13562306a36Sopenharmony_ci .connected_output = neigh_connected_output, 13662306a36Sopenharmony_ci}; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_cistatic const struct neigh_ops arp_hh_ops = { 13962306a36Sopenharmony_ci .family = AF_INET, 14062306a36Sopenharmony_ci .solicit = arp_solicit, 14162306a36Sopenharmony_ci .error_report = arp_error_report, 14262306a36Sopenharmony_ci .output = neigh_resolve_output, 14362306a36Sopenharmony_ci .connected_output = neigh_resolve_output, 14462306a36Sopenharmony_ci}; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_cistatic const struct neigh_ops arp_direct_ops = { 14762306a36Sopenharmony_ci .family = AF_INET, 14862306a36Sopenharmony_ci .output = neigh_direct_output, 14962306a36Sopenharmony_ci .connected_output = neigh_direct_output, 15062306a36Sopenharmony_ci}; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_cistruct neigh_table arp_tbl = { 15362306a36Sopenharmony_ci .family = AF_INET, 15462306a36Sopenharmony_ci .key_len = 4, 15562306a36Sopenharmony_ci .protocol = cpu_to_be16(ETH_P_IP), 15662306a36Sopenharmony_ci .hash = arp_hash, 15762306a36Sopenharmony_ci .key_eq = arp_key_eq, 15862306a36Sopenharmony_ci .constructor = arp_constructor, 15962306a36Sopenharmony_ci .proxy_redo = parp_redo, 16062306a36Sopenharmony_ci .is_multicast = arp_is_multicast, 16162306a36Sopenharmony_ci .id = "arp_cache", 16262306a36Sopenharmony_ci .parms = { 16362306a36Sopenharmony_ci .tbl = &arp_tbl, 16462306a36Sopenharmony_ci .reachable_time = 30 * HZ, 16562306a36Sopenharmony_ci .data = { 16662306a36Sopenharmony_ci [NEIGH_VAR_MCAST_PROBES] = 3, 16762306a36Sopenharmony_ci [NEIGH_VAR_UCAST_PROBES] = 3, 16862306a36Sopenharmony_ci [NEIGH_VAR_RETRANS_TIME] = 1 * HZ, 16962306a36Sopenharmony_ci [NEIGH_VAR_BASE_REACHABLE_TIME] = 30 * HZ, 17062306a36Sopenharmony_ci [NEIGH_VAR_DELAY_PROBE_TIME] = 5 * HZ, 17162306a36Sopenharmony_ci [NEIGH_VAR_INTERVAL_PROBE_TIME_MS] = 5 * HZ, 17262306a36Sopenharmony_ci [NEIGH_VAR_GC_STALETIME] = 60 * HZ, 17362306a36Sopenharmony_ci [NEIGH_VAR_QUEUE_LEN_BYTES] = SK_WMEM_MAX, 17462306a36Sopenharmony_ci [NEIGH_VAR_PROXY_QLEN] = 64, 17562306a36Sopenharmony_ci [NEIGH_VAR_ANYCAST_DELAY] = 1 * HZ, 17662306a36Sopenharmony_ci [NEIGH_VAR_PROXY_DELAY] = (8 * HZ) / 10, 17762306a36Sopenharmony_ci [NEIGH_VAR_LOCKTIME] = 1 * HZ, 17862306a36Sopenharmony_ci }, 17962306a36Sopenharmony_ci }, 18062306a36Sopenharmony_ci .gc_interval = 30 * HZ, 18162306a36Sopenharmony_ci .gc_thresh1 = 128, 18262306a36Sopenharmony_ci .gc_thresh2 = 512, 18362306a36Sopenharmony_ci .gc_thresh3 = 1024, 18462306a36Sopenharmony_ci}; 18562306a36Sopenharmony_ciEXPORT_SYMBOL(arp_tbl); 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ciint arp_mc_map(__be32 addr, u8 *haddr, struct net_device *dev, int dir) 18862306a36Sopenharmony_ci{ 18962306a36Sopenharmony_ci switch (dev->type) { 19062306a36Sopenharmony_ci case ARPHRD_ETHER: 19162306a36Sopenharmony_ci case ARPHRD_FDDI: 19262306a36Sopenharmony_ci case ARPHRD_IEEE802: 19362306a36Sopenharmony_ci ip_eth_mc_map(addr, haddr); 19462306a36Sopenharmony_ci return 0; 19562306a36Sopenharmony_ci case ARPHRD_INFINIBAND: 19662306a36Sopenharmony_ci ip_ib_mc_map(addr, dev->broadcast, haddr); 19762306a36Sopenharmony_ci return 0; 19862306a36Sopenharmony_ci case ARPHRD_IPGRE: 19962306a36Sopenharmony_ci ip_ipgre_mc_map(addr, dev->broadcast, haddr); 20062306a36Sopenharmony_ci return 0; 20162306a36Sopenharmony_ci default: 20262306a36Sopenharmony_ci if (dir) { 20362306a36Sopenharmony_ci memcpy(haddr, dev->broadcast, dev->addr_len); 20462306a36Sopenharmony_ci return 0; 20562306a36Sopenharmony_ci } 20662306a36Sopenharmony_ci } 20762306a36Sopenharmony_ci return -EINVAL; 20862306a36Sopenharmony_ci} 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_cistatic u32 arp_hash(const void *pkey, 21262306a36Sopenharmony_ci const struct net_device *dev, 21362306a36Sopenharmony_ci __u32 *hash_rnd) 21462306a36Sopenharmony_ci{ 21562306a36Sopenharmony_ci return arp_hashfn(pkey, dev, hash_rnd); 21662306a36Sopenharmony_ci} 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_cistatic bool arp_key_eq(const struct neighbour *neigh, const void *pkey) 21962306a36Sopenharmony_ci{ 22062306a36Sopenharmony_ci return neigh_key_eq32(neigh, pkey); 22162306a36Sopenharmony_ci} 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_cistatic int arp_constructor(struct neighbour *neigh) 22462306a36Sopenharmony_ci{ 22562306a36Sopenharmony_ci __be32 addr; 22662306a36Sopenharmony_ci struct net_device *dev = neigh->dev; 22762306a36Sopenharmony_ci struct in_device *in_dev; 22862306a36Sopenharmony_ci struct neigh_parms *parms; 22962306a36Sopenharmony_ci u32 inaddr_any = INADDR_ANY; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci if (dev->flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) 23262306a36Sopenharmony_ci memcpy(neigh->primary_key, &inaddr_any, arp_tbl.key_len); 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci addr = *(__be32 *)neigh->primary_key; 23562306a36Sopenharmony_ci rcu_read_lock(); 23662306a36Sopenharmony_ci in_dev = __in_dev_get_rcu(dev); 23762306a36Sopenharmony_ci if (!in_dev) { 23862306a36Sopenharmony_ci rcu_read_unlock(); 23962306a36Sopenharmony_ci return -EINVAL; 24062306a36Sopenharmony_ci } 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci neigh->type = inet_addr_type_dev_table(dev_net(dev), dev, addr); 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci parms = in_dev->arp_parms; 24562306a36Sopenharmony_ci __neigh_parms_put(neigh->parms); 24662306a36Sopenharmony_ci neigh->parms = neigh_parms_clone(parms); 24762306a36Sopenharmony_ci rcu_read_unlock(); 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci if (!dev->header_ops) { 25062306a36Sopenharmony_ci neigh->nud_state = NUD_NOARP; 25162306a36Sopenharmony_ci neigh->ops = &arp_direct_ops; 25262306a36Sopenharmony_ci neigh->output = neigh_direct_output; 25362306a36Sopenharmony_ci } else { 25462306a36Sopenharmony_ci /* Good devices (checked by reading texts, but only Ethernet is 25562306a36Sopenharmony_ci tested) 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci ARPHRD_ETHER: (ethernet, apfddi) 25862306a36Sopenharmony_ci ARPHRD_FDDI: (fddi) 25962306a36Sopenharmony_ci ARPHRD_IEEE802: (tr) 26062306a36Sopenharmony_ci ARPHRD_METRICOM: (strip) 26162306a36Sopenharmony_ci ARPHRD_ARCNET: 26262306a36Sopenharmony_ci etc. etc. etc. 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci ARPHRD_IPDDP will also work, if author repairs it. 26562306a36Sopenharmony_ci I did not it, because this driver does not work even 26662306a36Sopenharmony_ci in old paradigm. 26762306a36Sopenharmony_ci */ 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci if (neigh->type == RTN_MULTICAST) { 27062306a36Sopenharmony_ci neigh->nud_state = NUD_NOARP; 27162306a36Sopenharmony_ci arp_mc_map(addr, neigh->ha, dev, 1); 27262306a36Sopenharmony_ci } else if (dev->flags & (IFF_NOARP | IFF_LOOPBACK)) { 27362306a36Sopenharmony_ci neigh->nud_state = NUD_NOARP; 27462306a36Sopenharmony_ci memcpy(neigh->ha, dev->dev_addr, dev->addr_len); 27562306a36Sopenharmony_ci } else if (neigh->type == RTN_BROADCAST || 27662306a36Sopenharmony_ci (dev->flags & IFF_POINTOPOINT)) { 27762306a36Sopenharmony_ci neigh->nud_state = NUD_NOARP; 27862306a36Sopenharmony_ci memcpy(neigh->ha, dev->broadcast, dev->addr_len); 27962306a36Sopenharmony_ci } 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci if (dev->header_ops->cache) 28262306a36Sopenharmony_ci neigh->ops = &arp_hh_ops; 28362306a36Sopenharmony_ci else 28462306a36Sopenharmony_ci neigh->ops = &arp_generic_ops; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci if (neigh->nud_state & NUD_VALID) 28762306a36Sopenharmony_ci neigh->output = neigh->ops->connected_output; 28862306a36Sopenharmony_ci else 28962306a36Sopenharmony_ci neigh->output = neigh->ops->output; 29062306a36Sopenharmony_ci } 29162306a36Sopenharmony_ci return 0; 29262306a36Sopenharmony_ci} 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_cistatic void arp_error_report(struct neighbour *neigh, struct sk_buff *skb) 29562306a36Sopenharmony_ci{ 29662306a36Sopenharmony_ci dst_link_failure(skb); 29762306a36Sopenharmony_ci kfree_skb_reason(skb, SKB_DROP_REASON_NEIGH_FAILED); 29862306a36Sopenharmony_ci} 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci/* Create and send an arp packet. */ 30162306a36Sopenharmony_cistatic void arp_send_dst(int type, int ptype, __be32 dest_ip, 30262306a36Sopenharmony_ci struct net_device *dev, __be32 src_ip, 30362306a36Sopenharmony_ci const unsigned char *dest_hw, 30462306a36Sopenharmony_ci const unsigned char *src_hw, 30562306a36Sopenharmony_ci const unsigned char *target_hw, 30662306a36Sopenharmony_ci struct dst_entry *dst) 30762306a36Sopenharmony_ci{ 30862306a36Sopenharmony_ci struct sk_buff *skb; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci /* arp on this interface. */ 31162306a36Sopenharmony_ci if (dev->flags & IFF_NOARP) 31262306a36Sopenharmony_ci return; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci skb = arp_create(type, ptype, dest_ip, dev, src_ip, 31562306a36Sopenharmony_ci dest_hw, src_hw, target_hw); 31662306a36Sopenharmony_ci if (!skb) 31762306a36Sopenharmony_ci return; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci skb_dst_set(skb, dst_clone(dst)); 32062306a36Sopenharmony_ci arp_xmit(skb); 32162306a36Sopenharmony_ci} 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_civoid arp_send(int type, int ptype, __be32 dest_ip, 32462306a36Sopenharmony_ci struct net_device *dev, __be32 src_ip, 32562306a36Sopenharmony_ci const unsigned char *dest_hw, const unsigned char *src_hw, 32662306a36Sopenharmony_ci const unsigned char *target_hw) 32762306a36Sopenharmony_ci{ 32862306a36Sopenharmony_ci arp_send_dst(type, ptype, dest_ip, dev, src_ip, dest_hw, src_hw, 32962306a36Sopenharmony_ci target_hw, NULL); 33062306a36Sopenharmony_ci} 33162306a36Sopenharmony_ciEXPORT_SYMBOL(arp_send); 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_cistatic void arp_solicit(struct neighbour *neigh, struct sk_buff *skb) 33462306a36Sopenharmony_ci{ 33562306a36Sopenharmony_ci __be32 saddr = 0; 33662306a36Sopenharmony_ci u8 dst_ha[MAX_ADDR_LEN], *dst_hw = NULL; 33762306a36Sopenharmony_ci struct net_device *dev = neigh->dev; 33862306a36Sopenharmony_ci __be32 target = *(__be32 *)neigh->primary_key; 33962306a36Sopenharmony_ci int probes = atomic_read(&neigh->probes); 34062306a36Sopenharmony_ci struct in_device *in_dev; 34162306a36Sopenharmony_ci struct dst_entry *dst = NULL; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci rcu_read_lock(); 34462306a36Sopenharmony_ci in_dev = __in_dev_get_rcu(dev); 34562306a36Sopenharmony_ci if (!in_dev) { 34662306a36Sopenharmony_ci rcu_read_unlock(); 34762306a36Sopenharmony_ci return; 34862306a36Sopenharmony_ci } 34962306a36Sopenharmony_ci switch (IN_DEV_ARP_ANNOUNCE(in_dev)) { 35062306a36Sopenharmony_ci default: 35162306a36Sopenharmony_ci case 0: /* By default announce any local IP */ 35262306a36Sopenharmony_ci if (skb && inet_addr_type_dev_table(dev_net(dev), dev, 35362306a36Sopenharmony_ci ip_hdr(skb)->saddr) == RTN_LOCAL) 35462306a36Sopenharmony_ci saddr = ip_hdr(skb)->saddr; 35562306a36Sopenharmony_ci break; 35662306a36Sopenharmony_ci case 1: /* Restrict announcements of saddr in same subnet */ 35762306a36Sopenharmony_ci if (!skb) 35862306a36Sopenharmony_ci break; 35962306a36Sopenharmony_ci saddr = ip_hdr(skb)->saddr; 36062306a36Sopenharmony_ci if (inet_addr_type_dev_table(dev_net(dev), dev, 36162306a36Sopenharmony_ci saddr) == RTN_LOCAL) { 36262306a36Sopenharmony_ci /* saddr should be known to target */ 36362306a36Sopenharmony_ci if (inet_addr_onlink(in_dev, target, saddr)) 36462306a36Sopenharmony_ci break; 36562306a36Sopenharmony_ci } 36662306a36Sopenharmony_ci saddr = 0; 36762306a36Sopenharmony_ci break; 36862306a36Sopenharmony_ci case 2: /* Avoid secondary IPs, get a primary/preferred one */ 36962306a36Sopenharmony_ci break; 37062306a36Sopenharmony_ci } 37162306a36Sopenharmony_ci rcu_read_unlock(); 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci if (!saddr) 37462306a36Sopenharmony_ci saddr = inet_select_addr(dev, target, RT_SCOPE_LINK); 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci probes -= NEIGH_VAR(neigh->parms, UCAST_PROBES); 37762306a36Sopenharmony_ci if (probes < 0) { 37862306a36Sopenharmony_ci if (!(READ_ONCE(neigh->nud_state) & NUD_VALID)) 37962306a36Sopenharmony_ci pr_debug("trying to ucast probe in NUD_INVALID\n"); 38062306a36Sopenharmony_ci neigh_ha_snapshot(dst_ha, neigh, dev); 38162306a36Sopenharmony_ci dst_hw = dst_ha; 38262306a36Sopenharmony_ci } else { 38362306a36Sopenharmony_ci probes -= NEIGH_VAR(neigh->parms, APP_PROBES); 38462306a36Sopenharmony_ci if (probes < 0) { 38562306a36Sopenharmony_ci neigh_app_ns(neigh); 38662306a36Sopenharmony_ci return; 38762306a36Sopenharmony_ci } 38862306a36Sopenharmony_ci } 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci if (skb && !(dev->priv_flags & IFF_XMIT_DST_RELEASE)) 39162306a36Sopenharmony_ci dst = skb_dst(skb); 39262306a36Sopenharmony_ci arp_send_dst(ARPOP_REQUEST, ETH_P_ARP, target, dev, saddr, 39362306a36Sopenharmony_ci dst_hw, dev->dev_addr, NULL, dst); 39462306a36Sopenharmony_ci} 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_cistatic int arp_ignore(struct in_device *in_dev, __be32 sip, __be32 tip) 39762306a36Sopenharmony_ci{ 39862306a36Sopenharmony_ci struct net *net = dev_net(in_dev->dev); 39962306a36Sopenharmony_ci int scope; 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci switch (IN_DEV_ARP_IGNORE(in_dev)) { 40262306a36Sopenharmony_ci case 0: /* Reply, the tip is already validated */ 40362306a36Sopenharmony_ci return 0; 40462306a36Sopenharmony_ci case 1: /* Reply only if tip is configured on the incoming interface */ 40562306a36Sopenharmony_ci sip = 0; 40662306a36Sopenharmony_ci scope = RT_SCOPE_HOST; 40762306a36Sopenharmony_ci break; 40862306a36Sopenharmony_ci case 2: /* 40962306a36Sopenharmony_ci * Reply only if tip is configured on the incoming interface 41062306a36Sopenharmony_ci * and is in same subnet as sip 41162306a36Sopenharmony_ci */ 41262306a36Sopenharmony_ci scope = RT_SCOPE_HOST; 41362306a36Sopenharmony_ci break; 41462306a36Sopenharmony_ci case 3: /* Do not reply for scope host addresses */ 41562306a36Sopenharmony_ci sip = 0; 41662306a36Sopenharmony_ci scope = RT_SCOPE_LINK; 41762306a36Sopenharmony_ci in_dev = NULL; 41862306a36Sopenharmony_ci break; 41962306a36Sopenharmony_ci case 4: /* Reserved */ 42062306a36Sopenharmony_ci case 5: 42162306a36Sopenharmony_ci case 6: 42262306a36Sopenharmony_ci case 7: 42362306a36Sopenharmony_ci return 0; 42462306a36Sopenharmony_ci case 8: /* Do not reply */ 42562306a36Sopenharmony_ci return 1; 42662306a36Sopenharmony_ci default: 42762306a36Sopenharmony_ci return 0; 42862306a36Sopenharmony_ci } 42962306a36Sopenharmony_ci return !inet_confirm_addr(net, in_dev, sip, tip, scope); 43062306a36Sopenharmony_ci} 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_cistatic int arp_accept(struct in_device *in_dev, __be32 sip) 43362306a36Sopenharmony_ci{ 43462306a36Sopenharmony_ci struct net *net = dev_net(in_dev->dev); 43562306a36Sopenharmony_ci int scope = RT_SCOPE_LINK; 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci switch (IN_DEV_ARP_ACCEPT(in_dev)) { 43862306a36Sopenharmony_ci case 0: /* Don't create new entries from garp */ 43962306a36Sopenharmony_ci return 0; 44062306a36Sopenharmony_ci case 1: /* Create new entries from garp */ 44162306a36Sopenharmony_ci return 1; 44262306a36Sopenharmony_ci case 2: /* Create a neighbor in the arp table only if sip 44362306a36Sopenharmony_ci * is in the same subnet as an address configured 44462306a36Sopenharmony_ci * on the interface that received the garp message 44562306a36Sopenharmony_ci */ 44662306a36Sopenharmony_ci return !!inet_confirm_addr(net, in_dev, sip, 0, scope); 44762306a36Sopenharmony_ci default: 44862306a36Sopenharmony_ci return 0; 44962306a36Sopenharmony_ci } 45062306a36Sopenharmony_ci} 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_cistatic int arp_filter(__be32 sip, __be32 tip, struct net_device *dev) 45362306a36Sopenharmony_ci{ 45462306a36Sopenharmony_ci struct rtable *rt; 45562306a36Sopenharmony_ci int flag = 0; 45662306a36Sopenharmony_ci /*unsigned long now; */ 45762306a36Sopenharmony_ci struct net *net = dev_net(dev); 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci rt = ip_route_output(net, sip, tip, 0, l3mdev_master_ifindex_rcu(dev)); 46062306a36Sopenharmony_ci if (IS_ERR(rt)) 46162306a36Sopenharmony_ci return 1; 46262306a36Sopenharmony_ci if (rt->dst.dev != dev) { 46362306a36Sopenharmony_ci __NET_INC_STATS(net, LINUX_MIB_ARPFILTER); 46462306a36Sopenharmony_ci flag = 1; 46562306a36Sopenharmony_ci } 46662306a36Sopenharmony_ci ip_rt_put(rt); 46762306a36Sopenharmony_ci return flag; 46862306a36Sopenharmony_ci} 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci/* 47162306a36Sopenharmony_ci * Check if we can use proxy ARP for this path 47262306a36Sopenharmony_ci */ 47362306a36Sopenharmony_cistatic inline int arp_fwd_proxy(struct in_device *in_dev, 47462306a36Sopenharmony_ci struct net_device *dev, struct rtable *rt) 47562306a36Sopenharmony_ci{ 47662306a36Sopenharmony_ci struct in_device *out_dev; 47762306a36Sopenharmony_ci int imi, omi = -1; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci if (rt->dst.dev == dev) 48062306a36Sopenharmony_ci return 0; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci if (!IN_DEV_PROXY_ARP(in_dev)) 48362306a36Sopenharmony_ci return 0; 48462306a36Sopenharmony_ci imi = IN_DEV_MEDIUM_ID(in_dev); 48562306a36Sopenharmony_ci if (imi == 0) 48662306a36Sopenharmony_ci return 1; 48762306a36Sopenharmony_ci if (imi == -1) 48862306a36Sopenharmony_ci return 0; 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci /* place to check for proxy_arp for routes */ 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci out_dev = __in_dev_get_rcu(rt->dst.dev); 49362306a36Sopenharmony_ci if (out_dev) 49462306a36Sopenharmony_ci omi = IN_DEV_MEDIUM_ID(out_dev); 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci return omi != imi && omi != -1; 49762306a36Sopenharmony_ci} 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci/* 50062306a36Sopenharmony_ci * Check for RFC3069 proxy arp private VLAN (allow to send back to same dev) 50162306a36Sopenharmony_ci * 50262306a36Sopenharmony_ci * RFC3069 supports proxy arp replies back to the same interface. This 50362306a36Sopenharmony_ci * is done to support (ethernet) switch features, like RFC 3069, where 50462306a36Sopenharmony_ci * the individual ports are not allowed to communicate with each 50562306a36Sopenharmony_ci * other, BUT they are allowed to talk to the upstream router. As 50662306a36Sopenharmony_ci * described in RFC 3069, it is possible to allow these hosts to 50762306a36Sopenharmony_ci * communicate through the upstream router, by proxy_arp'ing. 50862306a36Sopenharmony_ci * 50962306a36Sopenharmony_ci * RFC 3069: "VLAN Aggregation for Efficient IP Address Allocation" 51062306a36Sopenharmony_ci * 51162306a36Sopenharmony_ci * This technology is known by different names: 51262306a36Sopenharmony_ci * In RFC 3069 it is called VLAN Aggregation. 51362306a36Sopenharmony_ci * Cisco and Allied Telesyn call it Private VLAN. 51462306a36Sopenharmony_ci * Hewlett-Packard call it Source-Port filtering or port-isolation. 51562306a36Sopenharmony_ci * Ericsson call it MAC-Forced Forwarding (RFC Draft). 51662306a36Sopenharmony_ci * 51762306a36Sopenharmony_ci */ 51862306a36Sopenharmony_cistatic inline int arp_fwd_pvlan(struct in_device *in_dev, 51962306a36Sopenharmony_ci struct net_device *dev, struct rtable *rt, 52062306a36Sopenharmony_ci __be32 sip, __be32 tip) 52162306a36Sopenharmony_ci{ 52262306a36Sopenharmony_ci /* Private VLAN is only concerned about the same ethernet segment */ 52362306a36Sopenharmony_ci if (rt->dst.dev != dev) 52462306a36Sopenharmony_ci return 0; 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci /* Don't reply on self probes (often done by windowz boxes)*/ 52762306a36Sopenharmony_ci if (sip == tip) 52862306a36Sopenharmony_ci return 0; 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci if (IN_DEV_PROXY_ARP_PVLAN(in_dev)) 53162306a36Sopenharmony_ci return 1; 53262306a36Sopenharmony_ci else 53362306a36Sopenharmony_ci return 0; 53462306a36Sopenharmony_ci} 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci/* 53762306a36Sopenharmony_ci * Interface to link layer: send routine and receive handler. 53862306a36Sopenharmony_ci */ 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci/* 54162306a36Sopenharmony_ci * Create an arp packet. If dest_hw is not set, we create a broadcast 54262306a36Sopenharmony_ci * message. 54362306a36Sopenharmony_ci */ 54462306a36Sopenharmony_cistruct sk_buff *arp_create(int type, int ptype, __be32 dest_ip, 54562306a36Sopenharmony_ci struct net_device *dev, __be32 src_ip, 54662306a36Sopenharmony_ci const unsigned char *dest_hw, 54762306a36Sopenharmony_ci const unsigned char *src_hw, 54862306a36Sopenharmony_ci const unsigned char *target_hw) 54962306a36Sopenharmony_ci{ 55062306a36Sopenharmony_ci struct sk_buff *skb; 55162306a36Sopenharmony_ci struct arphdr *arp; 55262306a36Sopenharmony_ci unsigned char *arp_ptr; 55362306a36Sopenharmony_ci int hlen = LL_RESERVED_SPACE(dev); 55462306a36Sopenharmony_ci int tlen = dev->needed_tailroom; 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci /* 55762306a36Sopenharmony_ci * Allocate a buffer 55862306a36Sopenharmony_ci */ 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci skb = alloc_skb(arp_hdr_len(dev) + hlen + tlen, GFP_ATOMIC); 56162306a36Sopenharmony_ci if (!skb) 56262306a36Sopenharmony_ci return NULL; 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci skb_reserve(skb, hlen); 56562306a36Sopenharmony_ci skb_reset_network_header(skb); 56662306a36Sopenharmony_ci arp = skb_put(skb, arp_hdr_len(dev)); 56762306a36Sopenharmony_ci skb->dev = dev; 56862306a36Sopenharmony_ci skb->protocol = htons(ETH_P_ARP); 56962306a36Sopenharmony_ci if (!src_hw) 57062306a36Sopenharmony_ci src_hw = dev->dev_addr; 57162306a36Sopenharmony_ci if (!dest_hw) 57262306a36Sopenharmony_ci dest_hw = dev->broadcast; 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci /* 57562306a36Sopenharmony_ci * Fill the device header for the ARP frame 57662306a36Sopenharmony_ci */ 57762306a36Sopenharmony_ci if (dev_hard_header(skb, dev, ptype, dest_hw, src_hw, skb->len) < 0) 57862306a36Sopenharmony_ci goto out; 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci /* 58162306a36Sopenharmony_ci * Fill out the arp protocol part. 58262306a36Sopenharmony_ci * 58362306a36Sopenharmony_ci * The arp hardware type should match the device type, except for FDDI, 58462306a36Sopenharmony_ci * which (according to RFC 1390) should always equal 1 (Ethernet). 58562306a36Sopenharmony_ci */ 58662306a36Sopenharmony_ci /* 58762306a36Sopenharmony_ci * Exceptions everywhere. AX.25 uses the AX.25 PID value not the 58862306a36Sopenharmony_ci * DIX code for the protocol. Make these device structure fields. 58962306a36Sopenharmony_ci */ 59062306a36Sopenharmony_ci switch (dev->type) { 59162306a36Sopenharmony_ci default: 59262306a36Sopenharmony_ci arp->ar_hrd = htons(dev->type); 59362306a36Sopenharmony_ci arp->ar_pro = htons(ETH_P_IP); 59462306a36Sopenharmony_ci break; 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_AX25) 59762306a36Sopenharmony_ci case ARPHRD_AX25: 59862306a36Sopenharmony_ci arp->ar_hrd = htons(ARPHRD_AX25); 59962306a36Sopenharmony_ci arp->ar_pro = htons(AX25_P_IP); 60062306a36Sopenharmony_ci break; 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_NETROM) 60362306a36Sopenharmony_ci case ARPHRD_NETROM: 60462306a36Sopenharmony_ci arp->ar_hrd = htons(ARPHRD_NETROM); 60562306a36Sopenharmony_ci arp->ar_pro = htons(AX25_P_IP); 60662306a36Sopenharmony_ci break; 60762306a36Sopenharmony_ci#endif 60862306a36Sopenharmony_ci#endif 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_FDDI) 61162306a36Sopenharmony_ci case ARPHRD_FDDI: 61262306a36Sopenharmony_ci arp->ar_hrd = htons(ARPHRD_ETHER); 61362306a36Sopenharmony_ci arp->ar_pro = htons(ETH_P_IP); 61462306a36Sopenharmony_ci break; 61562306a36Sopenharmony_ci#endif 61662306a36Sopenharmony_ci } 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci arp->ar_hln = dev->addr_len; 61962306a36Sopenharmony_ci arp->ar_pln = 4; 62062306a36Sopenharmony_ci arp->ar_op = htons(type); 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci arp_ptr = (unsigned char *)(arp + 1); 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci memcpy(arp_ptr, src_hw, dev->addr_len); 62562306a36Sopenharmony_ci arp_ptr += dev->addr_len; 62662306a36Sopenharmony_ci memcpy(arp_ptr, &src_ip, 4); 62762306a36Sopenharmony_ci arp_ptr += 4; 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci switch (dev->type) { 63062306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_FIREWIRE_NET) 63162306a36Sopenharmony_ci case ARPHRD_IEEE1394: 63262306a36Sopenharmony_ci break; 63362306a36Sopenharmony_ci#endif 63462306a36Sopenharmony_ci default: 63562306a36Sopenharmony_ci if (target_hw) 63662306a36Sopenharmony_ci memcpy(arp_ptr, target_hw, dev->addr_len); 63762306a36Sopenharmony_ci else 63862306a36Sopenharmony_ci memset(arp_ptr, 0, dev->addr_len); 63962306a36Sopenharmony_ci arp_ptr += dev->addr_len; 64062306a36Sopenharmony_ci } 64162306a36Sopenharmony_ci memcpy(arp_ptr, &dest_ip, 4); 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci return skb; 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ciout: 64662306a36Sopenharmony_ci kfree_skb(skb); 64762306a36Sopenharmony_ci return NULL; 64862306a36Sopenharmony_ci} 64962306a36Sopenharmony_ciEXPORT_SYMBOL(arp_create); 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_cistatic int arp_xmit_finish(struct net *net, struct sock *sk, struct sk_buff *skb) 65262306a36Sopenharmony_ci{ 65362306a36Sopenharmony_ci return dev_queue_xmit(skb); 65462306a36Sopenharmony_ci} 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci/* 65762306a36Sopenharmony_ci * Send an arp packet. 65862306a36Sopenharmony_ci */ 65962306a36Sopenharmony_civoid arp_xmit(struct sk_buff *skb) 66062306a36Sopenharmony_ci{ 66162306a36Sopenharmony_ci /* Send it off, maybe filter it using firewalling first. */ 66262306a36Sopenharmony_ci NF_HOOK(NFPROTO_ARP, NF_ARP_OUT, 66362306a36Sopenharmony_ci dev_net(skb->dev), NULL, skb, NULL, skb->dev, 66462306a36Sopenharmony_ci arp_xmit_finish); 66562306a36Sopenharmony_ci} 66662306a36Sopenharmony_ciEXPORT_SYMBOL(arp_xmit); 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_cistatic bool arp_is_garp(struct net *net, struct net_device *dev, 66962306a36Sopenharmony_ci int *addr_type, __be16 ar_op, 67062306a36Sopenharmony_ci __be32 sip, __be32 tip, 67162306a36Sopenharmony_ci unsigned char *sha, unsigned char *tha) 67262306a36Sopenharmony_ci{ 67362306a36Sopenharmony_ci bool is_garp = tip == sip; 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci /* Gratuitous ARP _replies_ also require target hwaddr to be 67662306a36Sopenharmony_ci * the same as source. 67762306a36Sopenharmony_ci */ 67862306a36Sopenharmony_ci if (is_garp && ar_op == htons(ARPOP_REPLY)) 67962306a36Sopenharmony_ci is_garp = 68062306a36Sopenharmony_ci /* IPv4 over IEEE 1394 doesn't provide target 68162306a36Sopenharmony_ci * hardware address field in its ARP payload. 68262306a36Sopenharmony_ci */ 68362306a36Sopenharmony_ci tha && 68462306a36Sopenharmony_ci !memcmp(tha, sha, dev->addr_len); 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci if (is_garp) { 68762306a36Sopenharmony_ci *addr_type = inet_addr_type_dev_table(net, dev, sip); 68862306a36Sopenharmony_ci if (*addr_type != RTN_UNICAST) 68962306a36Sopenharmony_ci is_garp = false; 69062306a36Sopenharmony_ci } 69162306a36Sopenharmony_ci return is_garp; 69262306a36Sopenharmony_ci} 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci/* 69562306a36Sopenharmony_ci * Process an arp request. 69662306a36Sopenharmony_ci */ 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_cistatic int arp_process(struct net *net, struct sock *sk, struct sk_buff *skb) 69962306a36Sopenharmony_ci{ 70062306a36Sopenharmony_ci struct net_device *dev = skb->dev; 70162306a36Sopenharmony_ci struct in_device *in_dev = __in_dev_get_rcu(dev); 70262306a36Sopenharmony_ci struct arphdr *arp; 70362306a36Sopenharmony_ci unsigned char *arp_ptr; 70462306a36Sopenharmony_ci struct rtable *rt; 70562306a36Sopenharmony_ci unsigned char *sha; 70662306a36Sopenharmony_ci unsigned char *tha = NULL; 70762306a36Sopenharmony_ci __be32 sip, tip; 70862306a36Sopenharmony_ci u16 dev_type = dev->type; 70962306a36Sopenharmony_ci int addr_type; 71062306a36Sopenharmony_ci struct neighbour *n; 71162306a36Sopenharmony_ci struct dst_entry *reply_dst = NULL; 71262306a36Sopenharmony_ci bool is_garp = false; 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci /* arp_rcv below verifies the ARP header and verifies the device 71562306a36Sopenharmony_ci * is ARP'able. 71662306a36Sopenharmony_ci */ 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci if (!in_dev) 71962306a36Sopenharmony_ci goto out_free_skb; 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci arp = arp_hdr(skb); 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci switch (dev_type) { 72462306a36Sopenharmony_ci default: 72562306a36Sopenharmony_ci if (arp->ar_pro != htons(ETH_P_IP) || 72662306a36Sopenharmony_ci htons(dev_type) != arp->ar_hrd) 72762306a36Sopenharmony_ci goto out_free_skb; 72862306a36Sopenharmony_ci break; 72962306a36Sopenharmony_ci case ARPHRD_ETHER: 73062306a36Sopenharmony_ci case ARPHRD_FDDI: 73162306a36Sopenharmony_ci case ARPHRD_IEEE802: 73262306a36Sopenharmony_ci /* 73362306a36Sopenharmony_ci * ETHERNET, and Fibre Channel (which are IEEE 802 73462306a36Sopenharmony_ci * devices, according to RFC 2625) devices will accept ARP 73562306a36Sopenharmony_ci * hardware types of either 1 (Ethernet) or 6 (IEEE 802.2). 73662306a36Sopenharmony_ci * This is the case also of FDDI, where the RFC 1390 says that 73762306a36Sopenharmony_ci * FDDI devices should accept ARP hardware of (1) Ethernet, 73862306a36Sopenharmony_ci * however, to be more robust, we'll accept both 1 (Ethernet) 73962306a36Sopenharmony_ci * or 6 (IEEE 802.2) 74062306a36Sopenharmony_ci */ 74162306a36Sopenharmony_ci if ((arp->ar_hrd != htons(ARPHRD_ETHER) && 74262306a36Sopenharmony_ci arp->ar_hrd != htons(ARPHRD_IEEE802)) || 74362306a36Sopenharmony_ci arp->ar_pro != htons(ETH_P_IP)) 74462306a36Sopenharmony_ci goto out_free_skb; 74562306a36Sopenharmony_ci break; 74662306a36Sopenharmony_ci case ARPHRD_AX25: 74762306a36Sopenharmony_ci if (arp->ar_pro != htons(AX25_P_IP) || 74862306a36Sopenharmony_ci arp->ar_hrd != htons(ARPHRD_AX25)) 74962306a36Sopenharmony_ci goto out_free_skb; 75062306a36Sopenharmony_ci break; 75162306a36Sopenharmony_ci case ARPHRD_NETROM: 75262306a36Sopenharmony_ci if (arp->ar_pro != htons(AX25_P_IP) || 75362306a36Sopenharmony_ci arp->ar_hrd != htons(ARPHRD_NETROM)) 75462306a36Sopenharmony_ci goto out_free_skb; 75562306a36Sopenharmony_ci break; 75662306a36Sopenharmony_ci } 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci /* Understand only these message types */ 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci if (arp->ar_op != htons(ARPOP_REPLY) && 76162306a36Sopenharmony_ci arp->ar_op != htons(ARPOP_REQUEST)) 76262306a36Sopenharmony_ci goto out_free_skb; 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci/* 76562306a36Sopenharmony_ci * Extract fields 76662306a36Sopenharmony_ci */ 76762306a36Sopenharmony_ci arp_ptr = (unsigned char *)(arp + 1); 76862306a36Sopenharmony_ci sha = arp_ptr; 76962306a36Sopenharmony_ci arp_ptr += dev->addr_len; 77062306a36Sopenharmony_ci memcpy(&sip, arp_ptr, 4); 77162306a36Sopenharmony_ci arp_ptr += 4; 77262306a36Sopenharmony_ci switch (dev_type) { 77362306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_FIREWIRE_NET) 77462306a36Sopenharmony_ci case ARPHRD_IEEE1394: 77562306a36Sopenharmony_ci break; 77662306a36Sopenharmony_ci#endif 77762306a36Sopenharmony_ci default: 77862306a36Sopenharmony_ci tha = arp_ptr; 77962306a36Sopenharmony_ci arp_ptr += dev->addr_len; 78062306a36Sopenharmony_ci } 78162306a36Sopenharmony_ci memcpy(&tip, arp_ptr, 4); 78262306a36Sopenharmony_ci/* 78362306a36Sopenharmony_ci * Check for bad requests for 127.x.x.x and requests for multicast 78462306a36Sopenharmony_ci * addresses. If this is one such, delete it. 78562306a36Sopenharmony_ci */ 78662306a36Sopenharmony_ci if (ipv4_is_multicast(tip) || 78762306a36Sopenharmony_ci (!IN_DEV_ROUTE_LOCALNET(in_dev) && ipv4_is_loopback(tip))) 78862306a36Sopenharmony_ci goto out_free_skb; 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci /* 79162306a36Sopenharmony_ci * For some 802.11 wireless deployments (and possibly other networks), 79262306a36Sopenharmony_ci * there will be an ARP proxy and gratuitous ARP frames are attacks 79362306a36Sopenharmony_ci * and thus should not be accepted. 79462306a36Sopenharmony_ci */ 79562306a36Sopenharmony_ci if (sip == tip && IN_DEV_ORCONF(in_dev, DROP_GRATUITOUS_ARP)) 79662306a36Sopenharmony_ci goto out_free_skb; 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci/* 79962306a36Sopenharmony_ci * Special case: We must set Frame Relay source Q.922 address 80062306a36Sopenharmony_ci */ 80162306a36Sopenharmony_ci if (dev_type == ARPHRD_DLCI) 80262306a36Sopenharmony_ci sha = dev->broadcast; 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci/* 80562306a36Sopenharmony_ci * Process entry. The idea here is we want to send a reply if it is a 80662306a36Sopenharmony_ci * request for us or if it is a request for someone else that we hold 80762306a36Sopenharmony_ci * a proxy for. We want to add an entry to our cache if it is a reply 80862306a36Sopenharmony_ci * to us or if it is a request for our address. 80962306a36Sopenharmony_ci * (The assumption for this last is that if someone is requesting our 81062306a36Sopenharmony_ci * address, they are probably intending to talk to us, so it saves time 81162306a36Sopenharmony_ci * if we cache their address. Their address is also probably not in 81262306a36Sopenharmony_ci * our cache, since ours is not in their cache.) 81362306a36Sopenharmony_ci * 81462306a36Sopenharmony_ci * Putting this another way, we only care about replies if they are to 81562306a36Sopenharmony_ci * us, in which case we add them to the cache. For requests, we care 81662306a36Sopenharmony_ci * about those for us and those for our proxies. We reply to both, 81762306a36Sopenharmony_ci * and in the case of requests for us we add the requester to the arp 81862306a36Sopenharmony_ci * cache. 81962306a36Sopenharmony_ci */ 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci if (arp->ar_op == htons(ARPOP_REQUEST) && skb_metadata_dst(skb)) 82262306a36Sopenharmony_ci reply_dst = (struct dst_entry *) 82362306a36Sopenharmony_ci iptunnel_metadata_reply(skb_metadata_dst(skb), 82462306a36Sopenharmony_ci GFP_ATOMIC); 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci /* Special case: IPv4 duplicate address detection packet (RFC2131) */ 82762306a36Sopenharmony_ci if (sip == 0) { 82862306a36Sopenharmony_ci if (arp->ar_op == htons(ARPOP_REQUEST) && 82962306a36Sopenharmony_ci inet_addr_type_dev_table(net, dev, tip) == RTN_LOCAL && 83062306a36Sopenharmony_ci !arp_ignore(in_dev, sip, tip)) 83162306a36Sopenharmony_ci arp_send_dst(ARPOP_REPLY, ETH_P_ARP, sip, dev, tip, 83262306a36Sopenharmony_ci sha, dev->dev_addr, sha, reply_dst); 83362306a36Sopenharmony_ci goto out_consume_skb; 83462306a36Sopenharmony_ci } 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci if (arp->ar_op == htons(ARPOP_REQUEST) && 83762306a36Sopenharmony_ci ip_route_input_noref(skb, tip, sip, 0, dev) == 0) { 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci rt = skb_rtable(skb); 84062306a36Sopenharmony_ci addr_type = rt->rt_type; 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci if (addr_type == RTN_LOCAL) { 84362306a36Sopenharmony_ci int dont_send; 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci dont_send = arp_ignore(in_dev, sip, tip); 84662306a36Sopenharmony_ci if (!dont_send && IN_DEV_ARPFILTER(in_dev)) 84762306a36Sopenharmony_ci dont_send = arp_filter(sip, tip, dev); 84862306a36Sopenharmony_ci if (!dont_send) { 84962306a36Sopenharmony_ci n = neigh_event_ns(&arp_tbl, sha, &sip, dev); 85062306a36Sopenharmony_ci if (n) { 85162306a36Sopenharmony_ci arp_send_dst(ARPOP_REPLY, ETH_P_ARP, 85262306a36Sopenharmony_ci sip, dev, tip, sha, 85362306a36Sopenharmony_ci dev->dev_addr, sha, 85462306a36Sopenharmony_ci reply_dst); 85562306a36Sopenharmony_ci neigh_release(n); 85662306a36Sopenharmony_ci } 85762306a36Sopenharmony_ci } 85862306a36Sopenharmony_ci goto out_consume_skb; 85962306a36Sopenharmony_ci } else if (IN_DEV_FORWARD(in_dev)) { 86062306a36Sopenharmony_ci if (addr_type == RTN_UNICAST && 86162306a36Sopenharmony_ci (arp_fwd_proxy(in_dev, dev, rt) || 86262306a36Sopenharmony_ci arp_fwd_pvlan(in_dev, dev, rt, sip, tip) || 86362306a36Sopenharmony_ci (rt->dst.dev != dev && 86462306a36Sopenharmony_ci pneigh_lookup(&arp_tbl, net, &tip, dev, 0)))) { 86562306a36Sopenharmony_ci n = neigh_event_ns(&arp_tbl, sha, &sip, dev); 86662306a36Sopenharmony_ci if (n) 86762306a36Sopenharmony_ci neigh_release(n); 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ci if (NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED || 87062306a36Sopenharmony_ci skb->pkt_type == PACKET_HOST || 87162306a36Sopenharmony_ci NEIGH_VAR(in_dev->arp_parms, PROXY_DELAY) == 0) { 87262306a36Sopenharmony_ci arp_send_dst(ARPOP_REPLY, ETH_P_ARP, 87362306a36Sopenharmony_ci sip, dev, tip, sha, 87462306a36Sopenharmony_ci dev->dev_addr, sha, 87562306a36Sopenharmony_ci reply_dst); 87662306a36Sopenharmony_ci } else { 87762306a36Sopenharmony_ci pneigh_enqueue(&arp_tbl, 87862306a36Sopenharmony_ci in_dev->arp_parms, skb); 87962306a36Sopenharmony_ci goto out_free_dst; 88062306a36Sopenharmony_ci } 88162306a36Sopenharmony_ci goto out_consume_skb; 88262306a36Sopenharmony_ci } 88362306a36Sopenharmony_ci } 88462306a36Sopenharmony_ci } 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci /* Update our ARP tables */ 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci n = __neigh_lookup(&arp_tbl, &sip, dev, 0); 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci addr_type = -1; 89162306a36Sopenharmony_ci if (n || arp_accept(in_dev, sip)) { 89262306a36Sopenharmony_ci is_garp = arp_is_garp(net, dev, &addr_type, arp->ar_op, 89362306a36Sopenharmony_ci sip, tip, sha, tha); 89462306a36Sopenharmony_ci } 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci if (arp_accept(in_dev, sip)) { 89762306a36Sopenharmony_ci /* Unsolicited ARP is not accepted by default. 89862306a36Sopenharmony_ci It is possible, that this option should be enabled for some 89962306a36Sopenharmony_ci devices (strip is candidate) 90062306a36Sopenharmony_ci */ 90162306a36Sopenharmony_ci if (!n && 90262306a36Sopenharmony_ci (is_garp || 90362306a36Sopenharmony_ci (arp->ar_op == htons(ARPOP_REPLY) && 90462306a36Sopenharmony_ci (addr_type == RTN_UNICAST || 90562306a36Sopenharmony_ci (addr_type < 0 && 90662306a36Sopenharmony_ci /* postpone calculation to as late as possible */ 90762306a36Sopenharmony_ci inet_addr_type_dev_table(net, dev, sip) == 90862306a36Sopenharmony_ci RTN_UNICAST))))) 90962306a36Sopenharmony_ci n = __neigh_lookup(&arp_tbl, &sip, dev, 1); 91062306a36Sopenharmony_ci } 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci if (n) { 91362306a36Sopenharmony_ci int state = NUD_REACHABLE; 91462306a36Sopenharmony_ci int override; 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci /* If several different ARP replies follows back-to-back, 91762306a36Sopenharmony_ci use the FIRST one. It is possible, if several proxy 91862306a36Sopenharmony_ci agents are active. Taking the first reply prevents 91962306a36Sopenharmony_ci arp trashing and chooses the fastest router. 92062306a36Sopenharmony_ci */ 92162306a36Sopenharmony_ci override = time_after(jiffies, 92262306a36Sopenharmony_ci n->updated + 92362306a36Sopenharmony_ci NEIGH_VAR(n->parms, LOCKTIME)) || 92462306a36Sopenharmony_ci is_garp; 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci /* Broadcast replies and request packets 92762306a36Sopenharmony_ci do not assert neighbour reachability. 92862306a36Sopenharmony_ci */ 92962306a36Sopenharmony_ci if (arp->ar_op != htons(ARPOP_REPLY) || 93062306a36Sopenharmony_ci skb->pkt_type != PACKET_HOST) 93162306a36Sopenharmony_ci state = NUD_STALE; 93262306a36Sopenharmony_ci neigh_update(n, sha, state, 93362306a36Sopenharmony_ci override ? NEIGH_UPDATE_F_OVERRIDE : 0, 0); 93462306a36Sopenharmony_ci neigh_release(n); 93562306a36Sopenharmony_ci } 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ciout_consume_skb: 93862306a36Sopenharmony_ci consume_skb(skb); 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ciout_free_dst: 94162306a36Sopenharmony_ci dst_release(reply_dst); 94262306a36Sopenharmony_ci return NET_RX_SUCCESS; 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ciout_free_skb: 94562306a36Sopenharmony_ci kfree_skb(skb); 94662306a36Sopenharmony_ci return NET_RX_DROP; 94762306a36Sopenharmony_ci} 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_cistatic void parp_redo(struct sk_buff *skb) 95062306a36Sopenharmony_ci{ 95162306a36Sopenharmony_ci arp_process(dev_net(skb->dev), NULL, skb); 95262306a36Sopenharmony_ci} 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_cistatic int arp_is_multicast(const void *pkey) 95562306a36Sopenharmony_ci{ 95662306a36Sopenharmony_ci return ipv4_is_multicast(*((__be32 *)pkey)); 95762306a36Sopenharmony_ci} 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci/* 96062306a36Sopenharmony_ci * Receive an arp request from the device layer. 96162306a36Sopenharmony_ci */ 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_cistatic int arp_rcv(struct sk_buff *skb, struct net_device *dev, 96462306a36Sopenharmony_ci struct packet_type *pt, struct net_device *orig_dev) 96562306a36Sopenharmony_ci{ 96662306a36Sopenharmony_ci const struct arphdr *arp; 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci /* do not tweak dropwatch on an ARP we will ignore */ 96962306a36Sopenharmony_ci if (dev->flags & IFF_NOARP || 97062306a36Sopenharmony_ci skb->pkt_type == PACKET_OTHERHOST || 97162306a36Sopenharmony_ci skb->pkt_type == PACKET_LOOPBACK) 97262306a36Sopenharmony_ci goto consumeskb; 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_ci skb = skb_share_check(skb, GFP_ATOMIC); 97562306a36Sopenharmony_ci if (!skb) 97662306a36Sopenharmony_ci goto out_of_mem; 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_ci /* ARP header, plus 2 device addresses, plus 2 IP addresses. */ 97962306a36Sopenharmony_ci if (!pskb_may_pull(skb, arp_hdr_len(dev))) 98062306a36Sopenharmony_ci goto freeskb; 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_ci arp = arp_hdr(skb); 98362306a36Sopenharmony_ci if (arp->ar_hln != dev->addr_len || arp->ar_pln != 4) 98462306a36Sopenharmony_ci goto freeskb; 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_ci memset(NEIGH_CB(skb), 0, sizeof(struct neighbour_cb)); 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci return NF_HOOK(NFPROTO_ARP, NF_ARP_IN, 98962306a36Sopenharmony_ci dev_net(dev), NULL, skb, dev, NULL, 99062306a36Sopenharmony_ci arp_process); 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ciconsumeskb: 99362306a36Sopenharmony_ci consume_skb(skb); 99462306a36Sopenharmony_ci return NET_RX_SUCCESS; 99562306a36Sopenharmony_cifreeskb: 99662306a36Sopenharmony_ci kfree_skb(skb); 99762306a36Sopenharmony_ciout_of_mem: 99862306a36Sopenharmony_ci return NET_RX_DROP; 99962306a36Sopenharmony_ci} 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_ci/* 100262306a36Sopenharmony_ci * User level interface (ioctl) 100362306a36Sopenharmony_ci */ 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ci/* 100662306a36Sopenharmony_ci * Set (create) an ARP cache entry. 100762306a36Sopenharmony_ci */ 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_cistatic int arp_req_set_proxy(struct net *net, struct net_device *dev, int on) 101062306a36Sopenharmony_ci{ 101162306a36Sopenharmony_ci if (!dev) { 101262306a36Sopenharmony_ci IPV4_DEVCONF_ALL(net, PROXY_ARP) = on; 101362306a36Sopenharmony_ci return 0; 101462306a36Sopenharmony_ci } 101562306a36Sopenharmony_ci if (__in_dev_get_rtnl(dev)) { 101662306a36Sopenharmony_ci IN_DEV_CONF_SET(__in_dev_get_rtnl(dev), PROXY_ARP, on); 101762306a36Sopenharmony_ci return 0; 101862306a36Sopenharmony_ci } 101962306a36Sopenharmony_ci return -ENXIO; 102062306a36Sopenharmony_ci} 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_cistatic int arp_req_set_public(struct net *net, struct arpreq *r, 102362306a36Sopenharmony_ci struct net_device *dev) 102462306a36Sopenharmony_ci{ 102562306a36Sopenharmony_ci __be32 ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr; 102662306a36Sopenharmony_ci __be32 mask = ((struct sockaddr_in *)&r->arp_netmask)->sin_addr.s_addr; 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci if (mask && mask != htonl(0xFFFFFFFF)) 102962306a36Sopenharmony_ci return -EINVAL; 103062306a36Sopenharmony_ci if (!dev && (r->arp_flags & ATF_COM)) { 103162306a36Sopenharmony_ci dev = dev_getbyhwaddr_rcu(net, r->arp_ha.sa_family, 103262306a36Sopenharmony_ci r->arp_ha.sa_data); 103362306a36Sopenharmony_ci if (!dev) 103462306a36Sopenharmony_ci return -ENODEV; 103562306a36Sopenharmony_ci } 103662306a36Sopenharmony_ci if (mask) { 103762306a36Sopenharmony_ci if (!pneigh_lookup(&arp_tbl, net, &ip, dev, 1)) 103862306a36Sopenharmony_ci return -ENOBUFS; 103962306a36Sopenharmony_ci return 0; 104062306a36Sopenharmony_ci } 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ci return arp_req_set_proxy(net, dev, 1); 104362306a36Sopenharmony_ci} 104462306a36Sopenharmony_ci 104562306a36Sopenharmony_cistatic int arp_req_set(struct net *net, struct arpreq *r, 104662306a36Sopenharmony_ci struct net_device *dev) 104762306a36Sopenharmony_ci{ 104862306a36Sopenharmony_ci __be32 ip; 104962306a36Sopenharmony_ci struct neighbour *neigh; 105062306a36Sopenharmony_ci int err; 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci if (r->arp_flags & ATF_PUBL) 105362306a36Sopenharmony_ci return arp_req_set_public(net, r, dev); 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr; 105662306a36Sopenharmony_ci if (r->arp_flags & ATF_PERM) 105762306a36Sopenharmony_ci r->arp_flags |= ATF_COM; 105862306a36Sopenharmony_ci if (!dev) { 105962306a36Sopenharmony_ci struct rtable *rt = ip_route_output(net, ip, 0, RTO_ONLINK, 0); 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_ci if (IS_ERR(rt)) 106262306a36Sopenharmony_ci return PTR_ERR(rt); 106362306a36Sopenharmony_ci dev = rt->dst.dev; 106462306a36Sopenharmony_ci ip_rt_put(rt); 106562306a36Sopenharmony_ci if (!dev) 106662306a36Sopenharmony_ci return -EINVAL; 106762306a36Sopenharmony_ci } 106862306a36Sopenharmony_ci switch (dev->type) { 106962306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_FDDI) 107062306a36Sopenharmony_ci case ARPHRD_FDDI: 107162306a36Sopenharmony_ci /* 107262306a36Sopenharmony_ci * According to RFC 1390, FDDI devices should accept ARP 107362306a36Sopenharmony_ci * hardware types of 1 (Ethernet). However, to be more 107462306a36Sopenharmony_ci * robust, we'll accept hardware types of either 1 (Ethernet) 107562306a36Sopenharmony_ci * or 6 (IEEE 802.2). 107662306a36Sopenharmony_ci */ 107762306a36Sopenharmony_ci if (r->arp_ha.sa_family != ARPHRD_FDDI && 107862306a36Sopenharmony_ci r->arp_ha.sa_family != ARPHRD_ETHER && 107962306a36Sopenharmony_ci r->arp_ha.sa_family != ARPHRD_IEEE802) 108062306a36Sopenharmony_ci return -EINVAL; 108162306a36Sopenharmony_ci break; 108262306a36Sopenharmony_ci#endif 108362306a36Sopenharmony_ci default: 108462306a36Sopenharmony_ci if (r->arp_ha.sa_family != dev->type) 108562306a36Sopenharmony_ci return -EINVAL; 108662306a36Sopenharmony_ci break; 108762306a36Sopenharmony_ci } 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ci neigh = __neigh_lookup_errno(&arp_tbl, &ip, dev); 109062306a36Sopenharmony_ci err = PTR_ERR(neigh); 109162306a36Sopenharmony_ci if (!IS_ERR(neigh)) { 109262306a36Sopenharmony_ci unsigned int state = NUD_STALE; 109362306a36Sopenharmony_ci if (r->arp_flags & ATF_PERM) 109462306a36Sopenharmony_ci state = NUD_PERMANENT; 109562306a36Sopenharmony_ci err = neigh_update(neigh, (r->arp_flags & ATF_COM) ? 109662306a36Sopenharmony_ci r->arp_ha.sa_data : NULL, state, 109762306a36Sopenharmony_ci NEIGH_UPDATE_F_OVERRIDE | 109862306a36Sopenharmony_ci NEIGH_UPDATE_F_ADMIN, 0); 109962306a36Sopenharmony_ci neigh_release(neigh); 110062306a36Sopenharmony_ci } 110162306a36Sopenharmony_ci return err; 110262306a36Sopenharmony_ci} 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_cistatic unsigned int arp_state_to_flags(struct neighbour *neigh) 110562306a36Sopenharmony_ci{ 110662306a36Sopenharmony_ci if (neigh->nud_state&NUD_PERMANENT) 110762306a36Sopenharmony_ci return ATF_PERM | ATF_COM; 110862306a36Sopenharmony_ci else if (neigh->nud_state&NUD_VALID) 110962306a36Sopenharmony_ci return ATF_COM; 111062306a36Sopenharmony_ci else 111162306a36Sopenharmony_ci return 0; 111262306a36Sopenharmony_ci} 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_ci/* 111562306a36Sopenharmony_ci * Get an ARP cache entry. 111662306a36Sopenharmony_ci */ 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_cistatic int arp_req_get(struct arpreq *r, struct net_device *dev) 111962306a36Sopenharmony_ci{ 112062306a36Sopenharmony_ci __be32 ip = ((struct sockaddr_in *) &r->arp_pa)->sin_addr.s_addr; 112162306a36Sopenharmony_ci struct neighbour *neigh; 112262306a36Sopenharmony_ci int err = -ENXIO; 112362306a36Sopenharmony_ci 112462306a36Sopenharmony_ci neigh = neigh_lookup(&arp_tbl, &ip, dev); 112562306a36Sopenharmony_ci if (neigh) { 112662306a36Sopenharmony_ci if (!(READ_ONCE(neigh->nud_state) & NUD_NOARP)) { 112762306a36Sopenharmony_ci read_lock_bh(&neigh->lock); 112862306a36Sopenharmony_ci memcpy(r->arp_ha.sa_data, neigh->ha, 112962306a36Sopenharmony_ci min(dev->addr_len, sizeof(r->arp_ha.sa_data_min))); 113062306a36Sopenharmony_ci r->arp_flags = arp_state_to_flags(neigh); 113162306a36Sopenharmony_ci read_unlock_bh(&neigh->lock); 113262306a36Sopenharmony_ci r->arp_ha.sa_family = dev->type; 113362306a36Sopenharmony_ci strscpy(r->arp_dev, dev->name, sizeof(r->arp_dev)); 113462306a36Sopenharmony_ci err = 0; 113562306a36Sopenharmony_ci } 113662306a36Sopenharmony_ci neigh_release(neigh); 113762306a36Sopenharmony_ci } 113862306a36Sopenharmony_ci return err; 113962306a36Sopenharmony_ci} 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ciint arp_invalidate(struct net_device *dev, __be32 ip, bool force) 114262306a36Sopenharmony_ci{ 114362306a36Sopenharmony_ci struct neighbour *neigh = neigh_lookup(&arp_tbl, &ip, dev); 114462306a36Sopenharmony_ci int err = -ENXIO; 114562306a36Sopenharmony_ci struct neigh_table *tbl = &arp_tbl; 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_ci if (neigh) { 114862306a36Sopenharmony_ci if ((READ_ONCE(neigh->nud_state) & NUD_VALID) && !force) { 114962306a36Sopenharmony_ci neigh_release(neigh); 115062306a36Sopenharmony_ci return 0; 115162306a36Sopenharmony_ci } 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_ci if (READ_ONCE(neigh->nud_state) & ~NUD_NOARP) 115462306a36Sopenharmony_ci err = neigh_update(neigh, NULL, NUD_FAILED, 115562306a36Sopenharmony_ci NEIGH_UPDATE_F_OVERRIDE| 115662306a36Sopenharmony_ci NEIGH_UPDATE_F_ADMIN, 0); 115762306a36Sopenharmony_ci write_lock_bh(&tbl->lock); 115862306a36Sopenharmony_ci neigh_release(neigh); 115962306a36Sopenharmony_ci neigh_remove_one(neigh, tbl); 116062306a36Sopenharmony_ci write_unlock_bh(&tbl->lock); 116162306a36Sopenharmony_ci } 116262306a36Sopenharmony_ci 116362306a36Sopenharmony_ci return err; 116462306a36Sopenharmony_ci} 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_cistatic int arp_req_delete_public(struct net *net, struct arpreq *r, 116762306a36Sopenharmony_ci struct net_device *dev) 116862306a36Sopenharmony_ci{ 116962306a36Sopenharmony_ci __be32 ip = ((struct sockaddr_in *) &r->arp_pa)->sin_addr.s_addr; 117062306a36Sopenharmony_ci __be32 mask = ((struct sockaddr_in *)&r->arp_netmask)->sin_addr.s_addr; 117162306a36Sopenharmony_ci 117262306a36Sopenharmony_ci if (mask == htonl(0xFFFFFFFF)) 117362306a36Sopenharmony_ci return pneigh_delete(&arp_tbl, net, &ip, dev); 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ci if (mask) 117662306a36Sopenharmony_ci return -EINVAL; 117762306a36Sopenharmony_ci 117862306a36Sopenharmony_ci return arp_req_set_proxy(net, dev, 0); 117962306a36Sopenharmony_ci} 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_cistatic int arp_req_delete(struct net *net, struct arpreq *r, 118262306a36Sopenharmony_ci struct net_device *dev) 118362306a36Sopenharmony_ci{ 118462306a36Sopenharmony_ci __be32 ip; 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ci if (r->arp_flags & ATF_PUBL) 118762306a36Sopenharmony_ci return arp_req_delete_public(net, r, dev); 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_ci ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr; 119062306a36Sopenharmony_ci if (!dev) { 119162306a36Sopenharmony_ci struct rtable *rt = ip_route_output(net, ip, 0, RTO_ONLINK, 0); 119262306a36Sopenharmony_ci if (IS_ERR(rt)) 119362306a36Sopenharmony_ci return PTR_ERR(rt); 119462306a36Sopenharmony_ci dev = rt->dst.dev; 119562306a36Sopenharmony_ci ip_rt_put(rt); 119662306a36Sopenharmony_ci if (!dev) 119762306a36Sopenharmony_ci return -EINVAL; 119862306a36Sopenharmony_ci } 119962306a36Sopenharmony_ci return arp_invalidate(dev, ip, true); 120062306a36Sopenharmony_ci} 120162306a36Sopenharmony_ci 120262306a36Sopenharmony_ci/* 120362306a36Sopenharmony_ci * Handle an ARP layer I/O control request. 120462306a36Sopenharmony_ci */ 120562306a36Sopenharmony_ci 120662306a36Sopenharmony_ciint arp_ioctl(struct net *net, unsigned int cmd, void __user *arg) 120762306a36Sopenharmony_ci{ 120862306a36Sopenharmony_ci int err; 120962306a36Sopenharmony_ci struct arpreq r; 121062306a36Sopenharmony_ci struct net_device *dev = NULL; 121162306a36Sopenharmony_ci 121262306a36Sopenharmony_ci switch (cmd) { 121362306a36Sopenharmony_ci case SIOCDARP: 121462306a36Sopenharmony_ci case SIOCSARP: 121562306a36Sopenharmony_ci if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) 121662306a36Sopenharmony_ci return -EPERM; 121762306a36Sopenharmony_ci fallthrough; 121862306a36Sopenharmony_ci case SIOCGARP: 121962306a36Sopenharmony_ci err = copy_from_user(&r, arg, sizeof(struct arpreq)); 122062306a36Sopenharmony_ci if (err) 122162306a36Sopenharmony_ci return -EFAULT; 122262306a36Sopenharmony_ci break; 122362306a36Sopenharmony_ci default: 122462306a36Sopenharmony_ci return -EINVAL; 122562306a36Sopenharmony_ci } 122662306a36Sopenharmony_ci 122762306a36Sopenharmony_ci if (r.arp_pa.sa_family != AF_INET) 122862306a36Sopenharmony_ci return -EPFNOSUPPORT; 122962306a36Sopenharmony_ci 123062306a36Sopenharmony_ci if (!(r.arp_flags & ATF_PUBL) && 123162306a36Sopenharmony_ci (r.arp_flags & (ATF_NETMASK | ATF_DONTPUB))) 123262306a36Sopenharmony_ci return -EINVAL; 123362306a36Sopenharmony_ci if (!(r.arp_flags & ATF_NETMASK)) 123462306a36Sopenharmony_ci ((struct sockaddr_in *)&r.arp_netmask)->sin_addr.s_addr = 123562306a36Sopenharmony_ci htonl(0xFFFFFFFFUL); 123662306a36Sopenharmony_ci rtnl_lock(); 123762306a36Sopenharmony_ci if (r.arp_dev[0]) { 123862306a36Sopenharmony_ci err = -ENODEV; 123962306a36Sopenharmony_ci dev = __dev_get_by_name(net, r.arp_dev); 124062306a36Sopenharmony_ci if (!dev) 124162306a36Sopenharmony_ci goto out; 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_ci /* Mmmm... It is wrong... ARPHRD_NETROM==0 */ 124462306a36Sopenharmony_ci if (!r.arp_ha.sa_family) 124562306a36Sopenharmony_ci r.arp_ha.sa_family = dev->type; 124662306a36Sopenharmony_ci err = -EINVAL; 124762306a36Sopenharmony_ci if ((r.arp_flags & ATF_COM) && r.arp_ha.sa_family != dev->type) 124862306a36Sopenharmony_ci goto out; 124962306a36Sopenharmony_ci } else if (cmd == SIOCGARP) { 125062306a36Sopenharmony_ci err = -ENODEV; 125162306a36Sopenharmony_ci goto out; 125262306a36Sopenharmony_ci } 125362306a36Sopenharmony_ci 125462306a36Sopenharmony_ci switch (cmd) { 125562306a36Sopenharmony_ci case SIOCDARP: 125662306a36Sopenharmony_ci err = arp_req_delete(net, &r, dev); 125762306a36Sopenharmony_ci break; 125862306a36Sopenharmony_ci case SIOCSARP: 125962306a36Sopenharmony_ci err = arp_req_set(net, &r, dev); 126062306a36Sopenharmony_ci break; 126162306a36Sopenharmony_ci case SIOCGARP: 126262306a36Sopenharmony_ci err = arp_req_get(&r, dev); 126362306a36Sopenharmony_ci break; 126462306a36Sopenharmony_ci } 126562306a36Sopenharmony_ciout: 126662306a36Sopenharmony_ci rtnl_unlock(); 126762306a36Sopenharmony_ci if (cmd == SIOCGARP && !err && copy_to_user(arg, &r, sizeof(r))) 126862306a36Sopenharmony_ci err = -EFAULT; 126962306a36Sopenharmony_ci return err; 127062306a36Sopenharmony_ci} 127162306a36Sopenharmony_ci 127262306a36Sopenharmony_cistatic int arp_netdev_event(struct notifier_block *this, unsigned long event, 127362306a36Sopenharmony_ci void *ptr) 127462306a36Sopenharmony_ci{ 127562306a36Sopenharmony_ci struct net_device *dev = netdev_notifier_info_to_dev(ptr); 127662306a36Sopenharmony_ci struct netdev_notifier_change_info *change_info; 127762306a36Sopenharmony_ci struct in_device *in_dev; 127862306a36Sopenharmony_ci bool evict_nocarrier; 127962306a36Sopenharmony_ci 128062306a36Sopenharmony_ci switch (event) { 128162306a36Sopenharmony_ci case NETDEV_CHANGEADDR: 128262306a36Sopenharmony_ci neigh_changeaddr(&arp_tbl, dev); 128362306a36Sopenharmony_ci rt_cache_flush(dev_net(dev)); 128462306a36Sopenharmony_ci break; 128562306a36Sopenharmony_ci case NETDEV_CHANGE: 128662306a36Sopenharmony_ci change_info = ptr; 128762306a36Sopenharmony_ci if (change_info->flags_changed & IFF_NOARP) 128862306a36Sopenharmony_ci neigh_changeaddr(&arp_tbl, dev); 128962306a36Sopenharmony_ci 129062306a36Sopenharmony_ci in_dev = __in_dev_get_rtnl(dev); 129162306a36Sopenharmony_ci if (!in_dev) 129262306a36Sopenharmony_ci evict_nocarrier = true; 129362306a36Sopenharmony_ci else 129462306a36Sopenharmony_ci evict_nocarrier = IN_DEV_ARP_EVICT_NOCARRIER(in_dev); 129562306a36Sopenharmony_ci 129662306a36Sopenharmony_ci if (evict_nocarrier && !netif_carrier_ok(dev)) 129762306a36Sopenharmony_ci neigh_carrier_down(&arp_tbl, dev); 129862306a36Sopenharmony_ci break; 129962306a36Sopenharmony_ci default: 130062306a36Sopenharmony_ci break; 130162306a36Sopenharmony_ci } 130262306a36Sopenharmony_ci 130362306a36Sopenharmony_ci return NOTIFY_DONE; 130462306a36Sopenharmony_ci} 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_cistatic struct notifier_block arp_netdev_notifier = { 130762306a36Sopenharmony_ci .notifier_call = arp_netdev_event, 130862306a36Sopenharmony_ci}; 130962306a36Sopenharmony_ci 131062306a36Sopenharmony_ci/* Note, that it is not on notifier chain. 131162306a36Sopenharmony_ci It is necessary, that this routine was called after route cache will be 131262306a36Sopenharmony_ci flushed. 131362306a36Sopenharmony_ci */ 131462306a36Sopenharmony_civoid arp_ifdown(struct net_device *dev) 131562306a36Sopenharmony_ci{ 131662306a36Sopenharmony_ci neigh_ifdown(&arp_tbl, dev); 131762306a36Sopenharmony_ci} 131862306a36Sopenharmony_ci 131962306a36Sopenharmony_ci 132062306a36Sopenharmony_ci/* 132162306a36Sopenharmony_ci * Called once on startup. 132262306a36Sopenharmony_ci */ 132362306a36Sopenharmony_ci 132462306a36Sopenharmony_cistatic struct packet_type arp_packet_type __read_mostly = { 132562306a36Sopenharmony_ci .type = cpu_to_be16(ETH_P_ARP), 132662306a36Sopenharmony_ci .func = arp_rcv, 132762306a36Sopenharmony_ci}; 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_ci#ifdef CONFIG_PROC_FS 133062306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_AX25) 133162306a36Sopenharmony_ci 133262306a36Sopenharmony_ci/* 133362306a36Sopenharmony_ci * ax25 -> ASCII conversion 133462306a36Sopenharmony_ci */ 133562306a36Sopenharmony_cistatic void ax2asc2(ax25_address *a, char *buf) 133662306a36Sopenharmony_ci{ 133762306a36Sopenharmony_ci char c, *s; 133862306a36Sopenharmony_ci int n; 133962306a36Sopenharmony_ci 134062306a36Sopenharmony_ci for (n = 0, s = buf; n < 6; n++) { 134162306a36Sopenharmony_ci c = (a->ax25_call[n] >> 1) & 0x7F; 134262306a36Sopenharmony_ci 134362306a36Sopenharmony_ci if (c != ' ') 134462306a36Sopenharmony_ci *s++ = c; 134562306a36Sopenharmony_ci } 134662306a36Sopenharmony_ci 134762306a36Sopenharmony_ci *s++ = '-'; 134862306a36Sopenharmony_ci n = (a->ax25_call[6] >> 1) & 0x0F; 134962306a36Sopenharmony_ci if (n > 9) { 135062306a36Sopenharmony_ci *s++ = '1'; 135162306a36Sopenharmony_ci n -= 10; 135262306a36Sopenharmony_ci } 135362306a36Sopenharmony_ci 135462306a36Sopenharmony_ci *s++ = n + '0'; 135562306a36Sopenharmony_ci *s++ = '\0'; 135662306a36Sopenharmony_ci 135762306a36Sopenharmony_ci if (*buf == '\0' || *buf == '-') { 135862306a36Sopenharmony_ci buf[0] = '*'; 135962306a36Sopenharmony_ci buf[1] = '\0'; 136062306a36Sopenharmony_ci } 136162306a36Sopenharmony_ci} 136262306a36Sopenharmony_ci#endif /* CONFIG_AX25 */ 136362306a36Sopenharmony_ci 136462306a36Sopenharmony_ci#define HBUFFERLEN 30 136562306a36Sopenharmony_ci 136662306a36Sopenharmony_cistatic void arp_format_neigh_entry(struct seq_file *seq, 136762306a36Sopenharmony_ci struct neighbour *n) 136862306a36Sopenharmony_ci{ 136962306a36Sopenharmony_ci char hbuffer[HBUFFERLEN]; 137062306a36Sopenharmony_ci int k, j; 137162306a36Sopenharmony_ci char tbuf[16]; 137262306a36Sopenharmony_ci struct net_device *dev = n->dev; 137362306a36Sopenharmony_ci int hatype = dev->type; 137462306a36Sopenharmony_ci 137562306a36Sopenharmony_ci read_lock(&n->lock); 137662306a36Sopenharmony_ci /* Convert hardware address to XX:XX:XX:XX ... form. */ 137762306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_AX25) 137862306a36Sopenharmony_ci if (hatype == ARPHRD_AX25 || hatype == ARPHRD_NETROM) 137962306a36Sopenharmony_ci ax2asc2((ax25_address *)n->ha, hbuffer); 138062306a36Sopenharmony_ci else { 138162306a36Sopenharmony_ci#endif 138262306a36Sopenharmony_ci for (k = 0, j = 0; k < HBUFFERLEN - 3 && j < dev->addr_len; j++) { 138362306a36Sopenharmony_ci hbuffer[k++] = hex_asc_hi(n->ha[j]); 138462306a36Sopenharmony_ci hbuffer[k++] = hex_asc_lo(n->ha[j]); 138562306a36Sopenharmony_ci hbuffer[k++] = ':'; 138662306a36Sopenharmony_ci } 138762306a36Sopenharmony_ci if (k != 0) 138862306a36Sopenharmony_ci --k; 138962306a36Sopenharmony_ci hbuffer[k] = 0; 139062306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_AX25) 139162306a36Sopenharmony_ci } 139262306a36Sopenharmony_ci#endif 139362306a36Sopenharmony_ci sprintf(tbuf, "%pI4", n->primary_key); 139462306a36Sopenharmony_ci seq_printf(seq, "%-16s 0x%-10x0x%-10x%-17s * %s\n", 139562306a36Sopenharmony_ci tbuf, hatype, arp_state_to_flags(n), hbuffer, dev->name); 139662306a36Sopenharmony_ci read_unlock(&n->lock); 139762306a36Sopenharmony_ci} 139862306a36Sopenharmony_ci 139962306a36Sopenharmony_cistatic void arp_format_pneigh_entry(struct seq_file *seq, 140062306a36Sopenharmony_ci struct pneigh_entry *n) 140162306a36Sopenharmony_ci{ 140262306a36Sopenharmony_ci struct net_device *dev = n->dev; 140362306a36Sopenharmony_ci int hatype = dev ? dev->type : 0; 140462306a36Sopenharmony_ci char tbuf[16]; 140562306a36Sopenharmony_ci 140662306a36Sopenharmony_ci sprintf(tbuf, "%pI4", n->key); 140762306a36Sopenharmony_ci seq_printf(seq, "%-16s 0x%-10x0x%-10x%s * %s\n", 140862306a36Sopenharmony_ci tbuf, hatype, ATF_PUBL | ATF_PERM, "00:00:00:00:00:00", 140962306a36Sopenharmony_ci dev ? dev->name : "*"); 141062306a36Sopenharmony_ci} 141162306a36Sopenharmony_ci 141262306a36Sopenharmony_cistatic int arp_seq_show(struct seq_file *seq, void *v) 141362306a36Sopenharmony_ci{ 141462306a36Sopenharmony_ci if (v == SEQ_START_TOKEN) { 141562306a36Sopenharmony_ci seq_puts(seq, "IP address HW type Flags " 141662306a36Sopenharmony_ci "HW address Mask Device\n"); 141762306a36Sopenharmony_ci } else { 141862306a36Sopenharmony_ci struct neigh_seq_state *state = seq->private; 141962306a36Sopenharmony_ci 142062306a36Sopenharmony_ci if (state->flags & NEIGH_SEQ_IS_PNEIGH) 142162306a36Sopenharmony_ci arp_format_pneigh_entry(seq, v); 142262306a36Sopenharmony_ci else 142362306a36Sopenharmony_ci arp_format_neigh_entry(seq, v); 142462306a36Sopenharmony_ci } 142562306a36Sopenharmony_ci 142662306a36Sopenharmony_ci return 0; 142762306a36Sopenharmony_ci} 142862306a36Sopenharmony_ci 142962306a36Sopenharmony_cistatic void *arp_seq_start(struct seq_file *seq, loff_t *pos) 143062306a36Sopenharmony_ci{ 143162306a36Sopenharmony_ci /* Don't want to confuse "arp -a" w/ magic entries, 143262306a36Sopenharmony_ci * so we tell the generic iterator to skip NUD_NOARP. 143362306a36Sopenharmony_ci */ 143462306a36Sopenharmony_ci return neigh_seq_start(seq, pos, &arp_tbl, NEIGH_SEQ_SKIP_NOARP); 143562306a36Sopenharmony_ci} 143662306a36Sopenharmony_ci 143762306a36Sopenharmony_cistatic const struct seq_operations arp_seq_ops = { 143862306a36Sopenharmony_ci .start = arp_seq_start, 143962306a36Sopenharmony_ci .next = neigh_seq_next, 144062306a36Sopenharmony_ci .stop = neigh_seq_stop, 144162306a36Sopenharmony_ci .show = arp_seq_show, 144262306a36Sopenharmony_ci}; 144362306a36Sopenharmony_ci#endif /* CONFIG_PROC_FS */ 144462306a36Sopenharmony_ci 144562306a36Sopenharmony_cistatic int __net_init arp_net_init(struct net *net) 144662306a36Sopenharmony_ci{ 144762306a36Sopenharmony_ci if (!proc_create_net("arp", 0444, net->proc_net, &arp_seq_ops, 144862306a36Sopenharmony_ci sizeof(struct neigh_seq_state))) 144962306a36Sopenharmony_ci return -ENOMEM; 145062306a36Sopenharmony_ci return 0; 145162306a36Sopenharmony_ci} 145262306a36Sopenharmony_ci 145362306a36Sopenharmony_cistatic void __net_exit arp_net_exit(struct net *net) 145462306a36Sopenharmony_ci{ 145562306a36Sopenharmony_ci remove_proc_entry("arp", net->proc_net); 145662306a36Sopenharmony_ci} 145762306a36Sopenharmony_ci 145862306a36Sopenharmony_cistatic struct pernet_operations arp_net_ops = { 145962306a36Sopenharmony_ci .init = arp_net_init, 146062306a36Sopenharmony_ci .exit = arp_net_exit, 146162306a36Sopenharmony_ci}; 146262306a36Sopenharmony_ci 146362306a36Sopenharmony_civoid __init arp_init(void) 146462306a36Sopenharmony_ci{ 146562306a36Sopenharmony_ci neigh_table_init(NEIGH_ARP_TABLE, &arp_tbl); 146662306a36Sopenharmony_ci 146762306a36Sopenharmony_ci dev_add_pack(&arp_packet_type); 146862306a36Sopenharmony_ci register_pernet_subsys(&arp_net_ops); 146962306a36Sopenharmony_ci#ifdef CONFIG_SYSCTL 147062306a36Sopenharmony_ci neigh_sysctl_register(NULL, &arp_tbl.parms, NULL); 147162306a36Sopenharmony_ci#endif 147262306a36Sopenharmony_ci register_netdevice_notifier(&arp_netdev_notifier); 147362306a36Sopenharmony_ci} 1474