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
nexedi
linux
Commits
fc1061be
Commit
fc1061be
authored
Oct 27, 2002
by
Hideaki Yoshifuji
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[IPV6]: Split ndisc_rcv into helper functions.
parent
c3bb1361
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
246 additions
and
236 deletions
+246
-236
net/ipv6/ndisc.c
net/ipv6/ndisc.c
+246
-236
No files found.
net/ipv6/ndisc.c
View file @
fc1061be
...
...
@@ -588,6 +588,249 @@ static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb)
}
}
void
ndisc_recv_ns
(
struct
sk_buff
*
skb
)
{
struct
nd_msg
*
msg
=
(
struct
nd_msg
*
)
skb
->
h
.
raw
;
struct
in6_addr
*
saddr
=
&
skb
->
nh
.
ipv6h
->
saddr
;
struct
in6_addr
*
daddr
=
&
skb
->
nh
.
ipv6h
->
daddr
;
u8
*
lladdr
=
NULL
;
int
lladdrlen
=
0
;
u32
ndoptlen
=
skb
->
tail
-
msg
->
opt
;
struct
ndisc_options
ndopts
;
struct
net_device
*
dev
=
skb
->
dev
;
struct
inet6_ifaddr
*
ifp
;
struct
neighbour
*
neigh
;
if
(
skb
->
len
<
sizeof
(
struct
nd_msg
))
{
if
(
net_ratelimit
())
printk
(
KERN_WARNING
"ICMP NS: packet too short
\n
"
);
return
;
}
if
(
ipv6_addr_type
(
&
msg
->
target
)
&
IPV6_ADDR_MULTICAST
)
{
if
(
net_ratelimit
())
printk
(
KERN_WARNING
"ICMP NS: target address is multicast
\n
"
);
return
;
}
if
(
!
ndisc_parse_options
(
msg
->
opt
,
ndoptlen
,
&
ndopts
))
{
if
(
net_ratelimit
())
printk
(
KERN_WARNING
"ICMP NS: invalid ND option, ignored.
\n
"
);
return
;
}
if
(
ndopts
.
nd_opts_src_lladdr
)
{
lladdr
=
(
u8
*
)(
ndopts
.
nd_opts_src_lladdr
+
1
);
lladdrlen
=
ndopts
.
nd_opts_src_lladdr
->
nd_opt_len
<<
3
;
if
(
lladdrlen
!=
NDISC_OPT_SPACE
(
dev
->
addr_len
))
{
if
(
net_ratelimit
())
printk
(
KERN_WARNING
"ICMP NS: bad lladdr length.
\n
"
);
return
;
}
}
/* XXX: RFC2461 7.1.1:
* If the IP source address is the unspecified address, there
* MUST NOT be source link-layer address option in the message.
*
* NOTE! Linux kernel < 2.4.4 broke this rule.
*/
/* XXX: RFC2461 7.1.1:
* If the IP source address is the unspecified address, the IP
* destination address MUST be a solicited-node multicast address.
*/
if
((
ifp
=
ipv6_get_ifaddr
(
&
msg
->
target
,
dev
))
!=
NULL
)
{
int
addr_type
=
ipv6_addr_type
(
saddr
);
if
(
ifp
->
flags
&
IFA_F_TENTATIVE
)
{
/* Address is tentative. If the source
is unspecified address, it is someone
does DAD, otherwise we ignore solicitations
until DAD timer expires.
*/
if
(
addr_type
==
IPV6_ADDR_ANY
)
{
if
(
dev
->
type
==
ARPHRD_IEEE802_TR
)
{
unsigned
char
*
sadr
=
skb
->
mac
.
raw
;
if
(((
sadr
[
8
]
&
0x7f
)
!=
(
dev
->
dev_addr
[
0
]
&
0x7f
))
||
(
sadr
[
9
]
!=
dev
->
dev_addr
[
1
])
||
(
sadr
[
10
]
!=
dev
->
dev_addr
[
2
])
||
(
sadr
[
11
]
!=
dev
->
dev_addr
[
3
])
||
(
sadr
[
12
]
!=
dev
->
dev_addr
[
4
])
||
(
sadr
[
13
]
!=
dev
->
dev_addr
[
5
]))
{
addrconf_dad_failure
(
ifp
)
;
}
}
else
{
addrconf_dad_failure
(
ifp
);
}
}
else
in6_ifa_put
(
ifp
);
return
;
}
if
(
addr_type
==
IPV6_ADDR_ANY
)
{
struct
in6_addr
maddr
;
ipv6_addr_all_nodes
(
&
maddr
);
ndisc_send_na
(
dev
,
NULL
,
&
maddr
,
&
ifp
->
addr
,
ifp
->
idev
->
cnf
.
forwarding
,
0
,
ipv6_addr_type
(
&
ifp
->
addr
)
&
IPV6_ADDR_ANYCAST
?
0
:
1
,
1
);
in6_ifa_put
(
ifp
);
return
;
}
if
(
addr_type
&
IPV6_ADDR_UNICAST
)
{
int
inc
=
ipv6_addr_type
(
daddr
)
&
IPV6_ADDR_MULTICAST
;
if
(
inc
)
nd_tbl
.
stats
.
rcv_probes_mcast
++
;
else
nd_tbl
.
stats
.
rcv_probes_ucast
++
;
/*
* update / create cache entry
* for the source adddress
*/
neigh
=
neigh_event_ns
(
&
nd_tbl
,
lladdr
,
saddr
,
dev
);
if
(
neigh
||
!
dev
->
hard_header
)
{
ndisc_send_na
(
dev
,
neigh
,
saddr
,
&
ifp
->
addr
,
ifp
->
idev
->
cnf
.
forwarding
,
1
,
ipv6_addr_type
(
&
ifp
->
addr
)
&
IPV6_ADDR_ANYCAST
?
0
:
1
,
1
);
if
(
neigh
)
neigh_release
(
neigh
);
}
}
in6_ifa_put
(
ifp
);
}
else
{
struct
inet6_dev
*
in6_dev
=
in6_dev_get
(
dev
);
int
addr_type
=
ipv6_addr_type
(
saddr
);
if
(
in6_dev
&&
in6_dev
->
cnf
.
forwarding
&&
(
addr_type
&
IPV6_ADDR_UNICAST
)
&&
pneigh_lookup
(
&
nd_tbl
,
&
msg
->
target
,
dev
,
0
))
{
int
inc
=
ipv6_addr_type
(
daddr
)
&
IPV6_ADDR_MULTICAST
;
if
(
skb
->
stamp
.
tv_sec
==
0
||
skb
->
pkt_type
==
PACKET_HOST
||
inc
==
0
||
in6_dev
->
nd_parms
->
proxy_delay
==
0
)
{
if
(
inc
)
nd_tbl
.
stats
.
rcv_probes_mcast
++
;
else
nd_tbl
.
stats
.
rcv_probes_ucast
++
;
neigh
=
neigh_event_ns
(
&
nd_tbl
,
lladdr
,
saddr
,
dev
);
if
(
neigh
)
{
ndisc_send_na
(
dev
,
neigh
,
saddr
,
&
msg
->
target
,
0
,
1
,
0
,
1
);
neigh_release
(
neigh
);
}
}
else
{
struct
sk_buff
*
n
=
skb_clone
(
skb
,
GFP_ATOMIC
);
if
(
n
)
pneigh_enqueue
(
&
nd_tbl
,
in6_dev
->
nd_parms
,
n
);
in6_dev_put
(
in6_dev
);
return
;
}
}
if
(
in6_dev
)
in6_dev_put
(
in6_dev
);
}
return
;
}
void
ndisc_recv_na
(
struct
sk_buff
*
skb
)
{
struct
nd_msg
*
msg
=
(
struct
nd_msg
*
)
skb
->
h
.
raw
;
struct
in6_addr
*
saddr
=
&
skb
->
nh
.
ipv6h
->
saddr
;
struct
in6_addr
*
daddr
=
&
skb
->
nh
.
ipv6h
->
daddr
;
u8
*
lladdr
=
NULL
;
int
lladdrlen
=
0
;
u32
ndoptlen
=
skb
->
tail
-
msg
->
opt
;
struct
ndisc_options
ndopts
;
struct
net_device
*
dev
=
skb
->
dev
;
struct
inet6_ifaddr
*
ifp
;
struct
neighbour
*
neigh
;
if
(
skb
->
len
<
sizeof
(
struct
nd_msg
))
{
if
(
net_ratelimit
())
printk
(
KERN_WARNING
"ICMP NA: packet too short
\n
"
);
return
;
}
if
(
ipv6_addr_type
(
&
msg
->
target
)
&
IPV6_ADDR_MULTICAST
)
{
if
(
net_ratelimit
())
printk
(
KERN_WARNING
"NDISC NA: target address is multicast
\n
"
);
return
;
}
if
((
ipv6_addr_type
(
daddr
)
&
IPV6_ADDR_MULTICAST
)
&&
msg
->
icmph
.
icmp6_solicited
)
{
ND_PRINTK0
(
"NDISC: solicited NA is multicasted
\n
"
);
return
;
}
if
(
!
ndisc_parse_options
(
msg
->
opt
,
ndoptlen
,
&
ndopts
))
{
if
(
net_ratelimit
())
printk
(
KERN_WARNING
"ICMP NS: invalid ND option, ignored.
\n
"
);
return
;
}
if
(
ndopts
.
nd_opts_tgt_lladdr
)
{
lladdr
=
(
u8
*
)(
ndopts
.
nd_opts_tgt_lladdr
+
1
);
lladdrlen
=
ndopts
.
nd_opts_tgt_lladdr
->
nd_opt_len
<<
3
;
if
(
lladdrlen
!=
NDISC_OPT_SPACE
(
dev
->
addr_len
))
{
if
(
net_ratelimit
())
printk
(
KERN_WARNING
"NDISC NA: invalid lladdr length.
\n
"
);
return
;
}
}
if
((
ifp
=
ipv6_get_ifaddr
(
&
msg
->
target
,
dev
)))
{
if
(
ifp
->
flags
&
IFA_F_TENTATIVE
)
{
addrconf_dad_failure
(
ifp
);
return
;
}
/* What should we make now? The advertisement
is invalid, but ndisc specs say nothing
about it. It could be misconfiguration, or
an smart proxy agent tries to help us :-)
*/
ND_PRINTK0
(
"%s: someone advertises our address!
\n
"
,
ifp
->
idev
->
dev
->
name
);
in6_ifa_put
(
ifp
);
return
;
}
neigh
=
neigh_lookup
(
&
nd_tbl
,
&
msg
->
target
,
dev
);
if
(
neigh
)
{
if
(
neigh
->
flags
&
NTF_ROUTER
)
{
if
(
msg
->
icmph
.
icmp6_router
==
0
)
{
/*
* Change: router to host
*/
struct
rt6_info
*
rt
;
rt
=
rt6_get_dflt_router
(
saddr
,
dev
);
if
(
rt
)
ip6_del_rt
(
rt
);
}
}
else
{
if
(
msg
->
icmph
.
icmp6_router
)
neigh
->
flags
|=
NTF_ROUTER
;
}
neigh_update
(
neigh
,
lladdr
,
msg
->
icmph
.
icmp6_solicited
?
NUD_REACHABLE
:
NUD_STALE
,
msg
->
icmph
.
icmp6_override
,
1
);
neigh_release
(
neigh
);
}
}
static
void
ndisc_router_discovery
(
struct
sk_buff
*
skb
)
{
struct
ra_msg
*
ra_msg
=
(
struct
ra_msg
*
)
skb
->
h
.
raw
;
...
...
@@ -995,12 +1238,7 @@ static void pndisc_redo(struct sk_buff *skb)
int
ndisc_rcv
(
struct
sk_buff
*
skb
)
{
struct
net_device
*
dev
=
skb
->
dev
;
struct
in6_addr
*
saddr
=
&
skb
->
nh
.
ipv6h
->
saddr
;
struct
in6_addr
*
daddr
=
&
skb
->
nh
.
ipv6h
->
daddr
;
struct
nd_msg
*
msg
=
(
struct
nd_msg
*
)
skb
->
h
.
raw
;
struct
neighbour
*
neigh
;
struct
inet6_ifaddr
*
ifp
;
__skb_push
(
skb
,
skb
->
data
-
skb
->
h
.
raw
);
...
...
@@ -1020,240 +1258,12 @@ int ndisc_rcv(struct sk_buff *skb)
switch
(
msg
->
icmph
.
icmp6_type
)
{
case
NDISC_NEIGHBOUR_SOLICITATION
:
{
struct
nd_msg
*
msg
=
(
struct
nd_msg
*
)
skb
->
h
.
raw
;
u8
*
lladdr
=
NULL
;
int
lladdrlen
=
0
;
u32
ndoptlen
=
skb
->
tail
-
msg
->
opt
;
struct
ndisc_options
ndopts
;
if
(
skb
->
len
<
sizeof
(
struct
nd_msg
))
{
if
(
net_ratelimit
())
printk
(
KERN_WARNING
"ICMP NS: packet too short
\n
"
);
return
0
;
}
if
(
ipv6_addr_type
(
&
msg
->
target
)
&
IPV6_ADDR_MULTICAST
)
{
if
(
net_ratelimit
())
printk
(
KERN_WARNING
"ICMP NS: target address is multicast
\n
"
);
return
0
;
}
if
(
!
ndisc_parse_options
(
msg
->
opt
,
ndoptlen
,
&
ndopts
))
{
if
(
net_ratelimit
())
printk
(
KERN_WARNING
"ICMP NS: invalid ND option, ignored.
\n
"
);
return
0
;
}
if
(
ndopts
.
nd_opts_src_lladdr
)
{
lladdr
=
(
u8
*
)(
ndopts
.
nd_opts_src_lladdr
+
1
);
lladdrlen
=
ndopts
.
nd_opts_src_lladdr
->
nd_opt_len
<<
3
;
if
(
lladdrlen
!=
NDISC_OPT_SPACE
(
skb
->
dev
->
addr_len
))
{
if
(
net_ratelimit
())
printk
(
KERN_WARNING
"ICMP NS: bad lladdr length.
\n
"
);
return
0
;
}
}
/* XXX: RFC2461 7.1.1:
* If the IP source address is the unspecified address, there
* MUST NOT be source link-layer address option in the message.
*
* NOTE! Linux kernel < 2.4.4 broke this rule.
*/
/* XXX: RFC2461 7.1.1:
* If the IP source address is the unspecified address, the IP
* destination address MUST be a solicited-node multicast address.
*/
if
((
ifp
=
ipv6_get_ifaddr
(
&
msg
->
target
,
dev
))
!=
NULL
)
{
int
addr_type
=
ipv6_addr_type
(
saddr
);
if
(
ifp
->
flags
&
IFA_F_TENTATIVE
)
{
/* Address is tentative. If the source
is unspecified address, it is someone
does DAD, otherwise we ignore solicitations
until DAD timer expires.
*/
if
(
addr_type
==
IPV6_ADDR_ANY
)
{
if
(
dev
->
type
==
ARPHRD_IEEE802_TR
)
{
unsigned
char
*
sadr
=
skb
->
mac
.
raw
;
if
(((
sadr
[
8
]
&
0x7f
)
!=
(
dev
->
dev_addr
[
0
]
&
0x7f
))
||
(
sadr
[
9
]
!=
dev
->
dev_addr
[
1
])
||
(
sadr
[
10
]
!=
dev
->
dev_addr
[
2
])
||
(
sadr
[
11
]
!=
dev
->
dev_addr
[
3
])
||
(
sadr
[
12
]
!=
dev
->
dev_addr
[
4
])
||
(
sadr
[
13
]
!=
dev
->
dev_addr
[
5
]))
{
addrconf_dad_failure
(
ifp
)
;
}
}
else
{
addrconf_dad_failure
(
ifp
);
}
}
else
in6_ifa_put
(
ifp
);
return
0
;
}
if
(
addr_type
==
IPV6_ADDR_ANY
)
{
struct
in6_addr
maddr
;
ipv6_addr_all_nodes
(
&
maddr
);
ndisc_send_na
(
dev
,
NULL
,
&
maddr
,
&
ifp
->
addr
,
ifp
->
idev
->
cnf
.
forwarding
,
0
,
ipv6_addr_type
(
&
ifp
->
addr
)
&
IPV6_ADDR_ANYCAST
?
0
:
1
,
1
);
in6_ifa_put
(
ifp
);
return
0
;
}
if
(
addr_type
&
IPV6_ADDR_UNICAST
)
{
int
inc
=
ipv6_addr_type
(
daddr
)
&
IPV6_ADDR_MULTICAST
;
if
(
inc
)
nd_tbl
.
stats
.
rcv_probes_mcast
++
;
else
nd_tbl
.
stats
.
rcv_probes_ucast
++
;
/*
* update / create cache entry
* for the source adddress
*/
neigh
=
neigh_event_ns
(
&
nd_tbl
,
lladdr
,
saddr
,
skb
->
dev
);
if
(
neigh
||
!
dev
->
hard_header
)
{
ndisc_send_na
(
dev
,
neigh
,
saddr
,
&
ifp
->
addr
,
ifp
->
idev
->
cnf
.
forwarding
,
1
,
ipv6_addr_type
(
&
ifp
->
addr
)
&
IPV6_ADDR_ANYCAST
?
0
:
1
,
1
);
if
(
neigh
)
neigh_release
(
neigh
);
}
}
in6_ifa_put
(
ifp
);
}
else
{
struct
inet6_dev
*
in6_dev
=
in6_dev_get
(
dev
);
int
addr_type
=
ipv6_addr_type
(
saddr
);
if
(
in6_dev
&&
in6_dev
->
cnf
.
forwarding
&&
(
addr_type
&
IPV6_ADDR_UNICAST
)
&&
pneigh_lookup
(
&
nd_tbl
,
&
msg
->
target
,
dev
,
0
))
{
int
inc
=
ipv6_addr_type
(
daddr
)
&
IPV6_ADDR_MULTICAST
;
if
(
skb
->
stamp
.
tv_sec
==
0
||
skb
->
pkt_type
==
PACKET_HOST
||
inc
==
0
||
in6_dev
->
nd_parms
->
proxy_delay
==
0
)
{
if
(
inc
)
nd_tbl
.
stats
.
rcv_probes_mcast
++
;
else
nd_tbl
.
stats
.
rcv_probes_ucast
++
;
neigh
=
neigh_event_ns
(
&
nd_tbl
,
lladdr
,
saddr
,
skb
->
dev
);
if
(
neigh
)
{
ndisc_send_na
(
dev
,
neigh
,
saddr
,
&
msg
->
target
,
0
,
1
,
0
,
1
);
neigh_release
(
neigh
);
}
}
else
{
struct
sk_buff
*
n
=
skb_clone
(
skb
,
GFP_ATOMIC
);
if
(
n
)
pneigh_enqueue
(
&
nd_tbl
,
in6_dev
->
nd_parms
,
n
);
in6_dev_put
(
in6_dev
);
return
0
;
}
}
if
(
in6_dev
)
in6_dev_put
(
in6_dev
);
}
return
0
;
}
ndisc_recv_ns
(
skb
);
break
;
case
NDISC_NEIGHBOUR_ADVERTISEMENT
:
{
struct
nd_msg
*
msg
=
(
struct
nd_msg
*
)
skb
->
h
.
raw
;
u8
*
lladdr
=
NULL
;
int
lladdrlen
=
0
;
u32
ndoptlen
=
skb
->
tail
-
msg
->
opt
;
struct
ndisc_options
ndopts
;
if
(
skb
->
len
<
sizeof
(
struct
nd_msg
))
{
if
(
net_ratelimit
())
printk
(
KERN_WARNING
"ICMP NA: packet too short
\n
"
);
return
0
;
}
if
(
ipv6_addr_type
(
&
msg
->
target
)
&
IPV6_ADDR_MULTICAST
)
{
if
(
net_ratelimit
())
printk
(
KERN_WARNING
"NDISC NA: target address is multicast
\n
"
);
return
0
;
}
if
((
ipv6_addr_type
(
daddr
)
&
IPV6_ADDR_MULTICAST
)
&&
msg
->
icmph
.
icmp6_solicited
)
{
ND_PRINTK0
(
"NDISC: solicited NA is multicasted
\n
"
);
return
0
;
}
if
(
!
ndisc_parse_options
(
msg
->
opt
,
ndoptlen
,
&
ndopts
))
{
if
(
net_ratelimit
())
printk
(
KERN_WARNING
"ICMP NS: invalid ND option, ignored.
\n
"
);
return
0
;
}
if
(
ndopts
.
nd_opts_tgt_lladdr
)
{
lladdr
=
(
u8
*
)(
ndopts
.
nd_opts_tgt_lladdr
+
1
);
lladdrlen
=
ndopts
.
nd_opts_tgt_lladdr
->
nd_opt_len
<<
3
;
if
(
lladdrlen
!=
NDISC_OPT_SPACE
(
skb
->
dev
->
addr_len
))
{
if
(
net_ratelimit
())
printk
(
KERN_WARNING
"NDISC NA: invalid lladdr length.
\n
"
);
return
0
;
}
}
if
((
ifp
=
ipv6_get_ifaddr
(
&
msg
->
target
,
dev
)))
{
if
(
ifp
->
flags
&
IFA_F_TENTATIVE
)
{
addrconf_dad_failure
(
ifp
);
return
0
;
}
/* What should we make now? The advertisement
is invalid, but ndisc specs say nothing
about it. It could be misconfiguration, or
an smart proxy agent tries to help us :-)
*/
ND_PRINTK0
(
"%s: someone advertises our address!
\n
"
,
ifp
->
idev
->
dev
->
name
);
in6_ifa_put
(
ifp
);
return
0
;
}
neigh
=
neigh_lookup
(
&
nd_tbl
,
&
msg
->
target
,
skb
->
dev
);
if
(
neigh
)
{
if
(
neigh
->
flags
&
NTF_ROUTER
)
{
if
(
msg
->
icmph
.
icmp6_router
==
0
)
{
/*
* Change: router to host
*/
struct
rt6_info
*
rt
;
rt
=
rt6_get_dflt_router
(
saddr
,
skb
->
dev
);
if
(
rt
)
ip6_del_rt
(
rt
);
}
}
else
{
if
(
msg
->
icmph
.
icmp6_router
)
neigh
->
flags
|=
NTF_ROUTER
;
}
neigh_update
(
neigh
,
lladdr
,
msg
->
icmph
.
icmp6_solicited
?
NUD_REACHABLE
:
NUD_STALE
,
msg
->
icmph
.
icmp6_override
,
1
);
neigh_release
(
neigh
);
}
ndisc_recv_na
(
skb
);
break
;
}
case
NDISC_ROUTER_ADVERTISEMENT
:
ndisc_router_discovery
(
skb
);
...
...
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