18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* linux/net/ipv4/arp.c 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 1994 by Florian La Roche 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * This module implements the Address Resolution Protocol ARP (RFC 826), 78c2ecf20Sopenharmony_ci * which is used to convert IP addresses (or in the future maybe other 88c2ecf20Sopenharmony_ci * high-level addresses) into a low-level hardware address (like an Ethernet 98c2ecf20Sopenharmony_ci * address). 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * Fixes: 128c2ecf20Sopenharmony_ci * Alan Cox : Removed the Ethernet assumptions in 138c2ecf20Sopenharmony_ci * Florian's code 148c2ecf20Sopenharmony_ci * Alan Cox : Fixed some small errors in the ARP 158c2ecf20Sopenharmony_ci * logic 168c2ecf20Sopenharmony_ci * Alan Cox : Allow >4K in /proc 178c2ecf20Sopenharmony_ci * Alan Cox : Make ARP add its own protocol entry 188c2ecf20Sopenharmony_ci * Ross Martin : Rewrote arp_rcv() and arp_get_info() 198c2ecf20Sopenharmony_ci * Stephen Henson : Add AX25 support to arp_get_info() 208c2ecf20Sopenharmony_ci * Alan Cox : Drop data when a device is downed. 218c2ecf20Sopenharmony_ci * Alan Cox : Use init_timer(). 228c2ecf20Sopenharmony_ci * Alan Cox : Double lock fixes. 238c2ecf20Sopenharmony_ci * Martin Seine : Move the arphdr structure 248c2ecf20Sopenharmony_ci * to if_arp.h for compatibility. 258c2ecf20Sopenharmony_ci * with BSD based programs. 268c2ecf20Sopenharmony_ci * Andrew Tridgell : Added ARP netmask code and 278c2ecf20Sopenharmony_ci * re-arranged proxy handling. 288c2ecf20Sopenharmony_ci * Alan Cox : Changed to use notifiers. 298c2ecf20Sopenharmony_ci * Niibe Yutaka : Reply for this device or proxies only. 308c2ecf20Sopenharmony_ci * Alan Cox : Don't proxy across hardware types! 318c2ecf20Sopenharmony_ci * Jonathan Naylor : Added support for NET/ROM. 328c2ecf20Sopenharmony_ci * Mike Shaver : RFC1122 checks. 338c2ecf20Sopenharmony_ci * Jonathan Naylor : Only lookup the hardware address for 348c2ecf20Sopenharmony_ci * the correct hardware type. 358c2ecf20Sopenharmony_ci * Germano Caronni : Assorted subtle races. 368c2ecf20Sopenharmony_ci * Craig Schlenter : Don't modify permanent entry 378c2ecf20Sopenharmony_ci * during arp_rcv. 388c2ecf20Sopenharmony_ci * Russ Nelson : Tidied up a few bits. 398c2ecf20Sopenharmony_ci * Alexey Kuznetsov: Major changes to caching and behaviour, 408c2ecf20Sopenharmony_ci * eg intelligent arp probing and 418c2ecf20Sopenharmony_ci * generation 428c2ecf20Sopenharmony_ci * of host down events. 438c2ecf20Sopenharmony_ci * Alan Cox : Missing unlock in device events. 448c2ecf20Sopenharmony_ci * Eckes : ARP ioctl control errors. 458c2ecf20Sopenharmony_ci * Alexey Kuznetsov: Arp free fix. 468c2ecf20Sopenharmony_ci * Manuel Rodriguez: Gratuitous ARP. 478c2ecf20Sopenharmony_ci * Jonathan Layes : Added arpd support through kerneld 488c2ecf20Sopenharmony_ci * message queue (960314) 498c2ecf20Sopenharmony_ci * Mike Shaver : /proc/sys/net/ipv4/arp_* support 508c2ecf20Sopenharmony_ci * Mike McLagan : Routing by source 518c2ecf20Sopenharmony_ci * Stuart Cheshire : Metricom and grat arp fixes 528c2ecf20Sopenharmony_ci * *** FOR 2.1 clean this up *** 538c2ecf20Sopenharmony_ci * Lawrence V. Stefani: (08/12/96) Added FDDI support. 548c2ecf20Sopenharmony_ci * Alan Cox : Took the AP1000 nasty FDDI hack and 558c2ecf20Sopenharmony_ci * folded into the mainstream FDDI code. 568c2ecf20Sopenharmony_ci * Ack spit, Linus how did you allow that 578c2ecf20Sopenharmony_ci * one in... 588c2ecf20Sopenharmony_ci * Jes Sorensen : Make FDDI work again in 2.1.x and 598c2ecf20Sopenharmony_ci * clean up the APFDDI & gen. FDDI bits. 608c2ecf20Sopenharmony_ci * Alexey Kuznetsov: new arp state machine; 618c2ecf20Sopenharmony_ci * now it is in net/core/neighbour.c. 628c2ecf20Sopenharmony_ci * Krzysztof Halasa: Added Frame Relay ARP support. 638c2ecf20Sopenharmony_ci * Arnaldo C. Melo : convert /proc/net/arp to seq_file 648c2ecf20Sopenharmony_ci * Shmulik Hen: Split arp_send to arp_create and 658c2ecf20Sopenharmony_ci * arp_xmit so intermediate drivers like 668c2ecf20Sopenharmony_ci * bonding can change the skb before 678c2ecf20Sopenharmony_ci * sending (e.g. insert 8021q tag). 688c2ecf20Sopenharmony_ci * Harald Welte : convert to make use of jenkins hash 698c2ecf20Sopenharmony_ci * Jesper D. Brouer: Proxy ARP PVLAN RFC 3069 support. 708c2ecf20Sopenharmony_ci */ 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci#include <linux/module.h> 758c2ecf20Sopenharmony_ci#include <linux/types.h> 768c2ecf20Sopenharmony_ci#include <linux/string.h> 778c2ecf20Sopenharmony_ci#include <linux/kernel.h> 788c2ecf20Sopenharmony_ci#include <linux/capability.h> 798c2ecf20Sopenharmony_ci#include <linux/socket.h> 808c2ecf20Sopenharmony_ci#include <linux/sockios.h> 818c2ecf20Sopenharmony_ci#include <linux/errno.h> 828c2ecf20Sopenharmony_ci#include <linux/in.h> 838c2ecf20Sopenharmony_ci#include <linux/mm.h> 848c2ecf20Sopenharmony_ci#include <linux/inet.h> 858c2ecf20Sopenharmony_ci#include <linux/inetdevice.h> 868c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 878c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 888c2ecf20Sopenharmony_ci#include <linux/fddidevice.h> 898c2ecf20Sopenharmony_ci#include <linux/if_arp.h> 908c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 918c2ecf20Sopenharmony_ci#include <linux/proc_fs.h> 928c2ecf20Sopenharmony_ci#include <linux/seq_file.h> 938c2ecf20Sopenharmony_ci#include <linux/stat.h> 948c2ecf20Sopenharmony_ci#include <linux/init.h> 958c2ecf20Sopenharmony_ci#include <linux/net.h> 968c2ecf20Sopenharmony_ci#include <linux/rcupdate.h> 978c2ecf20Sopenharmony_ci#include <linux/slab.h> 988c2ecf20Sopenharmony_ci#ifdef CONFIG_SYSCTL 998c2ecf20Sopenharmony_ci#include <linux/sysctl.h> 1008c2ecf20Sopenharmony_ci#endif 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci#include <net/net_namespace.h> 1038c2ecf20Sopenharmony_ci#include <net/ip.h> 1048c2ecf20Sopenharmony_ci#include <net/icmp.h> 1058c2ecf20Sopenharmony_ci#include <net/route.h> 1068c2ecf20Sopenharmony_ci#include <net/protocol.h> 1078c2ecf20Sopenharmony_ci#include <net/tcp.h> 1088c2ecf20Sopenharmony_ci#include <net/sock.h> 1098c2ecf20Sopenharmony_ci#include <net/arp.h> 1108c2ecf20Sopenharmony_ci#include <net/ax25.h> 1118c2ecf20Sopenharmony_ci#include <net/netrom.h> 1128c2ecf20Sopenharmony_ci#include <net/dst_metadata.h> 1138c2ecf20Sopenharmony_ci#include <net/ip_tunnels.h> 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci#include <linux/netfilter_arp.h> 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci/* 1208c2ecf20Sopenharmony_ci * Interface to generic neighbour cache. 1218c2ecf20Sopenharmony_ci */ 1228c2ecf20Sopenharmony_cistatic u32 arp_hash(const void *pkey, const struct net_device *dev, __u32 *hash_rnd); 1238c2ecf20Sopenharmony_cistatic bool arp_key_eq(const struct neighbour *n, const void *pkey); 1248c2ecf20Sopenharmony_cistatic int arp_constructor(struct neighbour *neigh); 1258c2ecf20Sopenharmony_cistatic void arp_solicit(struct neighbour *neigh, struct sk_buff *skb); 1268c2ecf20Sopenharmony_cistatic void arp_error_report(struct neighbour *neigh, struct sk_buff *skb); 1278c2ecf20Sopenharmony_cistatic void parp_redo(struct sk_buff *skb); 1288c2ecf20Sopenharmony_cistatic int arp_is_multicast(const void *pkey); 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cistatic const struct neigh_ops arp_generic_ops = { 1318c2ecf20Sopenharmony_ci .family = AF_INET, 1328c2ecf20Sopenharmony_ci .solicit = arp_solicit, 1338c2ecf20Sopenharmony_ci .error_report = arp_error_report, 1348c2ecf20Sopenharmony_ci .output = neigh_resolve_output, 1358c2ecf20Sopenharmony_ci .connected_output = neigh_connected_output, 1368c2ecf20Sopenharmony_ci}; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_cistatic const struct neigh_ops arp_hh_ops = { 1398c2ecf20Sopenharmony_ci .family = AF_INET, 1408c2ecf20Sopenharmony_ci .solicit = arp_solicit, 1418c2ecf20Sopenharmony_ci .error_report = arp_error_report, 1428c2ecf20Sopenharmony_ci .output = neigh_resolve_output, 1438c2ecf20Sopenharmony_ci .connected_output = neigh_resolve_output, 1448c2ecf20Sopenharmony_ci}; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_cistatic const struct neigh_ops arp_direct_ops = { 1478c2ecf20Sopenharmony_ci .family = AF_INET, 1488c2ecf20Sopenharmony_ci .output = neigh_direct_output, 1498c2ecf20Sopenharmony_ci .connected_output = neigh_direct_output, 1508c2ecf20Sopenharmony_ci}; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_cistruct neigh_table arp_tbl = { 1538c2ecf20Sopenharmony_ci .family = AF_INET, 1548c2ecf20Sopenharmony_ci .key_len = 4, 1558c2ecf20Sopenharmony_ci .protocol = cpu_to_be16(ETH_P_IP), 1568c2ecf20Sopenharmony_ci .hash = arp_hash, 1578c2ecf20Sopenharmony_ci .key_eq = arp_key_eq, 1588c2ecf20Sopenharmony_ci .constructor = arp_constructor, 1598c2ecf20Sopenharmony_ci .proxy_redo = parp_redo, 1608c2ecf20Sopenharmony_ci .is_multicast = arp_is_multicast, 1618c2ecf20Sopenharmony_ci .id = "arp_cache", 1628c2ecf20Sopenharmony_ci .parms = { 1638c2ecf20Sopenharmony_ci .tbl = &arp_tbl, 1648c2ecf20Sopenharmony_ci .reachable_time = 30 * HZ, 1658c2ecf20Sopenharmony_ci .data = { 1668c2ecf20Sopenharmony_ci [NEIGH_VAR_MCAST_PROBES] = 3, 1678c2ecf20Sopenharmony_ci [NEIGH_VAR_UCAST_PROBES] = 3, 1688c2ecf20Sopenharmony_ci [NEIGH_VAR_RETRANS_TIME] = 1 * HZ, 1698c2ecf20Sopenharmony_ci [NEIGH_VAR_BASE_REACHABLE_TIME] = 30 * HZ, 1708c2ecf20Sopenharmony_ci [NEIGH_VAR_DELAY_PROBE_TIME] = 5 * HZ, 1718c2ecf20Sopenharmony_ci [NEIGH_VAR_GC_STALETIME] = 60 * HZ, 1728c2ecf20Sopenharmony_ci [NEIGH_VAR_QUEUE_LEN_BYTES] = SK_WMEM_MAX, 1738c2ecf20Sopenharmony_ci [NEIGH_VAR_PROXY_QLEN] = 64, 1748c2ecf20Sopenharmony_ci [NEIGH_VAR_ANYCAST_DELAY] = 1 * HZ, 1758c2ecf20Sopenharmony_ci [NEIGH_VAR_PROXY_DELAY] = (8 * HZ) / 10, 1768c2ecf20Sopenharmony_ci [NEIGH_VAR_LOCKTIME] = 1 * HZ, 1778c2ecf20Sopenharmony_ci }, 1788c2ecf20Sopenharmony_ci }, 1798c2ecf20Sopenharmony_ci .gc_interval = 30 * HZ, 1808c2ecf20Sopenharmony_ci .gc_thresh1 = 128, 1818c2ecf20Sopenharmony_ci .gc_thresh2 = 512, 1828c2ecf20Sopenharmony_ci .gc_thresh3 = 1024, 1838c2ecf20Sopenharmony_ci}; 1848c2ecf20Sopenharmony_ciEXPORT_SYMBOL(arp_tbl); 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ciint arp_mc_map(__be32 addr, u8 *haddr, struct net_device *dev, int dir) 1878c2ecf20Sopenharmony_ci{ 1888c2ecf20Sopenharmony_ci switch (dev->type) { 1898c2ecf20Sopenharmony_ci case ARPHRD_ETHER: 1908c2ecf20Sopenharmony_ci case ARPHRD_FDDI: 1918c2ecf20Sopenharmony_ci case ARPHRD_IEEE802: 1928c2ecf20Sopenharmony_ci ip_eth_mc_map(addr, haddr); 1938c2ecf20Sopenharmony_ci return 0; 1948c2ecf20Sopenharmony_ci case ARPHRD_INFINIBAND: 1958c2ecf20Sopenharmony_ci ip_ib_mc_map(addr, dev->broadcast, haddr); 1968c2ecf20Sopenharmony_ci return 0; 1978c2ecf20Sopenharmony_ci case ARPHRD_IPGRE: 1988c2ecf20Sopenharmony_ci ip_ipgre_mc_map(addr, dev->broadcast, haddr); 1998c2ecf20Sopenharmony_ci return 0; 2008c2ecf20Sopenharmony_ci default: 2018c2ecf20Sopenharmony_ci if (dir) { 2028c2ecf20Sopenharmony_ci memcpy(haddr, dev->broadcast, dev->addr_len); 2038c2ecf20Sopenharmony_ci return 0; 2048c2ecf20Sopenharmony_ci } 2058c2ecf20Sopenharmony_ci } 2068c2ecf20Sopenharmony_ci return -EINVAL; 2078c2ecf20Sopenharmony_ci} 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_cistatic u32 arp_hash(const void *pkey, 2118c2ecf20Sopenharmony_ci const struct net_device *dev, 2128c2ecf20Sopenharmony_ci __u32 *hash_rnd) 2138c2ecf20Sopenharmony_ci{ 2148c2ecf20Sopenharmony_ci return arp_hashfn(pkey, dev, hash_rnd); 2158c2ecf20Sopenharmony_ci} 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_cistatic bool arp_key_eq(const struct neighbour *neigh, const void *pkey) 2188c2ecf20Sopenharmony_ci{ 2198c2ecf20Sopenharmony_ci return neigh_key_eq32(neigh, pkey); 2208c2ecf20Sopenharmony_ci} 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_cistatic int arp_constructor(struct neighbour *neigh) 2238c2ecf20Sopenharmony_ci{ 2248c2ecf20Sopenharmony_ci __be32 addr; 2258c2ecf20Sopenharmony_ci struct net_device *dev = neigh->dev; 2268c2ecf20Sopenharmony_ci struct in_device *in_dev; 2278c2ecf20Sopenharmony_ci struct neigh_parms *parms; 2288c2ecf20Sopenharmony_ci u32 inaddr_any = INADDR_ANY; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci if (dev->flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) 2318c2ecf20Sopenharmony_ci memcpy(neigh->primary_key, &inaddr_any, arp_tbl.key_len); 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci addr = *(__be32 *)neigh->primary_key; 2348c2ecf20Sopenharmony_ci rcu_read_lock(); 2358c2ecf20Sopenharmony_ci in_dev = __in_dev_get_rcu(dev); 2368c2ecf20Sopenharmony_ci if (!in_dev) { 2378c2ecf20Sopenharmony_ci rcu_read_unlock(); 2388c2ecf20Sopenharmony_ci return -EINVAL; 2398c2ecf20Sopenharmony_ci } 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci neigh->type = inet_addr_type_dev_table(dev_net(dev), dev, addr); 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci parms = in_dev->arp_parms; 2448c2ecf20Sopenharmony_ci __neigh_parms_put(neigh->parms); 2458c2ecf20Sopenharmony_ci neigh->parms = neigh_parms_clone(parms); 2468c2ecf20Sopenharmony_ci rcu_read_unlock(); 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci if (!dev->header_ops) { 2498c2ecf20Sopenharmony_ci neigh->nud_state = NUD_NOARP; 2508c2ecf20Sopenharmony_ci neigh->ops = &arp_direct_ops; 2518c2ecf20Sopenharmony_ci neigh->output = neigh_direct_output; 2528c2ecf20Sopenharmony_ci } else { 2538c2ecf20Sopenharmony_ci /* Good devices (checked by reading texts, but only Ethernet is 2548c2ecf20Sopenharmony_ci tested) 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci ARPHRD_ETHER: (ethernet, apfddi) 2578c2ecf20Sopenharmony_ci ARPHRD_FDDI: (fddi) 2588c2ecf20Sopenharmony_ci ARPHRD_IEEE802: (tr) 2598c2ecf20Sopenharmony_ci ARPHRD_METRICOM: (strip) 2608c2ecf20Sopenharmony_ci ARPHRD_ARCNET: 2618c2ecf20Sopenharmony_ci etc. etc. etc. 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci ARPHRD_IPDDP will also work, if author repairs it. 2648c2ecf20Sopenharmony_ci I did not it, because this driver does not work even 2658c2ecf20Sopenharmony_ci in old paradigm. 2668c2ecf20Sopenharmony_ci */ 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci if (neigh->type == RTN_MULTICAST) { 2698c2ecf20Sopenharmony_ci neigh->nud_state = NUD_NOARP; 2708c2ecf20Sopenharmony_ci arp_mc_map(addr, neigh->ha, dev, 1); 2718c2ecf20Sopenharmony_ci } else if (dev->flags & (IFF_NOARP | IFF_LOOPBACK)) { 2728c2ecf20Sopenharmony_ci neigh->nud_state = NUD_NOARP; 2738c2ecf20Sopenharmony_ci memcpy(neigh->ha, dev->dev_addr, dev->addr_len); 2748c2ecf20Sopenharmony_ci } else if (neigh->type == RTN_BROADCAST || 2758c2ecf20Sopenharmony_ci (dev->flags & IFF_POINTOPOINT)) { 2768c2ecf20Sopenharmony_ci neigh->nud_state = NUD_NOARP; 2778c2ecf20Sopenharmony_ci memcpy(neigh->ha, dev->broadcast, dev->addr_len); 2788c2ecf20Sopenharmony_ci } 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci if (dev->header_ops->cache) 2818c2ecf20Sopenharmony_ci neigh->ops = &arp_hh_ops; 2828c2ecf20Sopenharmony_ci else 2838c2ecf20Sopenharmony_ci neigh->ops = &arp_generic_ops; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci if (neigh->nud_state & NUD_VALID) 2868c2ecf20Sopenharmony_ci neigh->output = neigh->ops->connected_output; 2878c2ecf20Sopenharmony_ci else 2888c2ecf20Sopenharmony_ci neigh->output = neigh->ops->output; 2898c2ecf20Sopenharmony_ci } 2908c2ecf20Sopenharmony_ci return 0; 2918c2ecf20Sopenharmony_ci} 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_cistatic void arp_error_report(struct neighbour *neigh, struct sk_buff *skb) 2948c2ecf20Sopenharmony_ci{ 2958c2ecf20Sopenharmony_ci dst_link_failure(skb); 2968c2ecf20Sopenharmony_ci kfree_skb(skb); 2978c2ecf20Sopenharmony_ci} 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci/* Create and send an arp packet. */ 3008c2ecf20Sopenharmony_cistatic void arp_send_dst(int type, int ptype, __be32 dest_ip, 3018c2ecf20Sopenharmony_ci struct net_device *dev, __be32 src_ip, 3028c2ecf20Sopenharmony_ci const unsigned char *dest_hw, 3038c2ecf20Sopenharmony_ci const unsigned char *src_hw, 3048c2ecf20Sopenharmony_ci const unsigned char *target_hw, 3058c2ecf20Sopenharmony_ci struct dst_entry *dst) 3068c2ecf20Sopenharmony_ci{ 3078c2ecf20Sopenharmony_ci struct sk_buff *skb; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci /* arp on this interface. */ 3108c2ecf20Sopenharmony_ci if (dev->flags & IFF_NOARP) 3118c2ecf20Sopenharmony_ci return; 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci skb = arp_create(type, ptype, dest_ip, dev, src_ip, 3148c2ecf20Sopenharmony_ci dest_hw, src_hw, target_hw); 3158c2ecf20Sopenharmony_ci if (!skb) 3168c2ecf20Sopenharmony_ci return; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci skb_dst_set(skb, dst_clone(dst)); 3198c2ecf20Sopenharmony_ci arp_xmit(skb); 3208c2ecf20Sopenharmony_ci} 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_civoid arp_send(int type, int ptype, __be32 dest_ip, 3238c2ecf20Sopenharmony_ci struct net_device *dev, __be32 src_ip, 3248c2ecf20Sopenharmony_ci const unsigned char *dest_hw, const unsigned char *src_hw, 3258c2ecf20Sopenharmony_ci const unsigned char *target_hw) 3268c2ecf20Sopenharmony_ci{ 3278c2ecf20Sopenharmony_ci arp_send_dst(type, ptype, dest_ip, dev, src_ip, dest_hw, src_hw, 3288c2ecf20Sopenharmony_ci target_hw, NULL); 3298c2ecf20Sopenharmony_ci} 3308c2ecf20Sopenharmony_ciEXPORT_SYMBOL(arp_send); 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_cistatic void arp_solicit(struct neighbour *neigh, struct sk_buff *skb) 3338c2ecf20Sopenharmony_ci{ 3348c2ecf20Sopenharmony_ci __be32 saddr = 0; 3358c2ecf20Sopenharmony_ci u8 dst_ha[MAX_ADDR_LEN], *dst_hw = NULL; 3368c2ecf20Sopenharmony_ci struct net_device *dev = neigh->dev; 3378c2ecf20Sopenharmony_ci __be32 target = *(__be32 *)neigh->primary_key; 3388c2ecf20Sopenharmony_ci int probes = atomic_read(&neigh->probes); 3398c2ecf20Sopenharmony_ci struct in_device *in_dev; 3408c2ecf20Sopenharmony_ci struct dst_entry *dst = NULL; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci rcu_read_lock(); 3438c2ecf20Sopenharmony_ci in_dev = __in_dev_get_rcu(dev); 3448c2ecf20Sopenharmony_ci if (!in_dev) { 3458c2ecf20Sopenharmony_ci rcu_read_unlock(); 3468c2ecf20Sopenharmony_ci return; 3478c2ecf20Sopenharmony_ci } 3488c2ecf20Sopenharmony_ci switch (IN_DEV_ARP_ANNOUNCE(in_dev)) { 3498c2ecf20Sopenharmony_ci default: 3508c2ecf20Sopenharmony_ci case 0: /* By default announce any local IP */ 3518c2ecf20Sopenharmony_ci if (skb && inet_addr_type_dev_table(dev_net(dev), dev, 3528c2ecf20Sopenharmony_ci ip_hdr(skb)->saddr) == RTN_LOCAL) 3538c2ecf20Sopenharmony_ci saddr = ip_hdr(skb)->saddr; 3548c2ecf20Sopenharmony_ci break; 3558c2ecf20Sopenharmony_ci case 1: /* Restrict announcements of saddr in same subnet */ 3568c2ecf20Sopenharmony_ci if (!skb) 3578c2ecf20Sopenharmony_ci break; 3588c2ecf20Sopenharmony_ci saddr = ip_hdr(skb)->saddr; 3598c2ecf20Sopenharmony_ci if (inet_addr_type_dev_table(dev_net(dev), dev, 3608c2ecf20Sopenharmony_ci saddr) == RTN_LOCAL) { 3618c2ecf20Sopenharmony_ci /* saddr should be known to target */ 3628c2ecf20Sopenharmony_ci if (inet_addr_onlink(in_dev, target, saddr)) 3638c2ecf20Sopenharmony_ci break; 3648c2ecf20Sopenharmony_ci } 3658c2ecf20Sopenharmony_ci saddr = 0; 3668c2ecf20Sopenharmony_ci break; 3678c2ecf20Sopenharmony_ci case 2: /* Avoid secondary IPs, get a primary/preferred one */ 3688c2ecf20Sopenharmony_ci break; 3698c2ecf20Sopenharmony_ci } 3708c2ecf20Sopenharmony_ci rcu_read_unlock(); 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci if (!saddr) 3738c2ecf20Sopenharmony_ci saddr = inet_select_addr(dev, target, RT_SCOPE_LINK); 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci probes -= NEIGH_VAR(neigh->parms, UCAST_PROBES); 3768c2ecf20Sopenharmony_ci if (probes < 0) { 3778c2ecf20Sopenharmony_ci if (!(neigh->nud_state & NUD_VALID)) 3788c2ecf20Sopenharmony_ci pr_debug("trying to ucast probe in NUD_INVALID\n"); 3798c2ecf20Sopenharmony_ci neigh_ha_snapshot(dst_ha, neigh, dev); 3808c2ecf20Sopenharmony_ci dst_hw = dst_ha; 3818c2ecf20Sopenharmony_ci } else { 3828c2ecf20Sopenharmony_ci probes -= NEIGH_VAR(neigh->parms, APP_PROBES); 3838c2ecf20Sopenharmony_ci if (probes < 0) { 3848c2ecf20Sopenharmony_ci neigh_app_ns(neigh); 3858c2ecf20Sopenharmony_ci return; 3868c2ecf20Sopenharmony_ci } 3878c2ecf20Sopenharmony_ci } 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci if (skb && !(dev->priv_flags & IFF_XMIT_DST_RELEASE)) 3908c2ecf20Sopenharmony_ci dst = skb_dst(skb); 3918c2ecf20Sopenharmony_ci arp_send_dst(ARPOP_REQUEST, ETH_P_ARP, target, dev, saddr, 3928c2ecf20Sopenharmony_ci dst_hw, dev->dev_addr, NULL, dst); 3938c2ecf20Sopenharmony_ci} 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_cistatic int arp_ignore(struct in_device *in_dev, __be32 sip, __be32 tip) 3968c2ecf20Sopenharmony_ci{ 3978c2ecf20Sopenharmony_ci struct net *net = dev_net(in_dev->dev); 3988c2ecf20Sopenharmony_ci int scope; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci switch (IN_DEV_ARP_IGNORE(in_dev)) { 4018c2ecf20Sopenharmony_ci case 0: /* Reply, the tip is already validated */ 4028c2ecf20Sopenharmony_ci return 0; 4038c2ecf20Sopenharmony_ci case 1: /* Reply only if tip is configured on the incoming interface */ 4048c2ecf20Sopenharmony_ci sip = 0; 4058c2ecf20Sopenharmony_ci scope = RT_SCOPE_HOST; 4068c2ecf20Sopenharmony_ci break; 4078c2ecf20Sopenharmony_ci case 2: /* 4088c2ecf20Sopenharmony_ci * Reply only if tip is configured on the incoming interface 4098c2ecf20Sopenharmony_ci * and is in same subnet as sip 4108c2ecf20Sopenharmony_ci */ 4118c2ecf20Sopenharmony_ci scope = RT_SCOPE_HOST; 4128c2ecf20Sopenharmony_ci break; 4138c2ecf20Sopenharmony_ci case 3: /* Do not reply for scope host addresses */ 4148c2ecf20Sopenharmony_ci sip = 0; 4158c2ecf20Sopenharmony_ci scope = RT_SCOPE_LINK; 4168c2ecf20Sopenharmony_ci in_dev = NULL; 4178c2ecf20Sopenharmony_ci break; 4188c2ecf20Sopenharmony_ci case 4: /* Reserved */ 4198c2ecf20Sopenharmony_ci case 5: 4208c2ecf20Sopenharmony_ci case 6: 4218c2ecf20Sopenharmony_ci case 7: 4228c2ecf20Sopenharmony_ci return 0; 4238c2ecf20Sopenharmony_ci case 8: /* Do not reply */ 4248c2ecf20Sopenharmony_ci return 1; 4258c2ecf20Sopenharmony_ci default: 4268c2ecf20Sopenharmony_ci return 0; 4278c2ecf20Sopenharmony_ci } 4288c2ecf20Sopenharmony_ci return !inet_confirm_addr(net, in_dev, sip, tip, scope); 4298c2ecf20Sopenharmony_ci} 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_cistatic int arp_filter(__be32 sip, __be32 tip, struct net_device *dev) 4328c2ecf20Sopenharmony_ci{ 4338c2ecf20Sopenharmony_ci struct rtable *rt; 4348c2ecf20Sopenharmony_ci int flag = 0; 4358c2ecf20Sopenharmony_ci /*unsigned long now; */ 4368c2ecf20Sopenharmony_ci struct net *net = dev_net(dev); 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci rt = ip_route_output(net, sip, tip, 0, l3mdev_master_ifindex_rcu(dev)); 4398c2ecf20Sopenharmony_ci if (IS_ERR(rt)) 4408c2ecf20Sopenharmony_ci return 1; 4418c2ecf20Sopenharmony_ci if (rt->dst.dev != dev) { 4428c2ecf20Sopenharmony_ci __NET_INC_STATS(net, LINUX_MIB_ARPFILTER); 4438c2ecf20Sopenharmony_ci flag = 1; 4448c2ecf20Sopenharmony_ci } 4458c2ecf20Sopenharmony_ci ip_rt_put(rt); 4468c2ecf20Sopenharmony_ci return flag; 4478c2ecf20Sopenharmony_ci} 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci/* 4508c2ecf20Sopenharmony_ci * Check if we can use proxy ARP for this path 4518c2ecf20Sopenharmony_ci */ 4528c2ecf20Sopenharmony_cistatic inline int arp_fwd_proxy(struct in_device *in_dev, 4538c2ecf20Sopenharmony_ci struct net_device *dev, struct rtable *rt) 4548c2ecf20Sopenharmony_ci{ 4558c2ecf20Sopenharmony_ci struct in_device *out_dev; 4568c2ecf20Sopenharmony_ci int imi, omi = -1; 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci if (rt->dst.dev == dev) 4598c2ecf20Sopenharmony_ci return 0; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci if (!IN_DEV_PROXY_ARP(in_dev)) 4628c2ecf20Sopenharmony_ci return 0; 4638c2ecf20Sopenharmony_ci imi = IN_DEV_MEDIUM_ID(in_dev); 4648c2ecf20Sopenharmony_ci if (imi == 0) 4658c2ecf20Sopenharmony_ci return 1; 4668c2ecf20Sopenharmony_ci if (imi == -1) 4678c2ecf20Sopenharmony_ci return 0; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci /* place to check for proxy_arp for routes */ 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci out_dev = __in_dev_get_rcu(rt->dst.dev); 4728c2ecf20Sopenharmony_ci if (out_dev) 4738c2ecf20Sopenharmony_ci omi = IN_DEV_MEDIUM_ID(out_dev); 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci return omi != imi && omi != -1; 4768c2ecf20Sopenharmony_ci} 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci/* 4798c2ecf20Sopenharmony_ci * Check for RFC3069 proxy arp private VLAN (allow to send back to same dev) 4808c2ecf20Sopenharmony_ci * 4818c2ecf20Sopenharmony_ci * RFC3069 supports proxy arp replies back to the same interface. This 4828c2ecf20Sopenharmony_ci * is done to support (ethernet) switch features, like RFC 3069, where 4838c2ecf20Sopenharmony_ci * the individual ports are not allowed to communicate with each 4848c2ecf20Sopenharmony_ci * other, BUT they are allowed to talk to the upstream router. As 4858c2ecf20Sopenharmony_ci * described in RFC 3069, it is possible to allow these hosts to 4868c2ecf20Sopenharmony_ci * communicate through the upstream router, by proxy_arp'ing. 4878c2ecf20Sopenharmony_ci * 4888c2ecf20Sopenharmony_ci * RFC 3069: "VLAN Aggregation for Efficient IP Address Allocation" 4898c2ecf20Sopenharmony_ci * 4908c2ecf20Sopenharmony_ci * This technology is known by different names: 4918c2ecf20Sopenharmony_ci * In RFC 3069 it is called VLAN Aggregation. 4928c2ecf20Sopenharmony_ci * Cisco and Allied Telesyn call it Private VLAN. 4938c2ecf20Sopenharmony_ci * Hewlett-Packard call it Source-Port filtering or port-isolation. 4948c2ecf20Sopenharmony_ci * Ericsson call it MAC-Forced Forwarding (RFC Draft). 4958c2ecf20Sopenharmony_ci * 4968c2ecf20Sopenharmony_ci */ 4978c2ecf20Sopenharmony_cistatic inline int arp_fwd_pvlan(struct in_device *in_dev, 4988c2ecf20Sopenharmony_ci struct net_device *dev, struct rtable *rt, 4998c2ecf20Sopenharmony_ci __be32 sip, __be32 tip) 5008c2ecf20Sopenharmony_ci{ 5018c2ecf20Sopenharmony_ci /* Private VLAN is only concerned about the same ethernet segment */ 5028c2ecf20Sopenharmony_ci if (rt->dst.dev != dev) 5038c2ecf20Sopenharmony_ci return 0; 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci /* Don't reply on self probes (often done by windowz boxes)*/ 5068c2ecf20Sopenharmony_ci if (sip == tip) 5078c2ecf20Sopenharmony_ci return 0; 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci if (IN_DEV_PROXY_ARP_PVLAN(in_dev)) 5108c2ecf20Sopenharmony_ci return 1; 5118c2ecf20Sopenharmony_ci else 5128c2ecf20Sopenharmony_ci return 0; 5138c2ecf20Sopenharmony_ci} 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci/* 5168c2ecf20Sopenharmony_ci * Interface to link layer: send routine and receive handler. 5178c2ecf20Sopenharmony_ci */ 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci/* 5208c2ecf20Sopenharmony_ci * Create an arp packet. If dest_hw is not set, we create a broadcast 5218c2ecf20Sopenharmony_ci * message. 5228c2ecf20Sopenharmony_ci */ 5238c2ecf20Sopenharmony_cistruct sk_buff *arp_create(int type, int ptype, __be32 dest_ip, 5248c2ecf20Sopenharmony_ci struct net_device *dev, __be32 src_ip, 5258c2ecf20Sopenharmony_ci const unsigned char *dest_hw, 5268c2ecf20Sopenharmony_ci const unsigned char *src_hw, 5278c2ecf20Sopenharmony_ci const unsigned char *target_hw) 5288c2ecf20Sopenharmony_ci{ 5298c2ecf20Sopenharmony_ci struct sk_buff *skb; 5308c2ecf20Sopenharmony_ci struct arphdr *arp; 5318c2ecf20Sopenharmony_ci unsigned char *arp_ptr; 5328c2ecf20Sopenharmony_ci int hlen = LL_RESERVED_SPACE(dev); 5338c2ecf20Sopenharmony_ci int tlen = dev->needed_tailroom; 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci /* 5368c2ecf20Sopenharmony_ci * Allocate a buffer 5378c2ecf20Sopenharmony_ci */ 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci skb = alloc_skb(arp_hdr_len(dev) + hlen + tlen, GFP_ATOMIC); 5408c2ecf20Sopenharmony_ci if (!skb) 5418c2ecf20Sopenharmony_ci return NULL; 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci skb_reserve(skb, hlen); 5448c2ecf20Sopenharmony_ci skb_reset_network_header(skb); 5458c2ecf20Sopenharmony_ci arp = skb_put(skb, arp_hdr_len(dev)); 5468c2ecf20Sopenharmony_ci skb->dev = dev; 5478c2ecf20Sopenharmony_ci skb->protocol = htons(ETH_P_ARP); 5488c2ecf20Sopenharmony_ci if (!src_hw) 5498c2ecf20Sopenharmony_ci src_hw = dev->dev_addr; 5508c2ecf20Sopenharmony_ci if (!dest_hw) 5518c2ecf20Sopenharmony_ci dest_hw = dev->broadcast; 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci /* 5548c2ecf20Sopenharmony_ci * Fill the device header for the ARP frame 5558c2ecf20Sopenharmony_ci */ 5568c2ecf20Sopenharmony_ci if (dev_hard_header(skb, dev, ptype, dest_hw, src_hw, skb->len) < 0) 5578c2ecf20Sopenharmony_ci goto out; 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci /* 5608c2ecf20Sopenharmony_ci * Fill out the arp protocol part. 5618c2ecf20Sopenharmony_ci * 5628c2ecf20Sopenharmony_ci * The arp hardware type should match the device type, except for FDDI, 5638c2ecf20Sopenharmony_ci * which (according to RFC 1390) should always equal 1 (Ethernet). 5648c2ecf20Sopenharmony_ci */ 5658c2ecf20Sopenharmony_ci /* 5668c2ecf20Sopenharmony_ci * Exceptions everywhere. AX.25 uses the AX.25 PID value not the 5678c2ecf20Sopenharmony_ci * DIX code for the protocol. Make these device structure fields. 5688c2ecf20Sopenharmony_ci */ 5698c2ecf20Sopenharmony_ci switch (dev->type) { 5708c2ecf20Sopenharmony_ci default: 5718c2ecf20Sopenharmony_ci arp->ar_hrd = htons(dev->type); 5728c2ecf20Sopenharmony_ci arp->ar_pro = htons(ETH_P_IP); 5738c2ecf20Sopenharmony_ci break; 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_AX25) 5768c2ecf20Sopenharmony_ci case ARPHRD_AX25: 5778c2ecf20Sopenharmony_ci arp->ar_hrd = htons(ARPHRD_AX25); 5788c2ecf20Sopenharmony_ci arp->ar_pro = htons(AX25_P_IP); 5798c2ecf20Sopenharmony_ci break; 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_NETROM) 5828c2ecf20Sopenharmony_ci case ARPHRD_NETROM: 5838c2ecf20Sopenharmony_ci arp->ar_hrd = htons(ARPHRD_NETROM); 5848c2ecf20Sopenharmony_ci arp->ar_pro = htons(AX25_P_IP); 5858c2ecf20Sopenharmony_ci break; 5868c2ecf20Sopenharmony_ci#endif 5878c2ecf20Sopenharmony_ci#endif 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_FDDI) 5908c2ecf20Sopenharmony_ci case ARPHRD_FDDI: 5918c2ecf20Sopenharmony_ci arp->ar_hrd = htons(ARPHRD_ETHER); 5928c2ecf20Sopenharmony_ci arp->ar_pro = htons(ETH_P_IP); 5938c2ecf20Sopenharmony_ci break; 5948c2ecf20Sopenharmony_ci#endif 5958c2ecf20Sopenharmony_ci } 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci arp->ar_hln = dev->addr_len; 5988c2ecf20Sopenharmony_ci arp->ar_pln = 4; 5998c2ecf20Sopenharmony_ci arp->ar_op = htons(type); 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci arp_ptr = (unsigned char *)(arp + 1); 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci memcpy(arp_ptr, src_hw, dev->addr_len); 6048c2ecf20Sopenharmony_ci arp_ptr += dev->addr_len; 6058c2ecf20Sopenharmony_ci memcpy(arp_ptr, &src_ip, 4); 6068c2ecf20Sopenharmony_ci arp_ptr += 4; 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci switch (dev->type) { 6098c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_FIREWIRE_NET) 6108c2ecf20Sopenharmony_ci case ARPHRD_IEEE1394: 6118c2ecf20Sopenharmony_ci break; 6128c2ecf20Sopenharmony_ci#endif 6138c2ecf20Sopenharmony_ci default: 6148c2ecf20Sopenharmony_ci if (target_hw) 6158c2ecf20Sopenharmony_ci memcpy(arp_ptr, target_hw, dev->addr_len); 6168c2ecf20Sopenharmony_ci else 6178c2ecf20Sopenharmony_ci memset(arp_ptr, 0, dev->addr_len); 6188c2ecf20Sopenharmony_ci arp_ptr += dev->addr_len; 6198c2ecf20Sopenharmony_ci } 6208c2ecf20Sopenharmony_ci memcpy(arp_ptr, &dest_ip, 4); 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci return skb; 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ciout: 6258c2ecf20Sopenharmony_ci kfree_skb(skb); 6268c2ecf20Sopenharmony_ci return NULL; 6278c2ecf20Sopenharmony_ci} 6288c2ecf20Sopenharmony_ciEXPORT_SYMBOL(arp_create); 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_cistatic int arp_xmit_finish(struct net *net, struct sock *sk, struct sk_buff *skb) 6318c2ecf20Sopenharmony_ci{ 6328c2ecf20Sopenharmony_ci return dev_queue_xmit(skb); 6338c2ecf20Sopenharmony_ci} 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci/* 6368c2ecf20Sopenharmony_ci * Send an arp packet. 6378c2ecf20Sopenharmony_ci */ 6388c2ecf20Sopenharmony_civoid arp_xmit(struct sk_buff *skb) 6398c2ecf20Sopenharmony_ci{ 6408c2ecf20Sopenharmony_ci /* Send it off, maybe filter it using firewalling first. */ 6418c2ecf20Sopenharmony_ci NF_HOOK(NFPROTO_ARP, NF_ARP_OUT, 6428c2ecf20Sopenharmony_ci dev_net(skb->dev), NULL, skb, NULL, skb->dev, 6438c2ecf20Sopenharmony_ci arp_xmit_finish); 6448c2ecf20Sopenharmony_ci} 6458c2ecf20Sopenharmony_ciEXPORT_SYMBOL(arp_xmit); 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_cistatic bool arp_is_garp(struct net *net, struct net_device *dev, 6488c2ecf20Sopenharmony_ci int *addr_type, __be16 ar_op, 6498c2ecf20Sopenharmony_ci __be32 sip, __be32 tip, 6508c2ecf20Sopenharmony_ci unsigned char *sha, unsigned char *tha) 6518c2ecf20Sopenharmony_ci{ 6528c2ecf20Sopenharmony_ci bool is_garp = tip == sip; 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci /* Gratuitous ARP _replies_ also require target hwaddr to be 6558c2ecf20Sopenharmony_ci * the same as source. 6568c2ecf20Sopenharmony_ci */ 6578c2ecf20Sopenharmony_ci if (is_garp && ar_op == htons(ARPOP_REPLY)) 6588c2ecf20Sopenharmony_ci is_garp = 6598c2ecf20Sopenharmony_ci /* IPv4 over IEEE 1394 doesn't provide target 6608c2ecf20Sopenharmony_ci * hardware address field in its ARP payload. 6618c2ecf20Sopenharmony_ci */ 6628c2ecf20Sopenharmony_ci tha && 6638c2ecf20Sopenharmony_ci !memcmp(tha, sha, dev->addr_len); 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci if (is_garp) { 6668c2ecf20Sopenharmony_ci *addr_type = inet_addr_type_dev_table(net, dev, sip); 6678c2ecf20Sopenharmony_ci if (*addr_type != RTN_UNICAST) 6688c2ecf20Sopenharmony_ci is_garp = false; 6698c2ecf20Sopenharmony_ci } 6708c2ecf20Sopenharmony_ci return is_garp; 6718c2ecf20Sopenharmony_ci} 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci/* 6748c2ecf20Sopenharmony_ci * Process an arp request. 6758c2ecf20Sopenharmony_ci */ 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_cistatic int arp_process(struct net *net, struct sock *sk, struct sk_buff *skb) 6788c2ecf20Sopenharmony_ci{ 6798c2ecf20Sopenharmony_ci struct net_device *dev = skb->dev; 6808c2ecf20Sopenharmony_ci struct in_device *in_dev = __in_dev_get_rcu(dev); 6818c2ecf20Sopenharmony_ci struct arphdr *arp; 6828c2ecf20Sopenharmony_ci unsigned char *arp_ptr; 6838c2ecf20Sopenharmony_ci struct rtable *rt; 6848c2ecf20Sopenharmony_ci unsigned char *sha; 6858c2ecf20Sopenharmony_ci unsigned char *tha = NULL; 6868c2ecf20Sopenharmony_ci __be32 sip, tip; 6878c2ecf20Sopenharmony_ci u16 dev_type = dev->type; 6888c2ecf20Sopenharmony_ci int addr_type; 6898c2ecf20Sopenharmony_ci struct neighbour *n; 6908c2ecf20Sopenharmony_ci struct dst_entry *reply_dst = NULL; 6918c2ecf20Sopenharmony_ci bool is_garp = false; 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci /* arp_rcv below verifies the ARP header and verifies the device 6948c2ecf20Sopenharmony_ci * is ARP'able. 6958c2ecf20Sopenharmony_ci */ 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci if (!in_dev) 6988c2ecf20Sopenharmony_ci goto out_free_skb; 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci arp = arp_hdr(skb); 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci switch (dev_type) { 7038c2ecf20Sopenharmony_ci default: 7048c2ecf20Sopenharmony_ci if (arp->ar_pro != htons(ETH_P_IP) || 7058c2ecf20Sopenharmony_ci htons(dev_type) != arp->ar_hrd) 7068c2ecf20Sopenharmony_ci goto out_free_skb; 7078c2ecf20Sopenharmony_ci break; 7088c2ecf20Sopenharmony_ci case ARPHRD_ETHER: 7098c2ecf20Sopenharmony_ci case ARPHRD_FDDI: 7108c2ecf20Sopenharmony_ci case ARPHRD_IEEE802: 7118c2ecf20Sopenharmony_ci /* 7128c2ecf20Sopenharmony_ci * ETHERNET, and Fibre Channel (which are IEEE 802 7138c2ecf20Sopenharmony_ci * devices, according to RFC 2625) devices will accept ARP 7148c2ecf20Sopenharmony_ci * hardware types of either 1 (Ethernet) or 6 (IEEE 802.2). 7158c2ecf20Sopenharmony_ci * This is the case also of FDDI, where the RFC 1390 says that 7168c2ecf20Sopenharmony_ci * FDDI devices should accept ARP hardware of (1) Ethernet, 7178c2ecf20Sopenharmony_ci * however, to be more robust, we'll accept both 1 (Ethernet) 7188c2ecf20Sopenharmony_ci * or 6 (IEEE 802.2) 7198c2ecf20Sopenharmony_ci */ 7208c2ecf20Sopenharmony_ci if ((arp->ar_hrd != htons(ARPHRD_ETHER) && 7218c2ecf20Sopenharmony_ci arp->ar_hrd != htons(ARPHRD_IEEE802)) || 7228c2ecf20Sopenharmony_ci arp->ar_pro != htons(ETH_P_IP)) 7238c2ecf20Sopenharmony_ci goto out_free_skb; 7248c2ecf20Sopenharmony_ci break; 7258c2ecf20Sopenharmony_ci case ARPHRD_AX25: 7268c2ecf20Sopenharmony_ci if (arp->ar_pro != htons(AX25_P_IP) || 7278c2ecf20Sopenharmony_ci arp->ar_hrd != htons(ARPHRD_AX25)) 7288c2ecf20Sopenharmony_ci goto out_free_skb; 7298c2ecf20Sopenharmony_ci break; 7308c2ecf20Sopenharmony_ci case ARPHRD_NETROM: 7318c2ecf20Sopenharmony_ci if (arp->ar_pro != htons(AX25_P_IP) || 7328c2ecf20Sopenharmony_ci arp->ar_hrd != htons(ARPHRD_NETROM)) 7338c2ecf20Sopenharmony_ci goto out_free_skb; 7348c2ecf20Sopenharmony_ci break; 7358c2ecf20Sopenharmony_ci } 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci /* Understand only these message types */ 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci if (arp->ar_op != htons(ARPOP_REPLY) && 7408c2ecf20Sopenharmony_ci arp->ar_op != htons(ARPOP_REQUEST)) 7418c2ecf20Sopenharmony_ci goto out_free_skb; 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci/* 7448c2ecf20Sopenharmony_ci * Extract fields 7458c2ecf20Sopenharmony_ci */ 7468c2ecf20Sopenharmony_ci arp_ptr = (unsigned char *)(arp + 1); 7478c2ecf20Sopenharmony_ci sha = arp_ptr; 7488c2ecf20Sopenharmony_ci arp_ptr += dev->addr_len; 7498c2ecf20Sopenharmony_ci memcpy(&sip, arp_ptr, 4); 7508c2ecf20Sopenharmony_ci arp_ptr += 4; 7518c2ecf20Sopenharmony_ci switch (dev_type) { 7528c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_FIREWIRE_NET) 7538c2ecf20Sopenharmony_ci case ARPHRD_IEEE1394: 7548c2ecf20Sopenharmony_ci break; 7558c2ecf20Sopenharmony_ci#endif 7568c2ecf20Sopenharmony_ci default: 7578c2ecf20Sopenharmony_ci tha = arp_ptr; 7588c2ecf20Sopenharmony_ci arp_ptr += dev->addr_len; 7598c2ecf20Sopenharmony_ci } 7608c2ecf20Sopenharmony_ci memcpy(&tip, arp_ptr, 4); 7618c2ecf20Sopenharmony_ci/* 7628c2ecf20Sopenharmony_ci * Check for bad requests for 127.x.x.x and requests for multicast 7638c2ecf20Sopenharmony_ci * addresses. If this is one such, delete it. 7648c2ecf20Sopenharmony_ci */ 7658c2ecf20Sopenharmony_ci if (ipv4_is_multicast(tip) || 7668c2ecf20Sopenharmony_ci (!IN_DEV_ROUTE_LOCALNET(in_dev) && ipv4_is_loopback(tip))) 7678c2ecf20Sopenharmony_ci goto out_free_skb; 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci /* 7708c2ecf20Sopenharmony_ci * For some 802.11 wireless deployments (and possibly other networks), 7718c2ecf20Sopenharmony_ci * there will be an ARP proxy and gratuitous ARP frames are attacks 7728c2ecf20Sopenharmony_ci * and thus should not be accepted. 7738c2ecf20Sopenharmony_ci */ 7748c2ecf20Sopenharmony_ci if (sip == tip && IN_DEV_ORCONF(in_dev, DROP_GRATUITOUS_ARP)) 7758c2ecf20Sopenharmony_ci goto out_free_skb; 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci/* 7788c2ecf20Sopenharmony_ci * Special case: We must set Frame Relay source Q.922 address 7798c2ecf20Sopenharmony_ci */ 7808c2ecf20Sopenharmony_ci if (dev_type == ARPHRD_DLCI) 7818c2ecf20Sopenharmony_ci sha = dev->broadcast; 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci/* 7848c2ecf20Sopenharmony_ci * Process entry. The idea here is we want to send a reply if it is a 7858c2ecf20Sopenharmony_ci * request for us or if it is a request for someone else that we hold 7868c2ecf20Sopenharmony_ci * a proxy for. We want to add an entry to our cache if it is a reply 7878c2ecf20Sopenharmony_ci * to us or if it is a request for our address. 7888c2ecf20Sopenharmony_ci * (The assumption for this last is that if someone is requesting our 7898c2ecf20Sopenharmony_ci * address, they are probably intending to talk to us, so it saves time 7908c2ecf20Sopenharmony_ci * if we cache their address. Their address is also probably not in 7918c2ecf20Sopenharmony_ci * our cache, since ours is not in their cache.) 7928c2ecf20Sopenharmony_ci * 7938c2ecf20Sopenharmony_ci * Putting this another way, we only care about replies if they are to 7948c2ecf20Sopenharmony_ci * us, in which case we add them to the cache. For requests, we care 7958c2ecf20Sopenharmony_ci * about those for us and those for our proxies. We reply to both, 7968c2ecf20Sopenharmony_ci * and in the case of requests for us we add the requester to the arp 7978c2ecf20Sopenharmony_ci * cache. 7988c2ecf20Sopenharmony_ci */ 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci if (arp->ar_op == htons(ARPOP_REQUEST) && skb_metadata_dst(skb)) 8018c2ecf20Sopenharmony_ci reply_dst = (struct dst_entry *) 8028c2ecf20Sopenharmony_ci iptunnel_metadata_reply(skb_metadata_dst(skb), 8038c2ecf20Sopenharmony_ci GFP_ATOMIC); 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci /* Special case: IPv4 duplicate address detection packet (RFC2131) */ 8068c2ecf20Sopenharmony_ci if (sip == 0) { 8078c2ecf20Sopenharmony_ci if (arp->ar_op == htons(ARPOP_REQUEST) && 8088c2ecf20Sopenharmony_ci inet_addr_type_dev_table(net, dev, tip) == RTN_LOCAL && 8098c2ecf20Sopenharmony_ci !arp_ignore(in_dev, sip, tip)) 8108c2ecf20Sopenharmony_ci arp_send_dst(ARPOP_REPLY, ETH_P_ARP, sip, dev, tip, 8118c2ecf20Sopenharmony_ci sha, dev->dev_addr, sha, reply_dst); 8128c2ecf20Sopenharmony_ci goto out_consume_skb; 8138c2ecf20Sopenharmony_ci } 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci if (arp->ar_op == htons(ARPOP_REQUEST) && 8168c2ecf20Sopenharmony_ci ip_route_input_noref(skb, tip, sip, 0, dev) == 0) { 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci rt = skb_rtable(skb); 8198c2ecf20Sopenharmony_ci addr_type = rt->rt_type; 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci if (addr_type == RTN_LOCAL) { 8228c2ecf20Sopenharmony_ci int dont_send; 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci dont_send = arp_ignore(in_dev, sip, tip); 8258c2ecf20Sopenharmony_ci if (!dont_send && IN_DEV_ARPFILTER(in_dev)) 8268c2ecf20Sopenharmony_ci dont_send = arp_filter(sip, tip, dev); 8278c2ecf20Sopenharmony_ci if (!dont_send) { 8288c2ecf20Sopenharmony_ci n = neigh_event_ns(&arp_tbl, sha, &sip, dev); 8298c2ecf20Sopenharmony_ci if (n) { 8308c2ecf20Sopenharmony_ci arp_send_dst(ARPOP_REPLY, ETH_P_ARP, 8318c2ecf20Sopenharmony_ci sip, dev, tip, sha, 8328c2ecf20Sopenharmony_ci dev->dev_addr, sha, 8338c2ecf20Sopenharmony_ci reply_dst); 8348c2ecf20Sopenharmony_ci neigh_release(n); 8358c2ecf20Sopenharmony_ci } 8368c2ecf20Sopenharmony_ci } 8378c2ecf20Sopenharmony_ci goto out_consume_skb; 8388c2ecf20Sopenharmony_ci } else if (IN_DEV_FORWARD(in_dev)) { 8398c2ecf20Sopenharmony_ci if (addr_type == RTN_UNICAST && 8408c2ecf20Sopenharmony_ci (arp_fwd_proxy(in_dev, dev, rt) || 8418c2ecf20Sopenharmony_ci arp_fwd_pvlan(in_dev, dev, rt, sip, tip) || 8428c2ecf20Sopenharmony_ci (rt->dst.dev != dev && 8438c2ecf20Sopenharmony_ci pneigh_lookup(&arp_tbl, net, &tip, dev, 0)))) { 8448c2ecf20Sopenharmony_ci n = neigh_event_ns(&arp_tbl, sha, &sip, dev); 8458c2ecf20Sopenharmony_ci if (n) 8468c2ecf20Sopenharmony_ci neigh_release(n); 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci if (NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED || 8498c2ecf20Sopenharmony_ci skb->pkt_type == PACKET_HOST || 8508c2ecf20Sopenharmony_ci NEIGH_VAR(in_dev->arp_parms, PROXY_DELAY) == 0) { 8518c2ecf20Sopenharmony_ci arp_send_dst(ARPOP_REPLY, ETH_P_ARP, 8528c2ecf20Sopenharmony_ci sip, dev, tip, sha, 8538c2ecf20Sopenharmony_ci dev->dev_addr, sha, 8548c2ecf20Sopenharmony_ci reply_dst); 8558c2ecf20Sopenharmony_ci } else { 8568c2ecf20Sopenharmony_ci pneigh_enqueue(&arp_tbl, 8578c2ecf20Sopenharmony_ci in_dev->arp_parms, skb); 8588c2ecf20Sopenharmony_ci goto out_free_dst; 8598c2ecf20Sopenharmony_ci } 8608c2ecf20Sopenharmony_ci goto out_consume_skb; 8618c2ecf20Sopenharmony_ci } 8628c2ecf20Sopenharmony_ci } 8638c2ecf20Sopenharmony_ci } 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci /* Update our ARP tables */ 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci n = __neigh_lookup(&arp_tbl, &sip, dev, 0); 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci addr_type = -1; 8708c2ecf20Sopenharmony_ci if (n || IN_DEV_ARP_ACCEPT(in_dev)) { 8718c2ecf20Sopenharmony_ci is_garp = arp_is_garp(net, dev, &addr_type, arp->ar_op, 8728c2ecf20Sopenharmony_ci sip, tip, sha, tha); 8738c2ecf20Sopenharmony_ci } 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci if (IN_DEV_ARP_ACCEPT(in_dev)) { 8768c2ecf20Sopenharmony_ci /* Unsolicited ARP is not accepted by default. 8778c2ecf20Sopenharmony_ci It is possible, that this option should be enabled for some 8788c2ecf20Sopenharmony_ci devices (strip is candidate) 8798c2ecf20Sopenharmony_ci */ 8808c2ecf20Sopenharmony_ci if (!n && 8818c2ecf20Sopenharmony_ci (is_garp || 8828c2ecf20Sopenharmony_ci (arp->ar_op == htons(ARPOP_REPLY) && 8838c2ecf20Sopenharmony_ci (addr_type == RTN_UNICAST || 8848c2ecf20Sopenharmony_ci (addr_type < 0 && 8858c2ecf20Sopenharmony_ci /* postpone calculation to as late as possible */ 8868c2ecf20Sopenharmony_ci inet_addr_type_dev_table(net, dev, sip) == 8878c2ecf20Sopenharmony_ci RTN_UNICAST))))) 8888c2ecf20Sopenharmony_ci n = __neigh_lookup(&arp_tbl, &sip, dev, 1); 8898c2ecf20Sopenharmony_ci } 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci if (n) { 8928c2ecf20Sopenharmony_ci int state = NUD_REACHABLE; 8938c2ecf20Sopenharmony_ci int override; 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci /* If several different ARP replies follows back-to-back, 8968c2ecf20Sopenharmony_ci use the FIRST one. It is possible, if several proxy 8978c2ecf20Sopenharmony_ci agents are active. Taking the first reply prevents 8988c2ecf20Sopenharmony_ci arp trashing and chooses the fastest router. 8998c2ecf20Sopenharmony_ci */ 9008c2ecf20Sopenharmony_ci override = time_after(jiffies, 9018c2ecf20Sopenharmony_ci n->updated + 9028c2ecf20Sopenharmony_ci NEIGH_VAR(n->parms, LOCKTIME)) || 9038c2ecf20Sopenharmony_ci is_garp; 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci /* Broadcast replies and request packets 9068c2ecf20Sopenharmony_ci do not assert neighbour reachability. 9078c2ecf20Sopenharmony_ci */ 9088c2ecf20Sopenharmony_ci if (arp->ar_op != htons(ARPOP_REPLY) || 9098c2ecf20Sopenharmony_ci skb->pkt_type != PACKET_HOST) 9108c2ecf20Sopenharmony_ci state = NUD_STALE; 9118c2ecf20Sopenharmony_ci neigh_update(n, sha, state, 9128c2ecf20Sopenharmony_ci override ? NEIGH_UPDATE_F_OVERRIDE : 0, 0); 9138c2ecf20Sopenharmony_ci neigh_release(n); 9148c2ecf20Sopenharmony_ci } 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ciout_consume_skb: 9178c2ecf20Sopenharmony_ci consume_skb(skb); 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ciout_free_dst: 9208c2ecf20Sopenharmony_ci dst_release(reply_dst); 9218c2ecf20Sopenharmony_ci return NET_RX_SUCCESS; 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ciout_free_skb: 9248c2ecf20Sopenharmony_ci kfree_skb(skb); 9258c2ecf20Sopenharmony_ci return NET_RX_DROP; 9268c2ecf20Sopenharmony_ci} 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_cistatic void parp_redo(struct sk_buff *skb) 9298c2ecf20Sopenharmony_ci{ 9308c2ecf20Sopenharmony_ci arp_process(dev_net(skb->dev), NULL, skb); 9318c2ecf20Sopenharmony_ci} 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_cistatic int arp_is_multicast(const void *pkey) 9348c2ecf20Sopenharmony_ci{ 9358c2ecf20Sopenharmony_ci return ipv4_is_multicast(*((__be32 *)pkey)); 9368c2ecf20Sopenharmony_ci} 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci/* 9398c2ecf20Sopenharmony_ci * Receive an arp request from the device layer. 9408c2ecf20Sopenharmony_ci */ 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_cistatic int arp_rcv(struct sk_buff *skb, struct net_device *dev, 9438c2ecf20Sopenharmony_ci struct packet_type *pt, struct net_device *orig_dev) 9448c2ecf20Sopenharmony_ci{ 9458c2ecf20Sopenharmony_ci const struct arphdr *arp; 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci /* do not tweak dropwatch on an ARP we will ignore */ 9488c2ecf20Sopenharmony_ci if (dev->flags & IFF_NOARP || 9498c2ecf20Sopenharmony_ci skb->pkt_type == PACKET_OTHERHOST || 9508c2ecf20Sopenharmony_ci skb->pkt_type == PACKET_LOOPBACK) 9518c2ecf20Sopenharmony_ci goto consumeskb; 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci skb = skb_share_check(skb, GFP_ATOMIC); 9548c2ecf20Sopenharmony_ci if (!skb) 9558c2ecf20Sopenharmony_ci goto out_of_mem; 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci /* ARP header, plus 2 device addresses, plus 2 IP addresses. */ 9588c2ecf20Sopenharmony_ci if (!pskb_may_pull(skb, arp_hdr_len(dev))) 9598c2ecf20Sopenharmony_ci goto freeskb; 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci arp = arp_hdr(skb); 9628c2ecf20Sopenharmony_ci if (arp->ar_hln != dev->addr_len || arp->ar_pln != 4) 9638c2ecf20Sopenharmony_ci goto freeskb; 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci memset(NEIGH_CB(skb), 0, sizeof(struct neighbour_cb)); 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci return NF_HOOK(NFPROTO_ARP, NF_ARP_IN, 9688c2ecf20Sopenharmony_ci dev_net(dev), NULL, skb, dev, NULL, 9698c2ecf20Sopenharmony_ci arp_process); 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_ciconsumeskb: 9728c2ecf20Sopenharmony_ci consume_skb(skb); 9738c2ecf20Sopenharmony_ci return NET_RX_SUCCESS; 9748c2ecf20Sopenharmony_cifreeskb: 9758c2ecf20Sopenharmony_ci kfree_skb(skb); 9768c2ecf20Sopenharmony_ciout_of_mem: 9778c2ecf20Sopenharmony_ci return NET_RX_DROP; 9788c2ecf20Sopenharmony_ci} 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci/* 9818c2ecf20Sopenharmony_ci * User level interface (ioctl) 9828c2ecf20Sopenharmony_ci */ 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ci/* 9858c2ecf20Sopenharmony_ci * Set (create) an ARP cache entry. 9868c2ecf20Sopenharmony_ci */ 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_cistatic int arp_req_set_proxy(struct net *net, struct net_device *dev, int on) 9898c2ecf20Sopenharmony_ci{ 9908c2ecf20Sopenharmony_ci if (!dev) { 9918c2ecf20Sopenharmony_ci IPV4_DEVCONF_ALL(net, PROXY_ARP) = on; 9928c2ecf20Sopenharmony_ci return 0; 9938c2ecf20Sopenharmony_ci } 9948c2ecf20Sopenharmony_ci if (__in_dev_get_rtnl(dev)) { 9958c2ecf20Sopenharmony_ci IN_DEV_CONF_SET(__in_dev_get_rtnl(dev), PROXY_ARP, on); 9968c2ecf20Sopenharmony_ci return 0; 9978c2ecf20Sopenharmony_ci } 9988c2ecf20Sopenharmony_ci return -ENXIO; 9998c2ecf20Sopenharmony_ci} 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_cistatic int arp_req_set_public(struct net *net, struct arpreq *r, 10028c2ecf20Sopenharmony_ci struct net_device *dev) 10038c2ecf20Sopenharmony_ci{ 10048c2ecf20Sopenharmony_ci __be32 ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr; 10058c2ecf20Sopenharmony_ci __be32 mask = ((struct sockaddr_in *)&r->arp_netmask)->sin_addr.s_addr; 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci if (mask && mask != htonl(0xFFFFFFFF)) 10088c2ecf20Sopenharmony_ci return -EINVAL; 10098c2ecf20Sopenharmony_ci if (!dev && (r->arp_flags & ATF_COM)) { 10108c2ecf20Sopenharmony_ci dev = dev_getbyhwaddr_rcu(net, r->arp_ha.sa_family, 10118c2ecf20Sopenharmony_ci r->arp_ha.sa_data); 10128c2ecf20Sopenharmony_ci if (!dev) 10138c2ecf20Sopenharmony_ci return -ENODEV; 10148c2ecf20Sopenharmony_ci } 10158c2ecf20Sopenharmony_ci if (mask) { 10168c2ecf20Sopenharmony_ci if (!pneigh_lookup(&arp_tbl, net, &ip, dev, 1)) 10178c2ecf20Sopenharmony_ci return -ENOBUFS; 10188c2ecf20Sopenharmony_ci return 0; 10198c2ecf20Sopenharmony_ci } 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci return arp_req_set_proxy(net, dev, 1); 10228c2ecf20Sopenharmony_ci} 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_cistatic int arp_req_set(struct net *net, struct arpreq *r, 10258c2ecf20Sopenharmony_ci struct net_device *dev) 10268c2ecf20Sopenharmony_ci{ 10278c2ecf20Sopenharmony_ci __be32 ip; 10288c2ecf20Sopenharmony_ci struct neighbour *neigh; 10298c2ecf20Sopenharmony_ci int err; 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci if (r->arp_flags & ATF_PUBL) 10328c2ecf20Sopenharmony_ci return arp_req_set_public(net, r, dev); 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ci ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr; 10358c2ecf20Sopenharmony_ci if (r->arp_flags & ATF_PERM) 10368c2ecf20Sopenharmony_ci r->arp_flags |= ATF_COM; 10378c2ecf20Sopenharmony_ci if (!dev) { 10388c2ecf20Sopenharmony_ci struct rtable *rt = ip_route_output(net, ip, 0, RTO_ONLINK, 0); 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_ci if (IS_ERR(rt)) 10418c2ecf20Sopenharmony_ci return PTR_ERR(rt); 10428c2ecf20Sopenharmony_ci dev = rt->dst.dev; 10438c2ecf20Sopenharmony_ci ip_rt_put(rt); 10448c2ecf20Sopenharmony_ci if (!dev) 10458c2ecf20Sopenharmony_ci return -EINVAL; 10468c2ecf20Sopenharmony_ci } 10478c2ecf20Sopenharmony_ci switch (dev->type) { 10488c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_FDDI) 10498c2ecf20Sopenharmony_ci case ARPHRD_FDDI: 10508c2ecf20Sopenharmony_ci /* 10518c2ecf20Sopenharmony_ci * According to RFC 1390, FDDI devices should accept ARP 10528c2ecf20Sopenharmony_ci * hardware types of 1 (Ethernet). However, to be more 10538c2ecf20Sopenharmony_ci * robust, we'll accept hardware types of either 1 (Ethernet) 10548c2ecf20Sopenharmony_ci * or 6 (IEEE 802.2). 10558c2ecf20Sopenharmony_ci */ 10568c2ecf20Sopenharmony_ci if (r->arp_ha.sa_family != ARPHRD_FDDI && 10578c2ecf20Sopenharmony_ci r->arp_ha.sa_family != ARPHRD_ETHER && 10588c2ecf20Sopenharmony_ci r->arp_ha.sa_family != ARPHRD_IEEE802) 10598c2ecf20Sopenharmony_ci return -EINVAL; 10608c2ecf20Sopenharmony_ci break; 10618c2ecf20Sopenharmony_ci#endif 10628c2ecf20Sopenharmony_ci default: 10638c2ecf20Sopenharmony_ci if (r->arp_ha.sa_family != dev->type) 10648c2ecf20Sopenharmony_ci return -EINVAL; 10658c2ecf20Sopenharmony_ci break; 10668c2ecf20Sopenharmony_ci } 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_ci neigh = __neigh_lookup_errno(&arp_tbl, &ip, dev); 10698c2ecf20Sopenharmony_ci err = PTR_ERR(neigh); 10708c2ecf20Sopenharmony_ci if (!IS_ERR(neigh)) { 10718c2ecf20Sopenharmony_ci unsigned int state = NUD_STALE; 10728c2ecf20Sopenharmony_ci if (r->arp_flags & ATF_PERM) 10738c2ecf20Sopenharmony_ci state = NUD_PERMANENT; 10748c2ecf20Sopenharmony_ci err = neigh_update(neigh, (r->arp_flags & ATF_COM) ? 10758c2ecf20Sopenharmony_ci r->arp_ha.sa_data : NULL, state, 10768c2ecf20Sopenharmony_ci NEIGH_UPDATE_F_OVERRIDE | 10778c2ecf20Sopenharmony_ci NEIGH_UPDATE_F_ADMIN, 0); 10788c2ecf20Sopenharmony_ci neigh_release(neigh); 10798c2ecf20Sopenharmony_ci } 10808c2ecf20Sopenharmony_ci return err; 10818c2ecf20Sopenharmony_ci} 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_cistatic unsigned int arp_state_to_flags(struct neighbour *neigh) 10848c2ecf20Sopenharmony_ci{ 10858c2ecf20Sopenharmony_ci if (neigh->nud_state&NUD_PERMANENT) 10868c2ecf20Sopenharmony_ci return ATF_PERM | ATF_COM; 10878c2ecf20Sopenharmony_ci else if (neigh->nud_state&NUD_VALID) 10888c2ecf20Sopenharmony_ci return ATF_COM; 10898c2ecf20Sopenharmony_ci else 10908c2ecf20Sopenharmony_ci return 0; 10918c2ecf20Sopenharmony_ci} 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_ci/* 10948c2ecf20Sopenharmony_ci * Get an ARP cache entry. 10958c2ecf20Sopenharmony_ci */ 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_cistatic int arp_req_get(struct arpreq *r, struct net_device *dev) 10988c2ecf20Sopenharmony_ci{ 10998c2ecf20Sopenharmony_ci __be32 ip = ((struct sockaddr_in *) &r->arp_pa)->sin_addr.s_addr; 11008c2ecf20Sopenharmony_ci struct neighbour *neigh; 11018c2ecf20Sopenharmony_ci int err = -ENXIO; 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_ci neigh = neigh_lookup(&arp_tbl, &ip, dev); 11048c2ecf20Sopenharmony_ci if (neigh) { 11058c2ecf20Sopenharmony_ci if (!(neigh->nud_state & NUD_NOARP)) { 11068c2ecf20Sopenharmony_ci read_lock_bh(&neigh->lock); 11078c2ecf20Sopenharmony_ci memcpy(r->arp_ha.sa_data, neigh->ha, 11088c2ecf20Sopenharmony_ci min(dev->addr_len, (unsigned char)sizeof(r->arp_ha.sa_data_min))); 11098c2ecf20Sopenharmony_ci r->arp_flags = arp_state_to_flags(neigh); 11108c2ecf20Sopenharmony_ci read_unlock_bh(&neigh->lock); 11118c2ecf20Sopenharmony_ci r->arp_ha.sa_family = dev->type; 11128c2ecf20Sopenharmony_ci strlcpy(r->arp_dev, dev->name, sizeof(r->arp_dev)); 11138c2ecf20Sopenharmony_ci err = 0; 11148c2ecf20Sopenharmony_ci } 11158c2ecf20Sopenharmony_ci neigh_release(neigh); 11168c2ecf20Sopenharmony_ci } 11178c2ecf20Sopenharmony_ci return err; 11188c2ecf20Sopenharmony_ci} 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_ciint arp_invalidate(struct net_device *dev, __be32 ip, bool force) 11218c2ecf20Sopenharmony_ci{ 11228c2ecf20Sopenharmony_ci struct neighbour *neigh = neigh_lookup(&arp_tbl, &ip, dev); 11238c2ecf20Sopenharmony_ci int err = -ENXIO; 11248c2ecf20Sopenharmony_ci struct neigh_table *tbl = &arp_tbl; 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_ci if (neigh) { 11278c2ecf20Sopenharmony_ci if ((neigh->nud_state & NUD_VALID) && !force) { 11288c2ecf20Sopenharmony_ci neigh_release(neigh); 11298c2ecf20Sopenharmony_ci return 0; 11308c2ecf20Sopenharmony_ci } 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_ci if (neigh->nud_state & ~NUD_NOARP) 11338c2ecf20Sopenharmony_ci err = neigh_update(neigh, NULL, NUD_FAILED, 11348c2ecf20Sopenharmony_ci NEIGH_UPDATE_F_OVERRIDE| 11358c2ecf20Sopenharmony_ci NEIGH_UPDATE_F_ADMIN, 0); 11368c2ecf20Sopenharmony_ci write_lock_bh(&tbl->lock); 11378c2ecf20Sopenharmony_ci neigh_release(neigh); 11388c2ecf20Sopenharmony_ci neigh_remove_one(neigh, tbl); 11398c2ecf20Sopenharmony_ci write_unlock_bh(&tbl->lock); 11408c2ecf20Sopenharmony_ci } 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci return err; 11438c2ecf20Sopenharmony_ci} 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_cistatic int arp_req_delete_public(struct net *net, struct arpreq *r, 11468c2ecf20Sopenharmony_ci struct net_device *dev) 11478c2ecf20Sopenharmony_ci{ 11488c2ecf20Sopenharmony_ci __be32 ip = ((struct sockaddr_in *) &r->arp_pa)->sin_addr.s_addr; 11498c2ecf20Sopenharmony_ci __be32 mask = ((struct sockaddr_in *)&r->arp_netmask)->sin_addr.s_addr; 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_ci if (mask == htonl(0xFFFFFFFF)) 11528c2ecf20Sopenharmony_ci return pneigh_delete(&arp_tbl, net, &ip, dev); 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_ci if (mask) 11558c2ecf20Sopenharmony_ci return -EINVAL; 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_ci return arp_req_set_proxy(net, dev, 0); 11588c2ecf20Sopenharmony_ci} 11598c2ecf20Sopenharmony_ci 11608c2ecf20Sopenharmony_cistatic int arp_req_delete(struct net *net, struct arpreq *r, 11618c2ecf20Sopenharmony_ci struct net_device *dev) 11628c2ecf20Sopenharmony_ci{ 11638c2ecf20Sopenharmony_ci __be32 ip; 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_ci if (r->arp_flags & ATF_PUBL) 11668c2ecf20Sopenharmony_ci return arp_req_delete_public(net, r, dev); 11678c2ecf20Sopenharmony_ci 11688c2ecf20Sopenharmony_ci ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr; 11698c2ecf20Sopenharmony_ci if (!dev) { 11708c2ecf20Sopenharmony_ci struct rtable *rt = ip_route_output(net, ip, 0, RTO_ONLINK, 0); 11718c2ecf20Sopenharmony_ci if (IS_ERR(rt)) 11728c2ecf20Sopenharmony_ci return PTR_ERR(rt); 11738c2ecf20Sopenharmony_ci dev = rt->dst.dev; 11748c2ecf20Sopenharmony_ci ip_rt_put(rt); 11758c2ecf20Sopenharmony_ci if (!dev) 11768c2ecf20Sopenharmony_ci return -EINVAL; 11778c2ecf20Sopenharmony_ci } 11788c2ecf20Sopenharmony_ci return arp_invalidate(dev, ip, true); 11798c2ecf20Sopenharmony_ci} 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_ci/* 11828c2ecf20Sopenharmony_ci * Handle an ARP layer I/O control request. 11838c2ecf20Sopenharmony_ci */ 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_ciint arp_ioctl(struct net *net, unsigned int cmd, void __user *arg) 11868c2ecf20Sopenharmony_ci{ 11878c2ecf20Sopenharmony_ci int err; 11888c2ecf20Sopenharmony_ci struct arpreq r; 11898c2ecf20Sopenharmony_ci struct net_device *dev = NULL; 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_ci switch (cmd) { 11928c2ecf20Sopenharmony_ci case SIOCDARP: 11938c2ecf20Sopenharmony_ci case SIOCSARP: 11948c2ecf20Sopenharmony_ci if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) 11958c2ecf20Sopenharmony_ci return -EPERM; 11968c2ecf20Sopenharmony_ci fallthrough; 11978c2ecf20Sopenharmony_ci case SIOCGARP: 11988c2ecf20Sopenharmony_ci err = copy_from_user(&r, arg, sizeof(struct arpreq)); 11998c2ecf20Sopenharmony_ci if (err) 12008c2ecf20Sopenharmony_ci return -EFAULT; 12018c2ecf20Sopenharmony_ci break; 12028c2ecf20Sopenharmony_ci default: 12038c2ecf20Sopenharmony_ci return -EINVAL; 12048c2ecf20Sopenharmony_ci } 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_ci if (r.arp_pa.sa_family != AF_INET) 12078c2ecf20Sopenharmony_ci return -EPFNOSUPPORT; 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_ci if (!(r.arp_flags & ATF_PUBL) && 12108c2ecf20Sopenharmony_ci (r.arp_flags & (ATF_NETMASK | ATF_DONTPUB))) 12118c2ecf20Sopenharmony_ci return -EINVAL; 12128c2ecf20Sopenharmony_ci if (!(r.arp_flags & ATF_NETMASK)) 12138c2ecf20Sopenharmony_ci ((struct sockaddr_in *)&r.arp_netmask)->sin_addr.s_addr = 12148c2ecf20Sopenharmony_ci htonl(0xFFFFFFFFUL); 12158c2ecf20Sopenharmony_ci rtnl_lock(); 12168c2ecf20Sopenharmony_ci if (r.arp_dev[0]) { 12178c2ecf20Sopenharmony_ci err = -ENODEV; 12188c2ecf20Sopenharmony_ci dev = __dev_get_by_name(net, r.arp_dev); 12198c2ecf20Sopenharmony_ci if (!dev) 12208c2ecf20Sopenharmony_ci goto out; 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_ci /* Mmmm... It is wrong... ARPHRD_NETROM==0 */ 12238c2ecf20Sopenharmony_ci if (!r.arp_ha.sa_family) 12248c2ecf20Sopenharmony_ci r.arp_ha.sa_family = dev->type; 12258c2ecf20Sopenharmony_ci err = -EINVAL; 12268c2ecf20Sopenharmony_ci if ((r.arp_flags & ATF_COM) && r.arp_ha.sa_family != dev->type) 12278c2ecf20Sopenharmony_ci goto out; 12288c2ecf20Sopenharmony_ci } else if (cmd == SIOCGARP) { 12298c2ecf20Sopenharmony_ci err = -ENODEV; 12308c2ecf20Sopenharmony_ci goto out; 12318c2ecf20Sopenharmony_ci } 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_ci switch (cmd) { 12348c2ecf20Sopenharmony_ci case SIOCDARP: 12358c2ecf20Sopenharmony_ci err = arp_req_delete(net, &r, dev); 12368c2ecf20Sopenharmony_ci break; 12378c2ecf20Sopenharmony_ci case SIOCSARP: 12388c2ecf20Sopenharmony_ci err = arp_req_set(net, &r, dev); 12398c2ecf20Sopenharmony_ci break; 12408c2ecf20Sopenharmony_ci case SIOCGARP: 12418c2ecf20Sopenharmony_ci err = arp_req_get(&r, dev); 12428c2ecf20Sopenharmony_ci break; 12438c2ecf20Sopenharmony_ci } 12448c2ecf20Sopenharmony_ciout: 12458c2ecf20Sopenharmony_ci rtnl_unlock(); 12468c2ecf20Sopenharmony_ci if (cmd == SIOCGARP && !err && copy_to_user(arg, &r, sizeof(r))) 12478c2ecf20Sopenharmony_ci err = -EFAULT; 12488c2ecf20Sopenharmony_ci return err; 12498c2ecf20Sopenharmony_ci} 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_cistatic int arp_netdev_event(struct notifier_block *this, unsigned long event, 12528c2ecf20Sopenharmony_ci void *ptr) 12538c2ecf20Sopenharmony_ci{ 12548c2ecf20Sopenharmony_ci struct net_device *dev = netdev_notifier_info_to_dev(ptr); 12558c2ecf20Sopenharmony_ci struct netdev_notifier_change_info *change_info; 12568c2ecf20Sopenharmony_ci 12578c2ecf20Sopenharmony_ci switch (event) { 12588c2ecf20Sopenharmony_ci case NETDEV_CHANGEADDR: 12598c2ecf20Sopenharmony_ci neigh_changeaddr(&arp_tbl, dev); 12608c2ecf20Sopenharmony_ci rt_cache_flush(dev_net(dev)); 12618c2ecf20Sopenharmony_ci break; 12628c2ecf20Sopenharmony_ci case NETDEV_CHANGE: 12638c2ecf20Sopenharmony_ci change_info = ptr; 12648c2ecf20Sopenharmony_ci if (change_info->flags_changed & IFF_NOARP) 12658c2ecf20Sopenharmony_ci neigh_changeaddr(&arp_tbl, dev); 12668c2ecf20Sopenharmony_ci if (!netif_carrier_ok(dev)) 12678c2ecf20Sopenharmony_ci neigh_carrier_down(&arp_tbl, dev); 12688c2ecf20Sopenharmony_ci break; 12698c2ecf20Sopenharmony_ci default: 12708c2ecf20Sopenharmony_ci break; 12718c2ecf20Sopenharmony_ci } 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_ci return NOTIFY_DONE; 12748c2ecf20Sopenharmony_ci} 12758c2ecf20Sopenharmony_ci 12768c2ecf20Sopenharmony_cistatic struct notifier_block arp_netdev_notifier = { 12778c2ecf20Sopenharmony_ci .notifier_call = arp_netdev_event, 12788c2ecf20Sopenharmony_ci}; 12798c2ecf20Sopenharmony_ci 12808c2ecf20Sopenharmony_ci/* Note, that it is not on notifier chain. 12818c2ecf20Sopenharmony_ci It is necessary, that this routine was called after route cache will be 12828c2ecf20Sopenharmony_ci flushed. 12838c2ecf20Sopenharmony_ci */ 12848c2ecf20Sopenharmony_civoid arp_ifdown(struct net_device *dev) 12858c2ecf20Sopenharmony_ci{ 12868c2ecf20Sopenharmony_ci neigh_ifdown(&arp_tbl, dev); 12878c2ecf20Sopenharmony_ci} 12888c2ecf20Sopenharmony_ci 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_ci/* 12918c2ecf20Sopenharmony_ci * Called once on startup. 12928c2ecf20Sopenharmony_ci */ 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_cistatic struct packet_type arp_packet_type __read_mostly = { 12958c2ecf20Sopenharmony_ci .type = cpu_to_be16(ETH_P_ARP), 12968c2ecf20Sopenharmony_ci .func = arp_rcv, 12978c2ecf20Sopenharmony_ci}; 12988c2ecf20Sopenharmony_ci 12998c2ecf20Sopenharmony_cistatic int arp_proc_init(void); 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_civoid __init arp_init(void) 13028c2ecf20Sopenharmony_ci{ 13038c2ecf20Sopenharmony_ci neigh_table_init(NEIGH_ARP_TABLE, &arp_tbl); 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_ci dev_add_pack(&arp_packet_type); 13068c2ecf20Sopenharmony_ci arp_proc_init(); 13078c2ecf20Sopenharmony_ci#ifdef CONFIG_SYSCTL 13088c2ecf20Sopenharmony_ci neigh_sysctl_register(NULL, &arp_tbl.parms, NULL); 13098c2ecf20Sopenharmony_ci#endif 13108c2ecf20Sopenharmony_ci register_netdevice_notifier(&arp_netdev_notifier); 13118c2ecf20Sopenharmony_ci} 13128c2ecf20Sopenharmony_ci 13138c2ecf20Sopenharmony_ci#ifdef CONFIG_PROC_FS 13148c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_AX25) 13158c2ecf20Sopenharmony_ci 13168c2ecf20Sopenharmony_ci/* ------------------------------------------------------------------------ */ 13178c2ecf20Sopenharmony_ci/* 13188c2ecf20Sopenharmony_ci * ax25 -> ASCII conversion 13198c2ecf20Sopenharmony_ci */ 13208c2ecf20Sopenharmony_cistatic void ax2asc2(ax25_address *a, char *buf) 13218c2ecf20Sopenharmony_ci{ 13228c2ecf20Sopenharmony_ci char c, *s; 13238c2ecf20Sopenharmony_ci int n; 13248c2ecf20Sopenharmony_ci 13258c2ecf20Sopenharmony_ci for (n = 0, s = buf; n < 6; n++) { 13268c2ecf20Sopenharmony_ci c = (a->ax25_call[n] >> 1) & 0x7F; 13278c2ecf20Sopenharmony_ci 13288c2ecf20Sopenharmony_ci if (c != ' ') 13298c2ecf20Sopenharmony_ci *s++ = c; 13308c2ecf20Sopenharmony_ci } 13318c2ecf20Sopenharmony_ci 13328c2ecf20Sopenharmony_ci *s++ = '-'; 13338c2ecf20Sopenharmony_ci n = (a->ax25_call[6] >> 1) & 0x0F; 13348c2ecf20Sopenharmony_ci if (n > 9) { 13358c2ecf20Sopenharmony_ci *s++ = '1'; 13368c2ecf20Sopenharmony_ci n -= 10; 13378c2ecf20Sopenharmony_ci } 13388c2ecf20Sopenharmony_ci 13398c2ecf20Sopenharmony_ci *s++ = n + '0'; 13408c2ecf20Sopenharmony_ci *s++ = '\0'; 13418c2ecf20Sopenharmony_ci 13428c2ecf20Sopenharmony_ci if (*buf == '\0' || *buf == '-') { 13438c2ecf20Sopenharmony_ci buf[0] = '*'; 13448c2ecf20Sopenharmony_ci buf[1] = '\0'; 13458c2ecf20Sopenharmony_ci } 13468c2ecf20Sopenharmony_ci} 13478c2ecf20Sopenharmony_ci#endif /* CONFIG_AX25 */ 13488c2ecf20Sopenharmony_ci 13498c2ecf20Sopenharmony_ci#define HBUFFERLEN 30 13508c2ecf20Sopenharmony_ci 13518c2ecf20Sopenharmony_cistatic void arp_format_neigh_entry(struct seq_file *seq, 13528c2ecf20Sopenharmony_ci struct neighbour *n) 13538c2ecf20Sopenharmony_ci{ 13548c2ecf20Sopenharmony_ci char hbuffer[HBUFFERLEN]; 13558c2ecf20Sopenharmony_ci int k, j; 13568c2ecf20Sopenharmony_ci char tbuf[16]; 13578c2ecf20Sopenharmony_ci struct net_device *dev = n->dev; 13588c2ecf20Sopenharmony_ci int hatype = dev->type; 13598c2ecf20Sopenharmony_ci 13608c2ecf20Sopenharmony_ci read_lock(&n->lock); 13618c2ecf20Sopenharmony_ci /* Convert hardware address to XX:XX:XX:XX ... form. */ 13628c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_AX25) 13638c2ecf20Sopenharmony_ci if (hatype == ARPHRD_AX25 || hatype == ARPHRD_NETROM) 13648c2ecf20Sopenharmony_ci ax2asc2((ax25_address *)n->ha, hbuffer); 13658c2ecf20Sopenharmony_ci else { 13668c2ecf20Sopenharmony_ci#endif 13678c2ecf20Sopenharmony_ci for (k = 0, j = 0; k < HBUFFERLEN - 3 && j < dev->addr_len; j++) { 13688c2ecf20Sopenharmony_ci hbuffer[k++] = hex_asc_hi(n->ha[j]); 13698c2ecf20Sopenharmony_ci hbuffer[k++] = hex_asc_lo(n->ha[j]); 13708c2ecf20Sopenharmony_ci hbuffer[k++] = ':'; 13718c2ecf20Sopenharmony_ci } 13728c2ecf20Sopenharmony_ci if (k != 0) 13738c2ecf20Sopenharmony_ci --k; 13748c2ecf20Sopenharmony_ci hbuffer[k] = 0; 13758c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_AX25) 13768c2ecf20Sopenharmony_ci } 13778c2ecf20Sopenharmony_ci#endif 13788c2ecf20Sopenharmony_ci sprintf(tbuf, "%pI4", n->primary_key); 13798c2ecf20Sopenharmony_ci seq_printf(seq, "%-16s 0x%-10x0x%-10x%-17s * %s\n", 13808c2ecf20Sopenharmony_ci tbuf, hatype, arp_state_to_flags(n), hbuffer, dev->name); 13818c2ecf20Sopenharmony_ci read_unlock(&n->lock); 13828c2ecf20Sopenharmony_ci} 13838c2ecf20Sopenharmony_ci 13848c2ecf20Sopenharmony_cistatic void arp_format_pneigh_entry(struct seq_file *seq, 13858c2ecf20Sopenharmony_ci struct pneigh_entry *n) 13868c2ecf20Sopenharmony_ci{ 13878c2ecf20Sopenharmony_ci struct net_device *dev = n->dev; 13888c2ecf20Sopenharmony_ci int hatype = dev ? dev->type : 0; 13898c2ecf20Sopenharmony_ci char tbuf[16]; 13908c2ecf20Sopenharmony_ci 13918c2ecf20Sopenharmony_ci sprintf(tbuf, "%pI4", n->key); 13928c2ecf20Sopenharmony_ci seq_printf(seq, "%-16s 0x%-10x0x%-10x%s * %s\n", 13938c2ecf20Sopenharmony_ci tbuf, hatype, ATF_PUBL | ATF_PERM, "00:00:00:00:00:00", 13948c2ecf20Sopenharmony_ci dev ? dev->name : "*"); 13958c2ecf20Sopenharmony_ci} 13968c2ecf20Sopenharmony_ci 13978c2ecf20Sopenharmony_cistatic int arp_seq_show(struct seq_file *seq, void *v) 13988c2ecf20Sopenharmony_ci{ 13998c2ecf20Sopenharmony_ci if (v == SEQ_START_TOKEN) { 14008c2ecf20Sopenharmony_ci seq_puts(seq, "IP address HW type Flags " 14018c2ecf20Sopenharmony_ci "HW address Mask Device\n"); 14028c2ecf20Sopenharmony_ci } else { 14038c2ecf20Sopenharmony_ci struct neigh_seq_state *state = seq->private; 14048c2ecf20Sopenharmony_ci 14058c2ecf20Sopenharmony_ci if (state->flags & NEIGH_SEQ_IS_PNEIGH) 14068c2ecf20Sopenharmony_ci arp_format_pneigh_entry(seq, v); 14078c2ecf20Sopenharmony_ci else 14088c2ecf20Sopenharmony_ci arp_format_neigh_entry(seq, v); 14098c2ecf20Sopenharmony_ci } 14108c2ecf20Sopenharmony_ci 14118c2ecf20Sopenharmony_ci return 0; 14128c2ecf20Sopenharmony_ci} 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_cistatic void *arp_seq_start(struct seq_file *seq, loff_t *pos) 14158c2ecf20Sopenharmony_ci{ 14168c2ecf20Sopenharmony_ci /* Don't want to confuse "arp -a" w/ magic entries, 14178c2ecf20Sopenharmony_ci * so we tell the generic iterator to skip NUD_NOARP. 14188c2ecf20Sopenharmony_ci */ 14198c2ecf20Sopenharmony_ci return neigh_seq_start(seq, pos, &arp_tbl, NEIGH_SEQ_SKIP_NOARP); 14208c2ecf20Sopenharmony_ci} 14218c2ecf20Sopenharmony_ci 14228c2ecf20Sopenharmony_ci/* ------------------------------------------------------------------------ */ 14238c2ecf20Sopenharmony_ci 14248c2ecf20Sopenharmony_cistatic const struct seq_operations arp_seq_ops = { 14258c2ecf20Sopenharmony_ci .start = arp_seq_start, 14268c2ecf20Sopenharmony_ci .next = neigh_seq_next, 14278c2ecf20Sopenharmony_ci .stop = neigh_seq_stop, 14288c2ecf20Sopenharmony_ci .show = arp_seq_show, 14298c2ecf20Sopenharmony_ci}; 14308c2ecf20Sopenharmony_ci 14318c2ecf20Sopenharmony_ci/* ------------------------------------------------------------------------ */ 14328c2ecf20Sopenharmony_ci 14338c2ecf20Sopenharmony_cistatic int __net_init arp_net_init(struct net *net) 14348c2ecf20Sopenharmony_ci{ 14358c2ecf20Sopenharmony_ci if (!proc_create_net("arp", 0444, net->proc_net, &arp_seq_ops, 14368c2ecf20Sopenharmony_ci sizeof(struct neigh_seq_state))) 14378c2ecf20Sopenharmony_ci return -ENOMEM; 14388c2ecf20Sopenharmony_ci return 0; 14398c2ecf20Sopenharmony_ci} 14408c2ecf20Sopenharmony_ci 14418c2ecf20Sopenharmony_cistatic void __net_exit arp_net_exit(struct net *net) 14428c2ecf20Sopenharmony_ci{ 14438c2ecf20Sopenharmony_ci remove_proc_entry("arp", net->proc_net); 14448c2ecf20Sopenharmony_ci} 14458c2ecf20Sopenharmony_ci 14468c2ecf20Sopenharmony_cistatic struct pernet_operations arp_net_ops = { 14478c2ecf20Sopenharmony_ci .init = arp_net_init, 14488c2ecf20Sopenharmony_ci .exit = arp_net_exit, 14498c2ecf20Sopenharmony_ci}; 14508c2ecf20Sopenharmony_ci 14518c2ecf20Sopenharmony_cistatic int __init arp_proc_init(void) 14528c2ecf20Sopenharmony_ci{ 14538c2ecf20Sopenharmony_ci return register_pernet_subsys(&arp_net_ops); 14548c2ecf20Sopenharmony_ci} 14558c2ecf20Sopenharmony_ci 14568c2ecf20Sopenharmony_ci#else /* CONFIG_PROC_FS */ 14578c2ecf20Sopenharmony_ci 14588c2ecf20Sopenharmony_cistatic int __init arp_proc_init(void) 14598c2ecf20Sopenharmony_ci{ 14608c2ecf20Sopenharmony_ci return 0; 14618c2ecf20Sopenharmony_ci} 14628c2ecf20Sopenharmony_ci 14638c2ecf20Sopenharmony_ci#endif /* CONFIG_PROC_FS */ 1464