| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* linux/net/ipv4/arp.c |
|---|
| 2 | 3 | * |
|---|
| 3 | 4 | * Copyright (C) 1994 by Florian La Roche |
|---|
| .. | .. |
|---|
| 6 | 7 | * which is used to convert IP addresses (or in the future maybe other |
|---|
| 7 | 8 | * high-level addresses) into a low-level hardware address (like an Ethernet |
|---|
| 8 | 9 | * address). |
|---|
| 9 | | - * |
|---|
| 10 | | - * This program is free software; you can redistribute it and/or |
|---|
| 11 | | - * modify it under the terms of the GNU General Public License |
|---|
| 12 | | - * as published by the Free Software Foundation; either version |
|---|
| 13 | | - * 2 of the License, or (at your option) any later version. |
|---|
| 14 | 10 | * |
|---|
| 15 | 11 | * Fixes: |
|---|
| 16 | 12 | * Alan Cox : Removed the Ethernet assumptions in |
|---|
| .. | .. |
|---|
| 129 | 125 | static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb); |
|---|
| 130 | 126 | static void arp_error_report(struct neighbour *neigh, struct sk_buff *skb); |
|---|
| 131 | 127 | static void parp_redo(struct sk_buff *skb); |
|---|
| 128 | +static int arp_is_multicast(const void *pkey); |
|---|
| 132 | 129 | |
|---|
| 133 | 130 | static const struct neigh_ops arp_generic_ops = { |
|---|
| 134 | 131 | .family = AF_INET, |
|---|
| .. | .. |
|---|
| 160 | 157 | .key_eq = arp_key_eq, |
|---|
| 161 | 158 | .constructor = arp_constructor, |
|---|
| 162 | 159 | .proxy_redo = parp_redo, |
|---|
| 160 | + .is_multicast = arp_is_multicast, |
|---|
| 163 | 161 | .id = "arp_cache", |
|---|
| 164 | 162 | .parms = { |
|---|
| 165 | 163 | .tbl = &arp_tbl, |
|---|
| .. | .. |
|---|
| 932 | 930 | arp_process(dev_net(skb->dev), NULL, skb); |
|---|
| 933 | 931 | } |
|---|
| 934 | 932 | |
|---|
| 933 | +static int arp_is_multicast(const void *pkey) |
|---|
| 934 | +{ |
|---|
| 935 | + return ipv4_is_multicast(*((__be32 *)pkey)); |
|---|
| 936 | +} |
|---|
| 935 | 937 | |
|---|
| 936 | 938 | /* |
|---|
| 937 | 939 | * Receive an arp request from the device layer. |
|---|
| .. | .. |
|---|
| 1114 | 1116 | return err; |
|---|
| 1115 | 1117 | } |
|---|
| 1116 | 1118 | |
|---|
| 1117 | | -static int arp_invalidate(struct net_device *dev, __be32 ip) |
|---|
| 1119 | +int arp_invalidate(struct net_device *dev, __be32 ip, bool force) |
|---|
| 1118 | 1120 | { |
|---|
| 1119 | 1121 | struct neighbour *neigh = neigh_lookup(&arp_tbl, &ip, dev); |
|---|
| 1120 | 1122 | int err = -ENXIO; |
|---|
| 1121 | 1123 | struct neigh_table *tbl = &arp_tbl; |
|---|
| 1122 | 1124 | |
|---|
| 1123 | 1125 | if (neigh) { |
|---|
| 1126 | + if ((neigh->nud_state & NUD_VALID) && !force) { |
|---|
| 1127 | + neigh_release(neigh); |
|---|
| 1128 | + return 0; |
|---|
| 1129 | + } |
|---|
| 1130 | + |
|---|
| 1124 | 1131 | if (neigh->nud_state & ~NUD_NOARP) |
|---|
| 1125 | 1132 | err = neigh_update(neigh, NULL, NUD_FAILED, |
|---|
| 1126 | 1133 | NEIGH_UPDATE_F_OVERRIDE| |
|---|
| .. | .. |
|---|
| 1167 | 1174 | if (!dev) |
|---|
| 1168 | 1175 | return -EINVAL; |
|---|
| 1169 | 1176 | } |
|---|
| 1170 | | - return arp_invalidate(dev, ip); |
|---|
| 1177 | + return arp_invalidate(dev, ip, true); |
|---|
| 1171 | 1178 | } |
|---|
| 1172 | 1179 | |
|---|
| 1173 | 1180 | /* |
|---|
| .. | .. |
|---|
| 1185 | 1192 | case SIOCSARP: |
|---|
| 1186 | 1193 | if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) |
|---|
| 1187 | 1194 | return -EPERM; |
|---|
| 1188 | | - /* fall through */ |
|---|
| 1195 | + fallthrough; |
|---|
| 1189 | 1196 | case SIOCGARP: |
|---|
| 1190 | 1197 | err = copy_from_user(&r, arg, sizeof(struct arpreq)); |
|---|
| 1191 | 1198 | if (err) |
|---|
| .. | .. |
|---|
| 1255 | 1262 | change_info = ptr; |
|---|
| 1256 | 1263 | if (change_info->flags_changed & IFF_NOARP) |
|---|
| 1257 | 1264 | neigh_changeaddr(&arp_tbl, dev); |
|---|
| 1265 | + if (!netif_carrier_ok(dev)) |
|---|
| 1266 | + neigh_carrier_down(&arp_tbl, dev); |
|---|
| 1258 | 1267 | break; |
|---|
| 1259 | 1268 | default: |
|---|
| 1260 | 1269 | break; |
|---|