歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux基礎 >> 關於Linux

linux協議棧之鄰居子系統(相關流程六)

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發送

Copyright © Linux教程網 All Rights Reserved