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
f98e8569
Commit
f98e8569
authored
Nov 01, 2005
by
Linus Torvalds
Browse files
Options
Browse Files
Download
Plain Diff
Merge master.kernel.org:/pub/scm/linux/kernel/git/acme/net-2.6
parents
ec33b309
97300b5f
Changes
13
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
415 additions
and
219 deletions
+415
-219
include/linux/netfilter_arp/arp_tables.h
include/linux/netfilter_arp/arp_tables.h
+17
-3
include/linux/netfilter_ipv6/ip6_tables.h
include/linux/netfilter_ipv6/ip6_tables.h
+22
-5
net/bridge/br_fdb.c
net/bridge/br_fdb.c
+6
-6
net/bridge/br_input.c
net/bridge/br_input.c
+1
-1
net/bridge/br_stp_if.c
net/bridge/br_stp_if.c
+5
-4
net/dccp/dccp.h
net/dccp/dccp.h
+0
-1
net/dccp/output.c
net/dccp/output.c
+22
-12
net/ipv4/netfilter/arp_tables.c
net/ipv4/netfilter/arp_tables.c
+131
-70
net/ipv6/mcast.c
net/ipv6/mcast.c
+17
-2
net/ipv6/netfilter/ip6_tables.c
net/ipv6/netfilter/ip6_tables.c
+186
-112
net/ipv6/netfilter/ip6t_MARK.c
net/ipv6/netfilter/ip6t_MARK.c
+6
-2
net/ipv6/route.c
net/ipv6/route.c
+1
-1
net/rose/rose_timer.c
net/rose/rose_timer.c
+1
-0
No files found.
include/linux/netfilter_arp/arp_tables.h
View file @
f98e8569
...
@@ -68,7 +68,8 @@ struct arpt_entry_target
...
@@ -68,7 +68,8 @@ struct arpt_entry_target
u_int16_t
target_size
;
u_int16_t
target_size
;
/* Used by userspace */
/* Used by userspace */
char
name
[
ARPT_FUNCTION_MAXNAMELEN
];
char
name
[
ARPT_FUNCTION_MAXNAMELEN
-
1
];
u_int8_t
revision
;
}
user
;
}
user
;
struct
{
struct
{
u_int16_t
target_size
;
u_int16_t
target_size
;
...
@@ -148,7 +149,9 @@ struct arpt_entry
...
@@ -148,7 +149,9 @@ struct arpt_entry
#define ARPT_SO_GET_INFO (ARPT_BASE_CTL)
#define ARPT_SO_GET_INFO (ARPT_BASE_CTL)
#define ARPT_SO_GET_ENTRIES (ARPT_BASE_CTL + 1)
#define ARPT_SO_GET_ENTRIES (ARPT_BASE_CTL + 1)
#define ARPT_SO_GET_MAX ARPT_SO_GET_ENTRIES
/* #define ARPT_SO_GET_REVISION_MATCH (ARPT_BASE_CTL + 2)*/
#define ARPT_SO_GET_REVISION_TARGET (ARPT_BASE_CTL + 3)
#define ARPT_SO_GET_MAX ARPT_SO_GET_REVISION_TARGET
/* CONTINUE verdict for targets */
/* CONTINUE verdict for targets */
#define ARPT_CONTINUE 0xFFFFFFFF
#define ARPT_CONTINUE 0xFFFFFFFF
...
@@ -236,6 +239,15 @@ struct arpt_get_entries
...
@@ -236,6 +239,15 @@ struct arpt_get_entries
struct
arpt_entry
entrytable
[
0
];
struct
arpt_entry
entrytable
[
0
];
};
};
/* The argument to ARPT_SO_GET_REVISION_*. Returns highest revision
* kernel supports, if >= revision. */
struct
arpt_get_revision
{
char
name
[
ARPT_FUNCTION_MAXNAMELEN
-
1
];
u_int8_t
revision
;
};
/* Standard return verdict, or do jump. */
/* Standard return verdict, or do jump. */
#define ARPT_STANDARD_TARGET ""
#define ARPT_STANDARD_TARGET ""
/* Error verdict. */
/* Error verdict. */
...
@@ -274,7 +286,9 @@ struct arpt_target
...
@@ -274,7 +286,9 @@ struct arpt_target
{
{
struct
list_head
list
;
struct
list_head
list
;
const
char
name
[
ARPT_FUNCTION_MAXNAMELEN
];
const
char
name
[
ARPT_FUNCTION_MAXNAMELEN
-
1
];
u_int8_t
revision
;
/* Returns verdict. */
/* Returns verdict. */
unsigned
int
(
*
target
)(
struct
sk_buff
**
pskb
,
unsigned
int
(
*
target
)(
struct
sk_buff
**
pskb
,
...
...
include/linux/netfilter_ipv6/ip6_tables.h
View file @
f98e8569
...
@@ -57,7 +57,8 @@ struct ip6t_entry_match
...
@@ -57,7 +57,8 @@ struct ip6t_entry_match
u_int16_t
match_size
;
u_int16_t
match_size
;
/* Used by userspace */
/* Used by userspace */
char
name
[
IP6T_FUNCTION_MAXNAMELEN
];
char
name
[
IP6T_FUNCTION_MAXNAMELEN
-
1
];
u_int8_t
revision
;
}
user
;
}
user
;
struct
{
struct
{
u_int16_t
match_size
;
u_int16_t
match_size
;
...
@@ -80,7 +81,8 @@ struct ip6t_entry_target
...
@@ -80,7 +81,8 @@ struct ip6t_entry_target
u_int16_t
target_size
;
u_int16_t
target_size
;
/* Used by userspace */
/* Used by userspace */
char
name
[
IP6T_FUNCTION_MAXNAMELEN
];
char
name
[
IP6T_FUNCTION_MAXNAMELEN
-
1
];
u_int8_t
revision
;
}
user
;
}
user
;
struct
{
struct
{
u_int16_t
target_size
;
u_int16_t
target_size
;
...
@@ -161,7 +163,9 @@ struct ip6t_entry
...
@@ -161,7 +163,9 @@ struct ip6t_entry
#define IP6T_SO_GET_INFO (IP6T_BASE_CTL)
#define IP6T_SO_GET_INFO (IP6T_BASE_CTL)
#define IP6T_SO_GET_ENTRIES (IP6T_BASE_CTL + 1)
#define IP6T_SO_GET_ENTRIES (IP6T_BASE_CTL + 1)
#define IP6T_SO_GET_MAX IP6T_SO_GET_ENTRIES
#define IP6T_SO_GET_REVISION_MATCH (IP6T_BASE_CTL + 2)
#define IP6T_SO_GET_REVISION_TARGET (IP6T_BASE_CTL + 3)
#define IP6T_SO_GET_MAX IP6T_SO_GET_REVISION_TARGET
/* CONTINUE verdict for targets */
/* CONTINUE verdict for targets */
#define IP6T_CONTINUE 0xFFFFFFFF
#define IP6T_CONTINUE 0xFFFFFFFF
...
@@ -291,6 +295,15 @@ struct ip6t_get_entries
...
@@ -291,6 +295,15 @@ struct ip6t_get_entries
struct
ip6t_entry
entrytable
[
0
];
struct
ip6t_entry
entrytable
[
0
];
};
};
/* The argument to IP6T_SO_GET_REVISION_*. Returns highest revision
* kernel supports, if >= revision. */
struct
ip6t_get_revision
{
char
name
[
IP6T_FUNCTION_MAXNAMELEN
-
1
];
u_int8_t
revision
;
};
/* Standard return verdict, or do jump. */
/* Standard return verdict, or do jump. */
#define IP6T_STANDARD_TARGET ""
#define IP6T_STANDARD_TARGET ""
/* Error verdict. */
/* Error verdict. */
...
@@ -352,7 +365,9 @@ struct ip6t_match
...
@@ -352,7 +365,9 @@ struct ip6t_match
{
{
struct
list_head
list
;
struct
list_head
list
;
const
char
name
[
IP6T_FUNCTION_MAXNAMELEN
];
const
char
name
[
IP6T_FUNCTION_MAXNAMELEN
-
1
];
u_int8_t
revision
;
/* Return true or false: return FALSE and set *hotdrop = 1 to
/* Return true or false: return FALSE and set *hotdrop = 1 to
force immediate packet drop. */
force immediate packet drop. */
...
@@ -387,7 +402,9 @@ struct ip6t_target
...
@@ -387,7 +402,9 @@ struct ip6t_target
{
{
struct
list_head
list
;
struct
list_head
list
;
const
char
name
[
IP6T_FUNCTION_MAXNAMELEN
];
const
char
name
[
IP6T_FUNCTION_MAXNAMELEN
-
1
];
u_int8_t
revision
;
/* Returns verdict. Argument order changed since 2.6.9, as this
/* Returns verdict. Argument order changed since 2.6.9, as this
must now handle non-linear skbs, using skb_copy_bits and
must now handle non-linear skbs, using skb_copy_bits and
...
...
net/bridge/br_fdb.c
View file @
f98e8569
...
@@ -86,8 +86,8 @@ void br_fdb_changeaddr(struct net_bridge_port *p, const unsigned char *newaddr)
...
@@ -86,8 +86,8 @@ void br_fdb_changeaddr(struct net_bridge_port *p, const unsigned char *newaddr)
struct
net_bridge_port
*
op
;
struct
net_bridge_port
*
op
;
list_for_each_entry
(
op
,
&
br
->
port_list
,
list
)
{
list_for_each_entry
(
op
,
&
br
->
port_list
,
list
)
{
if
(
op
!=
p
&&
if
(
op
!=
p
&&
!
memcmp
(
op
->
dev
->
dev_addr
,
!
compare_ether_addr
(
op
->
dev
->
dev_addr
,
f
->
addr
.
addr
,
ETH_ALEN
))
{
f
->
addr
.
addr
))
{
f
->
dst
=
op
;
f
->
dst
=
op
;
goto
insert
;
goto
insert
;
}
}
...
@@ -151,8 +151,8 @@ void br_fdb_delete_by_port(struct net_bridge *br, struct net_bridge_port *p)
...
@@ -151,8 +151,8 @@ void br_fdb_delete_by_port(struct net_bridge *br, struct net_bridge_port *p)
struct
net_bridge_port
*
op
;
struct
net_bridge_port
*
op
;
list_for_each_entry
(
op
,
&
br
->
port_list
,
list
)
{
list_for_each_entry
(
op
,
&
br
->
port_list
,
list
)
{
if
(
op
!=
p
&&
if
(
op
!=
p
&&
!
memcmp
(
op
->
dev
->
dev_addr
,
!
compare_ether_addr
(
op
->
dev
->
dev_addr
,
f
->
addr
.
addr
,
ETH_ALEN
))
{
f
->
addr
.
addr
))
{
f
->
dst
=
op
;
f
->
dst
=
op
;
goto
skip_delete
;
goto
skip_delete
;
}
}
...
@@ -174,7 +174,7 @@ struct net_bridge_fdb_entry *__br_fdb_get(struct net_bridge *br,
...
@@ -174,7 +174,7 @@ struct net_bridge_fdb_entry *__br_fdb_get(struct net_bridge *br,
struct
net_bridge_fdb_entry
*
fdb
;
struct
net_bridge_fdb_entry
*
fdb
;
hlist_for_each_entry_rcu
(
fdb
,
h
,
&
br
->
hash
[
br_mac_hash
(
addr
)],
hlist
)
{
hlist_for_each_entry_rcu
(
fdb
,
h
,
&
br
->
hash
[
br_mac_hash
(
addr
)],
hlist
)
{
if
(
!
memcmp
(
fdb
->
addr
.
addr
,
addr
,
ETH_ALEN
))
{
if
(
!
compare_ether_addr
(
fdb
->
addr
.
addr
,
addr
))
{
if
(
unlikely
(
has_expired
(
br
,
fdb
)))
if
(
unlikely
(
has_expired
(
br
,
fdb
)))
break
;
break
;
return
fdb
;
return
fdb
;
...
@@ -264,7 +264,7 @@ static inline struct net_bridge_fdb_entry *fdb_find(struct hlist_head *head,
...
@@ -264,7 +264,7 @@ static inline struct net_bridge_fdb_entry *fdb_find(struct hlist_head *head,
struct
net_bridge_fdb_entry
*
fdb
;
struct
net_bridge_fdb_entry
*
fdb
;
hlist_for_each_entry_rcu
(
fdb
,
h
,
head
,
hlist
)
{
hlist_for_each_entry_rcu
(
fdb
,
h
,
head
,
hlist
)
{
if
(
!
memcmp
(
fdb
->
addr
.
addr
,
addr
,
ETH_ALEN
))
if
(
!
compare_ether_addr
(
fdb
->
addr
.
addr
,
addr
))
return
fdb
;
return
fdb
;
}
}
return
NULL
;
return
NULL
;
...
...
net/bridge/br_input.c
View file @
f98e8569
...
@@ -128,7 +128,7 @@ int br_handle_frame(struct net_bridge_port *p, struct sk_buff **pskb)
...
@@ -128,7 +128,7 @@ int br_handle_frame(struct net_bridge_port *p, struct sk_buff **pskb)
dest
=
eth_hdr
(
skb
)
->
h_dest
;
dest
=
eth_hdr
(
skb
)
->
h_dest
;
}
}
if
(
!
memcmp
(
p
->
br
->
dev
->
dev_addr
,
dest
,
ETH_ALEN
))
if
(
!
compare_ether_addr
(
p
->
br
->
dev
->
dev_addr
,
dest
))
skb
->
pkt_type
=
PACKET_HOST
;
skb
->
pkt_type
=
PACKET_HOST
;
NF_HOOK
(
PF_BRIDGE
,
NF_BR_PRE_ROUTING
,
skb
,
skb
->
dev
,
NULL
,
NF_HOOK
(
PF_BRIDGE
,
NF_BR_PRE_ROUTING
,
skb
,
skb
->
dev
,
NULL
,
...
...
net/bridge/br_stp_if.c
View file @
f98e8569
...
@@ -15,6 +15,7 @@
...
@@ -15,6 +15,7 @@
#include <linux/kernel.h>
#include <linux/kernel.h>
#include <linux/smp_lock.h>
#include <linux/smp_lock.h>
#include <linux/etherdevice.h>
#include "br_private.h"
#include "br_private.h"
#include "br_private_stp.h"
#include "br_private_stp.h"
...
@@ -133,10 +134,10 @@ static void br_stp_change_bridge_id(struct net_bridge *br,
...
@@ -133,10 +134,10 @@ static void br_stp_change_bridge_id(struct net_bridge *br,
memcpy
(
br
->
dev
->
dev_addr
,
addr
,
ETH_ALEN
);
memcpy
(
br
->
dev
->
dev_addr
,
addr
,
ETH_ALEN
);
list_for_each_entry
(
p
,
&
br
->
port_list
,
list
)
{
list_for_each_entry
(
p
,
&
br
->
port_list
,
list
)
{
if
(
!
memcmp
(
p
->
designated_bridge
.
addr
,
oldaddr
,
ETH_ALEN
))
if
(
!
compare_ether_addr
(
p
->
designated_bridge
.
addr
,
oldaddr
))
memcpy
(
p
->
designated_bridge
.
addr
,
addr
,
ETH_ALEN
);
memcpy
(
p
->
designated_bridge
.
addr
,
addr
,
ETH_ALEN
);
if
(
!
memcmp
(
p
->
designated_root
.
addr
,
oldaddr
,
ETH_ALEN
))
if
(
!
compare_ether_addr
(
p
->
designated_root
.
addr
,
oldaddr
))
memcpy
(
p
->
designated_root
.
addr
,
addr
,
ETH_ALEN
);
memcpy
(
p
->
designated_root
.
addr
,
addr
,
ETH_ALEN
);
}
}
...
@@ -157,12 +158,12 @@ void br_stp_recalculate_bridge_id(struct net_bridge *br)
...
@@ -157,12 +158,12 @@ void br_stp_recalculate_bridge_id(struct net_bridge *br)
list_for_each_entry
(
p
,
&
br
->
port_list
,
list
)
{
list_for_each_entry
(
p
,
&
br
->
port_list
,
list
)
{
if
(
addr
==
br_mac_zero
||
if
(
addr
==
br_mac_zero
||
memcmp
(
p
->
dev
->
dev_addr
,
addr
,
ETH_ALEN
)
<
0
)
compare_ether_addr
(
p
->
dev
->
dev_addr
,
addr
)
<
0
)
addr
=
p
->
dev
->
dev_addr
;
addr
=
p
->
dev
->
dev_addr
;
}
}
if
(
memcmp
(
br
->
bridge_id
.
addr
,
addr
,
ETH_ALEN
))
if
(
compare_ether_addr
(
br
->
bridge_id
.
addr
,
addr
))
br_stp_change_bridge_id
(
br
,
addr
);
br_stp_change_bridge_id
(
br
,
addr
);
}
}
...
...
net/dccp/dccp.h
View file @
f98e8569
...
@@ -118,7 +118,6 @@ DECLARE_SNMP_STAT(struct dccp_mib, dccp_statistics);
...
@@ -118,7 +118,6 @@ DECLARE_SNMP_STAT(struct dccp_mib, dccp_statistics);
#define DCCP_ADD_STATS_USER(field, val) \
#define DCCP_ADD_STATS_USER(field, val) \
SNMP_ADD_STATS_USER(dccp_statistics, field, val)
SNMP_ADD_STATS_USER(dccp_statistics, field, val)
extern
int
dccp_transmit_skb
(
struct
sock
*
sk
,
struct
sk_buff
*
skb
);
extern
int
dccp_retransmit_skb
(
struct
sock
*
sk
,
struct
sk_buff
*
skb
);
extern
int
dccp_retransmit_skb
(
struct
sock
*
sk
,
struct
sk_buff
*
skb
);
extern
int
dccp_send_response
(
struct
sock
*
sk
);
extern
int
dccp_send_response
(
struct
sock
*
sk
);
...
...
net/dccp/output.c
View file @
f98e8569
...
@@ -12,6 +12,7 @@
...
@@ -12,6 +12,7 @@
#include <linux/config.h>
#include <linux/config.h>
#include <linux/dccp.h>
#include <linux/dccp.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
#include <linux/skbuff.h>
#include <net/sock.h>
#include <net/sock.h>
...
@@ -25,13 +26,20 @@ static inline void dccp_event_ack_sent(struct sock *sk)
...
@@ -25,13 +26,20 @@ static inline void dccp_event_ack_sent(struct sock *sk)
inet_csk_clear_xmit_timer
(
sk
,
ICSK_TIME_DACK
);
inet_csk_clear_xmit_timer
(
sk
,
ICSK_TIME_DACK
);
}
}
static
inline
void
dccp_skb_entail
(
struct
sock
*
sk
,
struct
sk_buff
*
skb
)
{
skb_set_owner_w
(
skb
,
sk
);
WARN_ON
(
sk
->
sk_send_head
);
sk
->
sk_send_head
=
skb
;
}
/*
/*
* All SKB's seen here are completely headerless. It is our
* All SKB's seen here are completely headerless. It is our
* job to build the DCCP header, and pass the packet down to
* job to build the DCCP header, and pass the packet down to
* IP so it can do the same plus pass the packet off to the
* IP so it can do the same plus pass the packet off to the
* device.
* device.
*/
*/
int
dccp_transmit_skb
(
struct
sock
*
sk
,
struct
sk_buff
*
skb
)
static
int
dccp_transmit_skb
(
struct
sock
*
sk
,
struct
sk_buff
*
skb
)
{
{
if
(
likely
(
skb
!=
NULL
))
{
if
(
likely
(
skb
!=
NULL
))
{
const
struct
inet_sock
*
inet
=
inet_sk
(
sk
);
const
struct
inet_sock
*
inet
=
inet_sk
(
sk
);
...
@@ -50,10 +58,21 @@ int dccp_transmit_skb(struct sock *sk, struct sk_buff *skb)
...
@@ -50,10 +58,21 @@ int dccp_transmit_skb(struct sock *sk, struct sk_buff *skb)
switch
(
dcb
->
dccpd_type
)
{
switch
(
dcb
->
dccpd_type
)
{
case
DCCP_PKT_DATA
:
case
DCCP_PKT_DATA
:
set_ack
=
0
;
set_ack
=
0
;
/* fall through */
case
DCCP_PKT_DATAACK
:
break
;
break
;
case
DCCP_PKT_SYNC
:
case
DCCP_PKT_SYNC
:
case
DCCP_PKT_SYNCACK
:
case
DCCP_PKT_SYNCACK
:
ackno
=
dcb
->
dccpd_seq
;
ackno
=
dcb
->
dccpd_seq
;
/* fall through */
default:
/*
* Only data packets should come through with skb->sk
* set.
*/
WARN_ON
(
skb
->
sk
);
skb_set_owner_w
(
skb
,
sk
);
break
;
break
;
}
}
...
@@ -63,9 +82,6 @@ int dccp_transmit_skb(struct sock *sk, struct sk_buff *skb)
...
@@ -63,9 +82,6 @@ int dccp_transmit_skb(struct sock *sk, struct sk_buff *skb)
skb
->
h
.
raw
=
skb_push
(
skb
,
dccp_header_size
);
skb
->
h
.
raw
=
skb_push
(
skb
,
dccp_header_size
);
dh
=
dccp_hdr
(
skb
);
dh
=
dccp_hdr
(
skb
);
if
(
!
skb
->
sk
)
skb_set_owner_w
(
skb
,
sk
);
/* Build DCCP header and checksum it. */
/* Build DCCP header and checksum it. */
memset
(
dh
,
0
,
dccp_header_size
);
memset
(
dh
,
0
,
dccp_header_size
);
dh
->
dccph_type
=
dcb
->
dccpd_type
;
dh
->
dccph_type
=
dcb
->
dccpd_type
;
...
@@ -393,10 +409,8 @@ int dccp_connect(struct sock *sk)
...
@@ -393,10 +409,8 @@ int dccp_connect(struct sock *sk)
DCCP_SKB_CB
(
skb
)
->
dccpd_type
=
DCCP_PKT_REQUEST
;
DCCP_SKB_CB
(
skb
)
->
dccpd_type
=
DCCP_PKT_REQUEST
;
skb
->
csum
=
0
;
skb
->
csum
=
0
;
skb_set_owner_w
(
skb
,
sk
);
BUG_TRAP
(
sk
->
sk_send_head
==
NULL
);
dccp_skb_entail
(
sk
,
skb
);
sk
->
sk_send_head
=
skb
;
dccp_transmit_skb
(
sk
,
skb_clone
(
skb
,
GFP_KERNEL
));
dccp_transmit_skb
(
sk
,
skb_clone
(
skb
,
GFP_KERNEL
));
DCCP_INC_STATS
(
DCCP_MIB_ACTIVEOPENS
);
DCCP_INC_STATS
(
DCCP_MIB_ACTIVEOPENS
);
...
@@ -425,7 +439,6 @@ void dccp_send_ack(struct sock *sk)
...
@@ -425,7 +439,6 @@ void dccp_send_ack(struct sock *sk)
skb_reserve
(
skb
,
MAX_DCCP_HEADER
);
skb_reserve
(
skb
,
MAX_DCCP_HEADER
);
skb
->
csum
=
0
;
skb
->
csum
=
0
;
DCCP_SKB_CB
(
skb
)
->
dccpd_type
=
DCCP_PKT_ACK
;
DCCP_SKB_CB
(
skb
)
->
dccpd_type
=
DCCP_PKT_ACK
;
skb_set_owner_w
(
skb
,
sk
);
dccp_transmit_skb
(
sk
,
skb
);
dccp_transmit_skb
(
sk
,
skb
);
}
}
}
}
...
@@ -482,7 +495,6 @@ void dccp_send_sync(struct sock *sk, const u64 seq,
...
@@ -482,7 +495,6 @@ void dccp_send_sync(struct sock *sk, const u64 seq,
DCCP_SKB_CB
(
skb
)
->
dccpd_type
=
pkt_type
;
DCCP_SKB_CB
(
skb
)
->
dccpd_type
=
pkt_type
;
DCCP_SKB_CB
(
skb
)
->
dccpd_seq
=
seq
;
DCCP_SKB_CB
(
skb
)
->
dccpd_seq
=
seq
;
skb_set_owner_w
(
skb
,
sk
);
dccp_transmit_skb
(
sk
,
skb
);
dccp_transmit_skb
(
sk
,
skb
);
}
}
...
@@ -507,10 +519,8 @@ void dccp_send_close(struct sock *sk, const int active)
...
@@ -507,10 +519,8 @@ void dccp_send_close(struct sock *sk, const int active)
DCCP_SKB_CB
(
skb
)
->
dccpd_type
=
dp
->
dccps_role
==
DCCP_ROLE_CLIENT
?
DCCP_SKB_CB
(
skb
)
->
dccpd_type
=
dp
->
dccps_role
==
DCCP_ROLE_CLIENT
?
DCCP_PKT_CLOSE
:
DCCP_PKT_CLOSEREQ
;
DCCP_PKT_CLOSE
:
DCCP_PKT_CLOSEREQ
;
skb_set_owner_w
(
skb
,
sk
);
if
(
active
)
{
if
(
active
)
{
BUG_TRAP
(
sk
->
sk_send_head
==
NULL
);
dccp_skb_entail
(
sk
,
skb
);
sk
->
sk_send_head
=
skb
;
dccp_transmit_skb
(
sk
,
skb_clone
(
skb
,
prio
));
dccp_transmit_skb
(
sk
,
skb_clone
(
skb
,
prio
));
}
else
}
else
dccp_transmit_skb
(
sk
,
skb
);
dccp_transmit_skb
(
sk
,
skb
);
...
...
net/ipv4/netfilter/arp_tables.c
View file @
f98e8569
...
@@ -347,58 +347,106 @@ unsigned int arpt_do_table(struct sk_buff **pskb,
...
@@ -347,58 +347,106 @@ unsigned int arpt_do_table(struct sk_buff **pskb,
return
verdict
;
return
verdict
;
}
}
static
inline
void
*
find_inlist_lock_noload
(
struct
list_head
*
head
,
/*
const
char
*
name
,
* These are weird, but module loading must not be done with mutex
int
*
error
,
* held (since they will register), and we have to have a single
struct
semaphore
*
mutex
)
* function to use try_then_request_module().
*/
/* Find table by name, grabs mutex & ref. Returns ERR_PTR() on error. */
static
inline
struct
arpt_table
*
find_table_lock
(
const
char
*
name
)
{
{
void
*
re
t
;
struct
arpt_table
*
t
;
*
error
=
down_interruptible
(
mutex
);
if
(
down_interruptible
(
&
arpt_mutex
)
!=
0
)
if
(
*
error
!=
0
)
return
ERR_PTR
(
-
EINTR
);
return
NULL
;
ret
=
list_named_find
(
head
,
name
);
list_for_each_entry
(
t
,
&
arpt_tables
,
list
)
if
(
!
ret
)
{
if
(
strcmp
(
t
->
name
,
name
)
==
0
&&
try_module_get
(
t
->
me
))
*
error
=
-
ENOENT
;
return
t
;
up
(
mutex
);
up
(
&
arpt_mutex
);
}
return
NULL
;
return
ret
;
}
}
#ifndef CONFIG_KMOD
#define find_inlist_lock(h,n,p,e,m) find_inlist_lock_noload((h),(n),(e),(m))
/* Find target, grabs ref. Returns ERR_PTR() on error. */
#else
static
inline
struct
arpt_target
*
find_target
(
const
char
*
name
,
u8
revision
)
static
void
*
find_inlist_lock
(
struct
list_head
*
head
,
const
char
*
name
,
const
char
*
prefix
,
int
*
error
,
struct
semaphore
*
mutex
)
{
{
void
*
ret
;
struct
arpt_target
*
t
;
int
err
=
0
;
ret
=
find_inlist_lock_noload
(
head
,
name
,
error
,
mutex
);
if
(
down_interruptible
(
&
arpt_mutex
)
!=
0
)
if
(
!
ret
)
{
return
ERR_PTR
(
-
EINTR
);
duprintf
(
"find_inlist: loading `%s%s'.
\n
"
,
prefix
,
name
);
request_module
(
"%s%s"
,
prefix
,
name
);
list_for_each_entry
(
t
,
&
arpt_target
,
list
)
{
ret
=
find_inlist_lock_noload
(
head
,
name
,
error
,
mutex
);
if
(
strcmp
(
t
->
name
,
name
)
==
0
)
{
if
(
t
->
revision
==
revision
)
{
if
(
try_module_get
(
t
->
me
))
{
up
(
&
arpt_mutex
);
return
t
;
}
}
else
err
=
-
EPROTOTYPE
;
/* Found something. */
}
}
}
up
(
&
arpt_mutex
);
return
ERR_PTR
(
err
);
}
return
ret
;
struct
arpt_target
*
arpt_find_target
(
const
char
*
name
,
u8
revision
)
{
struct
arpt_target
*
target
;
target
=
try_then_request_module
(
find_target
(
name
,
revision
),
"arpt_%s"
,
name
);
if
(
IS_ERR
(
target
)
||
!
target
)
return
NULL
;
return
target
;
}
}
#endif
static
in
line
struct
arpt_table
*
arpt_find_table_lock
(
const
char
*
name
,
int
*
error
,
struct
semaphore
*
mutex
)
static
in
t
target_revfn
(
const
char
*
name
,
u8
revision
,
int
*
bestp
)
{
{
return
find_inlist_lock
(
&
arpt_tables
,
name
,
"arptable_"
,
error
,
mutex
);
struct
arpt_target
*
t
;
int
have_rev
=
0
;
list_for_each_entry
(
t
,
&
arpt_target
,
list
)
{
if
(
strcmp
(
t
->
name
,
name
)
==
0
)
{
if
(
t
->
revision
>
*
bestp
)
*
bestp
=
t
->
revision
;
if
(
t
->
revision
==
revision
)
have_rev
=
1
;
}
}
return
have_rev
;
}
}
static
struct
arpt_target
*
arpt_find_target_lock
(
const
char
*
name
,
int
*
error
,
struct
semaphore
*
mutex
)
/* Returns true or false (if no such extension at all) */
static
inline
int
find_revision
(
const
char
*
name
,
u8
revision
,
int
(
*
revfn
)(
const
char
*
,
u8
,
int
*
),
int
*
err
)
{
{
return
find_inlist_lock
(
&
arpt_target
,
name
,
"arpt_"
,
error
,
mutex
);
int
have_rev
,
best
=
-
1
;
if
(
down_interruptible
(
&
arpt_mutex
)
!=
0
)
{
*
err
=
-
EINTR
;
return
1
;
}
have_rev
=
revfn
(
name
,
revision
,
&
best
);
up
(
&
arpt_mutex
);
/* Nothing at all? Return 0 to try loading module. */
if
(
best
==
-
1
)
{
*
err
=
-
ENOENT
;
return
0
;
}
*
err
=
best
;
if
(
!
have_rev
)
*
err
=
-
EPROTONOSUPPORT
;
return
1
;
}
}
/* All zeroes == unconditional rule. */
/* All zeroes == unconditional rule. */
static
inline
int
unconditional
(
const
struct
arpt_arp
*
arp
)
static
inline
int
unconditional
(
const
struct
arpt_arp
*
arp
)
{
{
...
@@ -544,17 +592,15 @@ static inline int check_entry(struct arpt_entry *e, const char *name, unsigned i
...
@@ -544,17 +592,15 @@ static inline int check_entry(struct arpt_entry *e, const char *name, unsigned i
}
}
t
=
arpt_get_target
(
e
);
t
=
arpt_get_target
(
e
);
target
=
arpt_find_target_lock
(
t
->
u
.
user
.
name
,
&
ret
,
&
arpt_mutex
);
target
=
try_then_request_module
(
find_target
(
t
->
u
.
user
.
name
,
if
(
!
target
)
{
t
->
u
.
user
.
revision
),
"arpt_%s"
,
t
->
u
.
user
.
name
);
if
(
IS_ERR
(
target
)
||
!
target
)
{
duprintf
(
"check_entry: `%s' not found
\n
"
,
t
->
u
.
user
.
name
);
duprintf
(
"check_entry: `%s' not found
\n
"
,
t
->
u
.
user
.
name
);
ret
=
target
?
PTR_ERR
(
target
)
:
-
ENOENT
;
goto
out
;
goto
out
;
}
}
if
(
!
try_module_get
((
target
->
me
)))
{
ret
=
-
ENOENT
;
goto
out_unlock
;
}
t
->
u
.
kernel
.
target
=
target
;
t
->
u
.
kernel
.
target
=
target
;
up
(
&
arpt_mutex
);
if
(
t
->
u
.
kernel
.
target
==
&
arpt_standard_target
)
{
if
(
t
->
u
.
kernel
.
target
==
&
arpt_standard_target
)
{
if
(
!
standard_check
(
t
,
size
))
{
if
(
!
standard_check
(
t
,
size
))
{
...
@@ -576,8 +622,6 @@ static inline int check_entry(struct arpt_entry *e, const char *name, unsigned i
...
@@ -576,8 +622,6 @@ static inline int check_entry(struct arpt_entry *e, const char *name, unsigned i
(
*
i
)
++
;
(
*
i
)
++
;
return
0
;
return
0
;
out_unlock:
up
(
&
arpt_mutex
);
out:
out:
return
ret
;
return
ret
;
}
}
...
@@ -846,8 +890,8 @@ static int get_entries(const struct arpt_get_entries *entries,
...
@@ -846,8 +890,8 @@ static int get_entries(const struct arpt_get_entries *entries,
int
ret
;
int
ret
;
struct
arpt_table
*
t
;
struct
arpt_table
*
t
;
t
=
arpt_find_table_lock
(
entries
->
name
,
&
ret
,
&
arpt_mutex
);
t
=
find_table_lock
(
entries
->
name
);
if
(
t
)
{
if
(
t
||
!
IS_ERR
(
t
)
)
{
duprintf
(
"t->private->number = %u
\n
"
,
duprintf
(
"t->private->number = %u
\n
"
,
t
->
private
->
number
);
t
->
private
->
number
);
if
(
entries
->
size
==
t
->
private
->
size
)
if
(
entries
->
size
==
t
->
private
->
size
)
...
@@ -859,10 +903,10 @@ static int get_entries(const struct arpt_get_entries *entries,
...
@@ -859,10 +903,10 @@ static int get_entries(const struct arpt_get_entries *entries,
entries
->
size
);
entries
->
size
);
ret
=
-
EINVAL
;
ret
=
-
EINVAL
;
}
}
module_put
(
t
->
me
);
up
(
&
arpt_mutex
);
up
(
&
arpt_mutex
);
}
else
}
else
duprintf
(
"get_entries: Can't find %s!
\n
"
,
ret
=
t
?
PTR_ERR
(
t
)
:
-
ENOENT
;
entries
->
name
);
return
ret
;
return
ret
;
}
}
...
@@ -913,22 +957,19 @@ static int do_replace(void __user *user, unsigned int len)
...
@@ -913,22 +957,19 @@ static int do_replace(void __user *user, unsigned int len)
duprintf
(
"arp_tables: Translated table
\n
"
);
duprintf
(
"arp_tables: Translated table
\n
"
);
t
=
arpt_find_table_lock
(
tmp
.
name
,
&
ret
,
&
arpt_mutex
);
t
=
try_then_request_module
(
find_table_lock
(
tmp
.
name
),
if
(
!
t
)
"arptable_%s"
,
tmp
.
name
);
if
(
!
t
||
IS_ERR
(
t
))
{
ret
=
t
?
PTR_ERR
(
t
)
:
-
ENOENT
;
goto
free_newinfo_counters_untrans
;
goto
free_newinfo_counters_untrans
;
}
/* You lied! */
/* You lied! */
if
(
tmp
.
valid_hooks
!=
t
->
valid_hooks
)
{
if
(
tmp
.
valid_hooks
!=
t
->
valid_hooks
)
{
duprintf
(
"Valid hook crap: %08X vs %08X
\n
"
,
duprintf
(
"Valid hook crap: %08X vs %08X
\n
"
,
tmp
.
valid_hooks
,
t
->
valid_hooks
);
tmp
.
valid_hooks
,
t
->
valid_hooks
);
ret
=
-
EINVAL
;
ret
=
-
EINVAL
;
goto
free_newinfo_counters_untrans_unlock
;
goto
put_module
;
}
/* Get a reference in advance, we're not allowed fail later */
if
(
!
try_module_get
(
t
->
me
))
{
ret
=
-
EBUSY
;
goto
free_newinfo_counters_untrans_unlock
;
}
}
oldinfo
=
replace_table
(
t
,
tmp
.
num_counters
,
newinfo
,
&
ret
);
oldinfo
=
replace_table
(
t
,
tmp
.
num_counters
,
newinfo
,
&
ret
);
...
@@ -959,7 +1000,6 @@ static int do_replace(void __user *user, unsigned int len)
...
@@ -959,7 +1000,6 @@ static int do_replace(void __user *user, unsigned int len)
put_module:
put_module:
module_put
(
t
->
me
);
module_put
(
t
->
me
);
free_newinfo_counters_untrans_unlock:
up
(
&
arpt_mutex
);
up
(
&
arpt_mutex
);
free_newinfo_counters_untrans:
free_newinfo_counters_untrans:
ARPT_ENTRY_ITERATE
(
newinfo
->
entries
,
newinfo
->
size
,
cleanup_entry
,
NULL
);
ARPT_ENTRY_ITERATE
(
newinfo
->
entries
,
newinfo
->
size
,
cleanup_entry
,
NULL
);
...
@@ -989,7 +1029,7 @@ static int do_add_counters(void __user *user, unsigned int len)
...
@@ -989,7 +1029,7 @@ static int do_add_counters(void __user *user, unsigned int len)
unsigned
int
i
;
unsigned
int
i
;
struct
arpt_counters_info
tmp
,
*
paddc
;
struct
arpt_counters_info
tmp
,
*
paddc
;
struct
arpt_table
*
t
;
struct
arpt_table
*
t
;
int
ret
;
int
ret
=
0
;
if
(
copy_from_user
(
&
tmp
,
user
,
sizeof
(
tmp
))
!=
0
)
if
(
copy_from_user
(
&
tmp
,
user
,
sizeof
(
tmp
))
!=
0
)
return
-
EFAULT
;
return
-
EFAULT
;
...
@@ -1006,9 +1046,11 @@ static int do_add_counters(void __user *user, unsigned int len)
...
@@ -1006,9 +1046,11 @@ static int do_add_counters(void __user *user, unsigned int len)
goto
free
;
goto
free
;
}
}
t
=
arpt_find_table_lock
(
tmp
.
name
,
&
ret
,
&
arpt_mutex
);
t
=
find_table_lock
(
tmp
.
name
);
if
(
!
t
)
if
(
!
t
||
IS_ERR
(
t
))
{
ret
=
t
?
PTR_ERR
(
t
)
:
-
ENOENT
;
goto
free
;
goto
free
;
}
write_lock_bh
(
&
t
->
lock
);
write_lock_bh
(
&
t
->
lock
);
if
(
t
->
private
->
number
!=
paddc
->
num_counters
)
{
if
(
t
->
private
->
number
!=
paddc
->
num_counters
)
{
...
@@ -1025,6 +1067,7 @@ static int do_add_counters(void __user *user, unsigned int len)
...
@@ -1025,6 +1067,7 @@ static int do_add_counters(void __user *user, unsigned int len)
unlock_up_free:
unlock_up_free:
write_unlock_bh
(
&
t
->
lock
);
write_unlock_bh
(
&
t
->
lock
);
up
(
&
arpt_mutex
);
up
(
&
arpt_mutex
);
module_put
(
t
->
me
);
free:
free:
vfree
(
paddc
);
vfree
(
paddc
);
...
@@ -1079,8 +1122,10 @@ static int do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len
...
@@ -1079,8 +1122,10 @@ static int do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len
break
;
break
;
}
}
name
[
ARPT_TABLE_MAXNAMELEN
-
1
]
=
'\0'
;
name
[
ARPT_TABLE_MAXNAMELEN
-
1
]
=
'\0'
;
t
=
arpt_find_table_lock
(
name
,
&
ret
,
&
arpt_mutex
);
if
(
t
)
{
t
=
try_then_request_module
(
find_table_lock
(
name
),
"arptable_%s"
,
name
);
if
(
t
&&
!
IS_ERR
(
t
))
{
struct
arpt_getinfo
info
;
struct
arpt_getinfo
info
;
info
.
valid_hooks
=
t
->
valid_hooks
;
info
.
valid_hooks
=
t
->
valid_hooks
;
...
@@ -1096,9 +1141,10 @@ static int do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len
...
@@ -1096,9 +1141,10 @@ static int do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len
ret
=
-
EFAULT
;
ret
=
-
EFAULT
;
else
else
ret
=
0
;
ret
=
0
;
up
(
&
arpt_mutex
);
up
(
&
arpt_mutex
);
}
module_put
(
t
->
me
);
}
else
ret
=
t
?
PTR_ERR
(
t
)
:
-
ENOENT
;
}
}
break
;
break
;
...
@@ -1119,6 +1165,24 @@ static int do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len
...
@@ -1119,6 +1165,24 @@ static int do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len
break
;
break
;
}
}
case
ARPT_SO_GET_REVISION_TARGET
:
{
struct
arpt_get_revision
rev
;
if
(
*
len
!=
sizeof
(
rev
))
{
ret
=
-
EINVAL
;
break
;
}
if
(
copy_from_user
(
&
rev
,
user
,
sizeof
(
rev
))
!=
0
)
{
ret
=
-
EFAULT
;
break
;
}
try_then_request_module
(
find_revision
(
rev
.
name
,
rev
.
revision
,
target_revfn
,
&
ret
),
"arpt_%s"
,
rev
.
name
);
break
;
}
default:
default:
duprintf
(
"do_arpt_get_ctl: unknown request %i
\n
"
,
cmd
);
duprintf
(
"do_arpt_get_ctl: unknown request %i
\n
"
,
cmd
);
ret
=
-
EINVAL
;
ret
=
-
EINVAL
;
...
@@ -1136,12 +1200,9 @@ int arpt_register_target(struct arpt_target *target)
...
@@ -1136,12 +1200,9 @@ int arpt_register_target(struct arpt_target *target)
if
(
ret
!=
0
)
if
(
ret
!=
0
)
return
ret
;
return
ret
;
if
(
!
list_named_insert
(
&
arpt_target
,
target
))
{
list_add
(
&
target
->
list
,
&
arpt_target
);
duprintf
(
"arpt_register_target: `%s' already in list!
\n
"
,
target
->
name
);
ret
=
-
EINVAL
;
}
up
(
&
arpt_mutex
);
up
(
&
arpt_mutex
);
return
ret
;
return
ret
;
}
}
...
...
net/ipv6/mcast.c
View file @
f98e8569
...
@@ -1087,7 +1087,7 @@ static void mld_marksources(struct ifmcaddr6 *pmc, int nsrcs,
...
@@ -1087,7 +1087,7 @@ static void mld_marksources(struct ifmcaddr6 *pmc, int nsrcs,
int
igmp6_event_query
(
struct
sk_buff
*
skb
)
int
igmp6_event_query
(
struct
sk_buff
*
skb
)
{
{
struct
mld2_query
*
mlh2
=
(
struct
mld2_query
*
)
skb
->
h
.
raw
;
struct
mld2_query
*
mlh2
=
NULL
;
struct
ifmcaddr6
*
ma
;
struct
ifmcaddr6
*
ma
;
struct
in6_addr
*
group
;
struct
in6_addr
*
group
;
unsigned
long
max_delay
;
unsigned
long
max_delay
;
...
@@ -1140,6 +1140,13 @@ int igmp6_event_query(struct sk_buff *skb)
...
@@ -1140,6 +1140,13 @@ int igmp6_event_query(struct sk_buff *skb)
/* clear deleted report items */
/* clear deleted report items */
mld_clear_delrec
(
idev
);
mld_clear_delrec
(
idev
);
}
else
if
(
len
>=
28
)
{
}
else
if
(
len
>=
28
)
{
int
srcs_offset
=
sizeof
(
struct
mld2_query
)
-
sizeof
(
struct
icmp6hdr
);
if
(
!
pskb_may_pull
(
skb
,
srcs_offset
))
{
in6_dev_put
(
idev
);
return
-
EINVAL
;
}
mlh2
=
(
struct
mld2_query
*
)
skb
->
h
.
raw
;
max_delay
=
(
MLDV2_MRC
(
ntohs
(
mlh2
->
mrc
))
*
HZ
)
/
1000
;
max_delay
=
(
MLDV2_MRC
(
ntohs
(
mlh2
->
mrc
))
*
HZ
)
/
1000
;
if
(
!
max_delay
)
if
(
!
max_delay
)
max_delay
=
1
;
max_delay
=
1
;
...
@@ -1156,7 +1163,15 @@ int igmp6_event_query(struct sk_buff *skb)
...
@@ -1156,7 +1163,15 @@ int igmp6_event_query(struct sk_buff *skb)
return
0
;
return
0
;
}
}
/* mark sources to include, if group & source-specific */
/* mark sources to include, if group & source-specific */
mark
=
mlh2
->
nsrcs
!=
0
;
if
(
mlh2
->
nsrcs
!=
0
)
{
if
(
!
pskb_may_pull
(
skb
,
srcs_offset
+
mlh2
->
nsrcs
*
sizeof
(
struct
in6_addr
)))
{
in6_dev_put
(
idev
);
return
-
EINVAL
;
}
mlh2
=
(
struct
mld2_query
*
)
skb
->
h
.
raw
;
mark
=
1
;
}
}
else
{
}
else
{
in6_dev_put
(
idev
);
in6_dev_put
(
idev
);
return
-
EINVAL
;
return
-
EINVAL
;
...
...
net/ipv6/netfilter/ip6_tables.c
View file @
f98e8569
This diff is collapsed.
Click to expand it.
net/ipv6/netfilter/ip6t_MARK.c
View file @
f98e8569
...
@@ -56,8 +56,12 @@ checkentry(const char *tablename,
...
@@ -56,8 +56,12 @@ checkentry(const char *tablename,
return
1
;
return
1
;
}
}
static
struct
ip6t_target
ip6t_mark_reg
static
struct
ip6t_target
ip6t_mark_reg
=
{
=
{
{
NULL
,
NULL
},
"MARK"
,
target
,
checkentry
,
NULL
,
THIS_MODULE
};
.
name
=
"MARK"
,
.
target
=
target
,
.
checkentry
=
checkentry
,
.
me
=
THIS_MODULE
};
static
int
__init
init
(
void
)
static
int
__init
init
(
void
)
{
{
...
...
net/ipv6/route.c
View file @
f98e8569
...
@@ -483,7 +483,7 @@ void ip6_route_input(struct sk_buff *skb)
...
@@ -483,7 +483,7 @@ void ip6_route_input(struct sk_buff *skb)
goto
out
;
goto
out
;
}
}
rt
=
rt6_device_match
(
rt
,
skb
->
dev
->
ifindex
,
0
);
rt
=
rt6_device_match
(
rt
,
skb
->
dev
->
ifindex
,
strict
);
BACKTRACK
();
BACKTRACK
();
if
(
!
rt
->
rt6i_nexthop
&&
!
(
rt
->
rt6i_flags
&
RTF_NONEXTHOP
))
{
if
(
!
rt
->
rt6i_nexthop
&&
!
(
rt
->
rt6i_flags
&
RTF_NONEXTHOP
))
{
...
...
net/rose/rose_timer.c
View file @
f98e8569
...
@@ -138,6 +138,7 @@ static void rose_heartbeat_expiry(unsigned long param)
...
@@ -138,6 +138,7 @@ static void rose_heartbeat_expiry(unsigned long param)
is accepted() it isn't 'dead' so doesn't get removed. */
is accepted() it isn't 'dead' so doesn't get removed. */
if
(
sock_flag
(
sk
,
SOCK_DESTROY
)
||
if
(
sock_flag
(
sk
,
SOCK_DESTROY
)
||
(
sk
->
sk_state
==
TCP_LISTEN
&&
sock_flag
(
sk
,
SOCK_DEAD
)))
{
(
sk
->
sk_state
==
TCP_LISTEN
&&
sock_flag
(
sk
,
SOCK_DEAD
)))
{
bh_unlock_sock
(
sk
);
rose_destroy_socket
(
sk
);
rose_destroy_socket
(
sk
);
return
;
return
;
}
}
...
...
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