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
6bac9098
Commit
6bac9098
authored
May 12, 2003
by
Kazunori Miyazawa
Committed by
David S. Miller
May 12, 2003
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[IPV4]: Introduce ip6_append_data.
parent
d983ec93
Changes
8
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
1222 additions
and
253 deletions
+1222
-253
include/linux/ipv6.h
include/linux/ipv6.h
+7
-0
include/linux/skbuff.h
include/linux/skbuff.h
+9
-0
include/net/ipv6.h
include/net/ipv6.h
+20
-0
net/ipv4/ip_output.c
net/ipv4/ip_output.c
+0
-10
net/ipv6/icmp.c
net/ipv6/icmp.c
+130
-80
net/ipv6/ip6_output.c
net/ipv6/ip6_output.c
+668
-1
net/ipv6/raw.c
net/ipv6/raw.c
+148
-82
net/ipv6/udp.c
net/ipv6/udp.c
+240
-80
No files found.
include/linux/ipv6.h
View file @
6bac9098
...
...
@@ -121,6 +121,7 @@ struct ipv6hdr {
#include <linux/icmpv6.h>
#include <net/if_inet6.h>
/* struct ipv6_mc_socklist */
#include <linux/tcp.h>
#include <linux/udp.h>
/*
This structure contains results of exthdrs parsing
...
...
@@ -178,6 +179,11 @@ struct ipv6_pinfo {
struct
ipv6_txoptions
*
opt
;
struct
sk_buff
*
pktoptions
;
struct
{
struct
ipv6_txoptions
*
opt
;
struct
rt6_info
*
rt
;
struct
flowi
*
fl
;
}
cork
;
};
struct
raw6_opt
{
...
...
@@ -200,6 +206,7 @@ struct udp6_sock {
struct
sock
sk
;
struct
ipv6_pinfo
*
pinet6
;
struct
inet_opt
inet
;
struct
udp_opt
udp
;
struct
ipv6_pinfo
inet6
;
};
...
...
include/linux/skbuff.h
View file @
6bac9098
...
...
@@ -792,6 +792,15 @@ static inline int skb_pagelen(const struct sk_buff *skb)
return
len
+
skb_headlen
(
skb
);
}
static
inline
void
skb_fill_page_desc
(
struct
sk_buff
*
skb
,
int
i
,
struct
page
*
page
,
int
off
,
int
size
)
{
skb_frag_t
*
frag
=
&
skb_shinfo
(
skb
)
->
frags
[
i
];
frag
->
page
=
page
;
frag
->
page_offset
=
off
;
frag
->
size
=
size
;
skb_shinfo
(
skb
)
->
nr_frags
=
i
+
1
;
}
#define SKB_PAGE_ASSERT(skb) do { if (skb_shinfo(skb)->nr_frags) \
BUG(); } while (0)
#define SKB_FRAG_ASSERT(skb) do { if (skb_shinfo(skb)->frag_list) \
...
...
include/net/ipv6.h
View file @
6bac9098
...
...
@@ -316,6 +316,26 @@ extern int ip6_build_xmit(struct sock *sk,
struct
ipv6_txoptions
*
opt
,
int
hlimit
,
int
flags
);
extern
int
ip6_append_data
(
struct
sock
*
sk
,
int
getfrag
(
void
*
from
,
char
*
to
,
int
offset
,
int
len
,
int
odd
,
struct
sk_buff
*
skb
),
void
*
from
,
int
length
,
int
transhdrlen
,
int
hlimit
,
struct
ipv6_txoptions
*
opt
,
struct
flowi
*
fl
,
struct
rt6_info
*
rt
,
unsigned
int
flags
);
extern
int
ip6_push_pending_frames
(
struct
sock
*
sk
);
extern
void
ip6_flush_pending_frames
(
struct
sock
*
sk
);
extern
int
ip6_dst_lookup
(
struct
sock
*
sk
,
struct
dst_entry
**
dst
,
struct
flowi
*
fl
,
struct
in6_addr
**
saddr
);
/*
* skb processing functions
*/
...
...
net/ipv4/ip_output.c
View file @
6bac9098
...
...
@@ -685,16 +685,6 @@ skb_can_coalesce(struct sk_buff *skb, int i, struct page *page, int off)
return
0
;
}
static
void
skb_fill_page_desc
(
struct
sk_buff
*
skb
,
int
i
,
struct
page
*
page
,
int
off
,
int
size
)
{
skb_frag_t
*
frag
=
&
skb_shinfo
(
skb
)
->
frags
[
i
];
frag
->
page
=
page
;
frag
->
page_offset
=
off
;
frag
->
size
=
size
;
skb_shinfo
(
skb
)
->
nr_frags
=
i
+
1
;
}
static
inline
unsigned
int
csum_page
(
struct
page
*
page
,
int
offset
,
int
copy
)
{
...
...
net/ipv6/icmp.c
View file @
6bac9098
...
...
@@ -28,6 +28,7 @@
* YOSHIFUJI Hideaki @USAGI: added sysctl for icmp rate limit.
* Randy Dunlap and
* YOSHIFUJI Hideaki @USAGI: Per-interface statistics support
* Kazunori MIYAZAWA @USAGI: change output process to use ip6_append_data
*/
#include <linux/module.h>
...
...
@@ -104,42 +105,6 @@ static __inline__ void icmpv6_xmit_unlock(void)
spin_unlock_bh
(
&
icmpv6_socket
->
sk
->
lock
.
slock
);
}
/*
* getfrag callback
*/
static
int
icmpv6_getfrag
(
const
void
*
data
,
struct
in6_addr
*
saddr
,
char
*
buff
,
unsigned
int
offset
,
unsigned
int
len
)
{
struct
icmpv6_msg
*
msg
=
(
struct
icmpv6_msg
*
)
data
;
struct
icmp6hdr
*
icmph
;
__u32
csum
;
if
(
offset
)
{
csum
=
skb_copy_and_csum_bits
(
msg
->
skb
,
msg
->
offset
+
(
offset
-
sizeof
(
struct
icmp6hdr
)),
buff
,
len
,
msg
->
csum
);
msg
->
csum
=
csum
;
return
0
;
}
csum
=
csum_partial_copy_nocheck
((
void
*
)
&
msg
->
icmph
,
buff
,
sizeof
(
struct
icmp6hdr
),
msg
->
csum
);
csum
=
skb_copy_and_csum_bits
(
msg
->
skb
,
msg
->
offset
,
buff
+
sizeof
(
struct
icmp6hdr
),
len
-
sizeof
(
struct
icmp6hdr
),
csum
);
icmph
=
(
struct
icmp6hdr
*
)
buff
;
icmph
->
icmp6_cksum
=
csum_ipv6_magic
(
saddr
,
msg
->
daddr
,
msg
->
len
,
IPPROTO_ICMPV6
,
csum
);
return
0
;
}
/*
* Slightly more convenient version of icmpv6_send.
*/
...
...
@@ -242,22 +207,74 @@ static __inline__ int opt_unrec(struct sk_buff *skb, __u32 offset)
return
(
optval
&
0xC0
)
==
0x80
;
}
int
icmpv6_push_pending_frames
(
struct
sock
*
sk
,
struct
flowi
*
fl
,
struct
icmp6hdr
*
thdr
,
int
len
)
{
struct
sk_buff
*
skb
;
struct
icmp6hdr
*
icmp6h
;
int
err
=
0
;
if
((
skb
=
skb_peek
(
&
sk
->
write_queue
))
==
NULL
)
goto
out
;
icmp6h
=
(
struct
icmp6hdr
*
)
skb
->
h
.
raw
;
memcpy
(
icmp6h
,
thdr
,
sizeof
(
struct
icmp6hdr
));
icmp6h
->
icmp6_cksum
=
0
;
if
(
skb_queue_len
(
&
sk
->
write_queue
)
==
1
)
{
skb
->
csum
=
csum_partial
((
char
*
)
icmp6h
,
sizeof
(
struct
icmp6hdr
),
skb
->
csum
);
icmp6h
->
icmp6_cksum
=
csum_ipv6_magic
(
fl
->
fl6_src
,
fl
->
fl6_dst
,
len
,
fl
->
proto
,
skb
->
csum
);
}
else
{
u32
tmp_csum
=
0
;
skb_queue_walk
(
&
sk
->
write_queue
,
skb
)
{
tmp_csum
=
csum_add
(
tmp_csum
,
skb
->
csum
);
}
tmp_csum
=
csum_partial
((
char
*
)
icmp6h
,
sizeof
(
struct
icmp6hdr
),
tmp_csum
);
tmp_csum
=
csum_ipv6_magic
(
fl
->
fl6_src
,
fl
->
fl6_dst
,
len
,
fl
->
proto
,
tmp_csum
);
icmp6h
->
icmp6_cksum
=
tmp_csum
;
}
if
(
icmp6h
->
icmp6_cksum
==
0
)
icmp6h
->
icmp6_cksum
=
-
1
;
ip6_push_pending_frames
(
sk
);
out:
return
err
;
}
static
int
icmpv6_getfrag
(
void
*
from
,
char
*
to
,
int
offset
,
int
len
,
int
odd
,
struct
sk_buff
*
skb
)
{
struct
sk_buff
*
org_skb
=
(
struct
sk_buff
*
)
from
;
__u32
csum
=
0
;
csum
=
skb_copy_and_csum_bits
(
org_skb
,
offset
,
to
,
len
,
csum
);
skb
->
csum
=
csum_block_add
(
skb
->
csum
,
csum
,
odd
);
return
0
;
}
/*
* Send an ICMP message in response to a packet in error
*/
void
icmpv6_send
(
struct
sk_buff
*
skb
,
int
type
,
int
code
,
__u32
info
,
struct
net_device
*
dev
)
{
struct
inet6_dev
*
idev
;
struct
ipv6hdr
*
hdr
=
skb
->
nh
.
ipv6h
;
struct
sock
*
sk
=
icmpv6_socket
->
sk
;
struct
in6_addr
*
saddr
=
NULL
;
int
iif
=
0
;
struct
icmpv6_msg
msg
;
struct
ipv6_pinfo
*
np
=
inet6_sk
(
sk
);
struct
in6_addr
*
saddr
=
NULL
,
*
tmp_saddr
=
NULL
;
struct
dst_entry
*
dst
;
struct
icmp6hdr
tmp_hdr
;
struct
flowi
fl
;
int
iif
=
0
;
int
addr_type
=
0
;
int
len
;
int
len
,
plen
;
int
hlimit
=
-
1
;
int
err
=
0
;
if
((
u8
*
)
hdr
<
skb
->
head
||
(
u8
*
)(
hdr
+
1
)
>
skb
->
tail
)
return
;
...
...
@@ -328,36 +345,48 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info,
if
(
!
icmpv6_xrlim_allow
(
sk
,
type
,
&
fl
))
goto
out
;
/*
* ok. kick it. checksum will be provided by the
* getfrag_t callback.
*/
tmp_hdr
.
icmp6_type
=
type
;
tmp_hdr
.
icmp6_code
=
code
;
tmp_hdr
.
icmp6_cksum
=
0
;
tmp_hdr
.
icmp6_pointer
=
htonl
(
info
);
msg
.
icmph
.
icmp6_type
=
type
;
msg
.
icmph
.
icmp6_code
=
code
;
msg
.
icmph
.
icmp6_cksum
=
0
;
msg
.
icmph
.
icmp6_pointer
=
htonl
(
info
);
if
(
!
fl
.
oif
&&
ipv6_addr_is_multicast
(
fl
.
fl6_dst
))
fl
.
oif
=
np
->
mcast_oif
;
msg
.
skb
=
skb
;
msg
.
offset
=
skb
->
nh
.
raw
-
skb
->
data
;
msg
.
csum
=
0
;
msg
.
daddr
=
&
hdr
->
saddr
;
err
=
ip6_dst_lookup
(
sk
,
&
dst
,
&
fl
,
&
tmp_saddr
);
if
(
err
)
goto
out
;
len
=
skb
->
len
-
msg
.
offset
+
sizeof
(
struct
icmp6hdr
);
len
=
min_t
(
unsigned
int
,
len
,
IPV6_MIN_MTU
-
sizeof
(
struct
ipv6hdr
));
if
(
hlimit
<
0
)
{
if
(
ipv6_addr_is_multicast
(
fl
.
fl6_dst
))
hlimit
=
np
->
mcast_hops
;
else
hlimit
=
np
->
hop_limit
;
if
(
hlimit
<
0
)
hlimit
=
((
struct
rt6_info
*
)
dst
)
->
rt6i_hoplimit
;
}
plen
=
skb
->
nh
.
raw
-
skb
->
data
;
__skb_pull
(
skb
,
plen
);
len
=
skb
->
len
;
len
=
min_t
(
unsigned
int
,
len
,
IPV6_MIN_MTU
-
sizeof
(
struct
ipv6hdr
)
-
sizeof
(
struct
icmp6hdr
));
if
(
len
<
0
)
{
if
(
net_ratelimit
())
printk
(
KERN_DEBUG
"icmp: len problem
\n
"
);
__skb_push
(
skb
,
plen
);
goto
out
;
}
msg
.
len
=
len
;
idev
=
in6_dev_get
(
skb
->
dev
);
ip6_build_xmit
(
sk
,
icmpv6_getfrag
,
&
msg
,
&
fl
,
len
,
NULL
,
-
1
,
MSG_DONTWAIT
);
err
=
ip6_append_data
(
sk
,
icmpv6_getfrag
,
skb
,
len
+
sizeof
(
struct
icmp6hdr
),
sizeof
(
struct
icmp6hdr
),
hlimit
,
NULL
,
&
fl
,
(
struct
rt6_info
*
)
dst
,
MSG_DONTWAIT
);
if
(
err
)
{
ip6_flush_pending_frames
(
sk
);
goto
out
;
}
err
=
icmpv6_push_pending_frames
(
sk
,
&
fl
,
&
tmp_hdr
,
len
+
sizeof
(
struct
icmp6hdr
));
__skb_push
(
skb
,
plen
);
if
(
type
>=
ICMPV6_DEST_UNREACH
&&
type
<=
ICMPV6_PARAMPROB
)
ICMP6_INC_STATS_OFFSET_BH
(
idev
,
Icmp6OutDestUnreachs
,
type
-
ICMPV6_DEST_UNREACH
);
ICMP6_INC_STATS_BH
(
idev
,
Icmp6OutMsgs
);
...
...
@@ -365,6 +394,7 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info,
if
(
likely
(
idev
!=
NULL
))
in6_dev_put
(
idev
);
out:
if
(
tmp_saddr
)
kfree
(
tmp_saddr
);
icmpv6_xmit_unlock
();
}
...
...
@@ -372,10 +402,14 @@ static void icmpv6_echo_reply(struct sk_buff *skb)
{
struct
sock
*
sk
=
icmpv6_socket
->
sk
;
struct
inet6_dev
*
idev
;
struct
ipv6_pinfo
*
np
=
inet6_sk
(
sk
);
struct
in6_addr
*
saddr
=
NULL
,
*
tmp_saddr
=
NULL
;
struct
icmp6hdr
*
icmph
=
(
struct
icmp6hdr
*
)
skb
->
h
.
raw
;
struct
in6_addr
*
saddr
;
struct
icmpv6_msg
msg
;
struct
icmp6hdr
tmp_hdr
;
struct
flowi
fl
;
struct
dst_entry
*
dst
;
int
err
=
0
;
int
hlimit
=
-
1
;
saddr
=
&
skb
->
nh
.
ipv6h
->
daddr
;
...
...
@@ -383,39 +417,55 @@ static void icmpv6_echo_reply(struct sk_buff *skb)
ipv6_chk_acast_addr
(
0
,
saddr
))
saddr
=
NULL
;
msg
.
icmph
.
icmp6_type
=
ICMPV6_ECHO_REPLY
;
msg
.
icmph
.
icmp6_code
=
0
;
msg
.
icmph
.
icmp6_cksum
=
0
;
msg
.
icmph
.
icmp6_identifier
=
icmph
->
icmp6_identifier
;
msg
.
icmph
.
icmp6_sequence
=
icmph
->
icmp6_sequence
;
msg
.
skb
=
skb
;
msg
.
offset
=
0
;
msg
.
csum
=
0
;
msg
.
len
=
skb
->
len
+
sizeof
(
struct
icmp6hdr
);
msg
.
daddr
=
&
skb
->
nh
.
ipv6h
->
saddr
;
memcpy
(
&
tmp_hdr
,
icmph
,
sizeof
(
tmp_hdr
));
tmp_hdr
.
icmp6_type
=
ICMPV6_ECHO_REPLY
;
fl
.
proto
=
IPPROTO_ICMPV6
;
fl
.
fl6_dst
=
msg
.
d
addr
;
fl
.
fl6_dst
=
&
skb
->
nh
.
ipv6h
->
s
addr
;
fl
.
fl6_src
=
saddr
;
fl
.
oif
=
skb
->
dev
->
ifindex
;
fl
.
fl6_flowlabel
=
0
;
fl
.
fl_icmp_type
=
ICMPV6_ECHO_REPLY
;
fl
.
fl_icmp_code
=
0
;
icmpv6_xmit_lock
();
if
(
!
fl
.
oif
&&
ipv6_addr_is_multicast
(
fl
.
nl_u
.
ip6_u
.
daddr
))
fl
.
oif
=
np
->
mcast_oif
;
err
=
ip6_dst_lookup
(
sk
,
&
dst
,
&
fl
,
&
tmp_saddr
);
if
(
err
)
goto
out
;
if
(
hlimit
<
0
)
{
if
(
ipv6_addr_is_multicast
(
fl
.
fl6_dst
))
hlimit
=
np
->
mcast_hops
;
else
hlimit
=
np
->
hop_limit
;
if
(
hlimit
<
0
)
hlimit
=
((
struct
rt6_info
*
)
dst
)
->
rt6i_hoplimit
;
}
idev
=
in6_dev_get
(
skb
->
dev
);
icmpv6_xmit_lock
();
err
=
ip6_append_data
(
sk
,
icmpv6_getfrag
,
skb
,
skb
->
len
+
sizeof
(
struct
icmp6hdr
),
sizeof
(
struct
icmp6hdr
),
hlimit
,
NULL
,
&
fl
,
(
struct
rt6_info
*
)
dst
,
MSG_DONTWAIT
);
ip6_build_xmit
(
sk
,
icmpv6_getfrag
,
&
msg
,
&
fl
,
msg
.
len
,
NULL
,
-
1
,
MSG_DONTWAIT
);
ICMP6_INC_STATS_BH
(
idev
,
Icmp6OutEchoReplies
);
ICMP6_INC_STATS_BH
(
idev
,
Icmp6OutMsgs
);
if
(
err
)
{
ip6_flush_pending_frames
(
sk
);
goto
out
;
}
err
=
icmpv6_push_pending_frames
(
sk
,
&
fl
,
&
tmp_hdr
,
skb
->
len
+
sizeof
(
struct
icmp6hdr
));
icmpv6_xmit_unlock
();
ICMP6_INC_STATS_BH
(
idev
,
Icmp6OutEchoReplies
);
ICMP6_INC_STATS_BH
(
idev
,
Icmp6OutMsgs
);
if
(
likely
(
idev
!=
NULL
))
in6_dev_put
(
idev
);
out:
if
(
tmp_saddr
)
kfree
(
tmp_saddr
);
icmpv6_xmit_unlock
();
}
static
void
icmpv6_notify
(
struct
sk_buff
*
skb
,
int
type
,
int
code
,
u32
info
)
...
...
net/ipv6/ip6_output.c
View file @
6bac9098
This diff is collapsed.
Click to expand it.
net/ipv6/raw.c
View file @
6bac9098
...
...
@@ -12,6 +12,7 @@
* Fixes:
* Hideaki YOSHIFUJI : sin6_scope_id support
* YOSHIFUJI,H.@USAGI : raw checksum (RFC2292(bis) compliance)
* Kazunori MIYAZAWA @USAGI: change process style to use ip6_append_data
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
...
...
@@ -29,6 +30,8 @@
#include <linux/netdevice.h>
#include <linux/if_arp.h>
#include <linux/icmpv6.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv6.h>
#include <asm/uaccess.h>
#include <asm/ioctls.h>
...
...
@@ -438,87 +441,115 @@ static int rawv6_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg
goto
out_free
;
}
/*
* Sending...
*/
static
int
rawv6_push_pending_frames
(
struct
sock
*
sk
,
struct
flowi
*
fl
,
struct
raw6_opt
*
opt
,
int
len
)
{
struct
sk_buff
*
skb
;
int
err
=
0
;
u16
*
csum
;
struct
rawv6_fakehdr
{
struct
iovec
*
iov
;
struct
sock
*
sk
;
__u32
len
;
__u32
cksum
;
__u32
proto
;
struct
in6_addr
*
daddr
;
};
if
((
skb
=
skb_peek
(
&
sk
->
write_queue
))
==
NULL
)
goto
out
;
static
int
rawv6_getfrag
(
const
void
*
data
,
struct
in6_addr
*
saddr
,
char
*
buff
,
unsigned
int
offset
,
unsigned
int
len
)
{
struct
iovec
*
iov
=
(
struct
iovec
*
)
data
;
if
(
opt
->
offset
+
1
<
len
)
csum
=
(
u16
*
)(
skb
->
h
.
raw
+
opt
->
offset
);
else
{
err
=
-
EINVAL
;
goto
out
;
}
if
(
skb_queue_len
(
&
sk
->
write_queue
)
==
1
)
{
/*
* Only one fragment on the socket.
*/
/* should be check HW csum miyazawa */
*
csum
=
csum_ipv6_magic
(
fl
->
fl6_src
,
fl
->
fl6_dst
,
len
,
fl
->
proto
,
skb
->
csum
);
}
else
{
u32
tmp_csum
=
0
;
skb_queue_walk
(
&
sk
->
write_queue
,
skb
)
{
tmp_csum
=
csum_add
(
tmp_csum
,
skb
->
csum
);
}
return
memcpy_fromiovecend
(
buff
,
iov
,
offset
,
len
);
tmp_csum
=
csum_ipv6_magic
(
fl
->
fl6_src
,
fl
->
fl6_dst
,
len
,
fl
->
proto
,
tmp_csum
);
*
csum
=
tmp_csum
;
}
if
(
*
csum
==
0
)
*
csum
=
-
1
;
ip6_push_pending_frames
(
sk
);
out:
return
err
;
}
static
int
rawv6_
frag_cksum
(
const
void
*
data
,
struct
in6_addr
*
addr
,
char
*
buff
,
unsigned
int
offse
t
,
unsigned
int
len
)
static
int
rawv6_
send_hdrinc
(
struct
sock
*
sk
,
void
*
from
,
int
length
,
struct
flowi
*
fl
,
struct
rt6_info
*
r
t
,
unsigned
int
flags
)
{
struct
rawv6_fakehdr
*
hdr
=
(
struct
rawv6_fakehdr
*
)
data
;
if
(
csum_partial_copy_fromiovecend
(
buff
,
hdr
->
iov
,
offset
,
len
,
&
hdr
->
cksum
))
return
-
EFAULT
;
if
(
offset
==
0
)
{
struct
sock
*
sk
;
struct
raw6_opt
*
opt
;
struct
in6_addr
*
daddr
;
sk
=
hdr
->
sk
;
opt
=
raw6_sk
(
sk
);
struct
inet_opt
*
inet
=
inet_sk
(
sk
);
struct
ipv6hdr
*
iph
;
struct
sk_buff
*
skb
;
unsigned
int
hh_len
;
int
err
;
if
(
hdr
->
daddr
)
daddr
=
hdr
->
daddr
;
else
daddr
=
addr
+
1
;
hdr
->
cksum
=
csum_ipv6_magic
(
addr
,
daddr
,
hdr
->
len
,
hdr
->
proto
,
hdr
->
cksum
);
if
(
opt
->
offset
+
1
<
len
)
{
__u16
*
csum
;
csum
=
(
__u16
*
)
(
buff
+
opt
->
offset
);
if
(
*
csum
)
{
/* in case cksum was not initialized */
__u32
sum
=
hdr
->
cksum
;
sum
+=
*
csum
;
*
csum
=
hdr
->
cksum
=
(
sum
+
(
sum
>>
16
));
}
else
{
*
csum
=
hdr
->
cksum
;
}
}
else
{
if
(
net_ratelimit
())
printk
(
KERN_DEBUG
"icmp: cksum offset too big
\n
"
);
return
-
EINVAL
;
}
}
return
0
;
}
if
(
length
>
rt
->
u
.
dst
.
dev
->
mtu
)
{
ipv6_local_error
(
sk
,
EMSGSIZE
,
fl
,
rt
->
u
.
dst
.
dev
->
mtu
);
return
-
EMSGSIZE
;
}
if
(
flags
&
MSG_PROBE
)
goto
out
;
hh_len
=
LL_RESERVED_SPACE
(
rt
->
u
.
dst
.
dev
);
skb
=
sock_alloc_send_skb
(
sk
,
length
+
hh_len
+
15
,
flags
&
MSG_DONTWAIT
,
&
err
);
if
(
skb
==
NULL
)
goto
error
;
skb_reserve
(
skb
,
hh_len
);
skb
->
priority
=
sk
->
priority
;
skb
->
dst
=
dst_clone
(
&
rt
->
u
.
dst
);
skb
->
nh
.
ipv6h
=
iph
=
(
struct
ipv6hdr
*
)
skb_put
(
skb
,
length
);
skb
->
ip_summed
=
CHECKSUM_NONE
;
skb
->
h
.
raw
=
skb
->
nh
.
raw
;
err
=
memcpy_fromiovecend
((
void
*
)
iph
,
from
,
0
,
length
);
if
(
err
)
goto
error_fault
;
err
=
NF_HOOK
(
PF_INET6
,
NF_IP6_LOCAL_OUT
,
skb
,
NULL
,
rt
->
u
.
dst
.
dev
,
dst_output
);
if
(
err
>
0
)
err
=
inet
->
recverr
?
net_xmit_errno
(
err
)
:
0
;
if
(
err
)
goto
error
;
out:
return
0
;
error_fault:
err
=
-
EFAULT
;
kfree_skb
(
skb
);
error:
IP6_INC_STATS
(
Ip6OutDiscards
);
return
err
;
}
static
int
rawv6_sendmsg
(
struct
kiocb
*
iocb
,
struct
sock
*
sk
,
struct
msghdr
*
msg
,
int
len
)
{
struct
ipv6_txoptions
opt_space
;
struct
sockaddr_in6
*
sin6
=
(
struct
sockaddr_in6
*
)
msg
->
msg_name
;
struct
in6_addr
*
daddr
,
*
saddr
=
NULL
;
struct
inet_opt
*
inet
=
inet_sk
(
sk
);
struct
ipv6_pinfo
*
np
=
inet6_sk
(
sk
);
struct
raw6_opt
*
raw_opt
=
raw6_sk
(
sk
);
struct
ipv6_txoptions
*
opt
=
NULL
;
struct
ip6_flowlabel
*
flowlabel
=
NULL
;
struct
dst_entry
*
dst
=
NULL
;
struct
flowi
fl
;
int
addr_len
=
msg
->
msg_namelen
;
struct
in6_addr
*
daddr
;
struct
raw6_opt
*
raw_opt
;
int
hlimit
=
-
1
;
u16
proto
;
int
err
;
...
...
@@ -552,6 +583,8 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg
if
(
!
proto
)
proto
=
inet
->
num
;
else
if
(
proto
!=
inet
->
num
)
return
(
-
EINVAL
);
if
(
proto
>
255
)
return
(
-
EINVAL
);
...
...
@@ -590,6 +623,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg
* unspecfied destination address
* treated as error... is this correct ?
*/
fl6_sock_release
(
flowlabel
);
return
(
-
EINVAL
);
}
...
...
@@ -619,39 +653,71 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg
if
(
flowlabel
)
opt
=
fl6_merge_options
(
&
opt_space
,
flowlabel
,
opt
);
raw_opt
=
raw6_sk
(
sk
);
fl
.
proto
=
proto
;
fl
.
fl6_dst
=
daddr
;
if
(
fl
.
fl6_src
==
NULL
&&
!
ipv6_addr_any
(
&
np
->
saddr
))
fl
.
fl6_src
=
&
np
->
saddr
;
fl
.
fl_icmp_type
=
0
;
fl
.
fl_icmp_code
=
0
;
if
(
raw_opt
->
checksum
)
{
struct
rawv6_fakehdr
hdr
;
hdr
.
iov
=
msg
->
msg_iov
;
hdr
.
sk
=
sk
;
hdr
.
len
=
len
;
hdr
.
cksum
=
0
;
hdr
.
proto
=
proto
;
if
(
opt
&&
opt
->
srcrt
)
hdr
.
daddr
=
daddr
;
/* merge ip6_build_xmit from ip6_output */
if
(
opt
&&
opt
->
srcrt
)
{
struct
rt0_hdr
*
rt0
=
(
struct
rt0_hdr
*
)
opt
->
srcrt
;
fl
.
fl6_dst
=
rt0
->
addr
;
}
if
(
!
fl
.
oif
&&
ipv6_addr_is_multicast
(
fl
.
nl_u
.
ip6_u
.
daddr
))
fl
.
oif
=
np
->
mcast_oif
;
err
=
ip6_dst_lookup
(
sk
,
&
dst
,
&
fl
,
&
saddr
);
if
(
err
)
goto
out
;
if
(
hlimit
<
0
)
{
if
(
ipv6_addr_is_multicast
(
fl
.
fl6_dst
))
hlimit
=
np
->
mcast_hops
;
else
hdr
.
daddr
=
NULL
;
hlimit
=
np
->
hop_limit
;
if
(
hlimit
<
0
)
hlimit
=
((
struct
rt6_info
*
)
dst
)
->
rt6i_hoplimit
;
}
err
=
ip6_build_xmit
(
sk
,
rawv6_frag_cksum
,
&
hdr
,
&
fl
,
len
,
opt
,
hlimit
,
msg
->
msg_flags
);
if
(
msg
->
msg_flags
&
MSG_CONFIRM
)
goto
do_confirm
;
back_from_confirm:
if
(
inet
->
hdrincl
)
{
err
=
rawv6_send_hdrinc
(
sk
,
msg
->
msg_iov
,
len
,
&
fl
,
(
struct
rt6_info
*
)
dst
,
msg
->
msg_flags
);
}
else
{
err
=
ip6_build_xmit
(
sk
,
rawv6_getfrag
,
msg
->
msg_iov
,
&
fl
,
len
,
opt
,
hlimit
,
msg
->
msg_flags
);
lock_sock
(
sk
);
err
=
ip6_append_data
(
sk
,
ip_generic_getfrag
,
msg
->
msg_iov
,
len
,
0
,
hlimit
,
opt
,
&
fl
,
(
struct
rt6_info
*
)
dst
,
msg
->
msg_flags
);
if
(
err
)
ip6_flush_pending_frames
(
sk
);
else
if
(
!
(
msg
->
msg_flags
&
MSG_MORE
))
{
if
(
raw_opt
->
checksum
)
{
err
=
rawv6_push_pending_frames
(
sk
,
&
fl
,
raw_opt
,
len
);
}
else
{
err
=
ip6_push_pending_frames
(
sk
);
}
}
}
done:
ip6_dst_store
(
sk
,
dst
,
fl
.
nl_u
.
ip6_u
.
daddr
==
&
np
->
daddr
?
&
np
->
daddr
:
NULL
);
if
(
err
>
0
)
err
=
np
->
recverr
?
net_xmit_errno
(
err
)
:
0
;
release_sock
(
sk
);
out:
fl6_sock_release
(
flowlabel
);
if
(
saddr
)
kfree
(
saddr
);
return
err
<
0
?
err
:
len
;
do_confirm:
dst_confirm
(
dst
);
if
(
!
(
msg
->
msg_flags
&
MSG_PROBE
)
||
len
)
goto
back_from_confirm
;
err
=
0
;
goto
done
;
}
static
int
rawv6_seticmpfilter
(
struct
sock
*
sk
,
int
level
,
int
optname
,
...
...
net/ipv6/udp.c
View file @
6bac9098
This diff is collapsed.
Click to expand it.
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