.. | .. |
---|
| 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; |
---|