static inline struct neighbour *
__neigh_lookup(struct neigh_table *tbl, const void *pkey, struct net_device *dev, int creat)
{
struct neighbour *n = neigh_lookup(tbl, pkey, dev);
if (n || !creat)
return n;
//將添息添加至鄰居表
n = neigh_create(tbl, pkey, dev);
return IS_ERR(n) ? NULL : n;
}
int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new,
u32 flags)
{
u8 old;
int err;
#ifdef CONFIG_ARPD
int notify = 0;
#endif
struct net_device *dev;
int update_isrouter = 0;
write_lock_bh(&neigh->lock);
dev = neigh->dev;
old = neigh->nud_state;
err = -EPERM;
if (!(flags & NEIGH_UPDATE_F_ADMIN) &&
(old & (NUD_NOARP | NUD_PERMANENT)))
goto out;
//若不是更改為有效狀態
if (!(new & NUD_VALID)) {
//移除定時器
neigh_del_timer(neigh);
//若以前的狀態是NUD_CONNECTED
//則調整鄰居項對應的out函數指針
if (old & NUD_CONNECTED)
neigh_suspect(neigh);
neigh->nud_state = new;
err = 0;
#ifdef CONFIG_ARPD
notify = old & NUD_VALID;
#endif
goto out;
}
/* Compare new lladdr with cached one */
if (!dev->addr_len) {
/* First case: device needs no address. */
lladdr = neigh->ha;
} else if (lladdr) {
/* The second case: if something is already cached
and a new address is proposed:
- compare new & old
- if they are different, check override flag
*/
if ((old & NUD_VALID) &&
!memcmp(lladdr, neigh->ha, dev->addr_len))
lladdr = neigh->ha;
} else {
/* No address is supplied; if we know something,
use it, otherwise discard the request.
*/
err = -EINVAL;
if (!(old & NUD_VALID))
goto out;
lladdr = neigh->ha;
}
//如果是轉換到連接狀態,則重置被證實時間
if (new & NUD_CONNECTED)
neigh->confirmed = jiffies;
//重置更新時間
neigh->updated = jiffies;
/* If entry was valid and address is not changed,
do not change entry state, if new one is STALE.
*/
err = 0;
update_isrouter = flags & NEIGH_UPDATE_F_OVERRIDE_ISROUTER;
//更新鄰居項對應的鄰居L2地址
if (old & NUD_VALID) {
if (lladdr != neigh->ha && !(flags & NEIGH_UPDATE_F_OVERRIDE)) {
update_isrouter = 0;
if ((flags & NEIGH_UPDATE_F_WEAK_OVERRIDE) &&
(old & NUD_CONNECTED)) {
lladdr = neigh->ha;
new = NUD_STALE;
} else
goto out;
} else {
if (lladdr == neigh->ha && new == NUD_STALE &&
((flags & NEIGH_UPDATE_F_WEAK_OVERRIDE) ||
(old & NUD_CONNECTED))
)
new = old;
}
}
if (new != old) {
neigh_del_timer(neigh);
if (new & NUD_IN_TIMER) {
neigh_hold(neigh);
neigh->timer.expires = jiffies +
((new & NUD_REACHABLE) ?
neigh->parms->reachable_time : 0);
add_timer(&neigh->timer);
}
neigh->nud_state = new;
}
//設置ha項
if (lladdr != neigh->ha) {
memcpy(&neigh->ha, lladdr, dev->addr_len);
//更新hh項
neigh_update_hhs(neigh);
if (!(new & NUD_CONNECTED))
neigh->confirmed = jiffies -
(neigh->parms->base_reachable_time << 1);
#ifdef CONFIG_ARPD
notify = 1;
#endif
}
if (new == old)
goto out;
//如果是被轉至連接狀態,置out為connect_outp
if (new & NUD_CONNECTED)
neigh_connect(neigh);
else
neigh_suspect(neigh);
//如果鄰居項是從無效轉至有效,則把arp_queue中對應的
//skb發送