Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
410e9a9b
Commit
410e9a9b
authored
Jun 06, 2002
by
David S. Miller
Browse files
Options
Browse Files
Download
Plain Diff
Merge
http://kernel-acme.bkbits.net:8080/net-cleanups-2.5-neighbour
into nuts.ninka.net:/home/davem/src/BK/net-2.5
parents
3da9cf28
3e978a40
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
523 additions
and
408 deletions
+523
-408
net/core/neighbour.c
net/core/neighbour.c
+523
-408
No files found.
net/core/neighbour.c
View file @
410e9a9b
...
...
@@ -101,7 +101,7 @@ static int neigh_blackhole(struct sk_buff *skb)
unsigned
long
neigh_rand_reach_time
(
unsigned
long
base
)
{
return
(
net_random
()
%
base
)
+
(
base
>>
1
);
return
(
net_random
()
%
base
)
+
(
base
>>
1
);
}
...
...
@@ -110,7 +110,7 @@ static int neigh_forced_gc(struct neigh_table *tbl)
int
shrunk
=
0
;
int
i
;
for
(
i
=
0
;
i
<=
NEIGH_HASHMASK
;
i
++
)
{
for
(
i
=
0
;
i
<=
NEIGH_HASHMASK
;
i
++
)
{
struct
neighbour
*
n
,
**
np
;
np
=
&
tbl
->
hash_buckets
[
i
];
...
...
@@ -128,7 +128,7 @@ static int neigh_forced_gc(struct neigh_table *tbl)
*/
write_lock
(
&
n
->
lock
);
if
(
atomic_read
(
&
n
->
refcnt
)
==
1
&&
!
(
n
->
nud_state
&
NUD_PERMANENT
)
&&
!
(
n
->
nud_state
&
NUD_PERMANENT
)
&&
(
n
->
nud_state
!=
NUD_INCOMPLETE
||
jiffies
-
n
->
used
>
n
->
parms
->
retrans_time
))
{
*
np
=
n
->
next
;
...
...
@@ -150,12 +150,11 @@ static int neigh_forced_gc(struct neigh_table *tbl)
static
int
neigh_del_timer
(
struct
neighbour
*
n
)
{
if
(
n
->
nud_state
&
NUD_IN_TIMER
)
{
if
(
del_timer
(
&
n
->
timer
))
{
if
(
(
n
->
nud_state
&
NUD_IN_TIMER
)
&&
del_timer
(
&
n
->
timer
))
{
neigh_release
(
n
);
return
1
;
}
}
return
0
;
}
...
...
@@ -175,10 +174,9 @@ int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev)
write_lock_bh
(
&
tbl
->
lock
);
for
(
i
=
0
;
i
<=
NEIGH_HASHMASK
;
i
++
)
{
struct
neighbour
*
n
,
**
np
;
for
(
i
=
0
;
i
<=
NEIGH_HASHMASK
;
i
++
)
{
struct
neighbour
*
n
,
**
np
=
&
tbl
->
hash_buckets
[
i
]
;
np
=
&
tbl
->
hash_buckets
[
i
];
while
((
n
=
*
np
)
!=
NULL
)
{
if
(
dev
&&
n
->
dev
!=
dev
)
{
np
=
&
n
->
next
;
...
...
@@ -202,7 +200,7 @@ int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev)
n
->
parms
=
&
tbl
->
parms
;
skb_queue_purge
(
&
n
->
arp_queue
);
n
->
output
=
neigh_blackhole
;
if
(
n
->
nud_state
&
NUD_VALID
)
if
(
n
->
nud_state
&
NUD_VALID
)
n
->
nud_state
=
NUD_NOARP
;
else
n
->
nud_state
=
NUD_NONE
;
...
...
@@ -223,20 +221,20 @@ int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev)
static
struct
neighbour
*
neigh_alloc
(
struct
neigh_table
*
tbl
)
{
struct
neighbour
*
n
;
struct
neighbour
*
n
=
NULL
;
unsigned
long
now
=
jiffies
;
if
(
tbl
->
entries
>
tbl
->
gc_thresh3
||
(
tbl
->
entries
>
tbl
->
gc_thresh2
&&
now
-
tbl
->
last_flush
>
5
*
HZ
))
{
if
(
neigh_forced_gc
(
tbl
)
==
0
&&
now
-
tbl
->
last_flush
>
5
*
HZ
))
{
if
(
!
neigh_forced_gc
(
tbl
)
&&
tbl
->
entries
>
tbl
->
gc_thresh3
)
return
NULL
;
goto
out
;
}
n
=
kmem_cache_alloc
(
tbl
->
kmem_cachep
,
SLAB_ATOMIC
);
if
(
n
==
NULL
)
return
NULL
;
if
(
!
n
)
goto
out
;
memset
(
n
,
0
,
tbl
->
entry_size
);
...
...
@@ -255,6 +253,7 @@ static struct neighbour *neigh_alloc(struct neigh_table *tbl)
n
->
tbl
=
tbl
;
atomic_set
(
&
n
->
refcnt
,
1
);
n
->
dead
=
1
;
out:
return
n
;
}
...
...
@@ -262,15 +261,12 @@ struct neighbour *neigh_lookup(struct neigh_table *tbl, const void *pkey,
struct
net_device
*
dev
)
{
struct
neighbour
*
n
;
u32
hash_val
;
int
key_len
=
tbl
->
key_len
;
hash_val
=
tbl
->
hash
(
pkey
,
dev
);
u32
hash_val
=
tbl
->
hash
(
pkey
,
dev
);
read_lock_bh
(
&
tbl
->
lock
);
for
(
n
=
tbl
->
hash_buckets
[
hash_val
];
n
;
n
=
n
->
next
)
{
if
(
dev
==
n
->
dev
&&
memcmp
(
n
->
primary_key
,
pkey
,
key_len
)
==
0
)
{
if
(
dev
==
n
->
dev
&&
!
memcmp
(
n
->
primary_key
,
pkey
,
key_len
))
{
neigh_hold
(
n
);
break
;
}
...
...
@@ -279,17 +275,18 @@ struct neighbour *neigh_lookup(struct neigh_table *tbl, const void *pkey,
return
n
;
}
struct
neighbour
*
neigh_create
(
struct
neigh_table
*
tbl
,
const
void
*
pkey
,
struct
neighbour
*
neigh_create
(
struct
neigh_table
*
tbl
,
const
void
*
pkey
,
struct
net_device
*
dev
)
{
struct
neighbour
*
n
,
*
n1
;
u32
hash_val
;
int
key_len
=
tbl
->
key_len
;
int
error
;
struct
neighbour
*
n1
,
*
rc
,
*
n
=
neigh_alloc
(
tbl
);
n
=
neigh_alloc
(
tbl
);
if
(
n
==
NULL
)
return
ERR_PTR
(
-
ENOBUFS
);
if
(
!
n
)
{
rc
=
ERR_PTR
(
-
ENOBUFS
);
goto
out
;
}
memcpy
(
n
->
primary_key
,
pkey
,
key_len
);
n
->
dev
=
dev
;
...
...
@@ -297,29 +294,28 @@ struct neighbour * neigh_create(struct neigh_table *tbl, const void *pkey,
/* Protocol specific setup. */
if
(
tbl
->
constructor
&&
(
error
=
tbl
->
constructor
(
n
))
<
0
)
{
neigh_release
(
n
);
return
ERR_PTR
(
error
)
;
rc
=
ERR_PTR
(
error
);
goto
out_neigh_release
;
}
/* Device specific setup. */
if
(
n
->
parms
->
neigh_setup
&&
(
error
=
n
->
parms
->
neigh_setup
(
n
))
<
0
)
{
neigh_release
(
n
);
return
ERR_PTR
(
error
)
;
rc
=
ERR_PTR
(
error
);
goto
out_neigh_release
;
}
n
->
confirmed
=
jiffies
-
(
n
->
parms
->
base_reachable_time
<<
1
);
n
->
confirmed
=
jiffies
-
(
n
->
parms
->
base_reachable_time
<<
1
);
hash_val
=
tbl
->
hash
(
pkey
,
dev
);
write_lock_bh
(
&
tbl
->
lock
);
for
(
n1
=
tbl
->
hash_buckets
[
hash_val
];
n1
;
n1
=
n1
->
next
)
{
if
(
dev
==
n1
->
dev
&&
memcmp
(
n1
->
primary_key
,
pkey
,
key_len
)
==
0
)
{
if
(
dev
==
n1
->
dev
&&
!
memcmp
(
n1
->
primary_key
,
pkey
,
key_len
))
{
neigh_hold
(
n1
);
write_unlock_bh
(
&
tbl
->
lock
);
neigh_release
(
n
)
;
return
n1
;
rc
=
n1
;
goto
out_neigh_release
;
}
}
...
...
@@ -329,69 +325,77 @@ struct neighbour * neigh_create(struct neigh_table *tbl, const void *pkey,
neigh_hold
(
n
);
write_unlock_bh
(
&
tbl
->
lock
);
NEIGH_PRINTK2
(
"neigh %p is created.
\n
"
,
n
);
return
n
;
rc
=
n
;
out:
return
rc
;
out_neigh_release:
neigh_release
(
n
);
goto
out
;
}
struct
pneigh_entry
*
pneigh_lookup
(
struct
neigh_table
*
tbl
,
const
void
*
pkey
,
struct
net_device
*
dev
,
int
creat
)
{
struct
pneigh_entry
*
n
;
u32
hash_val
;
int
key_len
=
tbl
->
key_len
;
u32
hash_val
=
*
(
u32
*
)(
pkey
+
key_len
-
4
);
hash_val
=
*
(
u32
*
)(
pkey
+
key_len
-
4
);
hash_val
^=
(
hash_val
>>
16
);
hash_val
^=
hash_val
>>
8
;
hash_val
^=
hash_val
>>
4
;
hash_val
^=
(
hash_val
>>
16
);
hash_val
^=
hash_val
>>
8
;
hash_val
^=
hash_val
>>
4
;
hash_val
&=
PNEIGH_HASHMASK
;
read_lock_bh
(
&
tbl
->
lock
);
for
(
n
=
tbl
->
phash_buckets
[
hash_val
];
n
;
n
=
n
->
next
)
{
if
(
memcmp
(
n
->
key
,
pkey
,
key_len
)
==
0
&&
if
(
!
memcmp
(
n
->
key
,
pkey
,
key_len
)
&&
(
n
->
dev
==
dev
||
!
n
->
dev
))
{
read_unlock_bh
(
&
tbl
->
lock
);
return
n
;
goto
out
;
}
}
read_unlock_bh
(
&
tbl
->
lock
);
n
=
NULL
;
if
(
!
creat
)
return
NULL
;
goto
out
;
n
=
kmalloc
(
sizeof
(
*
n
)
+
key_len
,
GFP_KERNEL
);
if
(
n
==
NULL
)
return
NULL
;
if
(
!
n
)
goto
out
;
memcpy
(
n
->
key
,
pkey
,
key_len
);
n
->
dev
=
dev
;
if
(
tbl
->
pconstructor
&&
tbl
->
pconstructor
(
n
))
{
kfree
(
n
);
return
NULL
;
n
=
NULL
;
goto
out
;
}
write_lock_bh
(
&
tbl
->
lock
);
n
->
next
=
tbl
->
phash_buckets
[
hash_val
];
tbl
->
phash_buckets
[
hash_val
]
=
n
;
write_unlock_bh
(
&
tbl
->
lock
);
out:
return
n
;
}
int
pneigh_delete
(
struct
neigh_table
*
tbl
,
const
void
*
pkey
,
struct
net_device
*
dev
)
int
pneigh_delete
(
struct
neigh_table
*
tbl
,
const
void
*
pkey
,
struct
net_device
*
dev
)
{
struct
pneigh_entry
*
n
,
**
np
;
u32
hash_val
;
int
key_len
=
tbl
->
key_len
;
u32
hash_val
=
*
(
u32
*
)(
pkey
+
key_len
-
4
);
hash_val
=
*
(
u32
*
)(
pkey
+
key_len
-
4
);
hash_val
^=
(
hash_val
>>
16
);
hash_val
^=
hash_val
>>
8
;
hash_val
^=
hash_val
>>
4
;
hash_val
^=
(
hash_val
>>
16
);
hash_val
^=
hash_val
>>
8
;
hash_val
^=
hash_val
>>
4
;
hash_val
&=
PNEIGH_HASHMASK
;
for
(
np
=
&
tbl
->
phash_buckets
[
hash_val
];
(
n
=*
np
)
!=
NULL
;
np
=
&
n
->
next
)
{
if
(
memcmp
(
n
->
key
,
pkey
,
key_len
)
==
0
&&
n
->
dev
==
dev
)
{
for
(
np
=
&
tbl
->
phash_buckets
[
hash_val
];
(
n
=
*
np
)
!=
NULL
;
np
=
&
n
->
next
)
{
if
(
!
memcmp
(
n
->
key
,
pkey
,
key_len
)
&&
n
->
dev
==
dev
)
{
write_lock_bh
(
&
tbl
->
lock
);
*
np
=
n
->
next
;
write_unlock_bh
(
&
tbl
->
lock
);
...
...
@@ -409,10 +413,10 @@ static int pneigh_ifdown(struct neigh_table *tbl, struct net_device *dev)
struct
pneigh_entry
*
n
,
**
np
;
u32
h
;
for
(
h
=
0
;
h
<=
PNEIGH_HASHMASK
;
h
++
)
{
for
(
h
=
0
;
h
<=
PNEIGH_HASHMASK
;
h
++
)
{
np
=
&
tbl
->
phash_buckets
[
h
];
while
((
n
=
*
np
)
!=
NULL
)
{
if
(
n
->
dev
==
dev
||
dev
==
NULL
)
{
while
((
n
=
*
np
)
!=
NULL
)
{
if
(
!
dev
||
n
->
dev
==
dev
)
{
*
np
=
n
->
next
;
if
(
tbl
->
pdestructor
)
tbl
->
pdestructor
(
n
);
...
...
@@ -435,13 +439,14 @@ void neigh_destroy(struct neighbour *neigh)
struct
hh_cache
*
hh
;
if
(
!
neigh
->
dead
)
{
printk
(
"Destroying alive neighbour %p from %08lx
\n
"
,
neigh
,
*
(((
unsigned
long
*
)
&
neigh
)
-
1
));
printk
(
KERN_WARNING
"Destroying alive neighbour %p from %08lx
\n
"
,
neigh
,
*
(((
unsigned
long
*
)
&
neigh
)
-
1
));
return
;
}
if
(
neigh_del_timer
(
neigh
))
printk
(
"Impossible event.
\n
"
);
printk
(
KERN_WARNING
"Impossible event.
\n
"
);
while
((
hh
=
neigh
->
hh
)
!=
NULL
)
{
neigh
->
hh
=
hh
->
hh_next
;
...
...
@@ -519,14 +524,14 @@ static void neigh_sync(struct neighbour *n)
unsigned
long
now
=
jiffies
;
u8
state
=
n
->
nud_state
;
if
(
state
&
(
NUD_NOARP
|
NUD_PERMANENT
))
if
(
state
&
(
NUD_NOARP
|
NUD_PERMANENT
))
return
;
if
(
state
&
NUD_REACHABLE
)
{
if
(
state
&
NUD_REACHABLE
)
{
if
(
now
-
n
->
confirmed
>
n
->
parms
->
reachable_time
)
{
n
->
nud_state
=
NUD_STALE
;
neigh_suspect
(
n
);
}
}
else
if
(
state
&
NUD_VALID
)
{
}
else
if
(
state
&
NUD_VALID
)
{
if
(
now
-
n
->
confirmed
<
n
->
parms
->
reachable_time
)
{
neigh_del_timer
(
n
);
n
->
nud_state
=
NUD_REACHABLE
;
...
...
@@ -537,7 +542,7 @@ static void neigh_sync(struct neighbour *n)
static
void
SMP_TIMER_NAME
(
neigh_periodic_timer
)(
unsigned
long
arg
)
{
struct
neigh_table
*
tbl
=
(
struct
neigh_table
*
)
arg
;
struct
neigh_table
*
tbl
=
(
struct
neigh_table
*
)
arg
;
unsigned
long
now
=
jiffies
;
int
i
;
...
...
@@ -548,14 +553,15 @@ static void SMP_TIMER_NAME(neigh_periodic_timer)(unsigned long arg)
* periodicly recompute ReachableTime from random function
*/
if
(
now
-
tbl
->
last_rand
>
300
*
HZ
)
{
if
(
now
-
tbl
->
last_rand
>
300
*
HZ
)
{
struct
neigh_parms
*
p
;
tbl
->
last_rand
=
now
;
for
(
p
=&
tbl
->
parms
;
p
;
p
=
p
->
next
)
p
->
reachable_time
=
neigh_rand_reach_time
(
p
->
base_reachable_time
);
for
(
p
=
&
tbl
->
parms
;
p
;
p
=
p
->
next
)
p
->
reachable_time
=
neigh_rand_reach_time
(
p
->
base_reachable_time
);
}
for
(
i
=
0
;
i
<=
NEIGH_HASHMASK
;
i
++
)
{
for
(
i
=
0
;
i
<=
NEIGH_HASHMASK
;
i
++
)
{
struct
neighbour
*
n
,
**
np
;
np
=
&
tbl
->
hash_buckets
[
i
];
...
...
@@ -565,7 +571,7 @@ static void SMP_TIMER_NAME(neigh_periodic_timer)(unsigned long arg)
write_lock
(
&
n
->
lock
);
state
=
n
->
nud_state
;
if
(
state
&
(
NUD_PERMANENT
|
NUD_IN_TIMER
))
{
if
(
state
&
(
NUD_PERMANENT
|
NUD_IN_TIMER
))
{
write_unlock
(
&
n
->
lock
);
goto
next_elt
;
}
...
...
@@ -574,7 +580,8 @@ static void SMP_TIMER_NAME(neigh_periodic_timer)(unsigned long arg)
n
->
used
=
n
->
confirmed
;
if
(
atomic_read
(
&
n
->
refcnt
)
==
1
&&
(
state
==
NUD_FAILED
||
now
-
n
->
used
>
n
->
parms
->
gc_staletime
))
{
(
state
==
NUD_FAILED
||
now
-
n
->
used
>
n
->
parms
->
gc_staletime
))
{
*
np
=
n
->
next
;
n
->
dead
=
1
;
write_unlock
(
&
n
->
lock
);
...
...
@@ -582,7 +589,7 @@ static void SMP_TIMER_NAME(neigh_periodic_timer)(unsigned long arg)
continue
;
}
if
(
n
->
nud_state
&
NUD_REACHABLE
&&
if
(
n
->
nud_state
&
NUD_REACHABLE
&&
now
-
n
->
confirmed
>
n
->
parms
->
reachable_time
)
{
n
->
nud_state
=
NUD_STALE
;
neigh_suspect
(
n
);
...
...
@@ -601,7 +608,7 @@ static void SMP_TIMER_NAME(neigh_periodic_timer)(unsigned long arg)
#ifdef CONFIG_SMP
static
void
neigh_periodic_timer
(
unsigned
long
arg
)
{
struct
neigh_table
*
tbl
=
(
struct
neigh_table
*
)
arg
;
struct
neigh_table
*
tbl
=
(
struct
neigh_table
*
)
arg
;
tasklet_schedule
(
&
tbl
->
gc_task
);
}
...
...
@@ -619,7 +626,7 @@ static __inline__ int neigh_max_probes(struct neighbour *n)
static
void
neigh_timer_handler
(
unsigned
long
arg
)
{
unsigned
long
now
=
jiffies
;
struct
neighbour
*
neigh
=
(
struct
neighbour
*
)
arg
;
struct
neighbour
*
neigh
=
(
struct
neighbour
*
)
arg
;
unsigned
state
;
int
notify
=
0
;
...
...
@@ -627,14 +634,14 @@ static void neigh_timer_handler(unsigned long arg)
state
=
neigh
->
nud_state
;
if
(
!
(
state
&
NUD_IN_TIMER
))
{
if
(
!
(
state
&
NUD_IN_TIMER
))
{
#ifndef CONFIG_SMP
printk
(
"neigh: timer & !nud_in_timer
\n
"
);
printk
(
KERN_WARNING
"neigh: timer & !nud_in_timer
\n
"
);
#endif
goto
out
;
}
if
((
state
&
NUD_VALID
)
&&
if
((
state
&
NUD_VALID
)
&&
now
-
neigh
->
confirmed
<
neigh
->
parms
->
reachable_time
)
{
neigh
->
nud_state
=
NUD_REACHABLE
;
NEIGH_PRINTK2
(
"neigh %p is still alive.
\n
"
,
neigh
);
...
...
@@ -660,7 +667,8 @@ static void neigh_timer_handler(unsigned long arg)
So that, we try to be accurate and avoid dead loop. --ANK
*/
while
(
neigh
->
nud_state
==
NUD_FAILED
&&
(
skb
=
__skb_dequeue
(
&
neigh
->
arp_queue
))
!=
NULL
)
{
while
(
neigh
->
nud_state
==
NUD_FAILED
&&
(
skb
=
__skb_dequeue
(
&
neigh
->
arp_queue
))
!=
NULL
)
{
write_unlock
(
&
neigh
->
lock
);
neigh
->
ops
->
error_report
(
neigh
,
skb
);
write_lock
(
&
neigh
->
lock
);
...
...
@@ -688,14 +696,21 @@ static void neigh_timer_handler(unsigned long arg)
int
__neigh_event_send
(
struct
neighbour
*
neigh
,
struct
sk_buff
*
skb
)
{
int
rc
;
write_lock_bh
(
&
neigh
->
lock
);
if
(
!
(
neigh
->
nud_state
&
(
NUD_CONNECTED
|
NUD_DELAY
|
NUD_PROBE
)))
{
if
(
!
(
neigh
->
nud_state
&
(
NUD_STALE
|
NUD_INCOMPLETE
)))
{
rc
=
0
;
if
(
neigh
->
nud_state
&
(
NUD_CONNECTED
|
NUD_DELAY
|
NUD_PROBE
))
goto
out_unlock_bh
;
if
(
!
(
neigh
->
nud_state
&
(
NUD_STALE
|
NUD_INCOMPLETE
)))
{
if
(
neigh
->
parms
->
mcast_probes
+
neigh
->
parms
->
app_probes
)
{
atomic_set
(
&
neigh
->
probes
,
neigh
->
parms
->
ucast_probes
);
neigh
->
nud_state
=
NUD_INCOMPLETE
;
neigh_hold
(
neigh
);
neigh
->
timer
.
expires
=
jiffies
+
neigh
->
parms
->
retrans_time
;
neigh
->
timer
.
expires
=
jiffies
+
neigh
->
parms
->
retrans_time
;
add_timer
(
&
neigh
->
timer
);
write_unlock_bh
(
&
neigh
->
lock
);
neigh
->
ops
->
solicit
(
neigh
,
skb
);
...
...
@@ -710,9 +725,11 @@ int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
return
1
;
}
}
if
(
neigh
->
nud_state
==
NUD_INCOMPLETE
)
{
if
(
skb
)
{
if
(
skb_queue_len
(
&
neigh
->
arp_queue
)
>=
neigh
->
parms
->
queue_len
)
{
if
(
skb_queue_len
(
&
neigh
->
arp_queue
)
>=
neigh
->
parms
->
queue_len
)
{
struct
sk_buff
*
buff
;
buff
=
neigh
->
arp_queue
.
next
;
__skb_unlink
(
buff
,
&
neigh
->
arp_queue
);
...
...
@@ -720,29 +737,28 @@ int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
}
__skb_queue_tail
(
&
neigh
->
arp_queue
,
skb
);
}
write_unlock_bh
(
&
neigh
->
lock
);
return
1
;
}
if
(
neigh
->
nud_state
==
NUD_STALE
)
{
rc
=
1
;
}
else
if
(
neigh
->
nud_state
==
NUD_STALE
)
{
NEIGH_PRINTK2
(
"neigh %p is delayed.
\n
"
,
neigh
);
neigh_hold
(
neigh
);
neigh
->
nud_state
=
NUD_DELAY
;
neigh
->
timer
.
expires
=
jiffies
+
neigh
->
parms
->
delay_probe_time
;
add_timer
(
&
neigh
->
timer
);
rc
=
0
;
}
}
out_unlock_bh:
write_unlock_bh
(
&
neigh
->
lock
);
return
0
;
return
rc
;
}
static
__inline__
void
neigh_update_hhs
(
struct
neighbour
*
neigh
)
{
struct
hh_cache
*
hh
;
void
(
*
update
)(
struct
hh_cache
*
,
struct
net_device
*
,
unsigned
char
*
)
=
void
(
*
update
)(
struct
hh_cache
*
,
struct
net_device
*
,
unsigned
char
*
)
=
neigh
->
dev
->
header_cache_update
;
if
(
update
)
{
for
(
hh
=
neigh
->
hh
;
hh
;
hh
=
hh
->
hh_next
)
{
for
(
hh
=
neigh
->
hh
;
hh
;
hh
=
hh
->
hh_next
)
{
write_lock_bh
(
&
hh
->
hh_lock
);
update
(
hh
,
neigh
->
dev
,
neigh
->
ha
);
write_unlock_bh
(
&
hh
->
hh_lock
);
...
...
@@ -755,38 +771,45 @@ static __inline__ void neigh_update_hhs(struct neighbour *neigh)
/* Generic update routine.
-- lladdr is new lladdr or NULL, if it is not supplied.
-- new is new state.
-- override
==
1 allows to override existing lladdr, if it is different.
-- arp
==
0 means that the change is administrative.
-- override
==
1 allows to override existing lladdr, if it is different.
-- arp
==
0 means that the change is administrative.
Caller MUST hold reference count on the entry.
*/
int
neigh_update
(
struct
neighbour
*
neigh
,
const
u8
*
lladdr
,
u8
new
,
int
override
,
int
arp
)
int
neigh_update
(
struct
neighbour
*
neigh
,
const
u8
*
lladdr
,
u8
new
,
int
override
,
int
arp
)
{
u8
old
;
int
err
;
#ifdef CONFIG_ARPD
int
notify
=
0
;
struct
net_device
*
dev
=
neigh
->
dev
;
#endif
struct
net_device
*
dev
;
write_lock_bh
(
&
neigh
->
lock
);
old
=
neigh
->
nud_state
;
dev
=
neigh
->
dev
;
old
=
neigh
->
nud_state
;
err
=
-
EPERM
;
if
(
arp
&&
(
old
&
(
NUD_NOARP
|
NUD_PERMANENT
)))
if
(
arp
&&
(
old
&
(
NUD_NOARP
|
NUD_PERMANENT
)))
goto
out
;
if
(
!
(
new
&
NUD_VALID
))
{
if
(
!
(
new
&
NUD_VALID
))
{
neigh_del_timer
(
neigh
);
if
(
old
&
NUD_CONNECTED
)
if
(
old
&
NUD_CONNECTED
)
neigh_suspect
(
neigh
);
neigh
->
nud_state
=
new
;
err
=
0
;
notify
=
old
&
NUD_VALID
;
#ifdef CONFIG_ARPD
notify
=
old
&
NUD_VALID
;
#endif
goto
out
;
}
/* Compare new lladdr with cached one */
if
(
dev
->
addr_len
==
0
)
{
if
(
!
dev
->
addr_len
)
{
/* First case: device needs no address. */
lladdr
=
neigh
->
ha
;
}
else
if
(
lladdr
)
{
...
...
@@ -795,8 +818,8 @@ int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new, int override
- compare new & old
- if they are different, check override flag
*/
if
(
old
&
NUD_VALID
)
{
if
(
memcmp
(
lladdr
,
neigh
->
ha
,
dev
->
addr_len
)
==
0
)
if
(
old
&
NUD_VALID
)
{
if
(
!
memcmp
(
lladdr
,
neigh
->
ha
,
dev
->
addr_len
)
)
lladdr
=
neigh
->
ha
;
else
if
(
!
override
)
goto
out
;
...
...
@@ -806,14 +829,14 @@ int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new, int override
use it, otherwise discard the request.
*/
err
=
-
EINVAL
;
if
(
!
(
old
&
NUD_VALID
))
if
(
!
(
old
&
NUD_VALID
))
goto
out
;
lladdr
=
neigh
->
ha
;
}
neigh_sync
(
neigh
);
old
=
neigh
->
nud_state
;
if
(
new
&
NUD_CONNECTED
)
if
(
new
&
NUD_CONNECTED
)
neigh
->
confirmed
=
jiffies
;
neigh
->
updated
=
jiffies
;
...
...
@@ -821,35 +844,35 @@ int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new, int override
do not change entry state, if new one is STALE.
*/
err
=
0
;
if
(
old
&
NUD_VALID
)
{
if
(
lladdr
==
neigh
->
ha
)
if
(
new
==
old
||
(
new
==
NUD_STALE
&&
(
old
&
NUD_CONNECTED
)))
if
((
old
&
NUD_VALID
)
&&
lladdr
==
neigh
->
ha
&&
(
new
==
old
||
(
new
==
NUD_STALE
&&
(
old
&
NUD_CONNECTED
))))
goto
out
;
}
neigh_del_timer
(
neigh
);
neigh
->
nud_state
=
new
;
if
(
lladdr
!=
neigh
->
ha
)
{
memcpy
(
&
neigh
->
ha
,
lladdr
,
dev
->
addr_len
);
neigh_update_hhs
(
neigh
);
if
(
!
(
new
&
NUD_CONNECTED
))
neigh
->
confirmed
=
jiffies
-
(
neigh
->
parms
->
base_reachable_time
<<
1
);
if
(
!
(
new
&
NUD_CONNECTED
))
neigh
->
confirmed
=
jiffies
-
(
neigh
->
parms
->
base_reachable_time
<<
1
);
#ifdef CONFIG_ARPD
notify
=
1
;
#endif
}
if
(
new
==
old
)
goto
out
;
if
(
new
&
NUD_CONNECTED
)
if
(
new
&
NUD_CONNECTED
)
neigh_connect
(
neigh
);
else
neigh_suspect
(
neigh
);
if
(
!
(
old
&
NUD_VALID
))
{
if
(
!
(
old
&
NUD_VALID
))
{
struct
sk_buff
*
skb
;
/* Again: avoid dead loop if something went wrong */
while
(
neigh
->
nud_state
&
NUD_VALID
&&
(
skb
=
__skb_dequeue
(
&
neigh
->
arp_queue
))
!=
NULL
)
{
while
(
neigh
->
nud_state
&
NUD_VALID
&&
(
skb
=
__skb_dequeue
(
&
neigh
->
arp_queue
))
!=
NULL
)
{
struct
neighbour
*
n1
=
neigh
;
write_unlock_bh
(
&
neigh
->
lock
);
/* On shaper/eql skb->dst->neighbour != neigh :( */
...
...
@@ -869,24 +892,24 @@ int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new, int override
return
err
;
}
struct
neighbour
*
neigh_event_ns
(
struct
neigh_table
*
tbl
,
struct
neighbour
*
neigh_event_ns
(
struct
neigh_table
*
tbl
,
u8
*
lladdr
,
void
*
saddr
,
struct
net_device
*
dev
)
{
struct
neighbour
*
neigh
;
neigh
=
__neigh_lookup
(
tbl
,
saddr
,
dev
,
lladdr
||
!
dev
->
addr_len
);
struct
neighbour
*
neigh
=
__neigh_lookup
(
tbl
,
saddr
,
dev
,
lladdr
||
!
dev
->
addr_len
);
if
(
neigh
)
neigh_update
(
neigh
,
lladdr
,
NUD_STALE
,
1
,
1
);
return
neigh
;
}
static
void
neigh_hh_init
(
struct
neighbour
*
n
,
struct
dst_entry
*
dst
,
u16
protocol
)
static
void
neigh_hh_init
(
struct
neighbour
*
n
,
struct
dst_entry
*
dst
,
u16
protocol
)
{
struct
hh_cache
*
hh
=
NULL
;
struct
hh_cache
*
hh
;
struct
net_device
*
dev
=
dst
->
dev
;
for
(
hh
=
n
->
hh
;
hh
;
hh
=
hh
->
hh_next
)
for
(
hh
=
n
->
hh
;
hh
;
hh
=
hh
->
hh_next
)
if
(
hh
->
hh_type
==
protocol
)
break
;
...
...
@@ -903,7 +926,7 @@ static void neigh_hh_init(struct neighbour *n, struct dst_entry *dst, u16 protoc
atomic_inc
(
&
hh
->
hh_refcnt
);
hh
->
hh_next
=
n
->
hh
;
n
->
hh
=
hh
;
if
(
n
->
nud_state
&
NUD_CONNECTED
)
if
(
n
->
nud_state
&
NUD_CONNECTED
)
hh
->
hh_output
=
n
->
ops
->
hh_output
;
else
hh
->
hh_output
=
n
->
ops
->
output
;
...
...
@@ -927,7 +950,8 @@ int neigh_compat_output(struct sk_buff *skb)
__skb_pull
(
skb
,
skb
->
nh
.
raw
-
skb
->
data
);
if
(
dev
->
hard_header
&&
dev
->
hard_header
(
skb
,
dev
,
ntohs
(
skb
->
protocol
),
NULL
,
NULL
,
skb
->
len
)
<
0
&&
dev
->
hard_header
(
skb
,
dev
,
ntohs
(
skb
->
protocol
),
NULL
,
NULL
,
skb
->
len
)
<
0
&&
dev
->
rebuild_header
(
skb
))
return
0
;
...
...
@@ -940,37 +964,43 @@ int neigh_resolve_output(struct sk_buff *skb)
{
struct
dst_entry
*
dst
=
skb
->
dst
;
struct
neighbour
*
neigh
;
int
rc
=
0
;
if
(
!
dst
||
!
(
neigh
=
dst
->
neighbour
))
goto
discard
;
__skb_pull
(
skb
,
skb
->
nh
.
raw
-
skb
->
data
);
if
(
neigh_event_send
(
neigh
,
skb
)
==
0
)
{
if
(
!
neigh_event_send
(
neigh
,
skb
)
)
{
int
err
;
struct
net_device
*
dev
=
neigh
->
dev
;
if
(
dev
->
hard_header_cache
&&
dst
->
hh
==
NULL
)
{
if
(
dev
->
hard_header_cache
&&
!
dst
->
hh
)
{
write_lock_bh
(
&
neigh
->
lock
);
if
(
dst
->
hh
==
NULL
)
if
(
!
dst
->
hh
)
neigh_hh_init
(
neigh
,
dst
,
dst
->
ops
->
protocol
);
err
=
dev
->
hard_header
(
skb
,
dev
,
ntohs
(
skb
->
protocol
),
neigh
->
ha
,
NULL
,
skb
->
len
);
err
=
dev
->
hard_header
(
skb
,
dev
,
ntohs
(
skb
->
protocol
),
neigh
->
ha
,
NULL
,
skb
->
len
);
write_unlock_bh
(
&
neigh
->
lock
);
}
else
{
read_lock_bh
(
&
neigh
->
lock
);
err
=
dev
->
hard_header
(
skb
,
dev
,
ntohs
(
skb
->
protocol
),
neigh
->
ha
,
NULL
,
skb
->
len
);
err
=
dev
->
hard_header
(
skb
,
dev
,
ntohs
(
skb
->
protocol
),
neigh
->
ha
,
NULL
,
skb
->
len
);
read_unlock_bh
(
&
neigh
->
lock
);
}
if
(
err
>=
0
)
r
eturn
neigh
->
ops
->
queue_xmit
(
skb
);
kfree_skb
(
skb
);
return
-
EINVAL
;
r
c
=
neigh
->
ops
->
queue_xmit
(
skb
);
else
goto
out_kfree_skb
;
}
return
0
;
out:
return
rc
;
discard:
NEIGH_PRINTK1
(
"neigh_resolve_output: dst=%p neigh=%p
\n
"
,
dst
,
dst
?
dst
->
neighbour
:
NULL
);
NEIGH_PRINTK1
(
"neigh_resolve_output: dst=%p neigh=%p
\n
"
,
dst
,
dst
?
dst
->
neighbour
:
NULL
);
out_kfree_skb:
rc
=
-
EINVAL
;
kfree_skb
(
skb
);
return
-
EINVAL
;
goto
out
;
}
/* As fast as possible without hh cache */
...
...
@@ -985,12 +1015,16 @@ int neigh_connected_output(struct sk_buff *skb)
__skb_pull
(
skb
,
skb
->
nh
.
raw
-
skb
->
data
);
read_lock_bh
(
&
neigh
->
lock
);
err
=
dev
->
hard_header
(
skb
,
dev
,
ntohs
(
skb
->
protocol
),
neigh
->
ha
,
NULL
,
skb
->
len
);
err
=
dev
->
hard_header
(
skb
,
dev
,
ntohs
(
skb
->
protocol
),
neigh
->
ha
,
NULL
,
skb
->
len
);
read_unlock_bh
(
&
neigh
->
lock
);
if
(
err
>=
0
)
return
neigh
->
ops
->
queue_xmit
(
skb
);
err
=
neigh
->
ops
->
queue_xmit
(
skb
);
else
{
err
=
-
EINVAL
;
kfree_skb
(
skb
);
return
-
EINVAL
;
}
return
err
;
}
static
void
neigh_proxy_process
(
unsigned
long
arg
)
...
...
@@ -1004,7 +1038,7 @@ static void neigh_proxy_process(unsigned long arg)
skb
=
tbl
->
proxy_queue
.
next
;
while
(
skb
!=
(
struct
sk_buff
*
)
&
tbl
->
proxy_queue
)
{
while
(
skb
!=
(
struct
sk_buff
*
)
&
tbl
->
proxy_queue
)
{
struct
sk_buff
*
back
=
skb
;
long
tdif
=
back
->
stamp
.
tv_usec
-
now
;
...
...
@@ -1031,7 +1065,7 @@ void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p,
struct
sk_buff
*
skb
)
{
unsigned
long
now
=
jiffies
;
long
sched_next
=
net_random
()
%
p
->
proxy_delay
;
long
sched_next
=
net_random
()
%
p
->
proxy_delay
;
if
(
tbl
->
proxy_queue
.
qlen
>
p
->
proxy_qlen
)
{
kfree_skb
(
skb
);
...
...
@@ -1055,20 +1089,20 @@ void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p,
}
struct
neigh_parms
*
neigh_parms_alloc
(
struct
net_device
*
dev
,
struct
neigh_table
*
tbl
)
struct
neigh_parms
*
neigh_parms_alloc
(
struct
net_device
*
dev
,
struct
neigh_table
*
tbl
)
{
struct
neigh_parms
*
p
;
p
=
kmalloc
(
sizeof
(
*
p
),
GFP_KERNEL
);
struct
neigh_parms
*
p
=
kmalloc
(
sizeof
(
*
p
),
GFP_KERNEL
)
;
if
(
p
)
{
memcpy
(
p
,
&
tbl
->
parms
,
sizeof
(
*
p
));
p
->
tbl
=
tbl
;
p
->
reachable_time
=
neigh_rand_reach_time
(
p
->
base_reachable_time
);
if
(
dev
&&
dev
->
neigh_setup
)
{
if
(
dev
->
neigh_setup
(
dev
,
p
))
{
p
->
reachable_time
=
neigh_rand_reach_time
(
p
->
base_reachable_time
);
if
(
dev
&&
dev
->
neigh_setup
&&
dev
->
neigh_setup
(
dev
,
p
))
{
kfree
(
p
);
return
NULL
;
}
}
write_lock_bh
(
&
tbl
->
lock
);
p
->
next
=
tbl
->
parms
.
next
;
tbl
->
parms
.
next
=
p
;
...
...
@@ -1081,7 +1115,7 @@ void neigh_parms_release(struct neigh_table *tbl, struct neigh_parms *parms)
{
struct
neigh_parms
**
p
;
if
(
parms
==
NULL
||
parms
==
&
tbl
->
parms
)
if
(
!
parms
||
parms
==
&
tbl
->
parms
)
return
;
write_lock_bh
(
&
tbl
->
lock
);
for
(
p
=
&
tbl
->
parms
.
next
;
*
p
;
p
=
&
(
*
p
)
->
next
)
{
...
...
@@ -1104,22 +1138,25 @@ void neigh_table_init(struct neigh_table *tbl)
{
unsigned
long
now
=
jiffies
;
tbl
->
parms
.
reachable_time
=
neigh_rand_reach_time
(
tbl
->
parms
.
base_reachable_time
);
tbl
->
parms
.
reachable_time
=
neigh_rand_reach_time
(
tbl
->
parms
.
base_reachable_time
);
if
(
tbl
->
kmem_cachep
==
NULL
)
if
(
!
tbl
->
kmem_cachep
)
tbl
->
kmem_cachep
=
kmem_cache_create
(
tbl
->
id
,
(
tbl
->
entry_size
+
15
)
&~
15
,
(
tbl
->
entry_size
+
15
)
&
~
15
,
0
,
SLAB_HWCACHE_ALIGN
,
NULL
,
NULL
);
#ifdef CONFIG_SMP
tasklet_init
(
&
tbl
->
gc_task
,
SMP_TIMER_NAME
(
neigh_periodic_timer
),
(
unsigned
long
)
tbl
);
tasklet_init
(
&
tbl
->
gc_task
,
SMP_TIMER_NAME
(
neigh_periodic_timer
),
(
unsigned
long
)
tbl
);
#endif
init_timer
(
&
tbl
->
gc_timer
);
tbl
->
lock
=
RW_LOCK_UNLOCKED
;
tbl
->
gc_timer
.
data
=
(
unsigned
long
)
tbl
;
tbl
->
gc_timer
.
function
=
neigh_periodic_timer
;
tbl
->
gc_timer
.
expires
=
now
+
tbl
->
gc_interval
+
tbl
->
parms
.
reachable_time
;
tbl
->
gc_timer
.
expires
=
now
+
tbl
->
gc_interval
+
tbl
->
parms
.
reachable_time
;
add_timer
(
&
tbl
->
gc_timer
);
init_timer
(
&
tbl
->
proxy_timer
);
...
...
@@ -1128,7 +1165,7 @@ void neigh_table_init(struct neigh_table *tbl)
skb_queue_head_init
(
&
tbl
->
proxy_queue
);
tbl
->
last_flush
=
now
;
tbl
->
last_rand
=
now
+
tbl
->
parms
.
reachable_time
*
20
;
tbl
->
last_rand
=
now
+
tbl
->
parms
.
reachable_time
*
20
;
write_lock
(
&
neigh_tbl_lock
);
tbl
->
next
=
neigh_tables
;
neigh_tables
=
tbl
;
...
...
@@ -1167,15 +1204,14 @@ int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
struct
rtattr
**
nda
=
arg
;
struct
neigh_table
*
tbl
;
struct
net_device
*
dev
=
NULL
;
int
err
=
0
;
int
err
=
-
ENODEV
;
if
(
ndm
->
ndm_ifindex
)
{
if
((
dev
=
dev_get_by_index
(
ndm
->
ndm_ifindex
))
==
NULL
)
return
-
ENODEV
;
}
if
(
ndm
->
ndm_ifindex
&&
(
dev
=
dev_get_by_index
(
ndm
->
ndm_ifindex
))
==
NULL
)
goto
out
;
read_lock
(
&
neigh_tbl_lock
);
for
(
tbl
=
neigh_tables
;
tbl
;
tbl
=
tbl
->
next
)
{
for
(
tbl
=
neigh_tables
;
tbl
;
tbl
=
tbl
->
next
)
{
struct
neighbour
*
n
;
if
(
tbl
->
family
!=
ndm
->
ndm_family
)
...
...
@@ -1183,34 +1219,33 @@ int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
read_unlock
(
&
neigh_tbl_lock
);
err
=
-
EINVAL
;
if
(
nda
[
NDA_DST
-
1
]
==
NULL
||
nda
[
NDA_DST
-
1
]
->
rta_len
!=
RTA_LENGTH
(
tbl
->
key_len
))
goto
out
;
if
(
!
nda
[
NDA_DST
-
1
]
||
nda
[
NDA_DST
-
1
]
->
rta_len
!=
RTA_LENGTH
(
tbl
->
key_len
))
goto
out
_dev_put
;
if
(
ndm
->
ndm_flags
&
NTF_PROXY
)
{
err
=
pneigh_delete
(
tbl
,
RTA_DATA
(
nda
[
NDA_DST
-
1
]),
dev
);
goto
out
;
if
(
ndm
->
ndm_flags
&
NTF_PROXY
)
{
err
=
pneigh_delete
(
tbl
,
RTA_DATA
(
nda
[
NDA_DST
-
1
]),
dev
);
goto
out_dev_put
;
}
if
(
dev
==
NULL
)
return
-
EINVAL
;
if
(
!
dev
)
goto
out
;
n
=
neigh_lookup
(
tbl
,
RTA_DATA
(
nda
[
NDA_DST
-
1
]),
dev
);
n
=
neigh_lookup
(
tbl
,
RTA_DATA
(
nda
[
NDA_DST
-
1
]),
dev
);
if
(
n
)
{
err
=
neigh_update
(
n
,
NULL
,
NUD_FAILED
,
1
,
0
);
neigh_release
(
n
);
}
out:
if
(
dev
)
dev_put
(
dev
);
return
err
;
goto
out_dev_put
;
}
read_unlock
(
&
neigh_tbl_lock
);
err
=
-
EADDRNOTAVAIL
;
out_dev_put:
if
(
dev
)
dev_put
(
dev
);
return
-
EADDRNOTAVAIL
;
out:
return
err
;
}
int
neigh_add
(
struct
sk_buff
*
skb
,
struct
nlmsghdr
*
nlh
,
void
*
arg
)
...
...
@@ -1219,15 +1254,14 @@ int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
struct
rtattr
**
nda
=
arg
;
struct
neigh_table
*
tbl
;
struct
net_device
*
dev
=
NULL
;
int
err
=
-
ENODEV
;
if
(
ndm
->
ndm_ifindex
)
{
if
((
dev
=
dev_get_by_index
(
ndm
->
ndm_ifindex
))
==
NULL
)
return
-
ENODEV
;
}
if
(
ndm
->
ndm_ifindex
&&
(
dev
=
dev_get_by_index
(
ndm
->
ndm_ifindex
))
==
NULL
)
goto
out
;
read_lock
(
&
neigh_tbl_lock
);
for
(
tbl
=
neigh_tables
;
tbl
;
tbl
=
tbl
->
next
)
{
int
err
=
0
;
for
(
tbl
=
neigh_tables
;
tbl
;
tbl
=
tbl
->
next
)
{
int
override
=
1
;
struct
neighbour
*
n
;
...
...
@@ -1236,53 +1270,57 @@ int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
read_unlock
(
&
neigh_tbl_lock
);
err
=
-
EINVAL
;
if
(
nda
[
NDA_DST
-
1
]
==
NULL
||
nda
[
NDA_DST
-
1
]
->
rta_len
!=
RTA_LENGTH
(
tbl
->
key_len
))
goto
out
;
if
(
ndm
->
ndm_flags
&
NTF_PROXY
)
{
if
(
!
nda
[
NDA_DST
-
1
]
||
nda
[
NDA_DST
-
1
]
->
rta_len
!=
RTA_LENGTH
(
tbl
->
key_len
))
goto
out
_dev_put
;
if
(
ndm
->
ndm_flags
&
NTF_PROXY
)
{
err
=
-
ENOBUFS
;
if
(
pneigh_lookup
(
tbl
,
RTA_DATA
(
nda
[
NDA_DST
-
1
]),
dev
,
1
))
if
(
pneigh_lookup
(
tbl
,
RTA_DATA
(
nda
[
NDA_DST
-
1
]),
dev
,
1
))
err
=
0
;
goto
out
;
goto
out
_dev_put
;
}
if
(
dev
==
NULL
)
return
-
EINVAL
;
err
=
-
EINVAL
;
if
(
nda
[
NDA_LLADDR
-
1
]
!=
NULL
&&
nda
[
NDA_LLADDR
-
1
]
->
rta_len
!=
RTA_LENGTH
(
dev
->
addr_len
))
if
(
!
dev
)
goto
out
;
if
(
nda
[
NDA_LLADDR
-
1
]
&&
nda
[
NDA_LLADDR
-
1
]
->
rta_len
!=
RTA_LENGTH
(
dev
->
addr_len
))
goto
out_dev_put
;
err
=
0
;
n
=
neigh_lookup
(
tbl
,
RTA_DATA
(
nda
[
NDA_DST
-
1
]),
dev
);
n
=
neigh_lookup
(
tbl
,
RTA_DATA
(
nda
[
NDA_DST
-
1
]),
dev
);
if
(
n
)
{
if
(
nlh
->
nlmsg_flags
&
NLM_F_EXCL
)
if
(
nlh
->
nlmsg_flags
&
NLM_F_EXCL
)
err
=
-
EEXIST
;
override
=
nlh
->
nlmsg_flags
&
NLM_F_REPLACE
;
}
else
if
(
!
(
nlh
->
nlmsg_flags
&
NLM_F_CREATE
))
override
=
nlh
->
nlmsg_flags
&
NLM_F_REPLACE
;
}
else
if
(
!
(
nlh
->
nlmsg_flags
&
NLM_F_CREATE
))
err
=
-
ENOENT
;
else
{
n
=
__neigh_lookup_errno
(
tbl
,
RTA_DATA
(
nda
[
NDA_DST
-
1
]),
dev
);
n
=
__neigh_lookup_errno
(
tbl
,
RTA_DATA
(
nda
[
NDA_DST
-
1
]),
dev
);
if
(
IS_ERR
(
n
))
{
err
=
PTR_ERR
(
n
);
n
=
NULL
;
}
}
if
(
err
==
0
)
{
err
=
neigh_update
(
n
,
nda
[
NDA_LLADDR
-
1
]
?
RTA_DATA
(
nda
[
NDA_LLADDR
-
1
])
:
NULL
,
if
(
!
err
)
{
err
=
neigh_update
(
n
,
nda
[
NDA_LLADDR
-
1
]
?
RTA_DATA
(
nda
[
NDA_LLADDR
-
1
])
:
NULL
,
ndm
->
ndm_state
,
override
,
0
);
}
if
(
n
)
neigh_release
(
n
);
out:
if
(
dev
)
dev_put
(
dev
);
return
err
;
goto
out_dev_put
;
}
read_unlock
(
&
neigh_tbl_lock
);
read_unlock
(
&
neigh_tbl_lock
);
err
=
-
EADDRNOTAVAIL
;
out_dev_put:
if
(
dev
)
dev_put
(
dev
);
return
-
EADDRNOTAVAIL
;
out:
return
err
;
}
...
...
@@ -1290,30 +1328,29 @@ static int neigh_fill_info(struct sk_buff *skb, struct neighbour *n,
u32
pid
,
u32
seq
,
int
event
)
{
unsigned
long
now
=
jiffies
;
struct
ndmsg
*
ndm
;
struct
nlmsghdr
*
nlh
;
unsigned
char
*
b
=
skb
->
tail
;
struct
nda_cacheinfo
ci
;
int
locked
=
0
;
struct
nlmsghdr
*
nlh
=
NLMSG_PUT
(
skb
,
pid
,
seq
,
event
,
sizeof
(
struct
ndmsg
));
struct
ndmsg
*
ndm
=
NLMSG_DATA
(
nlh
);
nlh
=
NLMSG_PUT
(
skb
,
pid
,
seq
,
event
,
sizeof
(
*
ndm
));
ndm
=
NLMSG_DATA
(
nlh
);
ndm
->
ndm_family
=
n
->
ops
->
family
;
ndm
->
ndm_flags
=
n
->
flags
;
ndm
->
ndm_type
=
n
->
type
;
ndm
->
ndm_ifindex
=
n
->
dev
->
ifindex
;
RTA_PUT
(
skb
,
NDA_DST
,
n
->
tbl
->
key_len
,
n
->
primary_key
);
read_lock_bh
(
&
n
->
lock
);
locked
=
1
;
locked
=
1
;
ndm
->
ndm_state
=
n
->
nud_state
;
if
(
n
->
nud_state
&
NUD_VALID
)
if
(
n
->
nud_state
&
NUD_VALID
)
RTA_PUT
(
skb
,
NDA_LLADDR
,
n
->
dev
->
addr_len
,
n
->
ha
);
ci
.
ndm_used
=
now
-
n
->
used
;
ci
.
ndm_confirmed
=
now
-
n
->
confirmed
;
ci
.
ndm_updated
=
now
-
n
->
updated
;
ci
.
ndm_refcnt
=
atomic_read
(
&
n
->
refcnt
)
-
1
;
read_unlock_bh
(
&
n
->
lock
);
locked
=
0
;
locked
=
0
;
RTA_PUT
(
skb
,
NDA_CACHEINFO
,
sizeof
(
ci
),
&
ci
);
nlh
->
nlmsg_len
=
skb
->
tail
-
b
;
return
skb
->
len
;
...
...
@@ -1327,73 +1364,70 @@ static int neigh_fill_info(struct sk_buff *skb, struct neighbour *n,
}
static
int
neigh_dump_table
(
struct
neigh_table
*
tbl
,
struct
sk_buff
*
skb
,
struct
netlink_callback
*
cb
)
static
int
neigh_dump_table
(
struct
neigh_table
*
tbl
,
struct
sk_buff
*
skb
,
struct
netlink_callback
*
cb
)
{
struct
neighbour
*
n
;
int
h
,
s_h
;
int
idx
,
s_idx
;
int
rc
,
h
,
s_h
=
cb
->
args
[
1
]
;
int
idx
,
s_idx
=
idx
=
cb
->
args
[
2
]
;
s_h
=
cb
->
args
[
1
];
s_idx
=
idx
=
cb
->
args
[
2
];
for
(
h
=
0
;
h
<=
NEIGH_HASHMASK
;
h
++
)
{
if
(
h
<
s_h
)
continue
;
for
(
h
=
0
;
h
<=
NEIGH_HASHMASK
;
h
++
)
{
if
(
h
<
s_h
)
continue
;
if
(
h
>
s_h
)
s_idx
=
0
;
read_lock_bh
(
&
tbl
->
lock
);
for
(
n
=
tbl
->
hash_buckets
[
h
],
idx
=
0
;
n
;
n
=
n
->
next
,
idx
++
)
{
for
(
n
=
tbl
->
hash_buckets
[
h
],
idx
=
0
;
n
;
n
=
n
->
next
,
idx
++
)
{
if
(
idx
<
s_idx
)
continue
;
if
(
neigh_fill_info
(
skb
,
n
,
NETLINK_CB
(
cb
->
skb
).
pid
,
cb
->
nlh
->
nlmsg_seq
,
RTM_NEWNEIGH
)
<=
0
)
{
cb
->
nlh
->
nlmsg_seq
,
RTM_NEWNEIGH
)
<=
0
)
{
read_unlock_bh
(
&
tbl
->
lock
);
cb
->
args
[
1
]
=
h
;
cb
->
args
[
2
]
=
idx
;
return
-
1
;
rc
=
-
1
;
goto
out
;
}
}
read_unlock_bh
(
&
tbl
->
lock
);
}
rc
=
skb
->
len
;
out:
cb
->
args
[
1
]
=
h
;
cb
->
args
[
2
]
=
idx
;
return
skb
->
len
;
return
rc
;
}
int
neigh_dump_info
(
struct
sk_buff
*
skb
,
struct
netlink_callback
*
cb
)
{
int
t
;
int
s_t
;
struct
neigh_table
*
tbl
;
int
family
=
((
struct
rtgenmsg
*
)
NLMSG_DATA
(
cb
->
nlh
))
->
rtgen_family
;
int
t
,
family
,
s_t
;
read_lock
(
&
neigh_tbl_lock
);
family
=
((
struct
rtgenmsg
*
)
NLMSG_DATA
(
cb
->
nlh
))
->
rtgen_family
;
s_t
=
cb
->
args
[
0
];
read_lock
(
&
neigh_tbl_lock
);
for
(
tbl
=
neigh_tables
,
t
=
0
;
tbl
;
tbl
=
tbl
->
next
,
t
++
)
{
if
(
t
<
s_t
)
continue
;
if
(
family
&&
tbl
->
family
!=
family
)
for
(
tbl
=
neigh_tables
,
t
=
0
;
tbl
;
tbl
=
tbl
->
next
,
t
++
)
{
if
(
t
<
s_t
||
(
family
&&
tbl
->
family
!=
family
))
continue
;
if
(
t
>
s_t
)
memset
(
&
cb
->
args
[
1
],
0
,
sizeof
(
cb
->
args
)
-
sizeof
(
cb
->
args
[
0
]));
memset
(
&
cb
->
args
[
1
],
0
,
sizeof
(
cb
->
args
)
-
sizeof
(
cb
->
args
[
0
]));
if
(
neigh_dump_table
(
tbl
,
skb
,
cb
)
<
0
)
break
;
}
read_unlock
(
&
neigh_tbl_lock
);
cb
->
args
[
0
]
=
t
;
return
skb
->
len
;
}
#ifdef CONFIG_ARPD
void
neigh_app_ns
(
struct
neighbour
*
n
)
{
struct
sk_buff
*
skb
;
struct
nlmsghdr
*
nlh
;
int
size
=
NLMSG_SPACE
(
sizeof
(
struct
ndmsg
)
+
256
);
int
size
=
NLMSG_SPACE
(
sizeof
(
struct
ndmsg
)
+
256
);
struct
sk_buff
*
skb
=
alloc_skb
(
size
,
GFP_ATOMIC
);
skb
=
alloc_skb
(
size
,
GFP_ATOMIC
);
if
(
!
skb
)
return
;
...
...
@@ -1401,7 +1435,7 @@ void neigh_app_ns(struct neighbour *n)
kfree_skb
(
skb
);
return
;
}
nlh
=
(
struct
nlmsghdr
*
)
skb
->
data
;
nlh
=
(
struct
nlmsghdr
*
)
skb
->
data
;
nlh
->
nlmsg_flags
=
NLM_F_REQUEST
;
NETLINK_CB
(
skb
).
dst_groups
=
RTMGRP_NEIGH
;
netlink_broadcast
(
rtnl
,
skb
,
0
,
RTMGRP_NEIGH
,
GFP_ATOMIC
);
...
...
@@ -1409,11 +1443,10 @@ void neigh_app_ns(struct neighbour *n)
static
void
neigh_app_notify
(
struct
neighbour
*
n
)
{
struct
sk_buff
*
skb
;
struct
nlmsghdr
*
nlh
;
int
size
=
NLMSG_SPACE
(
sizeof
(
struct
ndmsg
)
+
256
);
int
size
=
NLMSG_SPACE
(
sizeof
(
struct
ndmsg
)
+
256
);
struct
sk_buff
*
skb
=
alloc_skb
(
size
,
GFP_ATOMIC
);
skb
=
alloc_skb
(
size
,
GFP_ATOMIC
);
if
(
!
skb
)
return
;
...
...
@@ -1421,7 +1454,7 @@ static void neigh_app_notify(struct neighbour *n)
kfree_skb
(
skb
);
return
;
}
nlh
=
(
struct
nlmsghdr
*
)
skb
->
data
;
nlh
=
(
struct
nlmsghdr
*
)
skb
->
data
;
NETLINK_CB
(
skb
).
dst_groups
=
RTMGRP_NEIGH
;
netlink_broadcast
(
rtnl
,
skb
,
0
,
RTMGRP_NEIGH
,
GFP_ATOMIC
);
}
...
...
@@ -1430,8 +1463,7 @@ static void neigh_app_notify(struct neighbour *n)
#ifdef CONFIG_SYSCTL
struct
neigh_sysctl_table
{
struct
neigh_sysctl_table
{
struct
ctl_table_header
*
sysctl_header
;
ctl_table
neigh_vars
[
17
];
ctl_table
neigh_dev
[
2
];
...
...
@@ -1439,70 +1471,153 @@ struct neigh_sysctl_table
ctl_table
neigh_proto_dir
[
2
];
ctl_table
neigh_root_dir
[
2
];
}
neigh_sysctl_template
=
{
NULL
,
{{
NET_NEIGH_MCAST_SOLICIT
,
"mcast_solicit"
,
NULL
,
sizeof
(
int
),
0644
,
NULL
,
&
proc_dointvec
},
{
NET_NEIGH_UCAST_SOLICIT
,
"ucast_solicit"
,
NULL
,
sizeof
(
int
),
0644
,
NULL
,
&
proc_dointvec
},
{
NET_NEIGH_APP_SOLICIT
,
"app_solicit"
,
NULL
,
sizeof
(
int
),
0644
,
NULL
,
&
proc_dointvec
},
{
NET_NEIGH_RETRANS_TIME
,
"retrans_time"
,
NULL
,
sizeof
(
int
),
0644
,
NULL
,
&
proc_dointvec
},
{
NET_NEIGH_REACHABLE_TIME
,
"base_reachable_time"
,
NULL
,
sizeof
(
int
),
0644
,
NULL
,
&
proc_dointvec_jiffies
},
{
NET_NEIGH_DELAY_PROBE_TIME
,
"delay_first_probe_time"
,
NULL
,
sizeof
(
int
),
0644
,
NULL
,
&
proc_dointvec_jiffies
},
{
NET_NEIGH_GC_STALE_TIME
,
"gc_stale_time"
,
NULL
,
sizeof
(
int
),
0644
,
NULL
,
&
proc_dointvec_jiffies
},
{
NET_NEIGH_UNRES_QLEN
,
"unres_qlen"
,
NULL
,
sizeof
(
int
),
0644
,
NULL
,
&
proc_dointvec
},
{
NET_NEIGH_PROXY_QLEN
,
"proxy_qlen"
,
NULL
,
sizeof
(
int
),
0644
,
NULL
,
&
proc_dointvec
},
{
NET_NEIGH_ANYCAST_DELAY
,
"anycast_delay"
,
NULL
,
sizeof
(
int
),
0644
,
NULL
,
&
proc_dointvec
},
{
NET_NEIGH_PROXY_DELAY
,
"proxy_delay"
,
NULL
,
sizeof
(
int
),
0644
,
NULL
,
&
proc_dointvec
},
{
NET_NEIGH_LOCKTIME
,
"locktime"
,
NULL
,
sizeof
(
int
),
0644
,
NULL
,
&
proc_dointvec
},
{
NET_NEIGH_GC_INTERVAL
,
"gc_interval"
,
NULL
,
sizeof
(
int
),
0644
,
NULL
,
&
proc_dointvec_jiffies
},
{
NET_NEIGH_GC_THRESH1
,
"gc_thresh1"
,
NULL
,
sizeof
(
int
),
0644
,
NULL
,
&
proc_dointvec
},
{
NET_NEIGH_GC_THRESH2
,
"gc_thresh2"
,
NULL
,
sizeof
(
int
),
0644
,
NULL
,
&
proc_dointvec
},
{
NET_NEIGH_GC_THRESH3
,
"gc_thresh3"
,
NULL
,
sizeof
(
int
),
0644
,
NULL
,
&
proc_dointvec
},
{
0
}},
{{
NET_PROTO_CONF_DEFAULT
,
"default"
,
NULL
,
0
,
0555
,
NULL
},{
0
}},
{{
0
,
"neigh"
,
NULL
,
0
,
0555
,
NULL
},{
0
}},
{{
0
,
NULL
,
NULL
,
0
,
0555
,
NULL
},{
0
}},
{{
CTL_NET
,
"net"
,
NULL
,
0
,
0555
,
NULL
},{
0
}}
neigh_vars:
{
{
ctl_name:
NET_NEIGH_MCAST_SOLICIT
,
procname:
"mcast_solicit"
,
maxlen:
sizeof
(
int
),
mode:
0644
,
proc_handler:
&
proc_dointvec
,
},
{
ctl_name:
NET_NEIGH_UCAST_SOLICIT
,
procname:
"ucast_solicit"
,
maxlen:
sizeof
(
int
),
mode:
0644
,
proc_handler:
&
proc_dointvec
,
},
{
ctl_name:
NET_NEIGH_APP_SOLICIT
,
procname:
"app_solicit"
,
maxlen:
sizeof
(
int
),
mode:
0644
,
proc_handler:
&
proc_dointvec
,
},
{
ctl_name:
NET_NEIGH_RETRANS_TIME
,
procname:
"retrans_time"
,
maxlen:
sizeof
(
int
),
mode:
0644
,
proc_handler:
&
proc_dointvec
,
},
{
ctl_name:
NET_NEIGH_REACHABLE_TIME
,
procname:
"base_reachable_time"
,
maxlen:
sizeof
(
int
),
mode:
0644
,
proc_handler:
&
proc_dointvec_jiffies
,
},
{
ctl_name:
NET_NEIGH_DELAY_PROBE_TIME
,
procname:
"delay_first_probe_time"
,
maxlen:
sizeof
(
int
),
mode:
0644
,
proc_handler:
&
proc_dointvec_jiffies
,
},
{
ctl_name:
NET_NEIGH_GC_STALE_TIME
,
procname:
"gc_stale_time"
,
maxlen:
sizeof
(
int
),
mode:
0644
,
proc_handler:
&
proc_dointvec_jiffies
,
},
{
ctl_name:
NET_NEIGH_UNRES_QLEN
,
procname:
"unres_qlen"
,
maxlen:
sizeof
(
int
),
mode:
0644
,
proc_handler:
&
proc_dointvec
,
},
{
ctl_name:
NET_NEIGH_PROXY_QLEN
,
procname:
"proxy_qlen"
,
maxlen:
sizeof
(
int
),
mode:
0644
,
proc_handler:
&
proc_dointvec
,
},
{
ctl_name:
NET_NEIGH_ANYCAST_DELAY
,
procname:
"anycast_delay"
,
maxlen:
sizeof
(
int
),
mode:
0644
,
proc_handler:
&
proc_dointvec
,
},
{
ctl_name:
NET_NEIGH_PROXY_DELAY
,
procname:
"proxy_delay"
,
maxlen:
sizeof
(
int
),
mode:
0644
,
proc_handler:
&
proc_dointvec
,
},
{
ctl_name:
NET_NEIGH_LOCKTIME
,
procname:
"locktime"
,
maxlen:
sizeof
(
int
),
mode:
0644
,
proc_handler:
&
proc_dointvec
,
},
{
ctl_name:
NET_NEIGH_GC_INTERVAL
,
procname:
"gc_interval"
,
maxlen:
sizeof
(
int
),
mode:
0644
,
proc_handler:
&
proc_dointvec_jiffies
,
},
{
ctl_name:
NET_NEIGH_GC_THRESH1
,
procname:
"gc_thresh1"
,
maxlen:
sizeof
(
int
),
mode:
0644
,
proc_handler:
&
proc_dointvec
,
},
{
ctl_name:
NET_NEIGH_GC_THRESH2
,
procname:
"gc_thresh2"
,
maxlen:
sizeof
(
int
),
mode:
0644
,
proc_handler:
&
proc_dointvec
,
},
{
ctl_name:
NET_NEIGH_GC_THRESH3
,
procname:
"gc_thresh3"
,
maxlen:
sizeof
(
int
),
mode:
0644
,
proc_handler:
&
proc_dointvec
,
},
},
neigh_dev:
{
{
ctl_name:
NET_PROTO_CONF_DEFAULT
,
procname:
"default"
,
mode:
0555
,
},
},
neigh_neigh_dir:
{
{
procname:
"neigh"
,
mode:
0555
,
},
},
neigh_proto_dir:
{
{
mode:
0555
,
},
},
neigh_root_dir:
{
{
ctl_name:
CTL_NET
,
procname:
"net"
,
mode:
0555
,
},
},
};
int
neigh_sysctl_register
(
struct
net_device
*
dev
,
struct
neigh_parms
*
p
,
int
p_id
,
int
pdev_id
,
char
*
p_name
)
{
struct
neigh_sysctl_table
*
t
;
struct
neigh_sysctl_table
*
t
=
kmalloc
(
sizeof
(
*
t
),
GFP_KERNEL
)
;
t
=
kmalloc
(
sizeof
(
*
t
),
GFP_KERNEL
);
if
(
t
==
NULL
)
if
(
!
t
)
return
-
ENOBUFS
;
memcpy
(
t
,
&
neigh_sysctl_template
,
sizeof
(
*
t
));
t
->
neigh_vars
[
0
].
data
=
&
p
->
mcast_probes
;
...
...
@@ -1522,10 +1637,10 @@ int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p,
t
->
neigh_dev
[
0
].
ctl_name
=
dev
->
ifindex
;
memset
(
&
t
->
neigh_vars
[
12
],
0
,
sizeof
(
ctl_table
));
}
else
{
t
->
neigh_vars
[
12
].
data
=
(
int
*
)(
p
+
1
);
t
->
neigh_vars
[
13
].
data
=
(
int
*
)(
p
+
1
)
+
1
;
t
->
neigh_vars
[
14
].
data
=
(
int
*
)(
p
+
1
)
+
2
;
t
->
neigh_vars
[
15
].
data
=
(
int
*
)(
p
+
1
)
+
3
;
t
->
neigh_vars
[
12
].
data
=
(
int
*
)(
p
+
1
);
t
->
neigh_vars
[
13
].
data
=
(
int
*
)(
p
+
1
)
+
1
;
t
->
neigh_vars
[
14
].
data
=
(
int
*
)(
p
+
1
)
+
2
;
t
->
neigh_vars
[
15
].
data
=
(
int
*
)(
p
+
1
)
+
3
;
}
t
->
neigh_neigh_dir
[
0
].
ctl_name
=
pdev_id
;
...
...
@@ -1538,7 +1653,7 @@ int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p,
t
->
neigh_root_dir
[
0
].
child
=
t
->
neigh_proto_dir
;
t
->
sysctl_header
=
register_sysctl_table
(
t
->
neigh_root_dir
,
0
);
if
(
t
->
sysctl_header
==
NULL
)
{
if
(
!
t
->
sysctl_header
)
{
kfree
(
t
);
return
-
ENOBUFS
;
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment