Commit d8650a57 authored by Linus Torvalds's avatar Linus Torvalds

Merge bk://kernel.bkbits.net/davem/net-2.6

into home.osdl.org:/home/torvalds/v2.5/linux
parents 1776300e 5196c43d
......@@ -499,6 +499,55 @@ arp_filter - BOOLEAN
conf/{all,interface}/arp_filter is set to TRUE,
it will be disabled otherwise
arp_announce - INTEGER
Define different restriction levels for announcing the local
source IP address from IP packets in ARP requests sent on
interface:
0 - (default) Use any local address, configured on any interface
1 - Try to avoid local addresses that are not in the target's
subnet for this interface. This mode is useful when target
hosts reachable via this interface require the source IP
address in ARP requests to be part of their logical network
configured on the receiving interface. When we generate the
request we will check all our subnets that include the
target IP and will preserve the source address if it is from
such subnet. If there is no such subnet we select source
address according to the rules for level 2.
2 - Always use the best local address for this target.
In this mode we ignore the source address in the IP packet
and try to select local address that we prefer for talks with
the target host. Such local address is selected by looking
for primary IP addresses on all our subnets on the outgoing
interface that include the target IP address. If no suitable
local address is found we select the first local address
we have on the outgoing interface or on all other interfaces,
with the hope we will receive reply for our request and
even sometimes no matter the source IP address we announce.
The max value from conf/{all,interface}/arp_announce is used.
Increasing the restriction level gives more chance for
receiving answer from the resolved target while decreasing
the level announces more valid sender's information.
arp_ignore - INTEGER
Define different modes for sending replies in response to
received ARP requests that resolve local target IP addresses:
0 - (default): reply for any local target IP address, configured
on any interface
1 - reply only if the target IP address is local address
configured on the incoming interface
2 - reply only if the target IP address is local address
configured on the incoming interface and both with the
sender's IP address are part from same subnet on this interface
3 - do not reply for local addresses configured with scope host,
only resolutions for global and link addresses are replied
4-7 - reserved
8 - do not reply for all local addresses
The max value from conf/{all,interface}/arp_ignore is used
when ARP request is received on the {interface}
tag - INTEGER
Allows you to write a number, which can be used as required.
Default value is 0.
......
......@@ -1715,7 +1715,8 @@ config NET_POCKET
<file:Documentation/Changes>) and you can say N here.
Laptop users should read the Linux Laptop home page at
<http://www.linux-on-laptops.com/>.
<http://www.linux-on-laptops.com/> or
Tuxmobil - Linux on Mobile Computers at <http://www.tuxmobil.org/>.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
......
......@@ -72,8 +72,8 @@ config DMASCC
certain parameters, such as channel access timing, clock mode, and
DMA channel. This is accomplished with a small utility program,
dmascc_cfg, available at
<http://www.nt.tuwien.ac.at/~kkudielk/Linux/>. Please be sure to get
at least version 1.27 of dmascc_cfg, as older versions will not
<http://cacofonix.nt.tuwien.ac.at/~oe1kib/Linux/>. Please be sure to
get at least version 1.27 of dmascc_cfg, as older versions will not
work with the current driver.
config SCC
......@@ -96,8 +96,9 @@ config SCC_DELAY
help
Say Y here if you experience problems with the SCC driver not
working properly; please read
<file:Documentation/networking/z8530drv.txt> for details. If unsure,
say N.
<file:Documentation/networking/z8530drv.txt> for details.
If unsure, say N.
config SCC_TRXECHO
bool "support for TRX that feedback the tx signal to rx"
......@@ -105,7 +106,9 @@ config SCC_TRXECHO
help
Some transmitters feed the transmitted signal back to the receive
line. Say Y here to foil this by explicitly disabling the receiver
during data transmission. If in doubt, say Y.
during data transmission.
If in doubt, say Y.
config BAYCOM_SER_FDX
tristate "BAYCOM ser12 fullduplex driver for AX.25"
......
......@@ -269,7 +269,7 @@ config MA600_DONGLE_OLD
information, download the following tar gzip file.
There is a pre-compiled module on
<http://engsvr.ust.hk/~eetwl95/download/ma600-2.4.x.tar.gz>
<http://engsvr.ust.hk/~eetwl95/ma600.html>
config EP7211_IR
tristate "EP7211 I/R support"
......@@ -292,6 +292,22 @@ config USB_IRDA
Please note that the driver is still experimental. And of course,
you will need both USB and IrDA support in your kernel...
config SIGMATEL_FIR
tristate "SigmaTel STIr4200 bridge (EXPERIMENTAL)"
depends on IRDA && USB && EXPERIMENTAL
select CRC32
---help---
Say Y here if you want to build support for the SigmaTel STIr4200
USB IrDA FIR bridge device driver.
USB bridge based on the SigmaTel STIr4200 don't conform to the
IrDA-USB device class specification, and therefore need their
own specific driver. Those dongles support SIR and FIR (4Mbps)
speeds.
To compile it as a module, choose M here: the module will be called
stir4200.
config NSC_FIR
tristate "NSC PC87108/PC87338"
depends on IRDA && ISA
......
......@@ -9,6 +9,7 @@
obj-$(CONFIG_IRPORT_SIR) += irport.o
# FIR drivers
obj-$(CONFIG_USB_IRDA) += irda-usb.o
obj-$(CONFIG_SIGMATEL_FIR) += stir4200.o
obj-$(CONFIG_NSC_FIR) += nsc-ircc.o
obj-$(CONFIG_WINBOND_FIR) += w83977af_ir.o
obj-$(CONFIG_SA1100_FIR) += sa1100_ir.o
......
This diff is collapsed.
......@@ -173,7 +173,7 @@ struct net_device loopback_dev = {
.rebuild_header = eth_rebuild_header,
.flags = IFF_LOOPBACK,
.features = NETIF_F_SG|NETIF_F_FRAGLIST
|NETIF_F_NO_CSUM|NETIF_F_HIGHDMA|NETIF_F_TSO,
|NETIF_F_NO_CSUM|NETIF_F_HIGHDMA,
};
/* Setup and register the of the LOOPBACK device. */
......
......@@ -1961,7 +1961,6 @@ static void gem_init_hw(struct gem *gp, int restart_link)
*/
static void gem_apple_powerup(struct gem *gp)
{
u16 cmd;
u32 mif_cfg;
mb();
......
This diff is collapsed.
/*
libata-core.c - helper library for ATA
Copyright 2003-2004 Red Hat, Inc. All rights reserved.
Copyright 2003-2004 Jeff Garzik
Copyright 2003 Red Hat, Inc. All rights reserved.
Copyright 2003 Jeff Garzik
The contents of this file are subject to the Open
Software License version 1.1 that can be found at
......@@ -2385,6 +2385,41 @@ static inline unsigned int ata_host_intr (struct ata_port *ap,
return handled;
}
/**
* ata_chk_spurious_int - Check for spurious interrupts
* @ap: port to which command is being issued
*
* Examines the DMA status registers and clears
* unexpected interrupts. Created to work around
* hardware bug on Intel ICH5, but is applied to all
* chipsets using the standard irq handler, just for safety.
* If the bug is not present, this is simply a single
* PIO or MMIO read addition to the irq handler.
*
* LOCKING:
*/
static inline void ata_chk_spurious_int(struct ata_port *ap) {
int host_stat;
if (ap->flags & ATA_FLAG_MMIO) {
void *mmio = (void *) ap->ioaddr.bmdma_addr;
host_stat = readb(mmio + ATA_DMA_STATUS);
} else
host_stat = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
if ((host_stat & (ATA_DMA_INTR | ATA_DMA_ERR | ATA_DMA_ACTIVE)) == ATA_DMA_INTR) {
if (ap->flags & ATA_FLAG_MMIO) {
void *mmio = (void *) ap->ioaddr.bmdma_addr;
writeb(host_stat & ~ATA_DMA_ERR, mmio + ATA_DMA_STATUS);
} else
outb(host_stat & ~ATA_DMA_ERR, ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
DPRINTK("ata%u: Caught spurious interrupt, status 0x%X\n", ap->id, host_stat);
udelay(1);
}
}
/**
* ata_interrupt -
* @irq:
......@@ -2417,6 +2452,7 @@ irqreturn_t ata_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
qc = ata_qc_from_tag(ap, ap->active_tag);
if (qc && ((qc->flags & ATA_QCFLAG_POLL) == 0))
handled += ata_host_intr(ap, qc);
ata_chk_spurious_int(ap);
}
}
......
......@@ -1976,6 +1976,8 @@ static int __init serial8250_console_setup(struct console *co, char *options)
if (co->index >= UART_NR)
co->index = 0;
port = &serial8250_ports[co->index].port;
if (port->type == PORT_UNKNOWN)
return -ENODEV;
/*
* Temporary fix.
......@@ -2007,6 +2009,14 @@ static int __init serial8250_console_init(void)
}
console_initcall(serial8250_console_init);
static int __init serial8250_late_console_init(void)
{
if (!(serial8250_console.flags & CON_ENABLED))
register_console(&serial8250_console);
return 0;
}
late_initcall(serial8250_late_console_init);
#define SERIAL8250_CONSOLE &serial8250_console
#else
#define SERIAL8250_CONSOLE NULL
......
......@@ -1871,9 +1871,6 @@ uart_set_options(struct uart_port *port, struct console *co,
if (flow == 'r')
termios.c_cflag |= CRTSCTS;
if (!port->ops)
return 0; /* "console=" on ia64 */
port->ops->set_termios(port, &termios, NULL);
co->cflag = termios.c_cflag;
......
......@@ -18,6 +18,8 @@ struct ipv4_devconf
int mc_forwarding;
int tag;
int arp_filter;
int arp_announce;
int arp_ignore;
int medium_id;
int no_xfrm;
int no_policy;
......@@ -71,6 +73,8 @@ struct in_device
(ipv4_devconf.accept_redirects || (in_dev)->cnf.accept_redirects)))
#define IN_DEV_ARPFILTER(in_dev) (ipv4_devconf.arp_filter || (in_dev)->cnf.arp_filter)
#define IN_DEV_ARP_ANNOUNCE(in_dev) (max(ipv4_devconf.arp_announce, (in_dev)->cnf.arp_announce))
#define IN_DEV_ARP_IGNORE(in_dev) (max(ipv4_devconf.arp_ignore, (in_dev)->cnf.arp_ignore))
struct in_ifaddr
{
......@@ -97,6 +101,7 @@ extern void devinet_init(void);
extern struct in_device *inetdev_init(struct net_device *dev);
extern struct in_device *inetdev_by_index(int);
extern u32 inet_select_addr(const struct net_device *dev, u32 dst, int scope);
extern u32 inet_confirm_addr(const struct net_device *dev, u32 dst, u32 local, int scope);
extern struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, u32 prefix, u32 mask);
extern void inet_forward_change(void);
......
......@@ -136,6 +136,7 @@ struct ipv6_devconf {
__s32 rtr_solicits;
__s32 rtr_solicit_interval;
__s32 rtr_solicit_delay;
__s32 force_mld_version;
#ifdef CONFIG_IPV6_PRIVACY
__s32 use_tempaddr;
__s32 temp_valid_lft;
......@@ -165,6 +166,7 @@ enum {
DEVCONF_REGEN_MAX_RETRY,
DEVCONF_MAX_DESYNC_FACTOR,
DEVCONF_MAX_ADDRESSES,
DEVCONF_FORCE_MLD_VERSION,
DEVCONF_MAX
};
......
......@@ -24,7 +24,6 @@
#define RTF_CACHE 0x01000000 /* cache entry */
#define RTF_FLOW 0x02000000 /* flow significant route */
#define RTF_POLICY 0x04000000 /* policy route */
#define RTF_NDISC 0x08000000 /* ndisc route */
#define RTF_LOCAL 0x80000000
......
......@@ -163,6 +163,7 @@ struct skb_shared_info {
* @cb: Control buffer. Free for use by every layer. Put private vars here
* @len: Length of actual data
* @data_len: Data length
* @mac_len: Length of link layer header
* @csum: Checksum
* @__unused: Dead field, may be reused
* @cloned: Head may be cloned (check refcnt to be sure)
......@@ -204,6 +205,7 @@ struct sk_buff {
struct icmphdr *icmph;
struct igmphdr *igmph;
struct iphdr *ipiph;
struct ipv6hdr *ipv6h;
unsigned char *raw;
} h;
......@@ -232,6 +234,7 @@ struct sk_buff {
unsigned int len,
data_len,
mac_len,
csum;
unsigned char local_df,
cloned,
......
......@@ -362,6 +362,8 @@ enum
NET_IPV4_CONF_NOXFRM=15,
NET_IPV4_CONF_NOPOLICY=16,
NET_IPV4_CONF_FORCE_IGMP_VERSION=17,
NET_IPV4_CONF_ARP_ANNOUNCE=18,
NET_IPV4_CONF_ARP_IGNORE=19,
};
/* /proc/sys/net/ipv4/netfilter */
......@@ -423,7 +425,8 @@ enum {
NET_IPV6_TEMP_PREFERED_LFT=13,
NET_IPV6_REGEN_MAX_RETRY=14,
NET_IPV6_MAX_DESYNC_FACTOR=15,
NET_IPV6_MAX_ADDRESSES=16
NET_IPV6_MAX_ADDRESSES=16,
NET_IPV6_FORCE_MLD_VERSION=17
};
/* /proc/sys/net/ipv6/icmp */
......
......@@ -98,6 +98,7 @@ extern void addrconf_dad_failure(struct inet6_ifaddr *ifp);
extern int ipv6_chk_mcast_addr(struct net_device *dev, struct in6_addr *group,
struct in6_addr *src_addr);
extern int ipv6_is_mld(struct sk_buff *skb, int nexthdr);
extern void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len);
......
......@@ -64,6 +64,7 @@ extern struct rt6_info *rt6_lookup(struct in6_addr *daddr,
extern struct dst_entry *ndisc_dst_alloc(struct net_device *dev,
struct neighbour *neigh,
struct in6_addr *addr,
int (*output)(struct sk_buff *));
extern int ndisc_dst_gc(int *more);
extern void fib6_force_start_gc(void);
......
......@@ -8,7 +8,7 @@
#include <asm/types.h> /* For __uXX types */
#define IP_VS_VERSION_CODE 0x010108
#define IP_VS_VERSION_CODE 0x010200
#define NVERSION(version) \
(version >> 16) & 0xFF, \
(version >> 8) & 0xFF, \
......
......@@ -355,6 +355,7 @@ extern int ip6_dst_lookup(struct sock *sk,
*/
extern int ip6_output(struct sk_buff *skb);
extern int ip6_output2(struct sk_buff *skb);
extern int ip6_forward(struct sk_buff *skb);
extern int ip6_input(struct sk_buff *skb);
extern int ip6_mc_input(struct sk_buff *skb);
......
......@@ -1742,6 +1742,7 @@ int netif_receive_skb(struct sk_buff *skb)
#endif
skb->h.raw = skb->nh.raw = skb->data;
skb->mac_len = skb->nh.raw - skb->mac.raw;
pt_prev = NULL;
rcu_read_lock();
......
......@@ -374,7 +374,7 @@ static int ethtool_set_ringparam(struct net_device *dev, void *useraddr)
{
struct ethtool_ringparam ringparam;
if (!dev->ethtool_ops->get_ringparam)
if (!dev->ethtool_ops->set_ringparam)
return -EOPNOTSUPP;
if (copy_from_user(&ringparam, useraddr, sizeof(ringparam)))
......
......@@ -1164,8 +1164,7 @@ void neigh_table_init(struct neigh_table *tbl)
if (!tbl->kmem_cachep)
tbl->kmem_cachep = kmem_cache_create(tbl->id,
(tbl->entry_size +
15) & ~15,
tbl->entry_size,
0, SLAB_HWCACHE_ALIGN,
NULL, NULL);
tbl->lock = RW_LOCK_UNLOCKED;
......
......@@ -50,6 +50,8 @@
* Fix refcount off by one if first packet fails, potential null deref,
* memleak 030710- KJP
*
* Fixed unaligned access on IA-64 Grant Grundler <grundler@parisc-linux.org>
*
* See Documentation/networking/pktgen.txt for how to use this.
*/
......@@ -88,7 +90,7 @@
#define cycles() ((u32)get_cycles())
#define VERSION "pktgen version 1.31"
#define VERSION "pktgen version 1.32"
static char version[] __initdata =
"pktgen.c: v1.3: Packet Generator for packet performance testing.\n";
......@@ -193,7 +195,8 @@ struct pktgen_info {
struct pktgen_hdr {
__u32 pgh_magic;
__u32 seq_num;
struct timeval timestamp;
__u32 tv_sec;
__u32 tv_usec;
};
static int cpu_speed;
......@@ -563,11 +566,14 @@ static struct sk_buff *fill_packet(struct net_device *odev, struct pktgen_info*
/* Stamp the time, and sequence number, convert them to network byte order */
if (pgh) {
struct timeval timestamp;
pgh->pgh_magic = htonl(PKTGEN_MAGIC);
do_gettimeofday(&(pgh->timestamp));
pgh->timestamp.tv_usec = htonl(pgh->timestamp.tv_usec);
pgh->timestamp.tv_sec = htonl(pgh->timestamp.tv_sec);
pgh->seq_num = htonl(info->seq_num);
pgh->seq_num = htonl(info->seq_num);
do_gettimeofday(&timestamp);
pgh->tv_sec = htonl(timestamp.tv_sec);
pgh->tv_usec = htonl(timestamp.tv_usec);
}
return skb;
......
......@@ -381,7 +381,7 @@ static int dn_fib_fill_rule(struct sk_buff *skb, struct dn_fib_rule *r, struct n
nlmsg_failure:
rtattr_failure:
skb_put(skb, b - skb->tail);
skb_trim(skb, b - skb->data);
return -1;
}
......
......@@ -325,15 +325,40 @@ static void arp_error_report(struct neighbour *neigh, struct sk_buff *skb)
static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb)
{
u32 saddr;
u32 saddr = 0;
u8 *dst_ha = NULL;
struct net_device *dev = neigh->dev;
u32 target = *(u32*)neigh->primary_key;
int probes = atomic_read(&neigh->probes);
struct in_device *in_dev = in_dev_get(dev);
if (!in_dev)
return;
if (skb && inet_addr_type(skb->nh.iph->saddr) == RTN_LOCAL)
switch (IN_DEV_ARP_ANNOUNCE(in_dev)) {
default:
case 0: /* By default announce any local IP */
if (skb && inet_addr_type(skb->nh.iph->saddr) == RTN_LOCAL)
saddr = skb->nh.iph->saddr;
break;
case 1: /* Restrict announcements of saddr in same subnet */
if (!skb)
break;
saddr = skb->nh.iph->saddr;
else
if (inet_addr_type(saddr) == RTN_LOCAL) {
/* saddr should be known to target */
if (inet_addr_onlink(in_dev, target, saddr))
break;
}
saddr = 0;
break;
case 2: /* Avoid secondary IPs, get a primary/preferred one */
break;
}
if (in_dev)
in_dev_put(in_dev);
if (!saddr)
saddr = inet_select_addr(dev, target, RT_SCOPE_LINK);
if ((probes -= neigh->parms->ucast_probes) < 0) {
......@@ -354,6 +379,42 @@ static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb)
read_unlock_bh(&neigh->lock);
}
static int arp_ignore(struct in_device *in_dev, struct net_device *dev,
u32 sip, u32 tip)
{
int scope;
switch (IN_DEV_ARP_IGNORE(in_dev)) {
case 0: /* Reply, the tip is already validated */
return 0;
case 1: /* Reply only if tip is configured on the incoming interface */
sip = 0;
scope = RT_SCOPE_HOST;
break;
case 2: /*
* Reply only if tip is configured on the incoming interface
* and is in same subnet as sip
*/
scope = RT_SCOPE_HOST;
break;
case 3: /* Do not reply for scope host addresses */
sip = 0;
scope = RT_SCOPE_LINK;
dev = NULL;
break;
case 4: /* Reserved */
case 5:
case 6:
case 7:
return 0;
case 8: /* Do not reply */
return 1;
default:
return 0;
}
return !inet_confirm_addr(dev, sip, tip, scope);
}
static int arp_filter(__u32 sip, __u32 tip, struct net_device *dev)
{
struct flowi fl = { .nl_u = { .ip4_u = { .daddr = sip,
......@@ -764,7 +825,8 @@ int arp_process(struct sk_buff *skb)
/* Special case: IPv4 duplicate address detection packet (RFC2131) */
if (sip == 0) {
if (arp->ar_op == htons(ARPOP_REQUEST) &&
inet_addr_type(tip) == RTN_LOCAL)
inet_addr_type(tip) == RTN_LOCAL &&
!arp_ignore(in_dev,dev,sip,tip))
arp_send(ARPOP_REPLY,ETH_P_ARP,tip,dev,tip,sha,dev->dev_addr,dev->dev_addr);
goto out;
}
......@@ -779,7 +841,10 @@ int arp_process(struct sk_buff *skb)
n = neigh_event_ns(&arp_tbl, sha, &sip, dev);
if (n) {
int dont_send = 0;
if (IN_DEV_ARPFILTER(in_dev))
if (!dont_send)
dont_send |= arp_ignore(in_dev,dev,sip,tip);
if (!dont_send && IN_DEV_ARPFILTER(in_dev))
dont_send |= arp_filter(sip,tip,dev);
if (!dont_send)
arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,dev->dev_addr,sha);
......
......@@ -809,6 +809,84 @@ u32 inet_select_addr(const struct net_device *dev, u32 dst, int scope)
goto out;
}
static u32 confirm_addr_indev(struct in_device *in_dev, u32 dst,
u32 local, int scope)
{
int same = 0;
u32 addr = 0;
for_ifa(in_dev) {
if (!addr &&
(local == ifa->ifa_local || !local) &&
ifa->ifa_scope <= scope) {
addr = ifa->ifa_local;
if (same)
break;
}
if (!same) {
same = (!local || inet_ifa_match(local, ifa)) &&
(!dst || inet_ifa_match(dst, ifa));
if (same && addr) {
if (local || !dst)
break;
/* Is the selected addr into dst subnet? */
if (inet_ifa_match(addr, ifa))
break;
/* No, then can we use new local src? */
if (ifa->ifa_scope <= scope) {
addr = ifa->ifa_local;
break;
}
/* search for large dst subnet for addr */
same = 0;
}
}
} endfor_ifa(in_dev);
return same? addr : 0;
}
/*
* Confirm that local IP address exists using wildcards:
* - dev: only on this interface, 0=any interface
* - dst: only in the same subnet as dst, 0=any dst
* - local: address, 0=autoselect the local address
* - scope: maximum allowed scope value for the local address
*/
u32 inet_confirm_addr(const struct net_device *dev, u32 dst, u32 local, int scope)
{
u32 addr = 0;
struct in_device *in_dev;
if (dev) {
read_lock(&inetdev_lock);
if ((in_dev = __in_dev_get(dev))) {
read_lock(&in_dev->lock);
addr = confirm_addr_indev(in_dev, dst, local, scope);
read_unlock(&in_dev->lock);
}
read_unlock(&inetdev_lock);
return addr;
}
read_lock(&dev_base_lock);
read_lock(&inetdev_lock);
for (dev = dev_base; dev; dev = dev->next) {
if ((in_dev = __in_dev_get(dev))) {
read_lock(&in_dev->lock);
addr = confirm_addr_indev(in_dev, dst, local, scope);
read_unlock(&in_dev->lock);
if (addr)
break;
}
}
read_unlock(&inetdev_lock);
read_unlock(&dev_base_lock);
return addr;
}
/*
* Device notifier
*/
......@@ -1132,7 +1210,7 @@ int ipv4_doint_and_flush_strategy(ctl_table *table, int *name, int nlen,
static struct devinet_sysctl_table {
struct ctl_table_header *sysctl_header;
ctl_table devinet_vars[18];
ctl_table devinet_vars[20];
ctl_table devinet_dev[2];
ctl_table devinet_conf_dir[2];
ctl_table devinet_proto_dir[2];
......@@ -1251,6 +1329,22 @@ static struct devinet_sysctl_table {
.mode = 0644,
.proc_handler = &proc_dointvec,
},
{
.ctl_name = NET_IPV4_CONF_ARP_ANNOUNCE,
.procname = "arp_announce",
.data = &ipv4_devconf.arp_announce,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = &proc_dointvec,
},
{
.ctl_name = NET_IPV4_CONF_ARP_IGNORE,
.procname = "arp_ignore",
.data = &ipv4_devconf.arp_ignore,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = &proc_dointvec,
},
{
.ctl_name = NET_IPV4_CONF_NOXFRM,
.procname = "disable_xfrm",
......
......@@ -438,7 +438,7 @@ static __inline__ int inet_fill_rule(struct sk_buff *skb,
nlmsg_failure:
rtattr_failure:
skb_put(skb, b - skb->tail);
skb_trim(skb, b - skb->data);
return -1;
}
......
......@@ -18,8 +18,6 @@
* messages filtering.
*/
#define __KERNEL_SYSCALLS__ /* for waitpid */
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
......@@ -27,7 +25,6 @@
#include <linux/slab.h>
#include <linux/net.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/unistd.h>
#include <linux/completion.h>
......@@ -621,8 +618,6 @@ ip_vs_receive(struct socket *sock, char *buffer, const size_t buflen)
}
static int errno;
static DECLARE_WAIT_QUEUE_HEAD(sync_wait);
static pid_t sync_master_pid = 0;
static pid_t sync_backup_pid = 0;
......@@ -769,10 +764,10 @@ static int sync_thread(void *startup)
if (ip_vs_sync_state & IP_VS_STATE_MASTER && !sync_master_pid) {
state = IP_VS_STATE_MASTER;
name = "ipvs syncmaster";
name = "ipvs_syncmaster";
} else if (ip_vs_sync_state & IP_VS_STATE_BACKUP && !sync_backup_pid) {
state = IP_VS_STATE_BACKUP;
name = "ipvs syncbackup";
name = "ipvs_syncbackup";
} else {
IP_VS_BUG();
ip_vs_use_count_dec();
......@@ -830,10 +825,19 @@ static int sync_thread(void *startup)
static int fork_sync_thread(void *startup)
{
pid_t pid;
/* fork the sync thread here, then the parent process of the
sync thread is the init process after this thread exits. */
if (kernel_thread(sync_thread, startup, 0) < 0)
IP_VS_BUG();
repeat:
if ((pid = kernel_thread(sync_thread, startup, 0)) < 0) {
IP_VS_ERR("could not create sync_thread due to %d... "
"retrying.\n", pid);
current->state = TASK_UNINTERRUPTIBLE;
schedule_timeout(HZ);
goto repeat;
}
return 0;
}
......@@ -842,7 +846,6 @@ int start_sync_thread(int state, char *mcast_ifn, __u8 syncid)
{
DECLARE_COMPLETION(startup);
pid_t pid;
int waitpid_result;
if ((state == IP_VS_STATE_MASTER && sync_master_pid) ||
(state == IP_VS_STATE_BACKUP && sync_backup_pid))
......@@ -861,12 +864,13 @@ int start_sync_thread(int state, char *mcast_ifn, __u8 syncid)
ip_vs_backup_syncid = syncid;
}
if ((pid = kernel_thread(fork_sync_thread, &startup, 0)) < 0)
IP_VS_BUG();
if ((waitpid_result = waitpid(pid, NULL, __WCLONE)) != pid) {
IP_VS_ERR("%s: waitpid(%d,...) failed, errno %d\n",
__FUNCTION__, pid, -waitpid_result);
repeat:
if ((pid = kernel_thread(fork_sync_thread, &startup, 0)) < 0) {
IP_VS_ERR("could not create fork_sync_thread due to %d... "
"retrying.\n", pid);
current->state = TASK_UNINTERRUPTIBLE;
schedule_timeout(HZ);
goto repeat;
}
wait_for_completion(&startup);
......
......@@ -9,6 +9,7 @@
*
*/
#include <linux/string.h>
#include <net/inet_ecn.h>
#include <net/ip.h>
#include <net/xfrm.h>
......@@ -18,9 +19,10 @@ int xfrm4_rcv(struct sk_buff *skb)
return xfrm4_rcv_encap(skb, 0);
}
static inline void ipip_ecn_decapsulate(struct iphdr *outer_iph, struct sk_buff *skb)
static inline void ipip_ecn_decapsulate(struct sk_buff *skb)
{
struct iphdr *inner_iph = skb->nh.iph;
struct iphdr *outer_iph = skb->nh.iph;
struct iphdr *inner_iph = skb->h.ipiph;
if (INET_ECN_is_ce(outer_iph->tos) &&
INET_ECN_is_not_ce(inner_iph->tos))
......@@ -95,10 +97,16 @@ int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type)
if (x->props.mode) {
if (iph->protocol != IPPROTO_IPIP)
goto drop;
skb->nh.raw = skb->data;
if (!pskb_may_pull(skb, sizeof(struct iphdr)))
goto drop;
if (skb_cloned(skb) &&
pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
goto drop;
if (!(x->props.flags & XFRM_STATE_NOECN))
ipip_ecn_decapsulate(iph, skb);
iph = skb->nh.iph;
ipip_ecn_decapsulate(skb);
skb->mac.raw = memmove(skb->data - skb->mac_len,
skb->mac.raw, skb->mac_len);
skb->nh.raw = skb->data;
memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options));
decaps = 1;
break;
......
......@@ -149,6 +149,7 @@ struct ipv6_devconf ipv6_devconf = {
.accept_ra = 1,
.accept_redirects = 1,
.autoconf = 1,
.force_mld_version = 0,
.dad_transmits = 1,
.rtr_solicits = MAX_RTR_SOLICITATIONS,
.rtr_solicit_interval = RTR_SOLICITATION_INTERVAL,
......@@ -231,7 +232,7 @@ int ipv6_addr_type(const struct in6_addr *addr)
if ((addr->s6_addr32[0] | addr->s6_addr32[1]) == 0) {
if (addr->s6_addr32[2] == 0) {
if (addr->in6_u.u6_addr32[3] == 0)
if (addr->s6_addr32[3] == 0)
return IPV6_ADDR_ANY;
if (addr->s6_addr32[3] == htonl(0x00000001))
......@@ -1071,7 +1072,7 @@ static int ipv6_generate_eui64(u8 *eui, struct net_device *dev)
eui[0] ^= 2;
return 0;
case ARPHRD_ARCNET:
/* XXX: inherit EUI-64 fro mother interface -- yoshfuji */
/* XXX: inherit EUI-64 from other interface -- yoshfuji */
if (dev->addr_len != ARCNET_ALEN)
return -1;
memset(eui, 0, 7);
......@@ -2739,6 +2740,7 @@ static void inline ipv6_store_devconf(struct ipv6_devconf *cnf,
array[DEVCONF_RTR_SOLICITS] = cnf->rtr_solicits;
array[DEVCONF_RTR_SOLICIT_INTERVAL] = cnf->rtr_solicit_interval;
array[DEVCONF_RTR_SOLICIT_DELAY] = cnf->rtr_solicit_delay;
array[DEVCONF_FORCE_MLD_VERSION] = cnf->force_mld_version;
#ifdef CONFIG_IPV6_PRIVACY
array[DEVCONF_USE_TEMPADDR] = cnf->use_tempaddr;
array[DEVCONF_TEMP_VALID_LFT] = cnf->temp_valid_lft;
......@@ -3042,7 +3044,7 @@ static int addrconf_sysctl_forward_strategy(ctl_table *table,
static struct addrconf_sysctl_table
{
struct ctl_table_header *sysctl_header;
ctl_table addrconf_vars[17];
ctl_table addrconf_vars[18];
ctl_table addrconf_dev[2];
ctl_table addrconf_conf_dir[2];
ctl_table addrconf_proto_dir[2];
......@@ -3133,6 +3135,14 @@ static struct addrconf_sysctl_table
.proc_handler = &proc_dointvec_jiffies,
.strategy = &sysctl_jiffies,
},
{
.ctl_name = NET_IPV6_FORCE_MLD_VERSION,
.procname = "force_mld_version",
.data = &ipv6_devconf.force_mld_version,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = &proc_dointvec,
},
#ifdef CONFIG_IPV6_PRIVACY
{
.ctl_name = NET_IPV6_USE_TEMPADDR,
......
......@@ -120,7 +120,7 @@ static int ip6_parse_tlv(struct tlvtype_proc *procs, struct sk_buff *skb)
for (curr=procs; curr->type >= 0; curr++) {
if (curr->type == skb->nh.raw[off]) {
/* type specific length/alignment
checks will be perfomed in the
checks will be performed in the
func(). */
if (curr->func(skb, off) == 0)
return 0;
......
......@@ -85,7 +85,7 @@ static struct fib6_node * fib6_repair_tree(struct fib6_node *fn);
/*
* A routing update causes an increase of the serial number on the
* afected subtree. This allows for cached routes to be asynchronously
* affected subtree. This allows for cached routes to be asynchronously
* tested when modifications are made to the destination cache as a
* result of redirects, path MTU changes, etc.
*/
......
......@@ -168,11 +168,19 @@ static inline int ip6_input_finish(struct sk_buff *skb)
smp_read_barrier_depends();
if (ipprot->flags & INET6_PROTO_FINAL) {
struct ipv6hdr *hdr;
if (!cksum_sub && skb->ip_summed == CHECKSUM_HW) {
skb->csum = csum_sub(skb->csum,
csum_partial(skb->nh.raw, skb->h.raw-skb->nh.raw, 0));
cksum_sub++;
}
hdr = skb->nh.ipv6h;
if (ipv6_addr_is_multicast(&hdr->daddr) &&
!ipv6_chk_mcast_addr(skb->dev, &hdr->daddr,
&hdr->saddr) &&
!ipv6_is_mld(skb, nexthdr))
goto discard;
}
if (!(ipprot->flags & INET6_PROTO_NOPOLICY) &&
!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
......@@ -211,15 +219,14 @@ int ip6_input(struct sk_buff *skb)
int ip6_mc_input(struct sk_buff *skb)
{
struct ipv6hdr *hdr;
int deliver = 0;
int discard = 1;
struct ipv6hdr *hdr;
int deliver;
IP6_INC_STATS_BH(Ip6InMcastPkts);
hdr = skb->nh.ipv6h;
if (ipv6_chk_mcast_addr(skb->dev, &hdr->daddr, &hdr->saddr))
deliver = 1;
deliver = likely(!(skb->dev->flags & (IFF_PROMISC|IFF_ALLMULTI))) ||
ipv6_chk_mcast_addr(skb->dev, &hdr->daddr, NULL);
/*
* IPv6 multicast router mode isnt currently supported.
......@@ -238,23 +245,21 @@ int ip6_mc_input(struct sk_buff *skb)
if (deliver) {
skb2 = skb_clone(skb, GFP_ATOMIC);
dst_output(skb2);
} else {
discard = 0;
skb2 = skb;
dst_output(skb);
return 0;
}
dst_output(skb2);
}
}
#endif
if (deliver) {
discard = 0;
if (likely(deliver)) {
ip6_input(skb);
return 0;
}
if (discard)
kfree_skb(skb);
/* discard */
kfree_skb(skb);
return 0;
}
......@@ -399,7 +399,7 @@ void ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
__u16 len;
/* If the packet doesn't contain the original IPv6 header we are
in trouble since we might need the source address for furter
in trouble since we might need the source address for further
processing of the error. */
read_lock(&ip6ip6_lock);
......
......@@ -152,8 +152,10 @@ int ip6_mc_leave_src(struct sock *sk, struct ipv6_mc_socklist *iml,
#define IGMP6_UNSOLICITED_IVAL (10*HZ)
#define MLD_QRV_DEFAULT 2
#define MLD_V1_SEEN(idev) ((idev)->mc_v1_seen && \
time_before(jiffies, (idev)->mc_v1_seen))
#define MLD_V1_SEEN(idev) (ipv6_devconf.force_mld_version == 1 || \
(idev)->cnf.force_mld_version == 1 || \
((idev)->mc_v1_seen && \
time_before(jiffies, (idev)->mc_v1_seen)))
#define MLDV2_MASK(value, nb) ((nb)>=32 ? (value) : ((1<<(nb))-1) & (value))
#define MLDV2_EXP(thresh, nbmant, nbexp, value) \
......@@ -900,6 +902,33 @@ int ipv6_dev_mc_dec(struct net_device *dev, struct in6_addr *addr)
return err;
}
/*
* identify MLD packets for MLD filter exceptions
*/
int ipv6_is_mld(struct sk_buff *skb, int nexthdr)
{
struct icmp6hdr *pic;
if (nexthdr != IPPROTO_ICMPV6)
return 0;
if (!pskb_may_pull(skb, sizeof(struct icmp6hdr)))
return 0;
pic = (struct icmp6hdr *)skb->h.raw;
switch (pic->icmp6_type) {
case ICMPV6_MGM_QUERY:
case ICMPV6_MGM_REPORT:
case ICMPV6_MGM_REDUCTION:
case ICMPV6_MLD2_REPORT:
return 1;
default:
break;
}
return 0;
}
/*
* check if the interface/address pair is valid
*/
......@@ -918,7 +947,7 @@ int ipv6_chk_mcast_addr(struct net_device *dev, struct in6_addr *group,
break;
}
if (mc) {
if (!ipv6_addr_any(src_addr)) {
if (src_addr && !ipv6_addr_any(src_addr)) {
struct ip6_sf_list *psf;
spin_lock_bh(&mc->mca_lock);
......
This diff is collapsed.
......@@ -50,7 +50,7 @@ match(const struct sk_buff *skb,
eui64[0] |= 0x02;
i=0;
while ((skb->nh.ipv6h->saddr.in6_u.u6_addr8[8+i] ==
while ((skb->nh.ipv6h->saddr.s6_addr[8+i] ==
eui64[i]) && (i<8)) i++;
if ( i == 8 )
......
......@@ -222,7 +222,7 @@ static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
}
/* ipv4 addr of the socket is invalid. Only the
* unpecified and mapped address have a v4 equivalent.
* unspecified and mapped address have a v4 equivalent.
*/
v4addr = LOOPBACK4_IPV6;
if (!(addr_type & IPV6_ADDR_MULTICAST)) {
......@@ -306,7 +306,7 @@ static inline int rawv6_rcv_skb(struct sock * sk, struct sk_buff * skb)
* This is next to useless...
* if we demultiplex in network layer we don't need the extra call
* just to queue the skb...
* maybe we could have the network decide uppon a hint if it
* maybe we could have the network decide upon a hint if it
* should call raw_rcv for demultiplexing
*/
int rawv6_rcv(struct sock *sk, struct sk_buff *skb)
......@@ -627,7 +627,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
if (ipv6_addr_any(daddr)) {
/*
* unspecfied destination address
* unspecified destination address
* treated as error... is this correct ?
*/
fl6_sock_release(flowlabel);
......
......@@ -223,7 +223,7 @@ static struct rt6_info *rt6_best_dflt(struct rt6_info *rt, int oif)
match = sprt;
mpri = m;
if (m >= 12) {
/* we choose the lastest default router if it
/* we choose the last default router if it
* is in (probably) reachable state.
* If route changed, we should do pmtu
* discovery. --yoshfuji
......@@ -563,6 +563,7 @@ static struct dst_entry *ndisc_dst_gc_list;
struct dst_entry *ndisc_dst_alloc(struct net_device *dev,
struct neighbour *neigh,
struct in6_addr *addr,
int (*output)(struct sk_buff *))
{
struct rt6_info *rt = ip6_dst_alloc();
......@@ -574,11 +575,13 @@ struct dst_entry *ndisc_dst_alloc(struct net_device *dev,
dev_hold(dev);
if (neigh)
neigh_hold(neigh);
else
neigh = ndisc_get_neigh(dev, addr);
rt->rt6i_dev = dev;
rt->rt6i_nexthop = neigh;
rt->rt6i_expires = 0;
rt->rt6i_flags = RTF_LOCAL | RTF_NDISC;
rt->rt6i_flags = RTF_LOCAL;
rt->rt6i_metric = 0;
atomic_set(&rt->u.dst.__refcnt, 1);
rt->u.dst.metrics[RTAX_HOPLIMIT-1] = 255;
......@@ -832,7 +835,7 @@ int ip6_route_add(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, void *_rtattr)
}
}
rt->rt6i_flags = rtmsg->rtmsg_flags & ~RTF_NDISC;
rt->rt6i_flags = rtmsg->rtmsg_flags;
install_route:
if (rta && rta[RTA_METRICS-1]) {
......@@ -1125,8 +1128,6 @@ static struct rt6_info * ip6_rt_copy(struct rt6_info *ort)
{
struct rt6_info *rt = ip6_dst_alloc();
BUG_ON(ort->rt6i_flags & RTF_NDISC);
if (rt) {
rt->u.dst.input = ort->u.dst.input;
rt->u.dst.output = ort->u.dst.output;
......
......@@ -9,17 +9,20 @@
* IPv6 support
*/
#include <linux/string.h>
#include <net/inet_ecn.h>
#include <net/ip.h>
#include <net/ipv6.h>
#include <net/xfrm.h>
static inline void ipip6_ecn_decapsulate(struct ipv6hdr *iph,
struct sk_buff *skb)
static inline void ipip6_ecn_decapsulate(struct sk_buff *skb)
{
if (INET_ECN_is_ce(ip6_get_dsfield(iph)) &&
INET_ECN_is_not_ce(ip6_get_dsfield(skb->nh.ipv6h)))
IP6_ECN_set_ce(skb->nh.ipv6h);
struct ipv6hdr *outer_iph = skb->nh.ipv6h;
struct ipv6hdr *inner_iph = skb->h.ipv6h;
if (INET_ECN_is_ce(ip6_get_dsfield(outer_iph)) &&
INET_ECN_is_not_ce(ip6_get_dsfield(inner_iph)))
IP6_ECN_set_ce(inner_iph);
}
int xfrm6_rcv(struct sk_buff **pskb, unsigned int *nhoffp)
......@@ -77,10 +80,16 @@ int xfrm6_rcv(struct sk_buff **pskb, unsigned int *nhoffp)
if (x->props.mode) { /* XXX */
if (nexthdr != IPPROTO_IPV6)
goto drop;
skb->nh.raw = skb->data;
if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
goto drop;
if (skb_cloned(skb) &&
pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
goto drop;
if (!(x->props.flags & XFRM_STATE_NOECN))
ipip6_ecn_decapsulate(iph, skb);
iph = skb->nh.ipv6h;
ipip6_ecn_decapsulate(skb);
skb->mac.raw = memmove(skb->data - skb->mac_len,
skb->mac.raw, skb->mac_len);
skb->nh.raw = skb->data;
decaps = 1;
break;
}
......
......@@ -55,13 +55,6 @@ static struct dst_entry *
__xfrm6_find_bundle(struct flowi *fl, struct rtable *rt, struct xfrm_policy *policy)
{
struct dst_entry *dst;
u32 ndisc_bit = 0;
if (fl->proto == IPPROTO_ICMPV6 &&
(fl->fl_icmp_type == NDISC_NEIGHBOUR_ADVERTISEMENT ||
fl->fl_icmp_type == NDISC_NEIGHBOUR_SOLICITATION ||
fl->fl_icmp_type == NDISC_ROUTER_SOLICITATION))
ndisc_bit = RTF_NDISC;
/* Still not clear if we should set fl->fl6_{src,dst}... */
read_lock_bh(&policy->lock);
......@@ -69,9 +62,6 @@ __xfrm6_find_bundle(struct flowi *fl, struct rtable *rt, struct xfrm_policy *pol
struct xfrm_dst *xdst = (struct xfrm_dst*)dst;
struct in6_addr fl_dst_prefix, fl_src_prefix;
if ((xdst->u.rt6.rt6i_flags & RTF_NDISC) != ndisc_bit)
continue;
ipv6_addr_prefix(&fl_dst_prefix,
&fl->fl6_dst,
xdst->u.rt6.rt6i_dst.plen);
......@@ -169,7 +159,7 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
dst_prev->output = dst_prev->xfrm->type->output;
/* Sheit... I remember I did this right. Apparently,
* it was magically lost, so this code needs audit */
x->u.rt6.rt6i_flags = rt0->rt6i_flags&(RTCF_BROADCAST|RTCF_MULTICAST|RTCF_LOCAL|RTF_NDISC);
x->u.rt6.rt6i_flags = rt0->rt6i_flags&(RTCF_BROADCAST|RTCF_MULTICAST|RTCF_LOCAL);
x->u.rt6.rt6i_metric = rt0->rt6i_metric;
x->u.rt6.rt6i_node = rt0->rt6i_node;
x->u.rt6.rt6i_gateway = rt0->rt6i_gateway;
......
......@@ -341,6 +341,7 @@ sfq_dequeue(struct Qdisc* sch)
/* Is the slot empty? */
if (q->qs[a].qlen == 0) {
q->ht[q->hash[a]] = SFQ_DEPTH;
a = q->next[a];
if (a == old_a) {
q->tail = SFQ_DEPTH;
......
......@@ -74,13 +74,19 @@ config SCTP_HMAC_NONE
establishment. It is advised to use either HMAC-MD5 or HMAC-SHA1.
config SCTP_HMAC_SHA1
bool "HMAC-SHA1" if CRYPTO_HMAC=y && CRYPTO_SHA1=y || CRYPTO_SHA1=m
bool "HMAC-SHA1"
select CRYPTO
select CRYPTO_HMAC
select CRYPTO_SHA1
help
Enable the use of HMAC-SHA1 during association establishment. It
is advised to use either HMAC-MD5 or HMAC-SHA1.
config SCTP_HMAC_MD5
bool "HMAC-MD5" if CRYPTO_HMAC=y && CRYPTO_MD5=y || CRYPTO_MD5=m
bool "HMAC-MD5"
select CRYPTO
select CRYPTO_HMAC
select CRYPTO_MD5
help
Enable the use of HMAC-MD5 during association establishment. It is
advised to use either HMAC-MD5 or HMAC-SHA1.
......
......@@ -40,6 +40,7 @@
#include <net/sctp/sctp.h>
#include <net/sctp/sm.h>
#define MAX_KMALLOC_SIZE 131072
/* Storage size needed for map includes 2 headers and then the
* specific needs of in or out streams.
......@@ -56,11 +57,14 @@ static inline size_t sctp_ssnmap_size(__u16 in, __u16 out)
struct sctp_ssnmap *sctp_ssnmap_new(__u16 in, __u16 out, int gfp)
{
struct sctp_ssnmap *retval;
int order;
order = get_order(sctp_ssnmap_size(in,out));
retval = (struct sctp_ssnmap *)__get_free_pages(gfp, order);
int size;
size = sctp_ssnmap_size(in, out);
if (size <= MAX_KMALLOC_SIZE)
retval = kmalloc(size, gfp);
else
retval = (struct sctp_ssnmap *)
__get_free_pages(gfp, get_order(size));
if (!retval)
goto fail;
......@@ -73,7 +77,10 @@ struct sctp_ssnmap *sctp_ssnmap_new(__u16 in, __u16 out, int gfp)
return retval;
fail_map:
free_pages((unsigned long)retval, order);
if (size <= MAX_KMALLOC_SIZE)
kfree(retval);
else
free_pages((unsigned long)retval, get_order(size));
fail:
return NULL;
}
......@@ -109,9 +116,13 @@ void sctp_ssnmap_clear(struct sctp_ssnmap *map)
void sctp_ssnmap_free(struct sctp_ssnmap *map)
{
if (map && map->malloced) {
free_pages((unsigned long)map,
get_order(sctp_ssnmap_size(map->in.len,
map->out.len)));
int size;
size = sctp_ssnmap_size(map->in.len, map->out.len);
if (size <= MAX_KMALLOC_SIZE)
kfree(map);
else
free_pages((unsigned long)map, get_order(size));
SCTP_DBG_OBJCNT_DEC(ssnmap);
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment