From 38f7efd52c4f3f0b22c460eadbfe7c42f9ebff82 Mon Sep 17 00:00:00 2001 From: Faidon Liambotis Date: Tue, 21 Nov 2006 21:46:02 -0800 Subject: [NETFILTER]: H.323 conntrack: fix crash with CONFIG_IP_NF_CT_ACCT H.323 connection tracking code calls ip_ct_refresh_acct() when processing RCFs and URQs but passes NULL as the skb. When CONFIG_IP_NF_CT_ACCT is enabled, the connection tracking core tries to derefence the skb, which results in an obvious panic. A similar fix was applied on the SIP connection tracking code some time ago. Signed-off-by: Faidon Liambotis Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/ipv4/netfilter/ip_conntrack_helper_h323.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/netfilter/ip_conntrack_helper_h323.c b/net/ipv4/netfilter/ip_conntrack_helper_h323.c index 7b7441202bf..6cb9070cd0b 100644 --- a/net/ipv4/netfilter/ip_conntrack_helper_h323.c +++ b/net/ipv4/netfilter/ip_conntrack_helper_h323.c @@ -1417,7 +1417,7 @@ static int process_rcf(struct sk_buff **pskb, struct ip_conntrack *ct, DEBUGP ("ip_ct_ras: set RAS connection timeout to %u seconds\n", info->timeout); - ip_ct_refresh_acct(ct, ctinfo, NULL, info->timeout * HZ); + ip_ct_refresh(ct, *pskb, info->timeout * HZ); /* Set expect timeout */ read_lock_bh(&ip_conntrack_lock); @@ -1465,7 +1465,7 @@ static int process_urq(struct sk_buff **pskb, struct ip_conntrack *ct, info->sig_port[!dir] = 0; /* Give it 30 seconds for UCF or URJ */ - ip_ct_refresh_acct(ct, ctinfo, NULL, 30 * HZ); + ip_ct_refresh(ct, *pskb, 30 * HZ); return 0; } -- cgit v1.2.3 From 753eab76a3337863a0d86ce045fa4eb6c3cbeef9 Mon Sep 17 00:00:00 2001 From: Olaf Kirch Date: Wed, 22 Nov 2006 20:11:42 -0800 Subject: [UDP]: Make udp_encap_rcv use pskb_may_pull Make udp_encap_rcv use pskb_may_pull IPsec with NAT-T breaks on some notebooks using the latest e1000 chipset, when header split is enabled. When receiving sufficiently large packets, the driver puts everything up to and including the UDP header into the header portion of the skb, and the rest goes into the paged part. udp_encap_rcv forgets to use pskb_may_pull, and fails to decapsulate it. Instead, it passes it up it to the IKE daemon. Signed-off-by: Olaf Kirch Signed-off-by: Jean Delvare Signed-off-by: David S. Miller --- net/ipv4/udp.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 865d75214a9..9e1bd374875 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -928,23 +928,32 @@ static int udp_encap_rcv(struct sock * sk, struct sk_buff *skb) return 1; #else struct udp_sock *up = udp_sk(sk); - struct udphdr *uh = skb->h.uh; + struct udphdr *uh; struct iphdr *iph; int iphlen, len; - __u8 *udpdata = (__u8 *)uh + sizeof(struct udphdr); - __be32 *udpdata32 = (__be32 *)udpdata; + __u8 *udpdata; + __be32 *udpdata32; __u16 encap_type = up->encap_type; /* if we're overly short, let UDP handle it */ - if (udpdata > skb->tail) + len = skb->len - sizeof(struct udphdr); + if (len <= 0) return 1; /* if this is not encapsulated socket, then just return now */ if (!encap_type) return 1; - len = skb->tail - udpdata; + /* If this is a paged skb, make sure we pull up + * whatever data we need to look at. */ + if (!pskb_may_pull(skb, sizeof(struct udphdr) + min(len, 8))) + return 1; + + /* Now we can get the pointers */ + uh = skb->h.uh; + udpdata = (__u8 *)uh + sizeof(struct udphdr); + udpdata32 = (__be32 *)udpdata; switch (encap_type) { default: -- cgit v1.2.3 From ac16ca6412d9feb5b2f8fc76a4ed938b5d107f94 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Wed, 22 Nov 2006 20:26:11 -0800 Subject: [NET]: Fix kfifo_alloc() error check. The return value of kfifo_alloc() should be checked by IS_ERR(). Signed-off-by: Akinobu Mita Signed-off-by: David S. Miller --- net/ipv4/tcp_probe.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'net/ipv4') diff --git a/net/ipv4/tcp_probe.c b/net/ipv4/tcp_probe.c index 4be336f1788..f230eeecf09 100644 --- a/net/ipv4/tcp_probe.c +++ b/net/ipv4/tcp_probe.c @@ -156,6 +156,8 @@ static __init int tcpprobe_init(void) init_waitqueue_head(&tcpw.wait); spin_lock_init(&tcpw.lock); tcpw.fifo = kfifo_alloc(bufsize, GFP_KERNEL, &tcpw.lock); + if (IS_ERR(tcpw.fifo)) + return PTR_ERR(tcpw.fifo); if (!proc_net_fops_create(procname, S_IRUSR, &tcpprobe_fops)) goto err0; -- cgit v1.2.3 From c537b75a3ba9f5d2569f313742cd379dff6ceb70 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Mon, 27 Nov 2006 10:26:25 -0800 Subject: [NETFILTER]: ctnetlink: fix reference count leak When NFA_NEST exceeds the skb size the protocol reference is leaked. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/ipv4/netfilter/ip_conntrack_netlink.c | 1 + 1 file changed, 1 insertion(+) (limited to 'net/ipv4') diff --git a/net/ipv4/netfilter/ip_conntrack_netlink.c b/net/ipv4/netfilter/ip_conntrack_netlink.c index 262d0d44ec1..55f0ae64108 100644 --- a/net/ipv4/netfilter/ip_conntrack_netlink.c +++ b/net/ipv4/netfilter/ip_conntrack_netlink.c @@ -153,6 +153,7 @@ ctnetlink_dump_protoinfo(struct sk_buff *skb, const struct ip_conntrack *ct) return ret; nfattr_failure: + ip_conntrack_proto_put(proto); return -1; } -- cgit v1.2.3 From 2e47c264a2e6ea24c27b4987607222202818c1f4 Mon Sep 17 00:00:00 2001 From: Yasuyuki Kozakai Date: Mon, 27 Nov 2006 10:26:46 -0800 Subject: [NETFILTER]: conntrack: fix refcount leak when finding expectation All users of __{ip,nf}_conntrack_expect_find() don't expect that it increments the reference count of expectation. Signed-off-by: Yasuyuki Kozakai Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/ipv4/netfilter/ip_conntrack_core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/netfilter/ip_conntrack_core.c b/net/ipv4/netfilter/ip_conntrack_core.c index 143c4668538..8b848aa77bf 100644 --- a/net/ipv4/netfilter/ip_conntrack_core.c +++ b/net/ipv4/netfilter/ip_conntrack_core.c @@ -225,10 +225,8 @@ __ip_conntrack_expect_find(const struct ip_conntrack_tuple *tuple) struct ip_conntrack_expect *i; list_for_each_entry(i, &ip_conntrack_expect_list, list) { - if (ip_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask)) { - atomic_inc(&i->use); + if (ip_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask)) return i; - } } return NULL; } @@ -241,6 +239,8 @@ ip_conntrack_expect_find(const struct ip_conntrack_tuple *tuple) read_lock_bh(&ip_conntrack_lock); i = __ip_conntrack_expect_find(tuple); + if (i) + atomic_inc(&i->use); read_unlock_bh(&ip_conntrack_lock); return i; -- cgit v1.2.3 From af443b6d90de17f7630621269cf0610d9d772670 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 28 Nov 2006 20:10:21 -0800 Subject: [NETFILTER]: ipt_REJECT: fix memory corruption On devices with hard_header_len > LL_MAX_HEADER ip_route_me_harder() reallocates the skb, leading to memory corruption when using the stale tcph pointer to update the checksum. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/ipv4/netfilter/ipt_REJECT.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c index ad0312d0e4f..264763adc39 100644 --- a/net/ipv4/netfilter/ipt_REJECT.c +++ b/net/ipv4/netfilter/ipt_REJECT.c @@ -114,6 +114,14 @@ static void send_reset(struct sk_buff *oldskb, int hook) tcph->window = 0; tcph->urg_ptr = 0; + /* Adjust TCP checksum */ + tcph->check = 0; + tcph->check = tcp_v4_check(tcph, sizeof(struct tcphdr), + nskb->nh.iph->saddr, + nskb->nh.iph->daddr, + csum_partial((char *)tcph, + sizeof(struct tcphdr), 0)); + /* Set DF, id = 0 */ nskb->nh.iph->frag_off = htons(IP_DF); nskb->nh.iph->id = 0; @@ -129,14 +137,8 @@ static void send_reset(struct sk_buff *oldskb, int hook) if (ip_route_me_harder(&nskb, addr_type)) goto free_nskb; - /* Adjust TCP checksum */ nskb->ip_summed = CHECKSUM_NONE; - tcph->check = 0; - tcph->check = tcp_v4_check(tcph, sizeof(struct tcphdr), - nskb->nh.iph->saddr, - nskb->nh.iph->daddr, - csum_partial((char *)tcph, - sizeof(struct tcphdr), 0)); + /* Adjust IP TTL */ nskb->nh.iph->ttl = dst_metric(nskb->dst, RTAX_HOPLIMIT); -- cgit v1.2.3 From 5a874db4d9bfd8a4c6324d844a4d1c7cfa5cf2c4 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 8 Nov 2006 00:19:38 -0800 Subject: [NET]: ipconfig and nfsroot annotations Signed-off-by: Al Viro Signed-off-by: David S. Miller --- net/ipv4/ipconfig.c | 105 ++++++++++++++++++++++++++-------------------------- 1 file changed, 53 insertions(+), 52 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index 955a07abb91..afa60b9a003 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c @@ -101,6 +101,7 @@ #define CONF_NAMESERVERS_MAX 3 /* Maximum number of nameservers - '3' from resolv.h */ +#define NONE __constant_htonl(INADDR_NONE) /* * Public IP configuration @@ -129,19 +130,19 @@ int ic_proto_enabled __initdata = 0 static int ic_host_name_set __initdata = 0; /* Host name set by us? */ -u32 ic_myaddr = INADDR_NONE; /* My IP address */ -static u32 ic_netmask = INADDR_NONE; /* Netmask for local subnet */ -u32 ic_gateway = INADDR_NONE; /* Gateway IP address */ +__be32 ic_myaddr = NONE; /* My IP address */ +static __be32 ic_netmask = NONE; /* Netmask for local subnet */ +__be32 ic_gateway = NONE; /* Gateway IP address */ -u32 ic_servaddr = INADDR_NONE; /* Boot server IP address */ +__be32 ic_servaddr = NONE; /* Boot server IP address */ -u32 root_server_addr = INADDR_NONE; /* Address of NFS server */ +__be32 root_server_addr = NONE; /* Address of NFS server */ u8 root_server_path[256] = { 0, }; /* Path to mount as root */ /* Persistent data: */ static int ic_proto_used; /* Protocol used, if any */ -static u32 ic_nameservers[CONF_NAMESERVERS_MAX]; /* DNS Server IP addresses */ +static __be32 ic_nameservers[CONF_NAMESERVERS_MAX]; /* DNS Server IP addresses */ static u8 ic_domain[64]; /* DNS (not NIS) domain name */ /* @@ -172,7 +173,7 @@ struct ic_device { struct net_device *dev; unsigned short flags; short able; - u32 xid; + __be32 xid; }; static struct ic_device *ic_first_dev __initdata = NULL;/* List of open device */ @@ -223,7 +224,7 @@ static int __init ic_open_devs(void) d->flags = oflags; d->able = able; if (able & IC_BOOTP) - get_random_bytes(&d->xid, sizeof(u32)); + get_random_bytes(&d->xid, sizeof(__be32)); else d->xid = 0; ic_proto_have_if |= able; @@ -269,7 +270,7 @@ static void __init ic_close_devs(void) */ static inline void -set_sockaddr(struct sockaddr_in *sin, u32 addr, u16 port) +set_sockaddr(struct sockaddr_in *sin, __be32 addr, __be16 port) { sin->sin_family = AF_INET; sin->sin_addr.s_addr = addr; @@ -332,7 +333,7 @@ static int __init ic_setup_routes(void) { /* No need to setup device routes, only the default route... */ - if (ic_gateway != INADDR_NONE) { + if (ic_gateway != NONE) { struct rtentry rm; int err; @@ -368,10 +369,10 @@ static int __init ic_defaults(void) if (!ic_host_name_set) sprintf(init_utsname()->nodename, "%u.%u.%u.%u", NIPQUAD(ic_myaddr)); - if (root_server_addr == INADDR_NONE) + if (root_server_addr == NONE) root_server_addr = ic_servaddr; - if (ic_netmask == INADDR_NONE) { + if (ic_netmask == NONE) { if (IN_CLASSA(ntohl(ic_myaddr))) ic_netmask = htonl(IN_CLASSA_NET); else if (IN_CLASSB(ntohl(ic_myaddr))) @@ -420,7 +421,7 @@ ic_rarp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt { struct arphdr *rarp; unsigned char *rarp_ptr; - u32 sip, tip; + __be32 sip, tip; unsigned char *sha, *tha; /* s for "source", t for "target" */ struct ic_device *d; @@ -485,12 +486,12 @@ ic_rarp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt goto drop_unlock; /* Discard packets which are not from specified server. */ - if (ic_servaddr != INADDR_NONE && ic_servaddr != sip) + if (ic_servaddr != NONE && ic_servaddr != sip) goto drop_unlock; /* We have a winner! */ ic_dev = dev; - if (ic_myaddr == INADDR_NONE) + if (ic_myaddr == NONE) ic_myaddr = tip; ic_servaddr = sip; ic_got_reply = IC_RARP; @@ -530,13 +531,13 @@ struct bootp_pkt { /* BOOTP packet format */ u8 htype; /* HW address type */ u8 hlen; /* HW address length */ u8 hops; /* Used only by gateways */ - u32 xid; /* Transaction ID */ - u16 secs; /* Seconds since we started */ - u16 flags; /* Just what it says */ - u32 client_ip; /* Client's IP address if known */ - u32 your_ip; /* Assigned IP address */ - u32 server_ip; /* (Next, e.g. NFS) Server's IP address */ - u32 relay_ip; /* IP address of BOOTP relay */ + __be32 xid; /* Transaction ID */ + __be16 secs; /* Seconds since we started */ + __be16 flags; /* Just what it says */ + __be32 client_ip; /* Client's IP address if known */ + __be32 your_ip; /* Assigned IP address */ + __be32 server_ip; /* (Next, e.g. NFS) Server's IP address */ + __be32 relay_ip; /* IP address of BOOTP relay */ u8 hw_addr[16]; /* Client's HW address */ u8 serv_name[64]; /* Server host name */ u8 boot_file[128]; /* Name of boot file */ @@ -576,7 +577,7 @@ static const u8 ic_bootp_cookie[4] = { 99, 130, 83, 99 }; static void __init ic_dhcp_init_options(u8 *options) { - u8 mt = ((ic_servaddr == INADDR_NONE) + u8 mt = ((ic_servaddr == NONE) ? DHCPDISCOVER : DHCPREQUEST); u8 *e = options; @@ -666,7 +667,7 @@ static inline void ic_bootp_init(void) int i; for (i = 0; i < CONF_NAMESERVERS_MAX; i++) - ic_nameservers[i] = INADDR_NONE; + ic_nameservers[i] = NONE; dev_add_pack(&bootp_packet_type); } @@ -708,7 +709,7 @@ static void __init ic_bootp_send_if(struct ic_device *d, unsigned long jiffies_d h->frag_off = htons(IP_DF); h->ttl = 64; h->protocol = IPPROTO_UDP; - h->daddr = INADDR_BROADCAST; + h->daddr = htonl(INADDR_BROADCAST); h->check = ip_fast_csum((unsigned char *) h, h->ihl); /* Construct UDP header */ @@ -730,8 +731,8 @@ static void __init ic_bootp_send_if(struct ic_device *d, unsigned long jiffies_d b->htype = dev->type; /* can cause undefined behavior */ } b->hlen = dev->addr_len; - b->your_ip = INADDR_NONE; - b->server_ip = INADDR_NONE; + b->your_ip = NONE; + b->server_ip = NONE; memcpy(b->hw_addr, dev->dev_addr, dev->addr_len); b->secs = htons(jiffies_diff / HZ); b->xid = d->xid; @@ -788,11 +789,11 @@ static void __init ic_do_bootp_ext(u8 *ext) switch (*ext++) { case 1: /* Subnet mask */ - if (ic_netmask == INADDR_NONE) + if (ic_netmask == NONE) memcpy(&ic_netmask, ext+1, 4); break; case 3: /* Default gateway */ - if (ic_gateway == INADDR_NONE) + if (ic_gateway == NONE) memcpy(&ic_gateway, ext+1, 4); break; case 6: /* DNS server */ @@ -800,7 +801,7 @@ static void __init ic_do_bootp_ext(u8 *ext) if (servers > CONF_NAMESERVERS_MAX) servers = CONF_NAMESERVERS_MAX; for (i = 0; i < servers; i++) { - if (ic_nameservers[i] == INADDR_NONE) + if (ic_nameservers[i] == NONE) memcpy(&ic_nameservers[i], ext+1+4*i, 4); } break; @@ -917,7 +918,7 @@ static int __init ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, str #ifdef IPCONFIG_DHCP if (ic_proto_enabled & IC_USE_DHCP) { - u32 server_id = INADDR_NONE; + __be32 server_id = NONE; int mt = 0; ext = &b->exten[4]; @@ -949,7 +950,7 @@ static int __init ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, str /* While in the process of accepting one offer, * ignore all others. */ - if (ic_myaddr != INADDR_NONE) + if (ic_myaddr != NONE) goto drop_unlock; /* Let's accept that offer. */ @@ -965,7 +966,7 @@ static int __init ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, str * precedence over the bootp header one if * they are different. */ - if ((server_id != INADDR_NONE) && + if ((server_id != NONE) && (b->server_ip != server_id)) b->server_ip = ic_servaddr; break; @@ -979,8 +980,8 @@ static int __init ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, str default: /* Urque. Forget it*/ - ic_myaddr = INADDR_NONE; - ic_servaddr = INADDR_NONE; + ic_myaddr = NONE; + ic_servaddr = NONE; goto drop_unlock; }; @@ -1004,9 +1005,9 @@ static int __init ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, str ic_dev = dev; ic_myaddr = b->your_ip; ic_servaddr = b->server_ip; - if (ic_gateway == INADDR_NONE && b->relay_ip) + if (ic_gateway == NONE && b->relay_ip) ic_gateway = b->relay_ip; - if (ic_nameservers[0] == INADDR_NONE) + if (ic_nameservers[0] == NONE) ic_nameservers[0] = ic_servaddr; ic_got_reply = IC_BOOTP; @@ -1150,7 +1151,7 @@ static int __init ic_dynamic(void) #endif if (!ic_got_reply) { - ic_myaddr = INADDR_NONE; + ic_myaddr = NONE; return -1; } @@ -1182,12 +1183,12 @@ static int pnp_seq_show(struct seq_file *seq, void *v) seq_printf(seq, "domain %s\n", ic_domain); for (i = 0; i < CONF_NAMESERVERS_MAX; i++) { - if (ic_nameservers[i] != INADDR_NONE) + if (ic_nameservers[i] != NONE) seq_printf(seq, "nameserver %u.%u.%u.%u\n", NIPQUAD(ic_nameservers[i])); } - if (ic_servaddr != INADDR_NONE) + if (ic_servaddr != NONE) seq_printf(seq, "bootserver %u.%u.%u.%u\n", NIPQUAD(ic_servaddr)); @@ -1213,9 +1214,9 @@ static struct file_operations pnp_seq_fops = { * need to have root_server_addr set _before_ IPConfig gets called as it * can override it. */ -u32 __init root_nfs_parse_addr(char *name) +__be32 __init root_nfs_parse_addr(char *name) { - u32 addr; + __be32 addr; int octets = 0; char *cp, *cq; @@ -1237,7 +1238,7 @@ u32 __init root_nfs_parse_addr(char *name) addr = in_aton(name); memmove(name, cp, strlen(cp) + 1); } else - addr = INADDR_NONE; + addr = NONE; return addr; } @@ -1248,7 +1249,7 @@ u32 __init root_nfs_parse_addr(char *name) static int __init ip_auto_config(void) { - u32 addr; + __be32 addr; #ifdef CONFIG_PROC_FS proc_net_fops_create("pnp", S_IRUGO, &pnp_seq_fops); @@ -1277,11 +1278,11 @@ static int __init ip_auto_config(void) * interfaces and no default was set), use BOOTP or RARP to get the * missing values. */ - if (ic_myaddr == INADDR_NONE || + if (ic_myaddr == NONE || #ifdef CONFIG_ROOT_NFS (MAJOR(ROOT_DEV) == UNNAMED_MAJOR - && root_server_addr == INADDR_NONE - && ic_servaddr == INADDR_NONE) || + && root_server_addr == NONE + && ic_servaddr == NONE) || #endif ic_first_dev->next) { #ifdef IPCONFIG_DYNAMIC @@ -1334,7 +1335,7 @@ static int __init ip_auto_config(void) } addr = root_nfs_parse_addr(root_server_path); - if (root_server_addr == INADDR_NONE) + if (root_server_addr == NONE) root_server_addr = addr; /* @@ -1461,19 +1462,19 @@ static int __init ip_auto_config_setup(char *addrs) switch (num) { case 0: if ((ic_myaddr = in_aton(ip)) == INADDR_ANY) - ic_myaddr = INADDR_NONE; + ic_myaddr = NONE; break; case 1: if ((ic_servaddr = in_aton(ip)) == INADDR_ANY) - ic_servaddr = INADDR_NONE; + ic_servaddr = NONE; break; case 2: if ((ic_gateway = in_aton(ip)) == INADDR_ANY) - ic_gateway = INADDR_NONE; + ic_gateway = NONE; break; case 3: if ((ic_netmask = in_aton(ip)) == INADDR_ANY) - ic_netmask = INADDR_NONE; + ic_netmask = NONE; break; case 4: if ((dp = strchr(ip, '.'))) { -- cgit v1.2.3 From 8c689a6eae2d83970e4f34753d513e96fb97a025 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 8 Nov 2006 00:20:21 -0800 Subject: [XFRM]: misc annotations Signed-off-by: Al Viro Signed-off-by: David S. Miller --- net/ipv4/xfrm4_policy.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c index 1bed0cdf53e..da766234607 100644 --- a/net/ipv4/xfrm4_policy.c +++ b/net/ipv4/xfrm4_policy.c @@ -72,8 +72,8 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int struct dst_entry *dst, *dst_prev; struct rtable *rt0 = (struct rtable*)(*dst_p); struct rtable *rt = rt0; - u32 remote = fl->fl4_dst; - u32 local = fl->fl4_src; + __be32 remote = fl->fl4_dst; + __be32 local = fl->fl4_src; struct flowi fl_tunnel = { .nl_u = { .ip4_u = { @@ -203,7 +203,7 @@ _decode_session4(struct sk_buff *skb, struct flowi *fl) case IPPROTO_SCTP: case IPPROTO_DCCP: if (pskb_may_pull(skb, xprth + 4 - skb->data)) { - u16 *ports = (u16 *)xprth; + __be16 *ports = (__be16 *)xprth; fl->fl_ip_sport = ports[0]; fl->fl_ip_dport = ports[1]; -- cgit v1.2.3 From d5a0a1e3109339090769e40fdaa62482fcf2a717 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 8 Nov 2006 00:23:14 -0800 Subject: [IPV4]: encapsulation annotations Signed-off-by: Al Viro Signed-off-by: David S. Miller --- net/ipv4/ah4.c | 4 ++-- net/ipv4/esp4.c | 4 ++-- net/ipv4/ip_gre.c | 52 ++++++++++++++++++++++++++-------------------------- net/ipv4/ipip.c | 16 ++++++++-------- 4 files changed, 38 insertions(+), 38 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c index 99542977e47..67a5509e26f 100644 --- a/net/ipv4/ah4.c +++ b/net/ipv4/ah4.c @@ -14,7 +14,7 @@ * into IP header for icv calculation. Options are already checked * for validity, so paranoia is not required. */ -static int ip_clear_mutable_options(struct iphdr *iph, u32 *daddr) +static int ip_clear_mutable_options(struct iphdr *iph, __be32 *daddr) { unsigned char * optptr = (unsigned char*)(iph+1); int l = iph->ihl*4 - sizeof(struct iphdr); @@ -162,7 +162,7 @@ static int ah_input(struct xfrm_state *x, struct sk_buff *skb) iph->frag_off = 0; iph->check = 0; if (ihl > sizeof(*iph)) { - u32 dummy; + __be32 dummy; if (ip_clear_mutable_options(iph, &dummy)) goto out; } diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c index b5c205b5766..f2c6776ea0e 100644 --- a/net/ipv4/esp4.c +++ b/net/ipv4/esp4.c @@ -67,7 +67,7 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb) if (x->encap) { struct xfrm_encap_tmpl *encap = x->encap; struct udphdr *uh; - u32 *udpdata32; + __be32 *udpdata32; uh = (struct udphdr *)esph; uh->source = encap->encap_sport; @@ -81,7 +81,7 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb) esph = (struct ip_esp_hdr *)(uh + 1); break; case UDP_ENCAP_ESPINUDP_NON_IKE: - udpdata32 = (u32 *)(uh + 1); + udpdata32 = (__be32 *)(uh + 1); udpdata32[0] = udpdata32[1] = 0; esph = (struct ip_esp_hdr *)(udpdata32 + 2); break; diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index d5b5dec075b..25221146deb 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -144,7 +144,7 @@ static struct net_device *ipgre_fb_tunnel_dev; */ #define HASH_SIZE 16 -#define HASH(addr) ((addr^(addr>>4))&0xF) +#define HASH(addr) (((__force u32)addr^((__force u32)addr>>4))&0xF) static struct ip_tunnel *tunnels[4][HASH_SIZE]; @@ -157,7 +157,7 @@ static DEFINE_RWLOCK(ipgre_lock); /* Given src, dst and key, find appropriate for input tunnel. */ -static struct ip_tunnel * ipgre_tunnel_lookup(u32 remote, u32 local, u32 key) +static struct ip_tunnel * ipgre_tunnel_lookup(__be32 remote, __be32 local, __be32 key) { unsigned h0 = HASH(remote); unsigned h1 = HASH(key); @@ -194,9 +194,9 @@ static struct ip_tunnel * ipgre_tunnel_lookup(u32 remote, u32 local, u32 key) static struct ip_tunnel **ipgre_bucket(struct ip_tunnel *t) { - u32 remote = t->parms.iph.daddr; - u32 local = t->parms.iph.saddr; - u32 key = t->parms.i_key; + __be32 remote = t->parms.iph.daddr; + __be32 local = t->parms.iph.saddr; + __be32 key = t->parms.i_key; unsigned h = HASH(key); int prio = 0; @@ -236,9 +236,9 @@ static void ipgre_tunnel_unlink(struct ip_tunnel *t) static struct ip_tunnel * ipgre_tunnel_locate(struct ip_tunnel_parm *parms, int create) { - u32 remote = parms->iph.daddr; - u32 local = parms->iph.saddr; - u32 key = parms->i_key; + __be32 remote = parms->iph.daddr; + __be32 local = parms->iph.saddr; + __be32 key = parms->i_key; struct ip_tunnel *t, **tp, *nt; struct net_device *dev; unsigned h = HASH(key); @@ -319,12 +319,12 @@ static void ipgre_err(struct sk_buff *skb, u32 info) */ struct iphdr *iph = (struct iphdr*)skb->data; - u16 *p = (u16*)(skb->data+(iph->ihl<<2)); + __be16 *p = (__be16*)(skb->data+(iph->ihl<<2)); int grehlen = (iph->ihl<<2) + 4; int type = skb->h.icmph->type; int code = skb->h.icmph->code; struct ip_tunnel *t; - u16 flags; + __be16 flags; flags = p[0]; if (flags&(GRE_CSUM|GRE_KEY|GRE_SEQ|GRE_ROUTING|GRE_VERSION)) { @@ -370,7 +370,7 @@ static void ipgre_err(struct sk_buff *skb, u32 info) } read_lock(&ipgre_lock); - t = ipgre_tunnel_lookup(iph->daddr, iph->saddr, (flags&GRE_KEY) ? *(((u32*)p) + (grehlen>>2) - 1) : 0); + t = ipgre_tunnel_lookup(iph->daddr, iph->saddr, (flags&GRE_KEY) ? *(((__be32*)p) + (grehlen>>2) - 1) : 0); if (t == NULL || t->parms.iph.daddr == 0 || MULTICAST(t->parms.iph.daddr)) goto out; @@ -388,14 +388,14 @@ out: #else struct iphdr *iph = (struct iphdr*)dp; struct iphdr *eiph; - u16 *p = (u16*)(dp+(iph->ihl<<2)); + __be16 *p = (__be16*)(dp+(iph->ihl<<2)); int type = skb->h.icmph->type; int code = skb->h.icmph->code; int rel_type = 0; int rel_code = 0; __be32 rel_info = 0; __u32 n = 0; - u16 flags; + __be16 flags; int grehlen = (iph->ihl<<2) + 4; struct sk_buff *skb2; struct flowi fl; @@ -556,9 +556,9 @@ static int ipgre_rcv(struct sk_buff *skb) { struct iphdr *iph; u8 *h; - u16 flags; + __be16 flags; u16 csum = 0; - u32 key = 0; + __be32 key = 0; u32 seqno = 0; struct ip_tunnel *tunnel; int offset = 4; @@ -568,7 +568,7 @@ static int ipgre_rcv(struct sk_buff *skb) iph = skb->nh.iph; h = skb->data; - flags = *(u16*)h; + flags = *(__be16*)h; if (flags&(GRE_CSUM|GRE_KEY|GRE_ROUTING|GRE_SEQ|GRE_VERSION)) { /* - Version must be 0. @@ -592,11 +592,11 @@ static int ipgre_rcv(struct sk_buff *skb) offset += 4; } if (flags&GRE_KEY) { - key = *(u32*)(h + offset); + key = *(__be32*)(h + offset); offset += 4; } if (flags&GRE_SEQ) { - seqno = ntohl(*(u32*)(h + offset)); + seqno = ntohl(*(__be32*)(h + offset)); offset += 4; } } @@ -605,7 +605,7 @@ static int ipgre_rcv(struct sk_buff *skb) if ((tunnel = ipgre_tunnel_lookup(iph->saddr, iph->daddr, key)) != NULL) { secpath_reset(skb); - skb->protocol = *(u16*)(h + 2); + skb->protocol = *(__be16*)(h + 2); /* WCCP version 1 and 2 protocol decoding. * - Change protocol to IP * - When dealing with WCCPv2, Skip extra 4 bytes in GRE header @@ -673,13 +673,13 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) struct iphdr *old_iph = skb->nh.iph; struct iphdr *tiph; u8 tos; - u16 df; + __be16 df; struct rtable *rt; /* Route to the other host */ struct net_device *tdev; /* Device to other host */ struct iphdr *iph; /* Our new IP header */ int max_headroom; /* The extra header space needed */ int gre_hlen; - u32 dst; + __be32 dst; int mtu; if (tunnel->recursion++) { @@ -860,11 +860,11 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) iph->ttl = dst_metric(&rt->u.dst, RTAX_HOPLIMIT); } - ((u16*)(iph+1))[0] = tunnel->parms.o_flags; - ((u16*)(iph+1))[1] = skb->protocol; + ((__be16*)(iph+1))[0] = tunnel->parms.o_flags; + ((__be16*)(iph+1))[1] = skb->protocol; if (tunnel->parms.o_flags&(GRE_KEY|GRE_CSUM|GRE_SEQ)) { - u32 *ptr = (u32*)(((u8*)iph) + tunnel->hlen - 4); + __be32 *ptr = (__be32*)(((u8*)iph) + tunnel->hlen - 4); if (tunnel->parms.o_flags&GRE_SEQ) { ++tunnel->o_seqno; @@ -877,7 +877,7 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) } if (tunnel->parms.o_flags&GRE_CSUM) { *ptr = 0; - *(__u16*)ptr = ip_compute_csum((void*)(iph+1), skb->len - sizeof(struct iphdr)); + *(__be16*)ptr = ip_compute_csum((void*)(iph+1), skb->len - sizeof(struct iphdr)); } } @@ -1068,7 +1068,7 @@ static int ipgre_header(struct sk_buff *skb, struct net_device *dev, unsigned sh { struct ip_tunnel *t = netdev_priv(dev); struct iphdr *iph = (struct iphdr *)skb_push(skb, t->hlen); - u16 *p = (u16*)(iph+1); + __be16 *p = (__be16*)(iph+1); memcpy(iph, &t->parms.iph, sizeof(struct iphdr)); p[0] = t->parms.o_flags; diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index 0c455652922..9d719d664e5 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -118,7 +118,7 @@ #include #define HASH_SIZE 16 -#define HASH(addr) ((addr^(addr>>4))&0xF) +#define HASH(addr) (((__force u32)addr^((__force u32)addr>>4))&0xF) static int ipip_fb_tunnel_init(struct net_device *dev); static int ipip_tunnel_init(struct net_device *dev); @@ -134,7 +134,7 @@ static struct ip_tunnel **tunnels[4] = { tunnels_wc, tunnels_l, tunnels_r, tunne static DEFINE_RWLOCK(ipip_lock); -static struct ip_tunnel * ipip_tunnel_lookup(u32 remote, u32 local) +static struct ip_tunnel * ipip_tunnel_lookup(__be32 remote, __be32 local) { unsigned h0 = HASH(remote); unsigned h1 = HASH(local); @@ -160,8 +160,8 @@ static struct ip_tunnel * ipip_tunnel_lookup(u32 remote, u32 local) static struct ip_tunnel **ipip_bucket(struct ip_tunnel *t) { - u32 remote = t->parms.iph.daddr; - u32 local = t->parms.iph.saddr; + __be32 remote = t->parms.iph.daddr; + __be32 local = t->parms.iph.saddr; unsigned h = 0; int prio = 0; @@ -203,8 +203,8 @@ static void ipip_tunnel_link(struct ip_tunnel *t) static struct ip_tunnel * ipip_tunnel_locate(struct ip_tunnel_parm *parms, int create) { - u32 remote = parms->iph.daddr; - u32 local = parms->iph.saddr; + __be32 remote = parms->iph.daddr; + __be32 local = parms->iph.saddr; struct ip_tunnel *t, **tp, *nt; struct net_device *dev; unsigned h = 0; @@ -519,13 +519,13 @@ static int ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) struct net_device_stats *stats = &tunnel->stat; struct iphdr *tiph = &tunnel->parms.iph; u8 tos = tunnel->parms.iph.tos; - u16 df = tiph->frag_off; + __be16 df = tiph->frag_off; struct rtable *rt; /* Route to the other host */ struct net_device *tdev; /* Device to other host */ struct iphdr *old_iph = skb->nh.iph; struct iphdr *iph; /* Our new IP header */ int max_headroom; /* The extra header space needed */ - u32 dst = tiph->daddr; + __be32 dst = tiph->daddr; int mtu; if (tunnel->recursion++) { -- cgit v1.2.3 From 6b877699c6f1efede4545bcecc367786a472eedb Mon Sep 17 00:00:00 2001 From: Venkat Yekkirala Date: Wed, 8 Nov 2006 17:04:09 -0600 Subject: SELinux: Return correct context for SO_PEERSEC Fix SO_PEERSEC for tcp sockets to return the security context of the peer (as represented by the SA from the peer) as opposed to the SA used by the local/source socket. Signed-off-by: Venkat Yekkirala Signed-off-by: James Morris --- net/ipv4/tcp_input.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'net/ipv4') diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index cf06accbe68..4a8c96cdec7 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -4230,6 +4230,8 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb, mb(); tcp_set_state(sk, TCP_ESTABLISHED); + security_inet_conn_established(sk, skb); + /* Make sure socket is routed, for correct metrics. */ icsk->icsk_af_ops->rebuild_header(sk); -- cgit v1.2.3 From 82e91ffef60e6eba9848fe149ce1eecd2b5aef12 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Thu, 9 Nov 2006 15:19:14 -0800 Subject: [NET]: Turn nfmark into generic mark nfmark is being used in various subsystems and has become the defacto mark field for all kinds of packets. Therefore it makes sense to rename it to `mark' and remove the dependency on CONFIG_NETFILTER. Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- net/ipv4/ip_output.c | 2 +- net/ipv4/ipvs/ip_vs_proto_tcp.c | 2 +- net/ipv4/ipvs/ip_vs_proto_udp.c | 2 +- net/ipv4/netfilter.c | 2 +- net/ipv4/netfilter/ip_queue.c | 2 +- net/ipv4/netfilter/ipt_REJECT.c | 2 +- net/ipv4/netfilter/ipt_ULOG.c | 2 +- net/ipv4/netfilter/iptable_mangle.c | 6 +++--- net/ipv4/route.c | 10 +++++----- 9 files changed, 15 insertions(+), 15 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index fc195a44fc2..23633bf042b 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -386,6 +386,7 @@ static void ip_copy_metadata(struct sk_buff *to, struct sk_buff *from) dst_release(to->dst); to->dst = dst_clone(from->dst); to->dev = from->dev; + to->mark = from->mark; /* Copy the flags to each fragment. */ IPCB(to)->flags = IPCB(from)->flags; @@ -394,7 +395,6 @@ static void ip_copy_metadata(struct sk_buff *to, struct sk_buff *from) to->tc_index = from->tc_index; #endif #ifdef CONFIG_NETFILTER - to->nfmark = from->nfmark; /* Connection association is same as pre-frag packet */ nf_conntrack_put(to->nfct); to->nfct = from->nfct; diff --git a/net/ipv4/ipvs/ip_vs_proto_tcp.c b/net/ipv4/ipvs/ip_vs_proto_tcp.c index 6ff05c3a32e..7de385267b3 100644 --- a/net/ipv4/ipvs/ip_vs_proto_tcp.c +++ b/net/ipv4/ipvs/ip_vs_proto_tcp.c @@ -84,7 +84,7 @@ tcp_conn_schedule(struct sk_buff *skb, } if (th->syn && - (svc = ip_vs_service_get(skb->nfmark, skb->nh.iph->protocol, + (svc = ip_vs_service_get(skb->mark, skb->nh.iph->protocol, skb->nh.iph->daddr, th->dest))) { if (ip_vs_todrop()) { /* diff --git a/net/ipv4/ipvs/ip_vs_proto_udp.c b/net/ipv4/ipvs/ip_vs_proto_udp.c index 691c8b637b2..452cb9c384b 100644 --- a/net/ipv4/ipvs/ip_vs_proto_udp.c +++ b/net/ipv4/ipvs/ip_vs_proto_udp.c @@ -89,7 +89,7 @@ udp_conn_schedule(struct sk_buff *skb, struct ip_vs_protocol *pp, return 0; } - if ((svc = ip_vs_service_get(skb->nfmark, skb->nh.iph->protocol, + if ((svc = ip_vs_service_get(skb->mark, skb->nh.iph->protocol, skb->nh.iph->daddr, uh->dest))) { if (ip_vs_todrop()) { /* diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c index e2005c6810a..bfc8d753a23 100644 --- a/net/ipv4/netfilter.c +++ b/net/ipv4/netfilter.c @@ -28,7 +28,7 @@ int ip_route_me_harder(struct sk_buff **pskb, unsigned addr_type) fl.nl_u.ip4_u.tos = RT_TOS(iph->tos); fl.oif = (*pskb)->sk ? (*pskb)->sk->sk_bound_dev_if : 0; #ifdef CONFIG_IP_ROUTE_FWMARK - fl.nl_u.ip4_u.fwmark = (*pskb)->nfmark; + fl.nl_u.ip4_u.fwmark = (*pskb)->mark; #endif if (ip_route_output_key(&rt, &fl) != 0) return -1; diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c index 97556cc2e4e..cd520df4dcf 100644 --- a/net/ipv4/netfilter/ip_queue.c +++ b/net/ipv4/netfilter/ip_queue.c @@ -243,7 +243,7 @@ ipq_build_packet_message(struct ipq_queue_entry *entry, int *errp) pmsg->data_len = data_len; pmsg->timestamp_sec = entry->skb->tstamp.off_sec; pmsg->timestamp_usec = entry->skb->tstamp.off_usec; - pmsg->mark = entry->skb->nfmark; + pmsg->mark = entry->skb->mark; pmsg->hook = entry->info->hook; pmsg->hw_protocol = entry->skb->protocol; diff --git a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c index 264763adc39..f0319e5ee43 100644 --- a/net/ipv4/netfilter/ipt_REJECT.c +++ b/net/ipv4/netfilter/ipt_REJECT.c @@ -76,7 +76,7 @@ static void send_reset(struct sk_buff *oldskb, int hook) /* This packet will not be the same as the other: clear nf fields */ nf_reset(nskb); - nskb->nfmark = 0; + nskb->mark = 0; skb_init_secmark(nskb); tcph = (struct tcphdr *)((u_int32_t*)nskb->nh.iph + nskb->nh.iph->ihl); diff --git a/net/ipv4/netfilter/ipt_ULOG.c b/net/ipv4/netfilter/ipt_ULOG.c index 2b104ea54f4..dbd34783a64 100644 --- a/net/ipv4/netfilter/ipt_ULOG.c +++ b/net/ipv4/netfilter/ipt_ULOG.c @@ -239,7 +239,7 @@ static void ipt_ulog_packet(unsigned int hooknum, pm->data_len = copy_len; pm->timestamp_sec = skb->tstamp.off_sec; pm->timestamp_usec = skb->tstamp.off_usec; - pm->mark = skb->nfmark; + pm->mark = skb->mark; pm->hook = hooknum; if (prefix != NULL) strncpy(pm->prefix, prefix, sizeof(pm->prefix)); diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c index b91f3582359..62d4ccc259c 100644 --- a/net/ipv4/netfilter/iptable_mangle.c +++ b/net/ipv4/netfilter/iptable_mangle.c @@ -132,7 +132,7 @@ ipt_local_hook(unsigned int hook, unsigned int ret; u_int8_t tos; __be32 saddr, daddr; - unsigned long nfmark; + u_int32_t mark; /* root is playing with raw sockets. */ if ((*pskb)->len < sizeof(struct iphdr) @@ -143,7 +143,7 @@ ipt_local_hook(unsigned int hook, } /* Save things which could affect route */ - nfmark = (*pskb)->nfmark; + mark = (*pskb)->mark; saddr = (*pskb)->nh.iph->saddr; daddr = (*pskb)->nh.iph->daddr; tos = (*pskb)->nh.iph->tos; @@ -154,7 +154,7 @@ ipt_local_hook(unsigned int hook, && ((*pskb)->nh.iph->saddr != saddr || (*pskb)->nh.iph->daddr != daddr #ifdef CONFIG_IP_ROUTE_FWMARK - || (*pskb)->nfmark != nfmark + || (*pskb)->mark != mark #endif || (*pskb)->nh.iph->tos != tos)) if (ip_route_me_harder(pskb, RTN_UNSPEC)) diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 925ee4dfc32..4de3e38fa1a 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1644,7 +1644,7 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr, rth->rt_dst = daddr; rth->fl.fl4_tos = tos; #ifdef CONFIG_IP_ROUTE_FWMARK - rth->fl.fl4_fwmark= skb->nfmark; + rth->fl.fl4_fwmark= skb->mark; #endif rth->fl.fl4_src = saddr; rth->rt_src = saddr; @@ -1790,7 +1790,7 @@ static inline int __mkroute_input(struct sk_buff *skb, rth->rt_dst = daddr; rth->fl.fl4_tos = tos; #ifdef CONFIG_IP_ROUTE_FWMARK - rth->fl.fl4_fwmark= skb->nfmark; + rth->fl.fl4_fwmark= skb->mark; #endif rth->fl.fl4_src = saddr; rth->rt_src = saddr; @@ -1921,7 +1921,7 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr, .tos = tos, .scope = RT_SCOPE_UNIVERSE, #ifdef CONFIG_IP_ROUTE_FWMARK - .fwmark = skb->nfmark + .fwmark = skb->mark #endif } }, .iif = dev->ifindex }; @@ -2035,7 +2035,7 @@ local_input: rth->rt_dst = daddr; rth->fl.fl4_tos = tos; #ifdef CONFIG_IP_ROUTE_FWMARK - rth->fl.fl4_fwmark= skb->nfmark; + rth->fl.fl4_fwmark= skb->mark; #endif rth->fl.fl4_src = saddr; rth->rt_src = saddr; @@ -2114,7 +2114,7 @@ int ip_route_input(struct sk_buff *skb, __be32 daddr, __be32 saddr, rth->fl.iif == iif && rth->fl.oif == 0 && #ifdef CONFIG_IP_ROUTE_FWMARK - rth->fl.fl4_fwmark == skb->nfmark && + rth->fl.fl4_fwmark == skb->mark && #endif rth->fl.fl4_tos == tos) { rth->u.dst.lastuse = jiffies; -- cgit v1.2.3 From 47dcf0cb1005e86d0eea780f2984b2e7490f63cd Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Thu, 9 Nov 2006 15:20:38 -0800 Subject: [NET]: Rethink mark field in struct flowi Now that all protocols have been made aware of the mark field it can be moved out of the union thus simplyfing its usage. The config options in the IPv4/IPv6/DECnet subsystems to enable respectively disable mark based routing only obfuscate the code with ifdefs, the cost for the additional comparison in the flow key is insignificant, and most distributions have all these options enabled by default anyway. Therefore it makes sense to remove the config options and enable mark based routing by default. Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- net/ipv4/Kconfig | 7 ------- net/ipv4/fib_frontend.c | 4 ++-- net/ipv4/fib_rules.c | 12 +----------- net/ipv4/netfilter.c | 4 +--- net/ipv4/netfilter/iptable_mangle.c | 2 -- net/ipv4/route.c | 36 +++++++++--------------------------- 6 files changed, 13 insertions(+), 52 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig index 5572071af73..bc298bcc344 100644 --- a/net/ipv4/Kconfig +++ b/net/ipv4/Kconfig @@ -104,13 +104,6 @@ config IP_MULTIPLE_TABLES If unsure, say N. -config IP_ROUTE_FWMARK - bool "IP: use netfilter MARK value as routing key" - depends on IP_MULTIPLE_TABLES && NETFILTER - help - If you say Y here, you will be able to specify different routes for - packets with different mark values (see iptables(8), MARK target). - config IP_ROUTE_MULTIPATH bool "IP: equal cost multipath" depends on IP_ADVANCED_ROUTER diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index af0190d8b6c..ee8daaebcfa 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -768,8 +768,8 @@ static void nl_fib_lookup(struct fib_result_nl *frn, struct fib_table *tb ) { struct fib_result res; - struct flowi fl = { .nl_u = { .ip4_u = { .daddr = frn->fl_addr, - .fwmark = frn->fl_fwmark, + struct flowi fl = { .mark = frn->fl_fwmark, + .nl_u = { .ip4_u = { .daddr = frn->fl_addr, .tos = frn->fl_tos, .scope = frn->fl_scope } } }; if (tb) { diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c index 0852b9cd065..de8d5dd7099 100644 --- a/net/ipv4/fib_rules.c +++ b/net/ipv4/fib_rules.c @@ -44,10 +44,8 @@ struct fib4_rule __be32 srcmask; __be32 dst; __be32 dstmask; -#ifdef CONFIG_IP_ROUTE_FWMARK u32 fwmark; u32 fwmask; -#endif #ifdef CONFIG_NET_CLS_ROUTE u32 tclassid; #endif @@ -160,10 +158,8 @@ static int fib4_rule_match(struct fib_rule *rule, struct flowi *fl, int flags) if (r->tos && (r->tos != fl->fl4_tos)) return 0; -#ifdef CONFIG_IP_ROUTE_FWMARK - if ((r->fwmark ^ fl->fl4_fwmark) & r->fwmask) + if ((r->fwmark ^ fl->mark) & r->fwmask) return 0; -#endif return 1; } @@ -220,7 +216,6 @@ static int fib4_rule_configure(struct fib_rule *rule, struct sk_buff *skb, if (tb[FRA_DST]) rule4->dst = nla_get_be32(tb[FRA_DST]); -#ifdef CONFIG_IP_ROUTE_FWMARK if (tb[FRA_FWMARK]) { rule4->fwmark = nla_get_u32(tb[FRA_FWMARK]); if (rule4->fwmark) @@ -232,7 +227,6 @@ static int fib4_rule_configure(struct fib_rule *rule, struct sk_buff *skb, if (tb[FRA_FWMASK]) rule4->fwmask = nla_get_u32(tb[FRA_FWMASK]); -#endif #ifdef CONFIG_NET_CLS_ROUTE if (tb[FRA_FLOW]) @@ -264,13 +258,11 @@ static int fib4_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh, if (frh->tos && (rule4->tos != frh->tos)) return 0; -#ifdef CONFIG_IP_ROUTE_FWMARK if (tb[FRA_FWMARK] && (rule4->fwmark != nla_get_u32(tb[FRA_FWMARK]))) return 0; if (tb[FRA_FWMASK] && (rule4->fwmask != nla_get_u32(tb[FRA_FWMASK]))) return 0; -#endif #ifdef CONFIG_NET_CLS_ROUTE if (tb[FRA_FLOW] && (rule4->tclassid != nla_get_u32(tb[FRA_FLOW]))) @@ -296,13 +288,11 @@ static int fib4_rule_fill(struct fib_rule *rule, struct sk_buff *skb, frh->src_len = rule4->src_len; frh->tos = rule4->tos; -#ifdef CONFIG_IP_ROUTE_FWMARK if (rule4->fwmark) NLA_PUT_U32(skb, FRA_FWMARK, rule4->fwmark); if (rule4->fwmask || rule4->fwmark) NLA_PUT_U32(skb, FRA_FWMASK, rule4->fwmask); -#endif if (rule4->dst_len) NLA_PUT_BE32(skb, FRA_DST, rule4->dst); diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c index bfc8d753a23..e49441ac357 100644 --- a/net/ipv4/netfilter.c +++ b/net/ipv4/netfilter.c @@ -27,9 +27,7 @@ int ip_route_me_harder(struct sk_buff **pskb, unsigned addr_type) fl.nl_u.ip4_u.saddr = iph->saddr; fl.nl_u.ip4_u.tos = RT_TOS(iph->tos); fl.oif = (*pskb)->sk ? (*pskb)->sk->sk_bound_dev_if : 0; -#ifdef CONFIG_IP_ROUTE_FWMARK - fl.nl_u.ip4_u.fwmark = (*pskb)->mark; -#endif + fl.mark = (*pskb)->mark; if (ip_route_output_key(&rt, &fl) != 0) return -1; diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c index 62d4ccc259c..af293988944 100644 --- a/net/ipv4/netfilter/iptable_mangle.c +++ b/net/ipv4/netfilter/iptable_mangle.c @@ -153,9 +153,7 @@ ipt_local_hook(unsigned int hook, if (ret != NF_DROP && ret != NF_STOLEN && ret != NF_QUEUE && ((*pskb)->nh.iph->saddr != saddr || (*pskb)->nh.iph->daddr != daddr -#ifdef CONFIG_IP_ROUTE_FWMARK || (*pskb)->mark != mark -#endif || (*pskb)->nh.iph->tos != tos)) if (ip_route_me_harder(pskb, RTN_UNSPEC)) ret = NF_DROP; diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 4de3e38fa1a..d7152b2b2c6 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -568,9 +568,7 @@ static inline int compare_keys(struct flowi *fl1, struct flowi *fl2) { return ((fl1->nl_u.ip4_u.daddr ^ fl2->nl_u.ip4_u.daddr) | (fl1->nl_u.ip4_u.saddr ^ fl2->nl_u.ip4_u.saddr) | -#ifdef CONFIG_IP_ROUTE_FWMARK - (fl1->nl_u.ip4_u.fwmark ^ fl2->nl_u.ip4_u.fwmark) | -#endif + (fl1->mark ^ fl2->mark) | (*(u16 *)&fl1->nl_u.ip4_u.tos ^ *(u16 *)&fl2->nl_u.ip4_u.tos) | (fl1->oif ^ fl2->oif) | @@ -1643,9 +1641,7 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr, rth->fl.fl4_dst = daddr; rth->rt_dst = daddr; rth->fl.fl4_tos = tos; -#ifdef CONFIG_IP_ROUTE_FWMARK - rth->fl.fl4_fwmark= skb->mark; -#endif + rth->fl.mark = skb->mark; rth->fl.fl4_src = saddr; rth->rt_src = saddr; #ifdef CONFIG_NET_CLS_ROUTE @@ -1789,9 +1785,7 @@ static inline int __mkroute_input(struct sk_buff *skb, rth->fl.fl4_dst = daddr; rth->rt_dst = daddr; rth->fl.fl4_tos = tos; -#ifdef CONFIG_IP_ROUTE_FWMARK - rth->fl.fl4_fwmark= skb->mark; -#endif + rth->fl.mark = skb->mark; rth->fl.fl4_src = saddr; rth->rt_src = saddr; rth->rt_gateway = daddr; @@ -1920,10 +1914,8 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr, .saddr = saddr, .tos = tos, .scope = RT_SCOPE_UNIVERSE, -#ifdef CONFIG_IP_ROUTE_FWMARK - .fwmark = skb->mark -#endif } }, + .mark = skb->mark, .iif = dev->ifindex }; unsigned flags = 0; u32 itag = 0; @@ -2034,9 +2026,7 @@ local_input: rth->fl.fl4_dst = daddr; rth->rt_dst = daddr; rth->fl.fl4_tos = tos; -#ifdef CONFIG_IP_ROUTE_FWMARK - rth->fl.fl4_fwmark= skb->mark; -#endif + rth->fl.mark = skb->mark; rth->fl.fl4_src = saddr; rth->rt_src = saddr; #ifdef CONFIG_NET_CLS_ROUTE @@ -2113,9 +2103,7 @@ int ip_route_input(struct sk_buff *skb, __be32 daddr, __be32 saddr, rth->fl.fl4_src == saddr && rth->fl.iif == iif && rth->fl.oif == 0 && -#ifdef CONFIG_IP_ROUTE_FWMARK - rth->fl.fl4_fwmark == skb->mark && -#endif + rth->fl.mark == skb->mark && rth->fl.fl4_tos == tos) { rth->u.dst.lastuse = jiffies; dst_hold(&rth->u.dst); @@ -2239,9 +2227,7 @@ static inline int __mkroute_output(struct rtable **result, rth->fl.fl4_tos = tos; rth->fl.fl4_src = oldflp->fl4_src; rth->fl.oif = oldflp->oif; -#ifdef CONFIG_IP_ROUTE_FWMARK - rth->fl.fl4_fwmark= oldflp->fl4_fwmark; -#endif + rth->fl.mark = oldflp->mark; rth->rt_dst = fl->fl4_dst; rth->rt_src = fl->fl4_src; rth->rt_iif = oldflp->oif ? : dev_out->ifindex; @@ -2385,10 +2371,8 @@ static int ip_route_output_slow(struct rtable **rp, const struct flowi *oldflp) .scope = ((tos & RTO_ONLINK) ? RT_SCOPE_LINK : RT_SCOPE_UNIVERSE), -#ifdef CONFIG_IP_ROUTE_FWMARK - .fwmark = oldflp->fl4_fwmark -#endif } }, + .mark = oldflp->mark, .iif = loopback_dev.ifindex, .oif = oldflp->oif }; struct fib_result res; @@ -2583,9 +2567,7 @@ int __ip_route_output_key(struct rtable **rp, const struct flowi *flp) rth->fl.fl4_src == flp->fl4_src && rth->fl.iif == 0 && rth->fl.oif == flp->oif && -#ifdef CONFIG_IP_ROUTE_FWMARK - rth->fl.fl4_fwmark == flp->fl4_fwmark && -#endif + rth->fl.mark == flp->mark && !((rth->fl.fl4_tos ^ flp->fl4_tos) & (IPTOS_RT_MASK | RTO_ONLINK))) { -- cgit v1.2.3 From 5f300893fdd3b6e30a226c9a848eaa39b99a6431 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Thu, 9 Nov 2006 15:21:41 -0800 Subject: [IPV4] nl_fib_lookup: Rename fl_fwmark to fl_mark For the sake of consistency. Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- net/ipv4/fib_frontend.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/ipv4') diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index ee8daaebcfa..14025345cc5 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -768,7 +768,7 @@ static void nl_fib_lookup(struct fib_result_nl *frn, struct fib_table *tb ) { struct fib_result res; - struct flowi fl = { .mark = frn->fl_fwmark, + struct flowi fl = { .mark = frn->fl_mark, .nl_u = { .ip4_u = { .daddr = frn->fl_addr, .tos = frn->fl_tos, .scope = frn->fl_scope } } }; -- cgit v1.2.3 From b8964ed9fa727109c9084abc807652ebfb681c18 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Thu, 9 Nov 2006 15:22:18 -0800 Subject: [NET] rules: Protocol independant mark selector Move mark selector currently implemented per protocol into the protocol independant part. Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- net/ipv4/fib_rules.c | 29 ----------------------------- 1 file changed, 29 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c index de8d5dd7099..d2a190a35d6 100644 --- a/net/ipv4/fib_rules.c +++ b/net/ipv4/fib_rules.c @@ -44,8 +44,6 @@ struct fib4_rule __be32 srcmask; __be32 dst; __be32 dstmask; - u32 fwmark; - u32 fwmask; #ifdef CONFIG_NET_CLS_ROUTE u32 tclassid; #endif @@ -158,9 +156,6 @@ static int fib4_rule_match(struct fib_rule *rule, struct flowi *fl, int flags) if (r->tos && (r->tos != fl->fl4_tos)) return 0; - if ((r->fwmark ^ fl->mark) & r->fwmask) - return 0; - return 1; } @@ -216,18 +211,6 @@ static int fib4_rule_configure(struct fib_rule *rule, struct sk_buff *skb, if (tb[FRA_DST]) rule4->dst = nla_get_be32(tb[FRA_DST]); - if (tb[FRA_FWMARK]) { - rule4->fwmark = nla_get_u32(tb[FRA_FWMARK]); - if (rule4->fwmark) - /* compatibility: if the mark value is non-zero all bits - * are compared unless a mask is explicitly specified. - */ - rule4->fwmask = 0xFFFFFFFF; - } - - if (tb[FRA_FWMASK]) - rule4->fwmask = nla_get_u32(tb[FRA_FWMASK]); - #ifdef CONFIG_NET_CLS_ROUTE if (tb[FRA_FLOW]) rule4->tclassid = nla_get_u32(tb[FRA_FLOW]); @@ -258,12 +241,6 @@ static int fib4_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh, if (frh->tos && (rule4->tos != frh->tos)) return 0; - if (tb[FRA_FWMARK] && (rule4->fwmark != nla_get_u32(tb[FRA_FWMARK]))) - return 0; - - if (tb[FRA_FWMASK] && (rule4->fwmask != nla_get_u32(tb[FRA_FWMASK]))) - return 0; - #ifdef CONFIG_NET_CLS_ROUTE if (tb[FRA_FLOW] && (rule4->tclassid != nla_get_u32(tb[FRA_FLOW]))) return 0; @@ -288,12 +265,6 @@ static int fib4_rule_fill(struct fib_rule *rule, struct sk_buff *skb, frh->src_len = rule4->src_len; frh->tos = rule4->tos; - if (rule4->fwmark) - NLA_PUT_U32(skb, FRA_FWMARK, rule4->fwmark); - - if (rule4->fwmask || rule4->fwmark) - NLA_PUT_U32(skb, FRA_FWMASK, rule4->fwmask); - if (rule4->dst_len) NLA_PUT_BE32(skb, FRA_DST, rule4->dst); -- cgit v1.2.3 From 1f6c9557e8206757c91b5737bb8dbd5b1ae3a773 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Thu, 9 Nov 2006 15:22:48 -0800 Subject: [NET] rules: Share common attribute validation policy Move the attribute policy for the non-specific attributes into net/fib_rules.h and include it in the respective protocols. Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- net/ipv4/fib_rules.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c index d2a190a35d6..fd4a8cd4c06 100644 --- a/net/ipv4/fib_rules.c +++ b/net/ipv4/fib_rules.c @@ -170,14 +170,10 @@ static struct fib_table *fib_empty_table(void) } static struct nla_policy fib4_rule_policy[FRA_MAX+1] __read_mostly = { - [FRA_IFNAME] = { .type = NLA_STRING, .len = IFNAMSIZ - 1 }, - [FRA_PRIORITY] = { .type = NLA_U32 }, + FRA_GENERIC_POLICY, [FRA_SRC] = { .type = NLA_U32 }, [FRA_DST] = { .type = NLA_U32 }, - [FRA_FWMARK] = { .type = NLA_U32 }, - [FRA_FWMASK] = { .type = NLA_U32 }, [FRA_FLOW] = { .type = NLA_U32 }, - [FRA_TABLE] = { .type = NLA_U32 }, }; static int fib4_rule_configure(struct fib_rule *rule, struct sk_buff *skb, -- cgit v1.2.3 From 72a3effaf633bcae9034b7e176bdbd78d64a71db Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 16 Nov 2006 02:30:37 -0800 Subject: [NET]: Size listen hash tables using backlog hint We currently allocate a fixed size (TCP_SYNQ_HSIZE=512) slots hash table for each LISTEN socket, regardless of various parameters (listen backlog for example) On x86_64, this means order-1 allocations (might fail), even for 'small' sockets, expecting few connections. On the contrary, a huge server wanting a backlog of 50000 is slowed down a bit because of this fixed limit. This patch makes the sizing of listen hash table a dynamic parameter, depending of : - net.core.somaxconn tunable (default is 128) - net.ipv4.tcp_max_syn_backlog tunable (default : 256, 1024 or 128) - backlog value given by user application (2nd parameter of listen()) For large allocations (bigger than PAGE_SIZE), we use vmalloc() instead of kmalloc(). We still limit memory allocation with the two existing tunables (somaxconn & tcp_max_syn_backlog). So for standard setups, this patch actually reduce RAM usage. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/af_inet.c | 2 +- net/ipv4/inet_connection_sock.c | 2 +- net/ipv4/tcp_ipv4.c | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index edcf0932ac6..4a81d54a756 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -204,7 +204,7 @@ int inet_listen(struct socket *sock, int backlog) * we can only allow the backlog to be adjusted. */ if (old_state != TCP_LISTEN) { - err = inet_csk_listen_start(sk, TCP_SYNQ_HSIZE); + err = inet_csk_listen_start(sk, backlog); if (err) goto out; } diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index 96bbe2a0aa1..9d68837888d 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -343,7 +343,7 @@ struct dst_entry* inet_csk_route_req(struct sock *sk, EXPORT_SYMBOL_GPL(inet_csk_route_req); static inline u32 inet_synq_hash(const __be32 raddr, const __be16 rport, - const u32 rnd, const u16 synq_hsize) + const u32 rnd, const u32 synq_hsize) { return jhash_2words((__force u32)raddr, (__force u32)rport, rnd) & (synq_hsize - 1); } diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 22ef8bd2662..5fbf96552ca 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -715,7 +715,7 @@ static struct ip_options *tcp_v4_save_options(struct sock *sk, return dopt; } -struct request_sock_ops tcp_request_sock_ops = { +struct request_sock_ops tcp_request_sock_ops __read_mostly = { .family = PF_INET, .obj_size = sizeof(struct tcp_request_sock), .rtx_syn_ack = tcp_v4_send_synack, @@ -1385,7 +1385,7 @@ static void *listening_get_next(struct seq_file *seq, void *cur) if (st->state == TCP_SEQ_STATE_OPENREQ) { struct request_sock *req = cur; - icsk = inet_csk(st->syn_wait_sk); + icsk = inet_csk(st->syn_wait_sk); req = req->dl_next; while (1) { while (req) { @@ -1395,7 +1395,7 @@ static void *listening_get_next(struct seq_file *seq, void *cur) } req = req->dl_next; } - if (++st->sbucket >= TCP_SYNQ_HSIZE) + if (++st->sbucket >= icsk->icsk_accept_queue.listen_opt->nr_table_entries) break; get_req: req = icsk->icsk_accept_queue.listen_opt->syn_table[st->sbucket]; -- cgit v1.2.3 From 3ff825b28d3345ef381eceae22bf9d92231f23dc Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 9 Nov 2006 16:32:06 -0800 Subject: [TCP]: Add tcp_available_congestion_control sysctl. Create /proc/sys/net/ipv4/tcp_available_congestion_control that reflects currently available TCP choices. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- net/ipv4/sysctl_net_ipv4.c | 24 ++++++++++++++++++++++++ net/ipv4/tcp_cong.c | 16 ++++++++++++++++ 2 files changed, 40 insertions(+) (limited to 'net/ipv4') diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index 15061b31441..2e770f45d82 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -129,6 +129,23 @@ static int sysctl_tcp_congestion_control(ctl_table *table, int __user *name, return ret; } +static int proc_tcp_available_congestion_control(ctl_table *ctl, + int write, struct file * filp, + void __user *buffer, size_t *lenp, + loff_t *ppos) +{ + ctl_table tbl = { .maxlen = TCP_CA_BUF_MAX, }; + int ret; + + tbl.data = kmalloc(tbl.maxlen, GFP_USER); + if (!tbl.data) + return -ENOMEM; + tcp_get_available_congestion_control(tbl.data, TCP_CA_BUF_MAX); + ret = proc_dostring(&tbl, write, filp, buffer, lenp, ppos); + kfree(tbl.data); + return ret; +} + ctl_table ipv4_table[] = { { .ctl_name = NET_IPV4_TCP_TIMESTAMPS, @@ -731,6 +748,13 @@ ctl_table ipv4_table[] = { .proc_handler = &proc_dointvec, }, #endif /* CONFIG_NETLABEL */ + { + .ctl_name = NET_TCP_AVAIL_CONG_CONTROL, + .procname = "tcp_available_congestion_control", + .maxlen = TCP_CA_BUF_MAX, + .mode = 0444, + .proc_handler = &proc_tcp_available_congestion_control, + }, { .ctl_name = 0 } }; diff --git a/net/ipv4/tcp_cong.c b/net/ipv4/tcp_cong.c index 1e2982f4acd..d846d7b95e1 100644 --- a/net/ipv4/tcp_cong.c +++ b/net/ipv4/tcp_cong.c @@ -139,6 +139,22 @@ static int __init tcp_congestion_default(void) late_initcall(tcp_congestion_default); +/* Build string with list of available congestion control values */ +void tcp_get_available_congestion_control(char *buf, size_t maxlen) +{ + struct tcp_congestion_ops *ca; + size_t offs = 0; + + rcu_read_lock(); + list_for_each_entry_rcu(ca, &tcp_cong_list, list) { + offs += snprintf(buf + offs, maxlen - offs, + "%s%s", + offs == 0 ? "" : " ", ca->name); + + } + rcu_read_unlock(); +} + /* Get current default congestion control */ void tcp_get_default_congestion_control(char *name) { -- cgit v1.2.3 From ce7bc3bf15cbf5dc5a5587ccb6b04c5b4dde4336 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 9 Nov 2006 16:35:15 -0800 Subject: [TCP]: Restrict congestion control choices. Allow normal users to only choose among a restricted set of congestion control choices. The default is reno and what ever has been configured as default. But the policy can be changed by administrator at any time. For example, to allow any choice: cp /proc/sys/net/ipv4/tcp_available_congestion_control \ /proc/sys/net/ipv4/tcp_allowed_congestion_control Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- net/ipv4/sysctl_net_ipv4.c | 52 ++++++++++++++++++++++++++++++++++++++ net/ipv4/tcp_cong.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 115 insertions(+) (limited to 'net/ipv4') diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index 2e770f45d82..dfcf47f10f8 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -146,6 +146,50 @@ static int proc_tcp_available_congestion_control(ctl_table *ctl, return ret; } +static int proc_allowed_congestion_control(ctl_table *ctl, + int write, struct file * filp, + void __user *buffer, size_t *lenp, + loff_t *ppos) +{ + ctl_table tbl = { .maxlen = TCP_CA_BUF_MAX }; + int ret; + + tbl.data = kmalloc(tbl.maxlen, GFP_USER); + if (!tbl.data) + return -ENOMEM; + + tcp_get_allowed_congestion_control(tbl.data, tbl.maxlen); + ret = proc_dostring(&tbl, write, filp, buffer, lenp, ppos); + if (write && ret == 0) + ret = tcp_set_allowed_congestion_control(tbl.data); + kfree(tbl.data); + return ret; +} + +static int strategy_allowed_congestion_control(ctl_table *table, int __user *name, + int nlen, void __user *oldval, + size_t __user *oldlenp, + void __user *newval, size_t newlen, + void **context) +{ + ctl_table tbl = { .maxlen = TCP_CA_BUF_MAX }; + int ret; + + tbl.data = kmalloc(tbl.maxlen, GFP_USER); + if (!tbl.data) + return -ENOMEM; + + tcp_get_available_congestion_control(tbl.data, tbl.maxlen); + ret = sysctl_string(&tbl, name, nlen, oldval, oldlenp, newval, newlen, + context); + if (ret == 0 && newval && newlen) + ret = tcp_set_allowed_congestion_control(tbl.data); + kfree(tbl.data); + + return ret; + +} + ctl_table ipv4_table[] = { { .ctl_name = NET_IPV4_TCP_TIMESTAMPS, @@ -755,6 +799,14 @@ ctl_table ipv4_table[] = { .mode = 0444, .proc_handler = &proc_tcp_available_congestion_control, }, + { + .ctl_name = NET_TCP_ALLOWED_CONG_CONTROL, + .procname = "tcp_allowed_congestion_control", + .maxlen = TCP_CA_BUF_MAX, + .mode = 0644, + .proc_handler = &proc_allowed_congestion_control, + .strategy = &strategy_allowed_congestion_control, + }, { .ctl_name = 0 } }; diff --git a/net/ipv4/tcp_cong.c b/net/ipv4/tcp_cong.c index d846d7b95e1..343d6197c92 100644 --- a/net/ipv4/tcp_cong.c +++ b/net/ipv4/tcp_cong.c @@ -123,6 +123,7 @@ int tcp_set_default_congestion_control(const char *name) #endif if (ca) { + ca->non_restricted = 1; /* default is always allowed */ list_move(&ca->list, &tcp_cong_list); ret = 0; } @@ -168,6 +169,64 @@ void tcp_get_default_congestion_control(char *name) rcu_read_unlock(); } +/* Built list of non-restricted congestion control values */ +void tcp_get_allowed_congestion_control(char *buf, size_t maxlen) +{ + struct tcp_congestion_ops *ca; + size_t offs = 0; + + *buf = '\0'; + rcu_read_lock(); + list_for_each_entry_rcu(ca, &tcp_cong_list, list) { + if (!ca->non_restricted) + continue; + offs += snprintf(buf + offs, maxlen - offs, + "%s%s", + offs == 0 ? "" : " ", ca->name); + + } + rcu_read_unlock(); +} + +/* Change list of non-restricted congestion control */ +int tcp_set_allowed_congestion_control(char *val) +{ + struct tcp_congestion_ops *ca; + char *clone, *name; + int ret = 0; + + clone = kstrdup(val, GFP_USER); + if (!clone) + return -ENOMEM; + + spin_lock(&tcp_cong_list_lock); + /* pass 1 check for bad entries */ + while ((name = strsep(&clone, " ")) && *name) { + ca = tcp_ca_find(name); + if (!ca) { + ret = -ENOENT; + goto out; + } + } + + /* pass 2 clear */ + list_for_each_entry_rcu(ca, &tcp_cong_list, list) + ca->non_restricted = 0; + + /* pass 3 mark as allowed */ + while ((name = strsep(&val, " ")) && *name) { + ca = tcp_ca_find(name); + WARN_ON(!ca); + if (ca) + ca->non_restricted = 1; + } +out: + spin_unlock(&tcp_cong_list_lock); + + return ret; +} + + /* Change congestion control for socket */ int tcp_set_congestion_control(struct sock *sk, const char *name) { @@ -183,6 +242,9 @@ int tcp_set_congestion_control(struct sock *sk, const char *name) if (!ca) err = -ENOENT; + else if (!(ca->non_restricted || capable(CAP_NET_ADMIN))) + err = -EPERM; + else if (!try_module_get(ca->owner)) err = -EBUSY; @@ -284,6 +346,7 @@ EXPORT_SYMBOL_GPL(tcp_reno_min_cwnd); struct tcp_congestion_ops tcp_reno = { .name = "reno", + .non_restricted = 1, .owner = THIS_MODULE, .ssthresh = tcp_reno_ssthresh, .cong_avoid = tcp_reno_cong_avoid, -- cgit v1.2.3 From 35bfbc94070e480f350c868abc4ff9f77e7f2051 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 9 Nov 2006 16:36:36 -0800 Subject: [TCP]: Allow autoloading of congestion control via setsockopt. If user has permision to load modules, then autoload then attempt autoload of TCP congestion module. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- net/ipv4/tcp_cong.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'net/ipv4') diff --git a/net/ipv4/tcp_cong.c b/net/ipv4/tcp_cong.c index 343d6197c92..5ca7723d079 100644 --- a/net/ipv4/tcp_cong.c +++ b/net/ipv4/tcp_cong.c @@ -113,7 +113,7 @@ int tcp_set_default_congestion_control(const char *name) spin_lock(&tcp_cong_list_lock); ca = tcp_ca_find(name); #ifdef CONFIG_KMOD - if (!ca) { + if (!ca && capable(CAP_SYS_MODULE)) { spin_unlock(&tcp_cong_list_lock); request_module("tcp_%s", name); @@ -236,9 +236,19 @@ int tcp_set_congestion_control(struct sock *sk, const char *name) rcu_read_lock(); ca = tcp_ca_find(name); + /* no change asking for existing value */ if (ca == icsk->icsk_ca_ops) goto out; +#ifdef CONFIG_KMOD + /* not found attempt to autoload module */ + if (!ca && capable(CAP_SYS_MODULE)) { + rcu_read_unlock(); + request_module("tcp_%s", name); + rcu_read_lock(); + ca = tcp_ca_find(name); + } +#endif if (!ca) err = -ENOENT; -- cgit v1.2.3 From 931731123a103cfb3f70ac4b7abfc71d94ba1f03 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 9 Nov 2006 19:58:25 -0800 Subject: [TCP]: Don't set SKB owner in tcp_transmit_skb(). The data itself is already charged to the SKB, doing the skb_set_owner_w() just generates a lot of noise and extra atomics we don't really need. Lmbench improvements on lat_tcp are minimal: before: TCP latency using localhost: 23.2701 microseconds TCP latency using localhost: 23.1994 microseconds TCP latency using localhost: 23.2257 microseconds after: TCP latency using localhost: 22.8380 microseconds TCP latency using localhost: 22.9465 microseconds TCP latency using localhost: 22.8462 microseconds Signed-off-by: David S. Miller --- net/ipv4/ip_output.c | 3 +-- net/ipv4/tcp_output.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 23633bf042b..def32d8d3b0 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -288,9 +288,8 @@ int ip_output(struct sk_buff *skb) !(IPCB(skb)->flags & IPSKB_REROUTED)); } -int ip_queue_xmit(struct sk_buff *skb, int ipfragok) +int ip_queue_xmit(struct sk_buff *skb, struct sock *sk, int ipfragok) { - struct sock *sk = skb->sk; struct inet_sock *inet = inet_sk(sk); struct ip_options *opt = inet->opt; struct rtable *rt; diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index ca406157724..f63e99aac2d 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -426,7 +426,6 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, th = (struct tcphdr *) skb_push(skb, tcp_header_size); skb->h.th = th; - skb_set_owner_w(skb, sk); /* Build TCP header and checksum it. */ th->source = inet->sport; @@ -479,7 +478,7 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, if (after(tcb->end_seq, tp->snd_nxt) || tcb->seq == tcb->end_seq) TCP_INC_STATS(TCP_MIB_OUTSEGS); - err = icsk->icsk_af_ops->queue_xmit(skb, 0); + err = icsk->icsk_af_ops->queue_xmit(skb, sk, 0); if (likely(err <= 0)) return err; -- cgit v1.2.3 From a94f723d595ee085f81b1788d18e031af7eeba91 Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Fri, 10 Nov 2006 14:06:49 -0800 Subject: [TCP]: Remove dead code in init_sequence This removes two redundancies: 1) The test (skb->protocol == htons(ETH_P_IPV6) in tcp_v6_init_sequence() is always true, due to * tcp_v6_conn_request() is the only function calling this one * tcp_v6_conn_request() redirects all skb's with ETH_P_IP protocol to tcp_v4_conn_request() [ cf. top of tcp_v6_conn_request()] 2) The first argument, `struct sock *sk' of tcp_v{4,6}_init_sequence() is never used. Signed-off-by: Gerrit Renker Signed-off-by: David S. Miller --- net/ipv4/tcp_ipv4.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 5fbf96552ca..2eb58844403 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -111,7 +111,7 @@ void tcp_unhash(struct sock *sk) inet_unhash(&tcp_hashinfo, sk); } -static inline __u32 tcp_v4_init_sequence(struct sock *sk, struct sk_buff *skb) +static inline __u32 tcp_v4_init_sequence(struct sk_buff *skb) { return secure_tcp_sequence_number(skb->nh.iph->daddr, skb->nh.iph->saddr, @@ -859,7 +859,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) goto drop_and_free; } - isn = tcp_v4_init_sequence(sk, skb); + isn = tcp_v4_init_sequence(skb); } tcp_rsk(req)->snt_isn = isn; -- cgit v1.2.3 From 339bf98ffc6a8d8eb16fc532ac57ffbced2f8a68 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Fri, 10 Nov 2006 14:10:15 -0800 Subject: [NETLINK]: Do precise netlink message allocations where possible Account for the netlink message header size directly in nlmsg_new() instead of relying on the caller calculate it correctly. Replaces error handling of message construction functions when constructing notifications with bug traps since a failure implies a bug in calculating the size of the skb. Signed-off-by: Thomas Graf Acked-by: Paul Moore Signed-off-by: David S. Miller --- net/ipv4/devinet.c | 18 +++++++++++++----- net/ipv4/fib_rules.c | 8 ++++++++ net/ipv4/fib_semantics.c | 36 ++++++++++++++++++++++++++++++------ 3 files changed, 51 insertions(+), 11 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 7602c79a389..f38cbbae0ae 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -1120,6 +1120,16 @@ static struct notifier_block ip_netdev_notifier = { .notifier_call =inetdev_event, }; +static inline size_t inet_nlmsg_size(void) +{ + return NLMSG_ALIGN(sizeof(struct ifaddrmsg)) + + nla_total_size(4) /* IFA_ADDRESS */ + + nla_total_size(4) /* IFA_LOCAL */ + + nla_total_size(4) /* IFA_BROADCAST */ + + nla_total_size(4) /* IFA_ANYCAST */ + + nla_total_size(IFNAMSIZ); /* IFA_LABEL */ +} + static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa, u32 pid, u32 seq, int event, unsigned int flags) { @@ -1208,15 +1218,13 @@ static void rtmsg_ifa(int event, struct in_ifaddr* ifa, struct nlmsghdr *nlh, u32 seq = nlh ? nlh->nlmsg_seq : 0; int err = -ENOBUFS; - skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + skb = nlmsg_new(inet_nlmsg_size(), GFP_KERNEL); if (skb == NULL) goto errout; err = inet_fill_ifaddr(skb, ifa, pid, seq, event, 0); - if (err < 0) { - kfree_skb(skb); - goto errout; - } + /* failure implies BUG in inet_nlmsg_size() */ + BUG_ON(err < 0); err = rtnl_notify(skb, pid, RTNLGRP_IPV4_IFADDR, nlh, GFP_KERNEL); errout: diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c index fd4a8cd4c06..b837c33e040 100644 --- a/net/ipv4/fib_rules.c +++ b/net/ipv4/fib_rules.c @@ -299,6 +299,13 @@ static u32 fib4_rule_default_pref(void) return 0; } +static size_t fib4_rule_nlmsg_payload(struct fib_rule *rule) +{ + return nla_total_size(4) /* dst */ + + nla_total_size(4) /* src */ + + nla_total_size(4); /* flow */ +} + static struct fib_rules_ops fib4_rules_ops = { .family = AF_INET, .rule_size = sizeof(struct fib4_rule), @@ -308,6 +315,7 @@ static struct fib_rules_ops fib4_rules_ops = { .compare = fib4_rule_compare, .fill = fib4_rule_fill, .default_pref = fib4_rule_default_pref, + .nlmsg_payload = fib4_rule_nlmsg_payload, .nlgroup = RTNLGRP_IPV4_RULE, .policy = fib4_rule_policy, .rules_list = &fib4_rules, diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index 884d176e008..e63b8a98fb4 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c @@ -273,25 +273,49 @@ int ip_fib_check_default(__be32 gw, struct net_device *dev) return -1; } +static inline size_t fib_nlmsg_size(struct fib_info *fi) +{ + size_t payload = NLMSG_ALIGN(sizeof(struct rtmsg)) + + nla_total_size(4) /* RTA_TABLE */ + + nla_total_size(4) /* RTA_DST */ + + nla_total_size(4) /* RTA_PRIORITY */ + + nla_total_size(4); /* RTA_PREFSRC */ + + /* space for nested metrics */ + payload += nla_total_size((RTAX_MAX * nla_total_size(4))); + + if (fi->fib_nhs) { + /* Also handles the special case fib_nhs == 1 */ + + /* each nexthop is packed in an attribute */ + size_t nhsize = nla_total_size(sizeof(struct rtnexthop)); + + /* may contain flow and gateway attribute */ + nhsize += 2 * nla_total_size(4); + + /* all nexthops are packed in a nested attribute */ + payload += nla_total_size(fi->fib_nhs * nhsize); + } + + return payload; +} + void rtmsg_fib(int event, __be32 key, struct fib_alias *fa, int dst_len, u32 tb_id, struct nl_info *info) { struct sk_buff *skb; - int payload = sizeof(struct rtmsg) + 256; u32 seq = info->nlh ? info->nlh->nlmsg_seq : 0; int err = -ENOBUFS; - skb = nlmsg_new(nlmsg_total_size(payload), GFP_KERNEL); + skb = nlmsg_new(fib_nlmsg_size(fa->fa_info), GFP_KERNEL); if (skb == NULL) goto errout; err = fib_dump_info(skb, info->pid, seq, event, tb_id, fa->fa_type, fa->fa_scope, key, dst_len, fa->fa_tos, fa->fa_info, 0); - if (err < 0) { - kfree_skb(skb); - goto errout; - } + /* failure implies BUG in fib_nlmsg_size() */ + BUG_ON(err < 0); err = rtnl_notify(skb, info->pid, RTNLGRP_IPV4_ROUTE, info->nlh, GFP_KERNEL); -- cgit v1.2.3 From 2404043a665a9f4c748ab81eef29c76b3e443801 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 10 Nov 2006 15:01:14 -0800 Subject: [TCP] htcp: Better packing of struct htcp. Based upon a patch by Joe Perches. Signed-off-by: David S. Miller --- net/ipv4/tcp_htcp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/tcp_htcp.c b/net/ipv4/tcp_htcp.c index 283be3cb466..753987a1048 100644 --- a/net/ipv4/tcp_htcp.c +++ b/net/ipv4/tcp_htcp.c @@ -26,12 +26,12 @@ struct htcp { u32 alpha; /* Fixed point arith, << 7 */ u8 beta; /* Fixed point arith, << 7 */ u8 modeswitch; /* Delay modeswitch until we had at least one congestion event */ - u32 last_cong; /* Time since last congestion event end */ - u32 undo_last_cong; u16 pkts_acked; u32 packetcount; u32 minRTT; u32 maxRTT; + u32 last_cong; /* Time since last congestion event end */ + u32 undo_last_cong; u32 undo_maxRTT; u32 undo_old_maxB; -- cgit v1.2.3 From b9df3cb8cf9a96e63dfdcd3056a9cbc71f2459e7 Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Tue, 14 Nov 2006 11:21:36 -0200 Subject: [TCP/DCCP]: Introduce net_xmit_eval Throughout the TCP/DCCP (and tunnelling) code, it often happens that the return code of a transmit function needs to be tested against NET_XMIT_CN which is a value that does not indicate a strict error condition. This patch uses a macro for these recurring situations which is consistent with the already existing macro net_xmit_errno, saving on duplicated code. Signed-off-by: Gerrit Renker Signed-off-by: Arnaldo Carvalho de Melo --- net/ipv4/tcp_ipv4.c | 3 +-- net/ipv4/tcp_output.c | 8 +------- 2 files changed, 2 insertions(+), 9 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 2eb58844403..0ad0904bf56 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -662,8 +662,7 @@ static int tcp_v4_send_synack(struct sock *sk, struct request_sock *req, err = ip_build_and_send_pkt(skb, sk, ireq->loc_addr, ireq->rmt_addr, ireq->opt); - if (err == NET_XMIT_CN) - err = 0; + err = net_xmit_eval(err); } out: diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index f63e99aac2d..6a8581ab9a2 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -484,13 +484,7 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, tcp_enter_cwr(sk); - /* NET_XMIT_CN is special. It does not guarantee, - * that this packet is lost. It tells that device - * is about to start to drop packets or already - * drops some packets of the same priority and - * invokes us to send less aggressively. - */ - return err == NET_XMIT_CN ? 0 : err; + return net_xmit_eval(err); #undef SYSCTL_FLAG_TSTAMPS #undef SYSCTL_FLAG_WSCALE -- cgit v1.2.3 From cfb6eeb4c860592edd123fdea908d23c6ad1c7dc Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Tue, 14 Nov 2006 19:07:45 -0800 Subject: [TCP]: MD5 Signature Option (RFC2385) support. Based on implementation by Rick Payne. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- net/ipv4/Kconfig | 16 ++ net/ipv4/tcp.c | 137 ++++++++++ net/ipv4/tcp_input.c | 8 + net/ipv4/tcp_ipv4.c | 673 ++++++++++++++++++++++++++++++++++++++++++++--- net/ipv4/tcp_minisocks.c | 64 ++++- net/ipv4/tcp_output.c | 111 +++++++- 6 files changed, 973 insertions(+), 36 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig index bc298bcc344..39e0cb76358 100644 --- a/net/ipv4/Kconfig +++ b/net/ipv4/Kconfig @@ -618,5 +618,21 @@ config DEFAULT_TCP_CONG default "reno" if DEFAULT_RENO default "cubic" +config TCP_MD5SIG + bool "TCP: MD5 Signature Option support (RFC2385) (EXPERIMENTAL)" + depends on EXPERIMENTAL + select CRYPTO + select CRYPTO_MD5 + ---help--- + RFC2385 specifices a method of giving MD5 protection to TCP sessions. + Its main (only?) use is to protect BGP sessions between core routers + on the Internet. + + If unsure, say N. + +config TCP_MD5SIG_DEBUG + bool "TCP: MD5 Signature Option debugging" + depends on TCP_MD5SIG + source "net/ipv4/ipvs/Kconfig" diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index c05e8edaf54..dadef867a3b 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -258,6 +258,7 @@ #include #include #include +#include #include #include @@ -1942,6 +1943,13 @@ static int do_tcp_setsockopt(struct sock *sk, int level, } break; +#ifdef CONFIG_TCP_MD5SIG + case TCP_MD5SIG: + /* Read the IP->Key mappings from userspace */ + err = tp->af_specific->md5_parse(sk, optval, optlen); + break; +#endif + default: err = -ENOPROTOOPT; break; @@ -2231,6 +2239,135 @@ out: } EXPORT_SYMBOL(tcp_tso_segment); +#ifdef CONFIG_TCP_MD5SIG +static unsigned long tcp_md5sig_users; +static struct tcp_md5sig_pool **tcp_md5sig_pool; +static DEFINE_SPINLOCK(tcp_md5sig_pool_lock); + +static void __tcp_free_md5sig_pool(struct tcp_md5sig_pool **pool) +{ + int cpu; + for_each_possible_cpu(cpu) { + struct tcp_md5sig_pool *p = *per_cpu_ptr(pool, cpu); + if (p) { + if (p->md5_desc.tfm) + crypto_free_hash(p->md5_desc.tfm); + kfree(p); + p = NULL; + } + } + free_percpu(pool); +} + +void tcp_free_md5sig_pool(void) +{ + struct tcp_md5sig_pool **pool = NULL; + + spin_lock(&tcp_md5sig_pool_lock); + if (--tcp_md5sig_users == 0) { + pool = tcp_md5sig_pool; + tcp_md5sig_pool = NULL; + } + spin_unlock(&tcp_md5sig_pool_lock); + if (pool) + __tcp_free_md5sig_pool(pool); +} + +EXPORT_SYMBOL(tcp_free_md5sig_pool); + +struct tcp_md5sig_pool **__tcp_alloc_md5sig_pool(void) +{ + int cpu; + struct tcp_md5sig_pool **pool; + + pool = alloc_percpu(struct tcp_md5sig_pool *); + if (!pool) + return NULL; + + for_each_possible_cpu(cpu) { + struct tcp_md5sig_pool *p; + struct crypto_hash *hash; + + p = kzalloc(sizeof(*p), GFP_KERNEL); + if (!p) + goto out_free; + *per_cpu_ptr(pool, cpu) = p; + + hash = crypto_alloc_hash("md5", 0, CRYPTO_ALG_ASYNC); + if (!hash || IS_ERR(hash)) + goto out_free; + + p->md5_desc.tfm = hash; + } + return pool; +out_free: + __tcp_free_md5sig_pool(pool); + return NULL; +} + +struct tcp_md5sig_pool **tcp_alloc_md5sig_pool(void) +{ + struct tcp_md5sig_pool **pool; + int alloc = 0; + +retry: + spin_lock(&tcp_md5sig_pool_lock); + pool = tcp_md5sig_pool; + if (tcp_md5sig_users++ == 0) { + alloc = 1; + spin_unlock(&tcp_md5sig_pool_lock); + } else if (!pool) { + tcp_md5sig_users--; + spin_unlock(&tcp_md5sig_pool_lock); + cpu_relax(); + goto retry; + } else + spin_unlock(&tcp_md5sig_pool_lock); + + if (alloc) { + /* we cannot hold spinlock here because this may sleep. */ + struct tcp_md5sig_pool **p = __tcp_alloc_md5sig_pool(); + spin_lock(&tcp_md5sig_pool_lock); + if (!p) { + tcp_md5sig_users--; + spin_unlock(&tcp_md5sig_pool_lock); + return NULL; + } + pool = tcp_md5sig_pool; + if (pool) { + /* oops, it has already been assigned. */ + spin_unlock(&tcp_md5sig_pool_lock); + __tcp_free_md5sig_pool(p); + } else { + tcp_md5sig_pool = pool = p; + spin_unlock(&tcp_md5sig_pool_lock); + } + } + return pool; +} + +EXPORT_SYMBOL(tcp_alloc_md5sig_pool); + +struct tcp_md5sig_pool *__tcp_get_md5sig_pool(int cpu) +{ + struct tcp_md5sig_pool **p; + spin_lock(&tcp_md5sig_pool_lock); + p = tcp_md5sig_pool; + if (p) + tcp_md5sig_users++; + spin_unlock(&tcp_md5sig_pool_lock); + return (p ? *per_cpu_ptr(p, cpu) : NULL); +} + +EXPORT_SYMBOL(__tcp_get_md5sig_pool); + +void __tcp_put_md5sig_pool(void) { + __tcp_free_md5sig_pool(tcp_md5sig_pool); +} + +EXPORT_SYMBOL(__tcp_put_md5sig_pool); +#endif + extern void __skb_cb_too_small_for_tcp(int, int); extern struct tcp_congestion_ops tcp_reno; diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 4a8c96cdec7..6ab3423674b 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -2677,6 +2677,14 @@ void tcp_parse_options(struct sk_buff *skb, struct tcp_options_received *opt_rx, opt_rx->sack_ok) { TCP_SKB_CB(skb)->sacked = (ptr - 2) - (unsigned char *)th; } +#ifdef CONFIG_TCP_MD5SIG + case TCPOPT_MD5SIG: + /* + * The MD5 Hash has already been + * checked (see tcp_v{4,6}_do_rcv()). + */ + break; +#endif }; ptr+=opsize-2; length-=opsize; diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 0ad0904bf56..8c8e8112f98 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -78,6 +78,9 @@ #include #include +#include +#include + int sysctl_tcp_tw_reuse __read_mostly; int sysctl_tcp_low_latency __read_mostly; @@ -89,6 +92,13 @@ static struct socket *tcp_socket; void tcp_v4_send_check(struct sock *sk, int len, struct sk_buff *skb); +#ifdef CONFIG_TCP_MD5SIG +static struct tcp_md5sig_key *tcp_v4_md5_do_lookup(struct sock *sk, __be32 addr); +static int tcp_v4_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, + __be32 saddr, __be32 daddr, struct tcphdr *th, + int protocol, int tcplen); +#endif + struct inet_hashinfo __cacheline_aligned tcp_hashinfo = { .lhash_lock = __RW_LOCK_UNLOCKED(tcp_hashinfo.lhash_lock), .lhash_users = ATOMIC_INIT(0), @@ -526,11 +536,19 @@ int tcp_v4_gso_send_check(struct sk_buff *skb) * Exception: precedence violation. We do not implement it in any case. */ -static void tcp_v4_send_reset(struct sk_buff *skb) +static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb) { struct tcphdr *th = skb->h.th; - struct tcphdr rth; + struct { + struct tcphdr th; +#ifdef CONFIG_TCP_MD5SIG + u32 opt[(TCPOLEN_MD5SIG_ALIGNED >> 2)]; +#endif + } rep; struct ip_reply_arg arg; +#ifdef CONFIG_TCP_MD5SIG + struct tcp_md5sig_key *key; +#endif /* Never send a reset in response to a reset. */ if (th->rst) @@ -540,29 +558,50 @@ static void tcp_v4_send_reset(struct sk_buff *skb) return; /* Swap the send and the receive. */ - memset(&rth, 0, sizeof(struct tcphdr)); - rth.dest = th->source; - rth.source = th->dest; - rth.doff = sizeof(struct tcphdr) / 4; - rth.rst = 1; + memset(&rep, 0, sizeof(rep)); + rep.th.dest = th->source; + rep.th.source = th->dest; + rep.th.doff = sizeof(struct tcphdr) / 4; + rep.th.rst = 1; if (th->ack) { - rth.seq = th->ack_seq; + rep.th.seq = th->ack_seq; } else { - rth.ack = 1; - rth.ack_seq = htonl(ntohl(th->seq) + th->syn + th->fin + - skb->len - (th->doff << 2)); + rep.th.ack = 1; + rep.th.ack_seq = htonl(ntohl(th->seq) + th->syn + th->fin + + skb->len - (th->doff << 2)); } memset(&arg, 0, sizeof arg); - arg.iov[0].iov_base = (unsigned char *)&rth; - arg.iov[0].iov_len = sizeof rth; + arg.iov[0].iov_base = (unsigned char *)&rep; + arg.iov[0].iov_len = sizeof(rep.th); + +#ifdef CONFIG_TCP_MD5SIG + key = sk ? tcp_v4_md5_do_lookup(sk, skb->nh.iph->daddr) : NULL; + if (key) { + rep.opt[0] = htonl((TCPOPT_NOP << 24) | + (TCPOPT_NOP << 16) | + (TCPOPT_MD5SIG << 8) | + TCPOLEN_MD5SIG); + /* Update length and the length the header thinks exists */ + arg.iov[0].iov_len += TCPOLEN_MD5SIG_ALIGNED; + rep.th.doff = arg.iov[0].iov_len / 4; + + tcp_v4_do_calc_md5_hash((__u8 *)&rep.opt[1], + key, + skb->nh.iph->daddr, + skb->nh.iph->saddr, + &rep.th, IPPROTO_TCP, + arg.iov[0].iov_len); + } +#endif + arg.csum = csum_tcpudp_nofold(skb->nh.iph->daddr, skb->nh.iph->saddr, /*XXX*/ sizeof(struct tcphdr), IPPROTO_TCP, 0); arg.csumoffset = offsetof(struct tcphdr, check) / 2; - ip_send_reply(tcp_socket->sk, skb, &arg, sizeof rth); + ip_send_reply(tcp_socket->sk, skb, &arg, arg.iov[0].iov_len); TCP_INC_STATS_BH(TCP_MIB_OUTSEGS); TCP_INC_STATS_BH(TCP_MIB_OUTRSTS); @@ -572,15 +611,24 @@ static void tcp_v4_send_reset(struct sk_buff *skb) outside socket context is ugly, certainly. What can I do? */ -static void tcp_v4_send_ack(struct sk_buff *skb, u32 seq, u32 ack, +static void tcp_v4_send_ack(struct tcp_timewait_sock *twsk, + struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 ts) { struct tcphdr *th = skb->h.th; struct { struct tcphdr th; - u32 tsopt[TCPOLEN_TSTAMP_ALIGNED >> 2]; + u32 opt[(TCPOLEN_TSTAMP_ALIGNED >> 2) +#ifdef CONFIG_TCP_MD5SIG + + (TCPOLEN_MD5SIG_ALIGNED >> 2) +#endif + ]; } rep; struct ip_reply_arg arg; +#ifdef CONFIG_TCP_MD5SIG + struct tcp_md5sig_key *key; + struct tcp_md5sig_key tw_key; +#endif memset(&rep.th, 0, sizeof(struct tcphdr)); memset(&arg, 0, sizeof arg); @@ -588,12 +636,12 @@ static void tcp_v4_send_ack(struct sk_buff *skb, u32 seq, u32 ack, arg.iov[0].iov_base = (unsigned char *)&rep; arg.iov[0].iov_len = sizeof(rep.th); if (ts) { - rep.tsopt[0] = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | - (TCPOPT_TIMESTAMP << 8) | - TCPOLEN_TIMESTAMP); - rep.tsopt[1] = htonl(tcp_time_stamp); - rep.tsopt[2] = htonl(ts); - arg.iov[0].iov_len = sizeof(rep); + rep.opt[0] = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | + (TCPOPT_TIMESTAMP << 8) | + TCPOLEN_TIMESTAMP); + rep.opt[1] = htonl(tcp_time_stamp); + rep.opt[2] = htonl(ts); + arg.iov[0].iov_len = TCPOLEN_TSTAMP_ALIGNED; } /* Swap the send and the receive. */ @@ -605,6 +653,44 @@ static void tcp_v4_send_ack(struct sk_buff *skb, u32 seq, u32 ack, rep.th.ack = 1; rep.th.window = htons(win); +#ifdef CONFIG_TCP_MD5SIG + /* + * The SKB holds an imcoming packet, but may not have a valid ->sk + * pointer. This is especially the case when we're dealing with a + * TIME_WAIT ack, because the sk structure is long gone, and only + * the tcp_timewait_sock remains. So the md5 key is stashed in that + * structure, and we use it in preference. I believe that (twsk || + * skb->sk) holds true, but we program defensively. + */ + if (!twsk && skb->sk) { + key = tcp_v4_md5_do_lookup(skb->sk, skb->nh.iph->daddr); + } else if (twsk && twsk->tw_md5_keylen) { + tw_key.key = twsk->tw_md5_key; + tw_key.keylen = twsk->tw_md5_keylen; + key = &tw_key; + } else { + key = NULL; + } + + if (key) { + int offset = (ts) ? 3 : 0; + + rep.opt[offset++] = htonl((TCPOPT_NOP << 24) | + (TCPOPT_NOP << 16) | + (TCPOPT_MD5SIG << 8) | + TCPOLEN_MD5SIG); + arg.iov[0].iov_len += TCPOLEN_MD5SIG_ALIGNED; + rep.th.doff = arg.iov[0].iov_len/4; + + tcp_v4_do_calc_md5_hash((__u8 *)&rep.opt[offset], + key, + skb->nh.iph->daddr, + skb->nh.iph->saddr, + &rep.th, IPPROTO_TCP, + arg.iov[0].iov_len); + } +#endif + arg.csum = csum_tcpudp_nofold(skb->nh.iph->daddr, skb->nh.iph->saddr, /*XXX*/ arg.iov[0].iov_len, IPPROTO_TCP, 0); @@ -618,9 +704,9 @@ static void tcp_v4_send_ack(struct sk_buff *skb, u32 seq, u32 ack, static void tcp_v4_timewait_ack(struct sock *sk, struct sk_buff *skb) { struct inet_timewait_sock *tw = inet_twsk(sk); - const struct tcp_timewait_sock *tcptw = tcp_twsk(sk); + struct tcp_timewait_sock *tcptw = tcp_twsk(sk); - tcp_v4_send_ack(skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt, + tcp_v4_send_ack(tcptw, skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt, tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale, tcptw->tw_ts_recent); inet_twsk_put(tw); @@ -628,7 +714,8 @@ static void tcp_v4_timewait_ack(struct sock *sk, struct sk_buff *skb) static void tcp_v4_reqsk_send_ack(struct sk_buff *skb, struct request_sock *req) { - tcp_v4_send_ack(skb, tcp_rsk(req)->snt_isn + 1, tcp_rsk(req)->rcv_isn + 1, req->rcv_wnd, + tcp_v4_send_ack(NULL, skb, tcp_rsk(req)->snt_isn + 1, + tcp_rsk(req)->rcv_isn + 1, req->rcv_wnd, req->ts_recent); } @@ -714,6 +801,461 @@ static struct ip_options *tcp_v4_save_options(struct sock *sk, return dopt; } +#ifdef CONFIG_TCP_MD5SIG +/* + * RFC2385 MD5 checksumming requires a mapping of + * IP address->MD5 Key. + * We need to maintain these in the sk structure. + */ + +/* Find the Key structure for an address. */ +static struct tcp_md5sig_key *tcp_v4_md5_do_lookup(struct sock *sk, __be32 addr) +{ + struct tcp_sock *tp = tcp_sk(sk); + int i; + + if (!tp->md5sig_info || !tp->md5sig_info->entries4) + return NULL; + for (i = 0; i < tp->md5sig_info->entries4; i++) { + if (tp->md5sig_info->keys4[i].addr == addr) + return (struct tcp_md5sig_key *)&tp->md5sig_info->keys4[i]; + } + return NULL; +} + +struct tcp_md5sig_key *tcp_v4_md5_lookup(struct sock *sk, + struct sock *addr_sk) +{ + return tcp_v4_md5_do_lookup(sk, inet_sk(addr_sk)->daddr); +} + +EXPORT_SYMBOL(tcp_v4_md5_lookup); + +struct tcp_md5sig_key *tcp_v4_reqsk_md5_lookup(struct sock *sk, + struct request_sock *req) +{ + return tcp_v4_md5_do_lookup(sk, inet_rsk(req)->rmt_addr); +} + +/* This can be called on a newly created socket, from other files */ +int tcp_v4_md5_do_add(struct sock *sk, __be32 addr, + u8 *newkey, u8 newkeylen) +{ + /* Add Key to the list */ + struct tcp4_md5sig_key *key; + struct tcp_sock *tp = tcp_sk(sk); + struct tcp4_md5sig_key *keys; + + key = (struct tcp4_md5sig_key *) tcp_v4_md5_do_lookup(sk, addr); + if (key) { + /* Pre-existing entry - just update that one. */ + kfree (key->key); + key->key = newkey; + key->keylen = newkeylen; + } else { + if (!tp->md5sig_info) { + tp->md5sig_info = kzalloc(sizeof(*tp->md5sig_info), GFP_ATOMIC); + if (!tp->md5sig_info) { + kfree(newkey); + return -ENOMEM; + } + } + if (tcp_alloc_md5sig_pool() == NULL) { + kfree(newkey); + return -ENOMEM; + } + if (tp->md5sig_info->alloced4 == tp->md5sig_info->entries4) { + keys = kmalloc((sizeof(struct tcp4_md5sig_key) * + (tp->md5sig_info->entries4 + 1)), GFP_ATOMIC); + if (!keys) { + kfree(newkey); + tcp_free_md5sig_pool(); + return -ENOMEM; + } + + if (tp->md5sig_info->entries4) + memcpy(keys, tp->md5sig_info->keys4, + (sizeof (struct tcp4_md5sig_key) * + tp->md5sig_info->entries4)); + + /* Free old key list, and reference new one */ + if (tp->md5sig_info->keys4) + kfree(tp->md5sig_info->keys4); + tp->md5sig_info->keys4 = keys; + tp->md5sig_info->alloced4++; + } + tp->md5sig_info->entries4++; + tp->md5sig_info->keys4[tp->md5sig_info->entries4 - 1].addr = addr; + tp->md5sig_info->keys4[tp->md5sig_info->entries4 - 1].key = newkey; + tp->md5sig_info->keys4[tp->md5sig_info->entries4 - 1].keylen = newkeylen; + } + return 0; +} + +EXPORT_SYMBOL(tcp_v4_md5_do_add); + +static int tcp_v4_md5_add_func(struct sock *sk, struct sock *addr_sk, + u8 *newkey, u8 newkeylen) +{ + return tcp_v4_md5_do_add(sk, inet_sk(addr_sk)->daddr, + newkey, newkeylen); +} + +int tcp_v4_md5_do_del(struct sock *sk, __be32 addr) +{ + struct tcp_sock *tp = tcp_sk(sk); + int i; + + for (i = 0; i < tp->md5sig_info->entries4; i++) { + if (tp->md5sig_info->keys4[i].addr == addr) { + /* Free the key */ + kfree(tp->md5sig_info->keys4[i].key); + tp->md5sig_info->entries4--; + + if (tp->md5sig_info->entries4 == 0) { + kfree(tp->md5sig_info->keys4); + tp->md5sig_info->keys4 = NULL; + } else { + /* Need to do some manipulation */ + if (tp->md5sig_info->entries4 != i) + memcpy(&tp->md5sig_info->keys4[i], + &tp->md5sig_info->keys4[i+1], + (tp->md5sig_info->entries4 - i) + * sizeof (struct tcp4_md5sig_key)); + } + tcp_free_md5sig_pool(); + return 0; + } + } + return -ENOENT; +} + +EXPORT_SYMBOL(tcp_v4_md5_do_del); + +static void tcp_v4_clear_md5_list (struct sock *sk) +{ + struct tcp_sock *tp = tcp_sk(sk); + + /* Free each key, then the set of key keys, + * the crypto element, and then decrement our + * hold on the last resort crypto. + */ + if (tp->md5sig_info->entries4) { + int i; + for (i = 0; i < tp->md5sig_info->entries4; i++) + kfree(tp->md5sig_info->keys4[i].key); + tp->md5sig_info->entries4 = 0; + tcp_free_md5sig_pool(); + } + if (tp->md5sig_info->keys4) { + kfree(tp->md5sig_info->keys4); + tp->md5sig_info->keys4 = NULL; + tp->md5sig_info->alloced4 = 0; + } +} + +static int tcp_v4_parse_md5_keys (struct sock *sk, char __user *optval, + int optlen) +{ + struct tcp_md5sig cmd; + struct sockaddr_in *sin = (struct sockaddr_in *)&cmd.tcpm_addr; + u8 *newkey; + + if (optlen < sizeof(cmd)) + return -EINVAL; + + if (copy_from_user (&cmd, optval, sizeof(cmd))) + return -EFAULT; + + if (sin->sin_family != AF_INET) + return -EINVAL; + + if (!cmd.tcpm_key || !cmd.tcpm_keylen) { + if (!tcp_sk(sk)->md5sig_info) + return -ENOENT; + return tcp_v4_md5_do_del(sk, sin->sin_addr.s_addr); + } + + if (cmd.tcpm_keylen > TCP_MD5SIG_MAXKEYLEN) + return -EINVAL; + + if (!tcp_sk(sk)->md5sig_info) { + struct tcp_sock *tp = tcp_sk(sk); + struct tcp_md5sig_info *p; + + p = kzalloc(sizeof(struct tcp_md5sig_info), GFP_KERNEL); + if (!p) + return -EINVAL; + + tp->md5sig_info = p; + + } + + newkey = kmalloc(cmd.tcpm_keylen, GFP_KERNEL); + if (!newkey) + return -ENOMEM; + memcpy(newkey, cmd.tcpm_key, cmd.tcpm_keylen); + return tcp_v4_md5_do_add(sk, sin->sin_addr.s_addr, + newkey, cmd.tcpm_keylen); +} + +static int tcp_v4_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, + __be32 saddr, __be32 daddr, + struct tcphdr *th, int protocol, + int tcplen) +{ + struct scatterlist sg[4]; + __u16 data_len; + int block = 0; +#ifdef CONFIG_TCP_MD5SIG_DEBUG + int i; +#endif + __u16 old_checksum; + struct tcp_md5sig_pool *hp; + struct tcp4_pseudohdr *bp; + struct hash_desc *desc; + int err; + unsigned int nbytes = 0; + + /* + * Okay, so RFC2385 is turned on for this connection, + * so we need to generate the MD5 hash for the packet now. + */ + + hp = tcp_get_md5sig_pool(); + if (!hp) + goto clear_hash_noput; + + bp = &hp->md5_blk.ip4; + desc = &hp->md5_desc; + + /* + * 1. the TCP pseudo-header (in the order: source IP address, + * destination IP address, zero-padded protocol number, and + * segment length) + */ + bp->saddr = saddr; + bp->daddr = daddr; + bp->pad = 0; + bp->protocol = protocol; + bp->len = htons(tcplen); + sg_set_buf(&sg[block++], bp, sizeof(*bp)); + nbytes += sizeof(*bp); + +#ifdef CONFIG_TCP_MD5SIG_DEBUG + printk("Calcuating hash for: "); + for (i = 0; i < sizeof (*bp); i++) + printk ("%02x ", (unsigned int)((unsigned char *)bp)[i]); + printk(" "); +#endif + + /* 2. the TCP header, excluding options, and assuming a + * checksum of zero/ + */ + old_checksum = th->check; + th->check = 0; + sg_set_buf(&sg[block++], th, sizeof(struct tcphdr)); + nbytes += sizeof(struct tcphdr); +#ifdef CONFIG_TCP_MD5SIG_DEBUG + for (i = 0; i < sizeof (struct tcphdr); i++) + printk (" %02x", (unsigned int)((unsigned char *)th)[i]); +#endif + /* 3. the TCP segment data (if any) */ + data_len = tcplen - (th->doff << 2); + if (data_len > 0) { + unsigned char *data = (unsigned char *)th + (th->doff << 2); + sg_set_buf(&sg[block++], data, data_len); + nbytes += data_len; + } + + /* 4. an independently-specified key or password, known to both + * TCPs and presumably connection-specific + */ + sg_set_buf(&sg[block++], key->key, key->keylen); + nbytes += key->keylen; + +#ifdef CONFIG_TCP_MD5SIG_DEBUG + printk (" and password: "); + for (i = 0; i < key->keylen; i++) + printk ("%02x ", (unsigned int)key->key[i]); +#endif + + /* Now store the Hash into the packet */ + err = crypto_hash_init(desc); + if (err) + goto clear_hash; + err = crypto_hash_update(desc, sg, nbytes); + if (err) + goto clear_hash; + err = crypto_hash_final(desc, md5_hash); + if (err) + goto clear_hash; + + /* Reset header, and free up the crypto */ + tcp_put_md5sig_pool(); + th->check = old_checksum; + +out: +#ifdef CONFIG_TCP_MD5SIG_DEBUG + printk(" result:"); + for (i = 0; i < 16; i++) + printk (" %02x", (unsigned int)(((u8*)md5_hash)[i])); + printk("\n"); +#endif + return 0; +clear_hash: + tcp_put_md5sig_pool(); +clear_hash_noput: + memset(md5_hash, 0, 16); + goto out; +} + +int tcp_v4_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, + struct sock *sk, + struct dst_entry *dst, + struct request_sock *req, + struct tcphdr *th, int protocol, + int tcplen) +{ + __be32 saddr, daddr; + + if (sk) { + saddr = inet_sk(sk)->saddr; + daddr = inet_sk(sk)->daddr; + } else { + struct rtable *rt = (struct rtable *)dst; + BUG_ON(!rt); + saddr = rt->rt_src; + daddr = rt->rt_dst; + } + return tcp_v4_do_calc_md5_hash(md5_hash, key, + saddr, daddr, + th, protocol, tcplen); +} + +EXPORT_SYMBOL(tcp_v4_calc_md5_hash); + +static int tcp_v4_inbound_md5_hash (struct sock *sk, struct sk_buff *skb) +{ + /* + * This gets called for each TCP segment that arrives + * so we want to be efficient. + * We have 3 drop cases: + * o No MD5 hash and one expected. + * o MD5 hash and we're not expecting one. + * o MD5 hash and its wrong. + */ + __u8 *hash_location = NULL; + struct tcp_md5sig_key *hash_expected; + struct iphdr *iph = skb->nh.iph; + struct tcphdr *th = skb->h.th; + int length = (th->doff << 2) - sizeof (struct tcphdr); + int genhash; + unsigned char *ptr; + unsigned char newhash[16]; + + hash_expected = tcp_v4_md5_do_lookup(sk, iph->saddr); + + /* + * If the TCP option length is less than the TCP_MD5SIG + * option length, then we can shortcut + */ + if (length < TCPOLEN_MD5SIG) { + if (hash_expected) + return 1; + else + return 0; + } + + /* Okay, we can't shortcut - we have to grub through the options */ + ptr = (unsigned char *)(th + 1); + while (length > 0) { + int opcode = *ptr++; + int opsize; + + switch (opcode) { + case TCPOPT_EOL: + goto done_opts; + case TCPOPT_NOP: + length--; + continue; + default: + opsize = *ptr++; + if (opsize < 2) + goto done_opts; + if (opsize > length) + goto done_opts; + + if (opcode == TCPOPT_MD5SIG) { + hash_location = ptr; + goto done_opts; + } + } + ptr += opsize-2; + length -= opsize; + } +done_opts: + /* We've parsed the options - do we have a hash? */ + if (!hash_expected && !hash_location) + return 0; + + if (hash_expected && !hash_location) { + if (net_ratelimit()) { + printk(KERN_INFO "MD5 Hash NOT expected but found " + "(" NIPQUAD_FMT ", %d)->(" NIPQUAD_FMT ", %d)\n", + NIPQUAD (iph->saddr), ntohs(th->source), + NIPQUAD (iph->daddr), ntohs(th->dest)); + } + return 1; + } + + if (!hash_expected && hash_location) { + if (net_ratelimit()) { + printk(KERN_INFO "MD5 Hash NOT expected but found " + "(" NIPQUAD_FMT ", %d)->(" NIPQUAD_FMT ", %d)\n", + NIPQUAD (iph->saddr), ntohs(th->source), + NIPQUAD (iph->daddr), ntohs(th->dest)); + } + return 1; + } + + /* Okay, so this is hash_expected and hash_location - + * so we need to calculate the checksum. + */ + genhash = tcp_v4_do_calc_md5_hash(newhash, + hash_expected, + iph->saddr, iph->daddr, + th, sk->sk_protocol, + skb->len); + + if (genhash || memcmp(hash_location, newhash, 16) != 0) { + if (net_ratelimit()) { + printk(KERN_INFO "MD5 Hash failed for " + "(" NIPQUAD_FMT ", %d)->(" NIPQUAD_FMT ", %d)%s\n", + NIPQUAD (iph->saddr), ntohs(th->source), + NIPQUAD (iph->daddr), ntohs(th->dest), + genhash ? " tcp_v4_calc_md5_hash failed" : ""); +#ifdef CONFIG_TCP_MD5SIG_DEBUG + do { + int i; + printk("Received: "); + for (i = 0; i < 16; i++) + printk("%02x ", 0xff & (int)hash_location[i]); + printk("\n"); + printk("Calculated: "); + for (i = 0; i < 16; i++) + printk("%02x ", 0xff & (int)newhash[i]); + printk("\n"); + } while(0); +#endif + } + return 1; + } + return 0; +} + +#endif + struct request_sock_ops tcp_request_sock_ops __read_mostly = { .family = PF_INET, .obj_size = sizeof(struct tcp_request_sock), @@ -723,9 +1265,16 @@ struct request_sock_ops tcp_request_sock_ops __read_mostly = { .send_reset = tcp_v4_send_reset, }; +struct tcp_request_sock_ops tcp_request_sock_ipv4_ops = { +#ifdef CONFIG_TCP_MD5SIG + .md5_lookup = tcp_v4_reqsk_md5_lookup, +#endif +}; + static struct timewait_sock_ops tcp_timewait_sock_ops = { .twsk_obj_size = sizeof(struct tcp_timewait_sock), .twsk_unique = tcp_twsk_unique, + .twsk_destructor= tcp_twsk_destructor, }; int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) @@ -773,6 +1322,10 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) if (!req) goto drop; +#ifdef CONFIG_TCP_MD5SIG + tcp_rsk(req)->af_specific = &tcp_request_sock_ipv4_ops; +#endif + tcp_clear_options(&tmp_opt); tmp_opt.mss_clamp = 536; tmp_opt.user_mss = tcp_sk(sk)->rx_opt.user_mss; @@ -891,6 +1444,9 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb, struct inet_sock *newinet; struct tcp_sock *newtp; struct sock *newsk; +#ifdef CONFIG_TCP_MD5SIG + struct tcp_md5sig_key *key; +#endif if (sk_acceptq_is_full(sk)) goto exit_overflow; @@ -925,6 +1481,24 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb, newtp->advmss = dst_metric(dst, RTAX_ADVMSS); tcp_initialize_rcv_mss(newsk); +#ifdef CONFIG_TCP_MD5SIG + /* Copy over the MD5 key from the original socket */ + if ((key = tcp_v4_md5_do_lookup(sk, newinet->daddr)) != NULL) { + /* + * We're using one, so create a matching key + * on the newsk structure. If we fail to get + * memory, then we end up not copying the key + * across. Shucks. + */ + char *newkey = kmalloc(key->keylen, GFP_ATOMIC); + if (newkey) { + memcpy(newkey, key->key, key->keylen); + tcp_v4_md5_do_add(newsk, inet_sk(sk)->daddr, + newkey, key->keylen); + } + } +#endif + __inet_hash(&tcp_hashinfo, newsk, 0); __inet_inherit_port(&tcp_hashinfo, sk, newsk); @@ -1000,10 +1574,24 @@ static int tcp_v4_checksum_init(struct sk_buff *skb) */ int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb) { + struct sock *rsk; +#ifdef CONFIG_TCP_MD5SIG + /* + * We really want to reject the packet as early as possible + * if: + * o We're expecting an MD5'd packet and this is no MD5 tcp option + * o There is an MD5 option and we're not expecting one + */ + if (tcp_v4_inbound_md5_hash (sk, skb)) + goto discard; +#endif + if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */ TCP_CHECK_TIMER(sk); - if (tcp_rcv_established(sk, skb, skb->h.th, skb->len)) + if (tcp_rcv_established(sk, skb, skb->h.th, skb->len)) { + rsk = sk; goto reset; + } TCP_CHECK_TIMER(sk); return 0; } @@ -1017,20 +1605,24 @@ int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb) goto discard; if (nsk != sk) { - if (tcp_child_process(sk, nsk, skb)) + if (tcp_child_process(sk, nsk, skb)) { + rsk = nsk; goto reset; + } return 0; } } TCP_CHECK_TIMER(sk); - if (tcp_rcv_state_process(sk, skb, skb->h.th, skb->len)) + if (tcp_rcv_state_process(sk, skb, skb->h.th, skb->len)) { + rsk = sk; goto reset; + } TCP_CHECK_TIMER(sk); return 0; reset: - tcp_v4_send_reset(skb); + tcp_v4_send_reset(rsk, skb); discard: kfree_skb(skb); /* Be careful here. If this function gets more complicated and @@ -1139,7 +1731,7 @@ no_tcp_socket: bad_packet: TCP_INC_STATS_BH(TCP_MIB_INERRS); } else { - tcp_v4_send_reset(skb); + tcp_v4_send_reset(NULL, skb); } discard_it: @@ -1262,6 +1854,15 @@ struct inet_connection_sock_af_ops ipv4_specific = { #endif }; +struct tcp_sock_af_ops tcp_sock_ipv4_specific = { +#ifdef CONFIG_TCP_MD5SIG + .md5_lookup = tcp_v4_md5_lookup, + .calc_md5_hash = tcp_v4_calc_md5_hash, + .md5_add = tcp_v4_md5_add_func, + .md5_parse = tcp_v4_parse_md5_keys, +#endif +}; + /* NOTE: A lot of things set to zero explicitly by call to * sk_alloc() so need not be done here. */ @@ -1301,6 +1902,9 @@ static int tcp_v4_init_sock(struct sock *sk) icsk->icsk_af_ops = &ipv4_specific; icsk->icsk_sync_mss = tcp_sync_mss; +#ifdef CONFIG_TCP_MD5SIG + tp->af_specific = &tcp_sock_ipv4_specific; +#endif sk->sk_sndbuf = sysctl_tcp_wmem[1]; sk->sk_rcvbuf = sysctl_tcp_rmem[1]; @@ -1324,6 +1928,15 @@ int tcp_v4_destroy_sock(struct sock *sk) /* Cleans up our, hopefully empty, out_of_order_queue. */ __skb_queue_purge(&tp->out_of_order_queue); +#ifdef CONFIG_TCP_MD5SIG + /* Clean up the MD5 key list, if any */ + if (tp->md5sig_info) { + tcp_v4_clear_md5_list(sk); + kfree(tp->md5sig_info); + tp->md5sig_info = NULL; + } +#endif + #ifdef CONFIG_NET_DMA /* Cleans up our sk_async_wait_queue */ __skb_queue_purge(&sk->sk_async_wait_queue); diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index 0163d982690..ac55d8892cf 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c @@ -306,6 +306,28 @@ void tcp_time_wait(struct sock *sk, int state, int timeo) tw->tw_ipv6only = np->ipv6only; } #endif + +#ifdef CONFIG_TCP_MD5SIG + /* + * The timewait bucket does not have the key DB from the + * sock structure. We just make a quick copy of the + * md5 key being used (if indeed we are using one) + * so the timewait ack generating code has the key. + */ + do { + struct tcp_md5sig_key *key; + memset(tcptw->tw_md5_key, 0, sizeof(tcptw->tw_md5_key)); + tcptw->tw_md5_keylen = 0; + key = tp->af_specific->md5_lookup(sk, sk); + if (key != NULL) { + memcpy(&tcptw->tw_md5_key, key->key, key->keylen); + tcptw->tw_md5_keylen = key->keylen; + if (tcp_alloc_md5sig_pool() == NULL) + BUG(); + } + } while(0); +#endif + /* Linkage updates. */ __inet_twsk_hashdance(tw, sk, &tcp_hashinfo); @@ -337,6 +359,17 @@ void tcp_time_wait(struct sock *sk, int state, int timeo) tcp_done(sk); } +void tcp_twsk_destructor(struct sock *sk) +{ + struct tcp_timewait_sock *twsk = tcp_twsk(sk); +#ifdef CONFIG_TCP_MD5SIG + if (twsk->tw_md5_keylen) + tcp_put_md5sig_pool(); +#endif +} + +EXPORT_SYMBOL_GPL(tcp_twsk_destructor); + /* This is not only more efficient than what we used to do, it eliminates * a lot of code duplication between IPv4/IPv6 SYN recv processing. -DaveM * @@ -435,6 +468,11 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req, newtp->rx_opt.ts_recent_stamp = 0; newtp->tcp_header_len = sizeof(struct tcphdr); } +#ifdef CONFIG_TCP_MD5SIG + newtp->md5sig_info = NULL; /*XXX*/ + if (newtp->af_specific->md5_lookup(sk, newsk)) + newtp->tcp_header_len += TCPOLEN_MD5SIG_ALIGNED; +#endif if (skb->len >= TCP_MIN_RCVMSS+newtp->tcp_header_len) newicsk->icsk_ack.last_seg_size = skb->len - newtp->tcp_header_len; newtp->rx_opt.mss_clamp = req->mss; @@ -617,6 +655,30 @@ struct sock *tcp_check_req(struct sock *sk,struct sk_buff *skb, req, NULL); if (child == NULL) goto listen_overflow; +#ifdef CONFIG_TCP_MD5SIG + else { + /* Copy over the MD5 key from the original socket */ + struct tcp_md5sig_key *key; + struct tcp_sock *tp = tcp_sk(sk); + key = tp->af_specific->md5_lookup(sk, child); + if (key != NULL) { + /* + * We're using one, so create a matching key on the + * newsk structure. If we fail to get memory then we + * end up not copying the key across. Shucks. + */ + char *newkey = kmalloc(key->keylen, GFP_ATOMIC); + if (newkey) { + if (!tcp_alloc_md5sig_pool()) + BUG(); + memcpy(newkey, key->key, key->keylen); + tp->af_specific->md5_add(child, child, + newkey, + key->keylen); + } + } + } +#endif inet_csk_reqsk_queue_unlink(sk, req, prev); inet_csk_reqsk_queue_removed(sk, req); @@ -633,7 +695,7 @@ struct sock *tcp_check_req(struct sock *sk,struct sk_buff *skb, embryonic_reset: NET_INC_STATS_BH(LINUX_MIB_EMBRYONICRSTS); if (!(flg & TCP_FLAG_RST)) - req->rsk_ops->send_reset(skb); + req->rsk_ops->send_reset(sk, skb); inet_csk_reqsk_queue_drop(sk, req, prev); return NULL; diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 6a8581ab9a2..32c1a972fa3 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -270,7 +270,7 @@ static u16 tcp_select_window(struct sock *sk) } static void tcp_build_and_update_options(__be32 *ptr, struct tcp_sock *tp, - __u32 tstamp) + __u32 tstamp, __u8 **md5_hash) { if (tp->rx_opt.tstamp_ok) { *ptr++ = htonl((TCPOPT_NOP << 24) | @@ -298,16 +298,29 @@ static void tcp_build_and_update_options(__be32 *ptr, struct tcp_sock *tp, tp->rx_opt.eff_sacks--; } } +#ifdef CONFIG_TCP_MD5SIG + if (md5_hash) { + *ptr++ = htonl((TCPOPT_NOP << 24) | + (TCPOPT_NOP << 16) | + (TCPOPT_MD5SIG << 8) | + TCPOLEN_MD5SIG); + *md5_hash = (__u8 *)ptr; + } +#endif } /* Construct a tcp options header for a SYN or SYN_ACK packet. * If this is every changed make sure to change the definition of * MAX_SYN_SIZE to match the new maximum number of options that you * can generate. + * + * Note - that with the RFC2385 TCP option, we make room for the + * 16 byte MD5 hash. This will be filled in later, so the pointer for the + * location to be filled is passed back up. */ static void tcp_syn_build_options(__be32 *ptr, int mss, int ts, int sack, int offer_wscale, int wscale, __u32 tstamp, - __u32 ts_recent) + __u32 ts_recent, __u8 **md5_hash) { /* We always get an MSS option. * The option bytes which will be seen in normal data @@ -346,6 +359,20 @@ static void tcp_syn_build_options(__be32 *ptr, int mss, int ts, int sack, (TCPOPT_WINDOW << 16) | (TCPOLEN_WINDOW << 8) | (wscale)); +#ifdef CONFIG_TCP_MD5SIG + /* + * If MD5 is enabled, then we set the option, and include the size + * (always 18). The actual MD5 hash is added just before the + * packet is sent. + */ + if (md5_hash) { + *ptr++ = htonl((TCPOPT_NOP << 24) | + (TCPOPT_NOP << 16) | + (TCPOPT_MD5SIG << 8) | + TCPOLEN_MD5SIG); + *md5_hash = (__u8 *) ptr; + } +#endif } /* This routine actually transmits TCP packets queued in by @@ -366,6 +393,10 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, struct tcp_sock *tp; struct tcp_skb_cb *tcb; int tcp_header_size; +#ifdef CONFIG_TCP_MD5SIG + struct tcp_md5sig_key *md5; + __u8 *md5_hash_location; +#endif struct tcphdr *th; int sysctl_flags; int err; @@ -424,6 +455,16 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, if (tcp_packets_in_flight(tp) == 0) tcp_ca_event(sk, CA_EVENT_TX_START); +#ifdef CONFIG_TCP_MD5SIG + /* + * Are we doing MD5 on this segment? If so - make + * room for it. + */ + md5 = tp->af_specific->md5_lookup(sk, sk); + if (md5) + tcp_header_size += TCPOLEN_MD5SIG_ALIGNED; +#endif + th = (struct tcphdr *) skb_push(skb, tcp_header_size); skb->h.th = th; @@ -460,13 +501,34 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, (sysctl_flags & SYSCTL_FLAG_WSCALE), tp->rx_opt.rcv_wscale, tcb->when, - tp->rx_opt.ts_recent); + tp->rx_opt.ts_recent, + +#ifdef CONFIG_TCP_MD5SIG + md5 ? &md5_hash_location : +#endif + NULL); } else { tcp_build_and_update_options((__be32 *)(th + 1), - tp, tcb->when); + tp, tcb->when, +#ifdef CONFIG_TCP_MD5SIG + md5 ? &md5_hash_location : +#endif + NULL); TCP_ECN_send(sk, tp, skb, tcp_header_size); } +#ifdef CONFIG_TCP_MD5SIG + /* Calculate the MD5 hash, as we have all we need now */ + if (md5) { + tp->af_specific->calc_md5_hash(md5_hash_location, + md5, + sk, NULL, NULL, + skb->h.th, + sk->sk_protocol, + skb->len); + } +#endif + icsk->icsk_af_ops->send_check(sk, skb->len, skb); if (likely(tcb->flags & TCPCB_FLAG_ACK)) @@ -840,6 +902,11 @@ unsigned int tcp_current_mss(struct sock *sk, int large_allowed) mss_now -= (TCPOLEN_SACK_BASE_ALIGNED + (tp->rx_opt.eff_sacks * TCPOLEN_SACK_PERBLOCK)); +#ifdef CONFIG_TCP_MD5SIG + if (tp->af_specific->md5_lookup(sk, sk)) + mss_now -= TCPOLEN_MD5SIG_ALIGNED; +#endif + xmit_size_goal = mss_now; if (doing_tso) { @@ -2033,6 +2100,10 @@ struct sk_buff * tcp_make_synack(struct sock *sk, struct dst_entry *dst, struct tcphdr *th; int tcp_header_size; struct sk_buff *skb; +#ifdef CONFIG_TCP_MD5SIG + struct tcp_md5sig_key *md5; + __u8 *md5_hash_location; +#endif skb = sock_wmalloc(sk, MAX_TCP_HEADER + 15, 1, GFP_ATOMIC); if (skb == NULL) @@ -2048,6 +2119,13 @@ struct sk_buff * tcp_make_synack(struct sock *sk, struct dst_entry *dst, (ireq->wscale_ok ? TCPOLEN_WSCALE_ALIGNED : 0) + /* SACK_PERM is in the place of NOP NOP of TS */ ((ireq->sack_ok && !ireq->tstamp_ok) ? TCPOLEN_SACKPERM_ALIGNED : 0)); + +#ifdef CONFIG_TCP_MD5SIG + /* Are we doing MD5 on this segment? If so - make room for it */ + md5 = tcp_rsk(req)->af_specific->md5_lookup(sk, req); + if (md5) + tcp_header_size += TCPOLEN_MD5SIG_ALIGNED; +#endif skb->h.th = th = (struct tcphdr *) skb_push(skb, tcp_header_size); memset(th, 0, sizeof(struct tcphdr)); @@ -2085,11 +2163,29 @@ struct sk_buff * tcp_make_synack(struct sock *sk, struct dst_entry *dst, tcp_syn_build_options((__be32 *)(th + 1), dst_metric(dst, RTAX_ADVMSS), ireq->tstamp_ok, ireq->sack_ok, ireq->wscale_ok, ireq->rcv_wscale, TCP_SKB_CB(skb)->when, - req->ts_recent); + req->ts_recent, + ( +#ifdef CONFIG_TCP_MD5SIG + md5 ? &md5_hash_location : +#endif + NULL) + ); skb->csum = 0; th->doff = (tcp_header_size >> 2); TCP_INC_STATS(TCP_MIB_OUTSEGS); + +#ifdef CONFIG_TCP_MD5SIG + /* Okay, we have all we need - do the md5 hash if needed */ + if (md5) { + tp->af_specific->calc_md5_hash(md5_hash_location, + md5, + NULL, dst, req, + skb->h.th, sk->sk_protocol, + skb->len); + } +#endif + return skb; } @@ -2108,6 +2204,11 @@ static void tcp_connect_init(struct sock *sk) tp->tcp_header_len = sizeof(struct tcphdr) + (sysctl_tcp_timestamps ? TCPOLEN_TSTAMP_ALIGNED : 0); +#ifdef CONFIG_TCP_MD5SIG + if (tp->af_specific->md5_lookup(sk, sk) != NULL) + tp->tcp_header_len += TCPOLEN_MD5SIG_ALIGNED; +#endif + /* If user gave his TCP_MAXSEG, record it to clamp */ if (tp->rx_opt.user_mss) tp->rx_opt.mss_clamp = tp->rx_opt.user_mss; -- cgit v1.2.3 From a928630a2ffeaf6aa9a6b78456935b6ab1be3066 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 14 Nov 2006 19:53:22 -0800 Subject: [TCP]: Fix some warning when MD5 is disabled. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Just some mis-placed ifdefs: net/ipv4/tcp_minisocks.c: In function ‘tcp_twsk_destructor’: net/ipv4/tcp_minisocks.c:364: warning: unused variable ‘twsk’ net/ipv6/tcp_ipv6.c:1846: warning: ‘tcp_sock_ipv6_specific’ defined but not used net/ipv6/tcp_ipv6.c:1877: warning: ‘tcp_sock_ipv6_mapped_specific’ defined but not used Signed-off-by: David S. Miller --- net/ipv4/tcp_minisocks.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/ipv4') diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index ac55d8892cf..4a0ee901a88 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c @@ -361,8 +361,8 @@ void tcp_time_wait(struct sock *sk, int state, int timeo) void tcp_twsk_destructor(struct sock *sk) { - struct tcp_timewait_sock *twsk = tcp_twsk(sk); #ifdef CONFIG_TCP_MD5SIG + struct tcp_timewait_sock *twsk = tcp_twsk(sk); if (twsk->tw_md5_keylen) tcp_put_md5sig_pool(); #endif -- cgit v1.2.3 From ba4e58eca8aa9473b44fdfd312f26c4a2e7798b3 Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Mon, 27 Nov 2006 11:10:57 -0800 Subject: [NET]: Supporting UDP-Lite (RFC 3828) in Linux This is a revision of the previously submitted patch, which alters the way files are organized and compiled in the following manner: * UDP and UDP-Lite now use separate object files * source file dependencies resolved via header files net/ipv{4,6}/udp_impl.h * order of inclusion files in udp.c/udplite.c adapted accordingly [NET/IPv4]: Support for the UDP-Lite protocol (RFC 3828) This patch adds support for UDP-Lite to the IPv4 stack, provided as an extension to the existing UDPv4 code: * generic routines are all located in net/ipv4/udp.c * UDP-Lite specific routines are in net/ipv4/udplite.c * MIB/statistics support in /proc/net/snmp and /proc/net/udplite * shared API with extensions for partial checksum coverage [NET/IPv6]: Extension for UDP-Lite over IPv6 It extends the existing UDPv6 code base with support for UDP-Lite in the same manner as per UDPv4. In particular, * UDPv6 generic and shared code is in net/ipv6/udp.c * UDP-Litev6 specific extensions are in net/ipv6/udplite.c * MIB/statistics support in /proc/net/snmp6 and /proc/net/udplite6 * support for IPV6_ADDRFORM * aligned the coding style of protocol initialisation with af_inet6.c * made the error handling in udpv6_queue_rcv_skb consistent; to return `-1' on error on all error cases * consolidation of shared code [NET]: UDP-Lite Documentation and basic XFRM/Netfilter support The UDP-Lite patch further provides * API documentation for UDP-Lite * basic xfrm support * basic netfilter support for IPv4 and IPv6 (LOG target) Signed-off-by: Gerrit Renker Signed-off-by: David S. Miller --- net/ipv4/Makefile | 3 +- net/ipv4/af_inet.c | 8 +- net/ipv4/netfilter/ipt_LOG.c | 11 +- net/ipv4/proc.c | 13 ++ net/ipv4/udp.c | 518 +++++++++++++++++++++++++------------------ net/ipv4/udp_impl.h | 38 ++++ net/ipv4/udplite.c | 119 ++++++++++ net/ipv4/xfrm4_policy.c | 1 + 8 files changed, 488 insertions(+), 223 deletions(-) create mode 100644 net/ipv4/udp_impl.h create mode 100644 net/ipv4/udplite.c (limited to 'net/ipv4') diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile index 15645c51520..7a068626fee 100644 --- a/net/ipv4/Makefile +++ b/net/ipv4/Makefile @@ -8,7 +8,8 @@ obj-y := route.o inetpeer.o protocol.o \ inet_timewait_sock.o inet_connection_sock.o \ tcp.o tcp_input.o tcp_output.o tcp_timer.o tcp_ipv4.o \ tcp_minisocks.o tcp_cong.o \ - datagram.o raw.o udp.o arp.o icmp.o devinet.o af_inet.o igmp.o \ + datagram.o raw.o udp.o udplite.o \ + arp.o icmp.o devinet.o af_inet.o igmp.o \ sysctl_net_ipv4.o fib_frontend.o fib_semantics.o obj-$(CONFIG_IP_FIB_HASH) += fib_hash.o diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 4a81d54a756..8db39f7e3bf 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -104,6 +104,7 @@ #include #include #include +#include #include #include #include @@ -1223,10 +1224,13 @@ static int __init init_ipv4_mibs(void) tcp_statistics[1] = alloc_percpu(struct tcp_mib); udp_statistics[0] = alloc_percpu(struct udp_mib); udp_statistics[1] = alloc_percpu(struct udp_mib); + udplite_statistics[0] = alloc_percpu(struct udp_mib); + udplite_statistics[1] = alloc_percpu(struct udp_mib); if (! (net_statistics[0] && net_statistics[1] && ip_statistics[0] && ip_statistics[1] && tcp_statistics[0] && tcp_statistics[1] - && udp_statistics[0] && udp_statistics[1])) + && udp_statistics[0] && udp_statistics[1] + && udplite_statistics[0] && udplite_statistics[1] ) ) return -ENOMEM; (void) tcp_mib_init(); @@ -1313,6 +1317,8 @@ static int __init inet_init(void) /* Setup TCP slab cache for open requests. */ tcp_init(); + /* Add UDP-Lite (RFC 3828) */ + udplite4_register(); /* * Set the ICMP layer up diff --git a/net/ipv4/netfilter/ipt_LOG.c b/net/ipv4/netfilter/ipt_LOG.c index 7dc820df8bc..46eee64a11f 100644 --- a/net/ipv4/netfilter/ipt_LOG.c +++ b/net/ipv4/netfilter/ipt_LOG.c @@ -171,11 +171,15 @@ static void dump_packet(const struct nf_loginfo *info, } break; } - case IPPROTO_UDP: { + case IPPROTO_UDP: + case IPPROTO_UDPLITE: { struct udphdr _udph, *uh; - /* Max length: 10 "PROTO=UDP " */ - printk("PROTO=UDP "); + if (ih->protocol == IPPROTO_UDP) + /* Max length: 10 "PROTO=UDP " */ + printk("PROTO=UDP " ); + else /* Max length: 14 "PROTO=UDPLITE " */ + printk("PROTO=UDPLITE "); if (ntohs(ih->frag_off) & IP_OFFSET) break; @@ -341,6 +345,7 @@ static void dump_packet(const struct nf_loginfo *info, /* IP: 40+46+6+11+127 = 230 */ /* TCP: 10+max(25,20+30+13+9+32+11+127) = 252 */ /* UDP: 10+max(25,20) = 35 */ + /* UDPLITE: 14+max(25,20) = 39 */ /* ICMP: 11+max(25, 18+25+max(19,14,24+3+n+10,3+n+10)) = 91+n */ /* ESP: 10+max(25)+15 = 50 */ /* AH: 9+max(25)+15 = 49 */ diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c index 9c6cbe3d9fb..cd873da54cb 100644 --- a/net/ipv4/proc.c +++ b/net/ipv4/proc.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -66,6 +67,7 @@ static int sockstat_seq_show(struct seq_file *seq, void *v) tcp_death_row.tw_count, atomic_read(&tcp_sockets_allocated), atomic_read(&tcp_memory_allocated)); seq_printf(seq, "UDP: inuse %d\n", fold_prot_inuse(&udp_prot)); + seq_printf(seq, "UDPLITE: inuse %d\n", fold_prot_inuse(&udplite_prot)); seq_printf(seq, "RAW: inuse %d\n", fold_prot_inuse(&raw_prot)); seq_printf(seq, "FRAG: inuse %d memory %d\n", ip_frag_nqueues, atomic_read(&ip_frag_mem)); @@ -304,6 +306,17 @@ static int snmp_seq_show(struct seq_file *seq, void *v) fold_field((void **) udp_statistics, snmp4_udp_list[i].entry)); + /* the UDP and UDP-Lite MIBs are the same */ + seq_puts(seq, "\nUdpLite:"); + for (i = 0; snmp4_udp_list[i].name != NULL; i++) + seq_printf(seq, " %s", snmp4_udp_list[i].name); + + seq_puts(seq, "\nUdpLite:"); + for (i = 0; snmp4_udp_list[i].name != NULL; i++) + seq_printf(seq, " %lu", + fold_field((void **) udplite_statistics, + snmp4_udp_list[i].entry) ); + seq_putc(seq, '\n'); return 0; } diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 9e1bd374875..98ba7509617 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -92,22 +92,16 @@ #include #include #include -#include #include -#include -#include #include -#include #include #include #include -#include -#include #include #include -#include #include #include +#include "udp_impl.h" /* * Snmp MIB for the UDP layer @@ -120,26 +114,30 @@ DEFINE_RWLOCK(udp_hash_lock); static int udp_port_rover; -static inline int udp_lport_inuse(u16 num) +static inline int __udp_lib_lport_inuse(__be16 num, struct hlist_head udptable[]) { struct sock *sk; struct hlist_node *node; - sk_for_each(sk, node, &udp_hash[num & (UDP_HTABLE_SIZE - 1)]) + sk_for_each(sk, node, &udptable[num & (UDP_HTABLE_SIZE - 1)]) if (inet_sk(sk)->num == num) return 1; return 0; } /** - * udp_get_port - common port lookup for IPv4 and IPv6 + * __udp_lib_get_port - UDP/-Lite port lookup for IPv4 and IPv6 * * @sk: socket struct in question * @snum: port number to look up + * @udptable: hash list table, must be of UDP_HTABLE_SIZE + * @port_rover: pointer to record of last unallocated port * @saddr_comp: AF-dependent comparison of bound local IP addresses */ -int udp_get_port(struct sock *sk, unsigned short snum, - int (*saddr_cmp)(const struct sock *sk1, const struct sock *sk2)) +int __udp_lib_get_port(struct sock *sk, unsigned short snum, + struct hlist_head udptable[], int *port_rover, + int (*saddr_comp)(const struct sock *sk1, + const struct sock *sk2 ) ) { struct hlist_node *node; struct hlist_head *head; @@ -150,15 +148,15 @@ int udp_get_port(struct sock *sk, unsigned short snum, if (snum == 0) { int best_size_so_far, best, result, i; - if (udp_port_rover > sysctl_local_port_range[1] || - udp_port_rover < sysctl_local_port_range[0]) - udp_port_rover = sysctl_local_port_range[0]; + if (*port_rover > sysctl_local_port_range[1] || + *port_rover < sysctl_local_port_range[0]) + *port_rover = sysctl_local_port_range[0]; best_size_so_far = 32767; - best = result = udp_port_rover; + best = result = *port_rover; for (i = 0; i < UDP_HTABLE_SIZE; i++, result++) { int size; - head = &udp_hash[result & (UDP_HTABLE_SIZE - 1)]; + head = &udptable[result & (UDP_HTABLE_SIZE - 1)]; if (hlist_empty(head)) { if (result > sysctl_local_port_range[1]) result = sysctl_local_port_range[0] + @@ -179,15 +177,15 @@ int udp_get_port(struct sock *sk, unsigned short snum, result = sysctl_local_port_range[0] + ((result - sysctl_local_port_range[0]) & (UDP_HTABLE_SIZE - 1)); - if (!udp_lport_inuse(result)) + if (! __udp_lib_lport_inuse(result, udptable)) break; } if (i >= (1 << 16) / UDP_HTABLE_SIZE) goto fail; gotit: - udp_port_rover = snum = result; + *port_rover = snum = result; } else { - head = &udp_hash[snum & (UDP_HTABLE_SIZE - 1)]; + head = &udptable[snum & (UDP_HTABLE_SIZE - 1)]; sk_for_each(sk2, node, head) if (inet_sk(sk2)->num == snum && @@ -195,12 +193,12 @@ gotit: (!sk2->sk_reuse || !sk->sk_reuse) && (!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if || sk2->sk_bound_dev_if == sk->sk_bound_dev_if) && - (*saddr_cmp)(sk, sk2) ) + (*saddr_comp)(sk, sk2) ) goto fail; } inet_sk(sk)->num = snum; if (sk_unhashed(sk)) { - head = &udp_hash[snum & (UDP_HTABLE_SIZE - 1)]; + head = &udptable[snum & (UDP_HTABLE_SIZE - 1)]; sk_add_node(sk, head); sock_prot_inc_use(sk->sk_prot); } @@ -210,7 +208,13 @@ fail: return error; } -static inline int ipv4_rcv_saddr_equal(const struct sock *sk1, const struct sock *sk2) +__inline__ int udp_get_port(struct sock *sk, unsigned short snum, + int (*scmp)(const struct sock *, const struct sock *)) +{ + return __udp_lib_get_port(sk, snum, udp_hash, &udp_port_rover, scmp); +} + +inline int ipv4_rcv_saddr_equal(const struct sock *sk1, const struct sock *sk2) { struct inet_sock *inet1 = inet_sk(sk1), *inet2 = inet_sk(sk2); @@ -224,34 +228,20 @@ static inline int udp_v4_get_port(struct sock *sk, unsigned short snum) return udp_get_port(sk, snum, ipv4_rcv_saddr_equal); } - -static void udp_v4_hash(struct sock *sk) -{ - BUG(); -} - -static void udp_v4_unhash(struct sock *sk) -{ - write_lock_bh(&udp_hash_lock); - if (sk_del_node_init(sk)) { - inet_sk(sk)->num = 0; - sock_prot_dec_use(sk->sk_prot); - } - write_unlock_bh(&udp_hash_lock); -} - /* UDP is nearly always wildcards out the wazoo, it makes no sense to try * harder than this. -DaveM */ -static struct sock *udp_v4_lookup_longway(__be32 saddr, __be16 sport, - __be32 daddr, __be16 dport, int dif) +static struct sock *__udp4_lib_lookup(__be32 saddr, __be16 sport, + __be32 daddr, __be16 dport, + int dif, struct hlist_head udptable[]) { struct sock *sk, *result = NULL; struct hlist_node *node; unsigned short hnum = ntohs(dport); int badness = -1; - sk_for_each(sk, node, &udp_hash[hnum & (UDP_HTABLE_SIZE - 1)]) { + read_lock(&udp_hash_lock); + sk_for_each(sk, node, &udptable[hnum & (UDP_HTABLE_SIZE - 1)]) { struct inet_sock *inet = inet_sk(sk); if (inet->num == hnum && !ipv6_only_sock(sk)) { @@ -285,20 +275,10 @@ static struct sock *udp_v4_lookup_longway(__be32 saddr, __be16 sport, } } } - return result; -} - -static __inline__ struct sock *udp_v4_lookup(__be32 saddr, __be16 sport, - __be32 daddr, __be16 dport, int dif) -{ - struct sock *sk; - - read_lock(&udp_hash_lock); - sk = udp_v4_lookup_longway(saddr, sport, daddr, dport, dif); - if (sk) - sock_hold(sk); + if (result) + sock_hold(result); read_unlock(&udp_hash_lock); - return sk; + return result; } static inline struct sock *udp_v4_mcast_next(struct sock *sk, @@ -340,7 +320,7 @@ found: * to find the appropriate port. */ -void udp_err(struct sk_buff *skb, u32 info) +void __udp4_lib_err(struct sk_buff *skb, u32 info, struct hlist_head udptable[]) { struct inet_sock *inet; struct iphdr *iph = (struct iphdr*)skb->data; @@ -351,7 +331,8 @@ void udp_err(struct sk_buff *skb, u32 info) int harderr; int err; - sk = udp_v4_lookup(iph->daddr, uh->dest, iph->saddr, uh->source, skb->dev->ifindex); + sk = __udp4_lib_lookup(iph->daddr, uh->dest, iph->saddr, uh->source, + skb->dev->ifindex, udptable ); if (sk == NULL) { ICMP_INC_STATS_BH(ICMP_MIB_INERRORS); return; /* No socket for error */ @@ -405,6 +386,11 @@ out: sock_put(sk); } +__inline__ void udp_err(struct sk_buff *skb, u32 info) +{ + return __udp4_lib_err(skb, info, udp_hash); +} + /* * Throw away all pending data and cancel the corking. Socket is locked. */ @@ -419,16 +405,56 @@ static void udp_flush_pending_frames(struct sock *sk) } } +/** + * udp4_hwcsum_outgoing - handle outgoing HW checksumming + * @sk: socket we are sending on + * @skb: sk_buff containing the filled-in UDP header + * (checksum field must be zeroed out) + */ +static void udp4_hwcsum_outgoing(struct sock *sk, struct sk_buff *skb, + __be32 src, __be32 dst, int len ) +{ + unsigned int csum = 0, offset; + struct udphdr *uh = skb->h.uh; + + if (skb_queue_len(&sk->sk_write_queue) == 1) { + /* + * Only one fragment on the socket. + */ + skb->csum = offsetof(struct udphdr, check); + uh->check = ~csum_tcpudp_magic(src, dst, len, IPPROTO_UDP, 0); + } else { + /* + * HW-checksum won't work as there are two or more + * fragments on the socket so that all csums of sk_buffs + * should be together + */ + offset = skb->h.raw - skb->data; + skb->csum = skb_checksum(skb, offset, skb->len - offset, 0); + + skb->ip_summed = CHECKSUM_NONE; + + skb_queue_walk(&sk->sk_write_queue, skb) { + csum = csum_add(csum, skb->csum); + } + + uh->check = csum_tcpudp_magic(src, dst, len, IPPROTO_UDP, csum); + if (uh->check == 0) + uh->check = -1; + } +} + /* * Push out all pending data as one UDP datagram. Socket is locked. */ -static int udp_push_pending_frames(struct sock *sk, struct udp_sock *up) +int udp_push_pending_frames(struct sock *sk, struct udp_sock *up) { struct inet_sock *inet = inet_sk(sk); struct flowi *fl = &inet->cork.fl; struct sk_buff *skb; struct udphdr *uh; int err = 0; + u32 csum = 0; /* Grab the skbuff where UDP header space exists. */ if ((skb = skb_peek(&sk->sk_write_queue)) == NULL) @@ -443,52 +469,28 @@ static int udp_push_pending_frames(struct sock *sk, struct udp_sock *up) uh->len = htons(up->len); uh->check = 0; - if (sk->sk_no_check == UDP_CSUM_NOXMIT) { + if (up->pcflag) /* UDP-Lite */ + csum = udplite_csum_outgoing(sk, skb); + + else if (sk->sk_no_check == UDP_CSUM_NOXMIT) { /* UDP csum disabled */ + skb->ip_summed = CHECKSUM_NONE; goto send; - } - if (skb_queue_len(&sk->sk_write_queue) == 1) { - /* - * Only one fragment on the socket. - */ - if (skb->ip_summed == CHECKSUM_PARTIAL) { - skb->csum = offsetof(struct udphdr, check); - uh->check = ~csum_tcpudp_magic(fl->fl4_src, fl->fl4_dst, - up->len, IPPROTO_UDP, 0); - } else { - skb->csum = csum_partial((char *)uh, - sizeof(struct udphdr), skb->csum); - uh->check = csum_tcpudp_magic(fl->fl4_src, fl->fl4_dst, - up->len, IPPROTO_UDP, skb->csum); - if (uh->check == 0) - uh->check = -1; - } - } else { - unsigned int csum = 0; - /* - * HW-checksum won't work as there are two or more - * fragments on the socket so that all csums of sk_buffs - * should be together. - */ - if (skb->ip_summed == CHECKSUM_PARTIAL) { - int offset = (unsigned char *)uh - skb->data; - skb->csum = skb_checksum(skb, offset, skb->len - offset, 0); + } else if (skb->ip_summed == CHECKSUM_PARTIAL) { /* UDP hardware csum */ - skb->ip_summed = CHECKSUM_NONE; - } else { - skb->csum = csum_partial((char *)uh, - sizeof(struct udphdr), skb->csum); - } + udp4_hwcsum_outgoing(sk, skb, fl->fl4_src,fl->fl4_dst, up->len); + goto send; + + } else /* `normal' UDP */ + csum = udp_csum_outgoing(sk, skb); + + /* add protocol-dependent pseudo-header */ + uh->check = csum_tcpudp_magic(fl->fl4_src, fl->fl4_dst, up->len, + sk->sk_protocol, csum ); + if (uh->check == 0) + uh->check = -1; - skb_queue_walk(&sk->sk_write_queue, skb) { - csum = csum_add(csum, skb->csum); - } - uh->check = csum_tcpudp_magic(fl->fl4_src, fl->fl4_dst, - up->len, IPPROTO_UDP, csum); - if (uh->check == 0) - uh->check = -1; - } send: err = ip_push_pending_frames(sk); out: @@ -497,12 +499,6 @@ out: return err; } - -static unsigned short udp_check(struct udphdr *uh, int len, __be32 saddr, __be32 daddr, unsigned long base) -{ - return(csum_tcpudp_magic(saddr, daddr, len, IPPROTO_UDP, base)); -} - int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, size_t len) { @@ -516,8 +512,9 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, __be32 daddr, faddr, saddr; __be16 dport; u8 tos; - int err; + int err, is_udplite = up->pcflag; int corkreq = up->corkflag || msg->msg_flags&MSG_MORE; + int (*getfrag)(void *, char *, int, int, int, struct sk_buff *); if (len > 0xFFFF) return -EMSGSIZE; @@ -622,7 +619,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, { .daddr = faddr, .saddr = saddr, .tos = tos } }, - .proto = IPPROTO_UDP, + .proto = sk->sk_protocol, .uli_u = { .ports = { .sport = inet->sport, .dport = dport } } }; @@ -668,8 +665,9 @@ back_from_confirm: do_append_data: up->len += ulen; - err = ip_append_data(sk, ip_generic_getfrag, msg->msg_iov, ulen, - sizeof(struct udphdr), &ipc, rt, + getfrag = is_udplite ? udplite_getfrag : ip_generic_getfrag; + err = ip_append_data(sk, getfrag, msg->msg_iov, ulen, + sizeof(struct udphdr), &ipc, rt, corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags); if (err) udp_flush_pending_frames(sk); @@ -684,7 +682,7 @@ out: if (free) kfree(ipc.opt); if (!err) { - UDP_INC_STATS_USER(UDP_MIB_OUTDATAGRAMS); + UDP_INC_STATS_USER(UDP_MIB_OUTDATAGRAMS, is_udplite); return len; } /* @@ -695,7 +693,7 @@ out: * seems like overkill. */ if (err == -ENOBUFS || test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) { - UDP_INC_STATS_USER(UDP_MIB_SNDBUFERRORS); + UDP_INC_STATS_USER(UDP_MIB_SNDBUFERRORS, is_udplite); } return err; @@ -707,8 +705,8 @@ do_confirm: goto out; } -static int udp_sendpage(struct sock *sk, struct page *page, int offset, - size_t size, int flags) +int udp_sendpage(struct sock *sk, struct page *page, int offset, + size_t size, int flags) { struct udp_sock *up = udp_sk(sk); int ret; @@ -795,29 +793,18 @@ int udp_ioctl(struct sock *sk, int cmd, unsigned long arg) return(0); } -static __inline__ int __udp_checksum_complete(struct sk_buff *skb) -{ - return __skb_checksum_complete(skb); -} - -static __inline__ int udp_checksum_complete(struct sk_buff *skb) -{ - return skb->ip_summed != CHECKSUM_UNNECESSARY && - __udp_checksum_complete(skb); -} - /* * This should be easy, if there is something there we * return it, otherwise we block. */ -static int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, - size_t len, int noblock, int flags, int *addr_len) +int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, + size_t len, int noblock, int flags, int *addr_len) { struct inet_sock *inet = inet_sk(sk); struct sockaddr_in *sin = (struct sockaddr_in *)msg->msg_name; struct sk_buff *skb; - int copied, err; + int copied, err, copy_only, is_udplite = IS_UDPLITE(sk); /* * Check any passed addresses @@ -839,15 +826,25 @@ try_again: msg->msg_flags |= MSG_TRUNC; } - if (skb->ip_summed==CHECKSUM_UNNECESSARY) { - err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov, - copied); - } else if (msg->msg_flags&MSG_TRUNC) { - if (__udp_checksum_complete(skb)) + /* + * Decide whether to checksum and/or copy data. + * + * UDP: checksum may have been computed in HW, + * (re-)compute it if message is truncated. + * UDP-Lite: always needs to checksum, no HW support. + */ + copy_only = (skb->ip_summed==CHECKSUM_UNNECESSARY); + + if (is_udplite || (!copy_only && msg->msg_flags&MSG_TRUNC)) { + if (__udp_lib_checksum_complete(skb)) goto csum_copy_err; - err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov, - copied); - } else { + copy_only = 1; + } + + if (copy_only) + err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), + msg->msg_iov, copied ); + else { err = skb_copy_and_csum_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov); if (err == -EINVAL) @@ -880,7 +877,7 @@ out: return err; csum_copy_err: - UDP_INC_STATS_BH(UDP_MIB_INERRORS); + UDP_INC_STATS_BH(UDP_MIB_INERRORS, is_udplite); skb_kill_datagram(sk, skb, flags); @@ -912,11 +909,6 @@ int udp_disconnect(struct sock *sk, int flags) return 0; } -static void udp_close(struct sock *sk, long timeout) -{ - sk_common_release(sk); -} - /* return: * 1 if the the UDP system should process it * 0 if we should drop this packet @@ -1022,7 +1014,7 @@ static int udp_encap_rcv(struct sock * sk, struct sk_buff *skb) * Note that in the success and error cases, the skb is assumed to * have either been requeued or freed. */ -static int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) +int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) { struct udp_sock *up = udp_sk(sk); int rc; @@ -1030,10 +1022,8 @@ static int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) /* * Charge it to the socket, dropping if the queue is full. */ - if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb)) { - kfree_skb(skb); - return -1; - } + if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb)) + goto drop; nf_reset(skb); if (up->encap_type) { @@ -1057,31 +1047,68 @@ static int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) if (ret < 0) { /* process the ESP packet */ ret = xfrm4_rcv_encap(skb, up->encap_type); - UDP_INC_STATS_BH(UDP_MIB_INDATAGRAMS); + UDP_INC_STATS_BH(UDP_MIB_INDATAGRAMS, up->pcflag); return -ret; } /* FALLTHROUGH -- it's a UDP Packet */ } - if (sk->sk_filter && skb->ip_summed != CHECKSUM_UNNECESSARY) { - if (__udp_checksum_complete(skb)) { - UDP_INC_STATS_BH(UDP_MIB_INERRORS); - kfree_skb(skb); - return -1; + /* + * UDP-Lite specific tests, ignored on UDP sockets + */ + if ((up->pcflag & UDPLITE_RECV_CC) && UDP_SKB_CB(skb)->partial_cov) { + + /* + * MIB statistics other than incrementing the error count are + * disabled for the following two types of errors: these depend + * on the application settings, not on the functioning of the + * protocol stack as such. + * + * RFC 3828 here recommends (sec 3.3): "There should also be a + * way ... to ... at least let the receiving application block + * delivery of packets with coverage values less than a value + * provided by the application." + */ + if (up->pcrlen == 0) { /* full coverage was set */ + LIMIT_NETDEBUG(KERN_WARNING "UDPLITE: partial coverage " + "%d while full coverage %d requested\n", + UDP_SKB_CB(skb)->cscov, skb->len); + goto drop; } + /* The next case involves violating the min. coverage requested + * by the receiver. This is subtle: if receiver wants x and x is + * greater than the buffersize/MTU then receiver will complain + * that it wants x while sender emits packets of smaller size y. + * Therefore the above ...()->partial_cov statement is essential. + */ + if (UDP_SKB_CB(skb)->cscov < up->pcrlen) { + LIMIT_NETDEBUG(KERN_WARNING + "UDPLITE: coverage %d too small, need min %d\n", + UDP_SKB_CB(skb)->cscov, up->pcrlen); + goto drop; + } + } + + if (sk->sk_filter && skb->ip_summed != CHECKSUM_UNNECESSARY) { + if (__udp_lib_checksum_complete(skb)) + goto drop; skb->ip_summed = CHECKSUM_UNNECESSARY; } if ((rc = sock_queue_rcv_skb(sk,skb)) < 0) { /* Note that an ENOMEM error is charged twice */ if (rc == -ENOMEM) - UDP_INC_STATS_BH(UDP_MIB_RCVBUFERRORS); - UDP_INC_STATS_BH(UDP_MIB_INERRORS); - kfree_skb(skb); - return -1; + UDP_INC_STATS_BH(UDP_MIB_RCVBUFERRORS, up->pcflag); + goto drop; } - UDP_INC_STATS_BH(UDP_MIB_INDATAGRAMS); + + UDP_INC_STATS_BH(UDP_MIB_INDATAGRAMS, up->pcflag); return 0; + +drop: + UDP_INC_STATS_BH(UDP_MIB_INERRORS, up->pcflag); + kfree_skb(skb); + return -1; } /* @@ -1090,14 +1117,16 @@ static int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) * Note: called only from the BH handler context, * so we don't need to lock the hashes. */ -static int udp_v4_mcast_deliver(struct sk_buff *skb, struct udphdr *uh, - __be32 saddr, __be32 daddr) +static int __udp4_lib_mcast_deliver(struct sk_buff *skb, + struct udphdr *uh, + __be32 saddr, __be32 daddr, + struct hlist_head udptable[]) { struct sock *sk; int dif; read_lock(&udp_hash_lock); - sk = sk_head(&udp_hash[ntohs(uh->dest) & (UDP_HTABLE_SIZE - 1)]); + sk = sk_head(&udptable[ntohs(uh->dest) & (UDP_HTABLE_SIZE - 1)]); dif = skb->dev->ifindex; sk = udp_v4_mcast_next(sk, uh->dest, daddr, uh->source, saddr, dif); if (sk) { @@ -1131,65 +1160,75 @@ static int udp_v4_mcast_deliver(struct sk_buff *skb, struct udphdr *uh, * Otherwise, csum completion requires chacksumming packet body, * including udp header and folding it to skb->csum. */ -static void udp_checksum_init(struct sk_buff *skb, struct udphdr *uh, - unsigned short ulen, __be32 saddr, __be32 daddr) +static inline void udp4_csum_init(struct sk_buff *skb, struct udphdr *uh) { if (uh->check == 0) { skb->ip_summed = CHECKSUM_UNNECESSARY; } else if (skb->ip_summed == CHECKSUM_COMPLETE) { - if (!udp_check(uh, ulen, saddr, daddr, skb->csum)) + if (!csum_tcpudp_magic(skb->nh.iph->saddr, skb->nh.iph->daddr, + skb->len, IPPROTO_UDP, skb->csum )) skb->ip_summed = CHECKSUM_UNNECESSARY; } if (skb->ip_summed != CHECKSUM_UNNECESSARY) - skb->csum = csum_tcpudp_nofold(saddr, daddr, ulen, IPPROTO_UDP, 0); + skb->csum = csum_tcpudp_nofold(skb->nh.iph->saddr, + skb->nh.iph->daddr, + skb->len, IPPROTO_UDP, 0); /* Probably, we should checksum udp header (it should be in cache * in any case) and data in tiny packets (< rx copybreak). */ + + /* UDP = UDP-Lite with a non-partial checksum coverage */ + UDP_SKB_CB(skb)->partial_cov = 0; } /* * All we need to do is get the socket, and then do a checksum. */ -int udp_rcv(struct sk_buff *skb) +int __udp4_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[], + int is_udplite) { struct sock *sk; - struct udphdr *uh; + struct udphdr *uh = skb->h.uh; unsigned short ulen; struct rtable *rt = (struct rtable*)skb->dst; __be32 saddr = skb->nh.iph->saddr; __be32 daddr = skb->nh.iph->daddr; - int len = skb->len; /* - * Validate the packet and the UDP length. + * Validate the packet. */ if (!pskb_may_pull(skb, sizeof(struct udphdr))) - goto no_header; - - uh = skb->h.uh; + goto drop; /* No space for header. */ ulen = ntohs(uh->len); - - if (ulen > len || ulen < sizeof(*uh)) + if (ulen > skb->len) goto short_packet; - if (pskb_trim_rcsum(skb, ulen)) - goto short_packet; + if(! is_udplite ) { /* UDP validates ulen. */ + + if (ulen < sizeof(*uh) || pskb_trim_rcsum(skb, ulen)) + goto short_packet; - udp_checksum_init(skb, uh, ulen, saddr, daddr); + udp4_csum_init(skb, uh); + + } else { /* UDP-Lite validates cscov. */ + if (udplite4_csum_init(skb, uh)) + goto csum_error; + } if(rt->rt_flags & (RTCF_BROADCAST|RTCF_MULTICAST)) - return udp_v4_mcast_deliver(skb, uh, saddr, daddr); + return __udp4_lib_mcast_deliver(skb, uh, saddr, daddr, udptable); - sk = udp_v4_lookup(saddr, uh->source, daddr, uh->dest, skb->dev->ifindex); + sk = __udp4_lib_lookup(saddr, uh->source, daddr, uh->dest, + skb->dev->ifindex, udptable ); if (sk != NULL) { int ret = udp_queue_rcv_skb(sk, skb); sock_put(sk); /* a return value > 0 means to resubmit the input, but - * it it wants the return to be -protocol, or 0 + * it wants the return to be -protocol, or 0 */ if (ret > 0) return -ret; @@ -1201,10 +1240,10 @@ int udp_rcv(struct sk_buff *skb) nf_reset(skb); /* No socket. Drop packet silently, if checksum is wrong */ - if (udp_checksum_complete(skb)) + if (udp_lib_checksum_complete(skb)) goto csum_error; - UDP_INC_STATS_BH(UDP_MIB_NOPORTS); + UDP_INC_STATS_BH(UDP_MIB_NOPORTS, is_udplite); icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); /* @@ -1215,36 +1254,40 @@ int udp_rcv(struct sk_buff *skb) return(0); short_packet: - LIMIT_NETDEBUG(KERN_DEBUG "UDP: short packet: From %u.%u.%u.%u:%u %d/%d to %u.%u.%u.%u:%u\n", + LIMIT_NETDEBUG(KERN_DEBUG "UDP%s: short packet: From %u.%u.%u.%u:%u %d/%d to %u.%u.%u.%u:%u\n", + is_udplite? "-Lite" : "", NIPQUAD(saddr), ntohs(uh->source), ulen, - len, + skb->len, NIPQUAD(daddr), ntohs(uh->dest)); -no_header: - UDP_INC_STATS_BH(UDP_MIB_INERRORS); - kfree_skb(skb); - return(0); + goto drop; csum_error: /* * RFC1122: OK. Discards the bad packet silently (as far as * the network is concerned, anyway) as per 4.1.3.4 (MUST). */ - LIMIT_NETDEBUG(KERN_DEBUG "UDP: bad checksum. From %d.%d.%d.%d:%d to %d.%d.%d.%d:%d ulen %d\n", + LIMIT_NETDEBUG(KERN_DEBUG "UDP%s: bad checksum. From %d.%d.%d.%d:%d to %d.%d.%d.%d:%d ulen %d\n", + is_udplite? "-Lite" : "", NIPQUAD(saddr), ntohs(uh->source), NIPQUAD(daddr), ntohs(uh->dest), ulen); drop: - UDP_INC_STATS_BH(UDP_MIB_INERRORS); + UDP_INC_STATS_BH(UDP_MIB_INERRORS, is_udplite); kfree_skb(skb); return(0); } -static int udp_destroy_sock(struct sock *sk) +__inline__ int udp_rcv(struct sk_buff *skb) +{ + return __udp4_lib_rcv(skb, udp_hash, 0); +} + +int udp_destroy_sock(struct sock *sk) { lock_sock(sk); udp_flush_pending_frames(sk); @@ -1293,6 +1336,32 @@ static int do_udp_setsockopt(struct sock *sk, int level, int optname, } break; + /* + * UDP-Lite's partial checksum coverage (RFC 3828). + */ + /* The sender sets actual checksum coverage length via this option. + * The case coverage > packet length is handled by send module. */ + case UDPLITE_SEND_CSCOV: + if (!up->pcflag) /* Disable the option on UDP sockets */ + return -ENOPROTOOPT; + if (val != 0 && val < 8) /* Illegal coverage: use default (8) */ + val = 8; + up->pcslen = val; + up->pcflag |= UDPLITE_SEND_CC; + break; + + /* The receiver specifies a minimum checksum coverage value. To make + * sense, this should be set to at least 8 (as done below). If zero is + * used, this again means full checksum coverage. */ + case UDPLITE_RECV_CSCOV: + if (!up->pcflag) /* Disable the option on UDP sockets */ + return -ENOPROTOOPT; + if (val != 0 && val < 8) /* Avoid silly minimal values. */ + val = 8; + up->pcrlen = val; + up->pcflag |= UDPLITE_RECV_CC; + break; + default: err = -ENOPROTOOPT; break; @@ -1301,21 +1370,21 @@ static int do_udp_setsockopt(struct sock *sk, int level, int optname, return err; } -static int udp_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen) +int udp_setsockopt(struct sock *sk, int level, int optname, + char __user *optval, int optlen) { - if (level != SOL_UDP) - return ip_setsockopt(sk, level, optname, optval, optlen); - return do_udp_setsockopt(sk, level, optname, optval, optlen); + if (level == SOL_UDP || level == SOL_UDPLITE) + return do_udp_setsockopt(sk, level, optname, optval, optlen); + return ip_setsockopt(sk, level, optname, optval, optlen); } #ifdef CONFIG_COMPAT -static int compat_udp_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen) +int compat_udp_setsockopt(struct sock *sk, int level, int optname, + char __user *optval, int optlen) { - if (level != SOL_UDP) - return compat_ip_setsockopt(sk, level, optname, optval, optlen); - return do_udp_setsockopt(sk, level, optname, optval, optlen); + if (level == SOL_UDP || level == SOL_UDPLITE) + return do_udp_setsockopt(sk, level, optname, optval, optlen); + return compat_ip_setsockopt(sk, level, optname, optval, optlen); } #endif @@ -1342,6 +1411,16 @@ static int do_udp_getsockopt(struct sock *sk, int level, int optname, val = up->encap_type; break; + /* The following two cannot be changed on UDP sockets, the return is + * always 0 (which corresponds to the full checksum coverage of UDP). */ + case UDPLITE_SEND_CSCOV: + val = up->pcslen; + break; + + case UDPLITE_RECV_CSCOV: + val = up->pcrlen; + break; + default: return -ENOPROTOOPT; }; @@ -1353,21 +1432,21 @@ static int do_udp_getsockopt(struct sock *sk, int level, int optname, return 0; } -static int udp_getsockopt(struct sock *sk, int level, int optname, - char __user *optval, int __user *optlen) +int udp_getsockopt(struct sock *sk, int level, int optname, + char __user *optval, int __user *optlen) { - if (level != SOL_UDP) - return ip_getsockopt(sk, level, optname, optval, optlen); - return do_udp_getsockopt(sk, level, optname, optval, optlen); + if (level == SOL_UDP || level == SOL_UDPLITE) + return do_udp_getsockopt(sk, level, optname, optval, optlen); + return ip_getsockopt(sk, level, optname, optval, optlen); } #ifdef CONFIG_COMPAT -static int compat_udp_getsockopt(struct sock *sk, int level, int optname, +int compat_udp_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen) { - if (level != SOL_UDP) - return compat_ip_getsockopt(sk, level, optname, optval, optlen); - return do_udp_getsockopt(sk, level, optname, optval, optlen); + if (level == SOL_UDP || level == SOL_UDPLITE) + return do_udp_getsockopt(sk, level, optname, optval, optlen); + return compat_ip_getsockopt(sk, level, optname, optval, optlen); } #endif /** @@ -1387,7 +1466,8 @@ unsigned int udp_poll(struct file *file, struct socket *sock, poll_table *wait) { unsigned int mask = datagram_poll(file, sock, wait); struct sock *sk = sock->sk; - + int is_lite = IS_UDPLITE(sk); + /* Check for false positives due to checksum errors */ if ( (mask & POLLRDNORM) && !(file->f_flags & O_NONBLOCK) && @@ -1397,8 +1477,8 @@ unsigned int udp_poll(struct file *file, struct socket *sock, poll_table *wait) spin_lock_bh(&rcvq->lock); while ((skb = skb_peek(rcvq)) != NULL) { - if (udp_checksum_complete(skb)) { - UDP_INC_STATS_BH(UDP_MIB_INERRORS); + if (udp_lib_checksum_complete(skb)) { + UDP_INC_STATS_BH(UDP_MIB_INERRORS, is_lite); __skb_unlink(skb, rcvq); kfree_skb(skb); } else { @@ -1420,7 +1500,7 @@ unsigned int udp_poll(struct file *file, struct socket *sock, poll_table *wait) struct proto udp_prot = { .name = "UDP", .owner = THIS_MODULE, - .close = udp_close, + .close = udp_lib_close, .connect = ip4_datagram_connect, .disconnect = udp_disconnect, .ioctl = udp_ioctl, @@ -1431,8 +1511,8 @@ struct proto udp_prot = { .recvmsg = udp_recvmsg, .sendpage = udp_sendpage, .backlog_rcv = udp_queue_rcv_skb, - .hash = udp_v4_hash, - .unhash = udp_v4_unhash, + .hash = udp_lib_hash, + .unhash = udp_lib_unhash, .get_port = udp_v4_get_port, .obj_size = sizeof(struct udp_sock), #ifdef CONFIG_COMPAT @@ -1451,7 +1531,7 @@ static struct sock *udp_get_first(struct seq_file *seq) for (state->bucket = 0; state->bucket < UDP_HTABLE_SIZE; ++state->bucket) { struct hlist_node *node; - sk_for_each(sk, node, &udp_hash[state->bucket]) { + sk_for_each(sk, node, state->hashtable + state->bucket) { if (sk->sk_family == state->family) goto found; } @@ -1472,7 +1552,7 @@ try_again: } while (sk && sk->sk_family != state->family); if (!sk && ++state->bucket < UDP_HTABLE_SIZE) { - sk = sk_head(&udp_hash[state->bucket]); + sk = sk_head(state->hashtable + state->bucket); goto try_again; } return sk; @@ -1522,6 +1602,7 @@ static int udp_seq_open(struct inode *inode, struct file *file) if (!s) goto out; s->family = afinfo->family; + s->hashtable = afinfo->hashtable; s->seq_ops.start = udp_seq_start; s->seq_ops.next = udp_seq_next; s->seq_ops.show = afinfo->seq_show; @@ -1588,7 +1669,7 @@ static void udp4_format_sock(struct sock *sp, char *tmpbuf, int bucket) atomic_read(&sp->sk_refcnt), sp); } -static int udp4_seq_show(struct seq_file *seq, void *v) +int udp4_seq_show(struct seq_file *seq, void *v) { if (v == SEQ_START_TOKEN) seq_printf(seq, "%-127s\n", @@ -1611,6 +1692,7 @@ static struct udp_seq_afinfo udp4_seq_afinfo = { .owner = THIS_MODULE, .name = "udp", .family = AF_INET, + .hashtable = udp_hash, .seq_show = udp4_seq_show, .seq_fops = &udp4_seq_fops, }; diff --git a/net/ipv4/udp_impl.h b/net/ipv4/udp_impl.h new file mode 100644 index 00000000000..f6f4277ba6d --- /dev/null +++ b/net/ipv4/udp_impl.h @@ -0,0 +1,38 @@ +#ifndef _UDP4_IMPL_H +#define _UDP4_IMPL_H +#include +#include +#include +#include + +extern int __udp4_lib_rcv(struct sk_buff *, struct hlist_head [], int ); +extern void __udp4_lib_err(struct sk_buff *, u32, struct hlist_head []); + +extern int __udp_lib_get_port(struct sock *sk, unsigned short snum, + struct hlist_head udptable[], int *port_rover, + int (*)(const struct sock*,const struct sock*)); +extern int ipv4_rcv_saddr_equal(const struct sock *, const struct sock *); + + +extern int udp_setsockopt(struct sock *sk, int level, int optname, + char __user *optval, int optlen); +extern int udp_getsockopt(struct sock *sk, int level, int optname, + char __user *optval, int __user *optlen); + +#ifdef CONFIG_COMPAT +extern int compat_udp_setsockopt(struct sock *sk, int level, int optname, + char __user *optval, int optlen); +extern int compat_udp_getsockopt(struct sock *sk, int level, int optname, + char __user *optval, int __user *optlen); +#endif +extern int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, + size_t len, int noblock, int flags, int *addr_len); +extern int udp_sendpage(struct sock *sk, struct page *page, int offset, + size_t size, int flags); +extern int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb); +extern int udp_destroy_sock(struct sock *sk); + +#ifdef CONFIG_PROC_FS +extern int udp4_seq_show(struct seq_file *seq, void *v); +#endif +#endif /* _UDP4_IMPL_H */ diff --git a/net/ipv4/udplite.c b/net/ipv4/udplite.c new file mode 100644 index 00000000000..561de6d8c73 --- /dev/null +++ b/net/ipv4/udplite.c @@ -0,0 +1,119 @@ +/* + * UDPLITE An implementation of the UDP-Lite protocol (RFC 3828). + * + * Version: $Id: udplite.c,v 1.25 2006/10/19 07:22:36 gerrit Exp $ + * + * Authors: Gerrit Renker + * + * Changes: + * Fixes: + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include "udp_impl.h" +DEFINE_SNMP_STAT(struct udp_mib, udplite_statistics) __read_mostly; + +struct hlist_head udplite_hash[UDP_HTABLE_SIZE]; +static int udplite_port_rover; + +__inline__ int udplite_get_port(struct sock *sk, unsigned short p, + int (*c)(const struct sock *, const struct sock *)) +{ + return __udp_lib_get_port(sk, p, udplite_hash, &udplite_port_rover, c); +} + +static __inline__ int udplite_v4_get_port(struct sock *sk, unsigned short snum) +{ + return udplite_get_port(sk, snum, ipv4_rcv_saddr_equal); +} + +__inline__ int udplite_rcv(struct sk_buff *skb) +{ + return __udp4_lib_rcv(skb, udplite_hash, 1); +} + +__inline__ void udplite_err(struct sk_buff *skb, u32 info) +{ + return __udp4_lib_err(skb, info, udplite_hash); +} + +static struct net_protocol udplite_protocol = { + .handler = udplite_rcv, + .err_handler = udplite_err, + .no_policy = 1, +}; + +struct proto udplite_prot = { + .name = "UDP-Lite", + .owner = THIS_MODULE, + .close = udp_lib_close, + .connect = ip4_datagram_connect, + .disconnect = udp_disconnect, + .ioctl = udp_ioctl, + .init = udplite_sk_init, + .destroy = udp_destroy_sock, + .setsockopt = udp_setsockopt, + .getsockopt = udp_getsockopt, + .sendmsg = udp_sendmsg, + .recvmsg = udp_recvmsg, + .sendpage = udp_sendpage, + .backlog_rcv = udp_queue_rcv_skb, + .hash = udp_lib_hash, + .unhash = udp_lib_unhash, + .get_port = udplite_v4_get_port, + .obj_size = sizeof(struct udp_sock), +#ifdef CONFIG_COMPAT + .compat_setsockopt = compat_udp_setsockopt, + .compat_getsockopt = compat_udp_getsockopt, +#endif +}; + +static struct inet_protosw udplite4_protosw = { + .type = SOCK_DGRAM, + .protocol = IPPROTO_UDPLITE, + .prot = &udplite_prot, + .ops = &inet_dgram_ops, + .capability = -1, + .no_check = 0, /* must checksum (RFC 3828) */ + .flags = INET_PROTOSW_PERMANENT, +}; + +#ifdef CONFIG_PROC_FS +static struct file_operations udplite4_seq_fops; +static struct udp_seq_afinfo udplite4_seq_afinfo = { + .owner = THIS_MODULE, + .name = "udplite", + .family = AF_INET, + .hashtable = udplite_hash, + .seq_show = udp4_seq_show, + .seq_fops = &udplite4_seq_fops, +}; +#endif + +void __init udplite4_register(void) +{ + if (proto_register(&udplite_prot, 1)) + goto out_register_err; + + if (inet_add_protocol(&udplite_protocol, IPPROTO_UDPLITE) < 0) + goto out_unregister_proto; + + inet_register_protosw(&udplite4_protosw); + +#ifdef CONFIG_PROC_FS + if (udp_proc_register(&udplite4_seq_afinfo)) /* udplite4_proc_init() */ + printk(KERN_ERR "%s: Cannot register /proc!\n", __FUNCTION__); +#endif + return; + +out_unregister_proto: + proto_unregister(&udplite_prot); +out_register_err: + printk(KERN_CRIT "%s: Cannot add UDP-Lite protocol.\n", __FUNCTION__); +} + +EXPORT_SYMBOL(udplite_hash); +EXPORT_SYMBOL(udplite_prot); +EXPORT_SYMBOL(udplite_get_port); diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c index da766234607..d4107bb701b 100644 --- a/net/ipv4/xfrm4_policy.c +++ b/net/ipv4/xfrm4_policy.c @@ -199,6 +199,7 @@ _decode_session4(struct sk_buff *skb, struct flowi *fl) if (!(iph->frag_off & htons(IP_MF | IP_OFFSET))) { switch (iph->protocol) { case IPPROTO_UDP: + case IPPROTO_UDPLITE: case IPPROTO_TCP: case IPPROTO_SCTP: case IPPROTO_DCCP: -- cgit v1.2.3 From 714e85be3557222bc25f69c252326207c900a7db Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 14 Nov 2006 20:51:49 -0800 Subject: [IPV6]: Assorted trivial endianness annotations. Signed-off-by: Al Viro Signed-off-by: David S. Miller --- net/ipv4/af_inet.c | 6 +++--- net/ipv4/arp.c | 2 +- net/ipv4/cipso_ipv4.c | 8 ++++---- net/ipv4/devinet.c | 10 +++++----- net/ipv4/ip_output.c | 2 +- net/ipv4/ip_sockglue.c | 2 +- net/ipv4/raw.c | 4 ++-- net/ipv4/route.c | 4 ++-- net/ipv4/syncookies.c | 18 +++++++++--------- net/ipv4/tcp_ipv4.c | 10 +++++----- net/ipv4/tcp_minisocks.c | 2 +- net/ipv4/tcp_timer.c | 2 +- 12 files changed, 35 insertions(+), 35 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 8db39f7e3bf..1144900d37f 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -644,7 +644,7 @@ int inet_getname(struct socket *sock, struct sockaddr *uaddr, sin->sin_port = inet->dport; sin->sin_addr.s_addr = inet->daddr; } else { - __u32 addr = inet->rcv_saddr; + __be32 addr = inet->rcv_saddr; if (!addr) addr = inet->saddr; sin->sin_port = inet->sport; @@ -995,8 +995,8 @@ static int inet_sk_reselect_saddr(struct sock *sk) struct inet_sock *inet = inet_sk(sk); int err; struct rtable *rt; - __u32 old_saddr = inet->saddr; - __u32 new_saddr; + __be32 old_saddr = inet->saddr; + __be32 new_saddr; __be32 daddr = inet->daddr; if (inet->opt && inet->opt->srr) diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index cfb5d3de9c8..3981e8be9ab 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -203,7 +203,7 @@ struct neigh_table arp_tbl = { .gc_thresh3 = 1024, }; -int arp_mc_map(u32 addr, u8 *haddr, struct net_device *dev, int dir) +int arp_mc_map(__be32 addr, u8 *haddr, struct net_device *dev, int dir) { switch (dev->type) { case ARPHRD_ETHER: diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c index 6460233407c..c3a61ebbade 100644 --- a/net/ipv4/cipso_ipv4.c +++ b/net/ipv4/cipso_ipv4.c @@ -966,7 +966,7 @@ static int cipso_v4_gentag_hdr(const struct cipso_v4_doi *doi_def, buf[0] = IPOPT_CIPSO; buf[1] = CIPSO_V4_HDR_LEN + len; - *(u32 *)&buf[2] = htonl(doi_def->doi); + *(__be32 *)&buf[2] = htonl(doi_def->doi); return 0; } @@ -1140,7 +1140,7 @@ int cipso_v4_validate(unsigned char **option) } rcu_read_lock(); - doi_def = cipso_v4_doi_getdef(ntohl(*((u32 *)&opt[2]))); + doi_def = cipso_v4_doi_getdef(ntohl(*((__be32 *)&opt[2]))); if (doi_def == NULL) { err_offset = 2; goto validate_return_locked; @@ -1370,7 +1370,7 @@ int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr) if (ret_val == 0) return ret_val; - doi = ntohl(*(u32 *)&cipso_ptr[2]); + doi = ntohl(*(__be32 *)&cipso_ptr[2]); rcu_read_lock(); doi_def = cipso_v4_doi_getdef(doi); if (doi_def == NULL) { @@ -1436,7 +1436,7 @@ int cipso_v4_skbuff_getattr(const struct sk_buff *skb, if (cipso_v4_cache_check(cipso_ptr, cipso_ptr[1], secattr) == 0) return 0; - doi = ntohl(*(u32 *)&cipso_ptr[2]); + doi = ntohl(*(__be32 *)&cipso_ptr[2]); rcu_read_lock(); doi_def = cipso_v4_doi_getdef(doi); if (doi_def == NULL) diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index f38cbbae0ae..a1b356c8aa5 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -577,20 +577,20 @@ static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg * Determine a default network mask, based on the IP address. */ -static __inline__ int inet_abc_len(u32 addr) +static __inline__ int inet_abc_len(__be32 addr) { int rc = -1; /* Something else, probably a multicast. */ if (ZERONET(addr)) rc = 0; else { - addr = ntohl(addr); + __u32 haddr = ntohl(addr); - if (IN_CLASSA(addr)) + if (IN_CLASSA(haddr)) rc = 8; - else if (IN_CLASSB(addr)) + else if (IN_CLASSB(haddr)) rc = 16; - else if (IN_CLASSC(addr)) + else if (IN_CLASSC(haddr)) rc = 24; } diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index def32d8d3b0..90942a384a4 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -341,7 +341,7 @@ packet_routed: /* OK, we know where to send it, allocate and build IP header. */ iph = (struct iphdr *) skb_push(skb, sizeof(struct iphdr) + (opt ? opt->optlen : 0)); - *((__u16 *)iph) = htons((4 << 12) | (5 << 8) | (inet->tos & 0xff)); + *((__be16 *)iph) = htons((4 << 12) | (5 << 8) | (inet->tos & 0xff)); iph->tot_len = htons(skb->len); if (ip_dont_fragment(sk, &rt->u.dst) && !ipfragok) iph->frag_off = htons(IP_DF); diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 4b132953bcc..57d4bae6f08 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -355,7 +355,7 @@ int ip_recv_error(struct sock *sk, struct msghdr *msg, int len) sin = (struct sockaddr_in *)msg->msg_name; if (sin) { sin->sin_family = AF_INET; - sin->sin_addr.s_addr = *(u32*)(skb->nh.raw + serr->addr_offset); + sin->sin_addr.s_addr = *(__be32*)(skb->nh.raw + serr->addr_offset); sin->sin_port = serr->port; memset(&sin->sin_zero, 0, sizeof(sin->sin_zero)); } diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 5c31dead2bd..a6c63bbd9dd 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -854,8 +854,8 @@ static void raw_seq_stop(struct seq_file *seq, void *v) static __inline__ char *get_raw_sock(struct sock *sp, char *tmpbuf, int i) { struct inet_sock *inet = inet_sk(sp); - unsigned int dest = inet->daddr, - src = inet->rcv_saddr; + __be32 dest = inet->daddr, + src = inet->rcv_saddr; __u16 destp = 0, srcp = inet->num; diff --git a/net/ipv4/route.c b/net/ipv4/route.c index d7152b2b2c6..ee00b6506ab 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -566,8 +566,8 @@ static inline u32 rt_score(struct rtable *rt) static inline int compare_keys(struct flowi *fl1, struct flowi *fl2) { - return ((fl1->nl_u.ip4_u.daddr ^ fl2->nl_u.ip4_u.daddr) | - (fl1->nl_u.ip4_u.saddr ^ fl2->nl_u.ip4_u.saddr) | + return ((__force u32)((fl1->nl_u.ip4_u.daddr ^ fl2->nl_u.ip4_u.daddr) | + (fl1->nl_u.ip4_u.saddr ^ fl2->nl_u.ip4_u.saddr)) | (fl1->mark ^ fl2->mark) | (*(u16 *)&fl1->nl_u.ip4_u.tos ^ *(u16 *)&fl2->nl_u.ip4_u.tos) | diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c index 661e0a4bca7..6b19530905a 100644 --- a/net/ipv4/syncookies.c +++ b/net/ipv4/syncookies.c @@ -35,23 +35,23 @@ module_init(init_syncookies); #define COOKIEBITS 24 /* Upper bits store count */ #define COOKIEMASK (((__u32)1 << COOKIEBITS) - 1) -static u32 cookie_hash(u32 saddr, u32 daddr, u32 sport, u32 dport, +static u32 cookie_hash(__be32 saddr, __be32 daddr, __be16 sport, __be16 dport, u32 count, int c) { __u32 tmp[16 + 5 + SHA_WORKSPACE_WORDS]; memcpy(tmp + 3, syncookie_secret[c], sizeof(syncookie_secret[c])); - tmp[0] = saddr; - tmp[1] = daddr; - tmp[2] = (sport << 16) + dport; + tmp[0] = (__force u32)saddr; + tmp[1] = (__force u32)daddr; + tmp[2] = ((__force u32)sport << 16) + (__force u32)dport; tmp[3] = count; sha_transform(tmp + 16, (__u8 *)tmp, tmp + 16 + 5); return tmp[17]; } -static __u32 secure_tcp_syn_cookie(__u32 saddr, __u32 daddr, __u16 sport, - __u16 dport, __u32 sseq, __u32 count, +static __u32 secure_tcp_syn_cookie(__be32 saddr, __be32 daddr, __be16 sport, + __be16 dport, __u32 sseq, __u32 count, __u32 data) { /* @@ -80,8 +80,8 @@ static __u32 secure_tcp_syn_cookie(__u32 saddr, __u32 daddr, __u16 sport, * "maxdiff" if the current (passed-in) "count". The return value * is (__u32)-1 if this test fails. */ -static __u32 check_tcp_syn_cookie(__u32 cookie, __u32 saddr, __u32 daddr, - __u16 sport, __u16 dport, __u32 sseq, +static __u32 check_tcp_syn_cookie(__u32 cookie, __be32 saddr, __be32 daddr, + __be16 sport, __be16 dport, __u32 sseq, __u32 count, __u32 maxdiff) { __u32 diff; @@ -220,7 +220,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb, } ireq = inet_rsk(req); treq = tcp_rsk(req); - treq->rcv_isn = htonl(skb->h.th->seq) - 1; + treq->rcv_isn = ntohl(skb->h.th->seq) - 1; treq->snt_isn = cookie; req->mss = mss; ireq->rmt_port = skb->h.th->source; diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 8c8e8112f98..0ca8dead03b 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -542,7 +542,7 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb) struct { struct tcphdr th; #ifdef CONFIG_TCP_MD5SIG - u32 opt[(TCPOLEN_MD5SIG_ALIGNED >> 2)]; + __be32 opt[(TCPOLEN_MD5SIG_ALIGNED >> 2)]; #endif } rep; struct ip_reply_arg arg; @@ -618,9 +618,9 @@ static void tcp_v4_send_ack(struct tcp_timewait_sock *twsk, struct tcphdr *th = skb->h.th; struct { struct tcphdr th; - u32 opt[(TCPOLEN_TSTAMP_ALIGNED >> 2) + __be32 opt[(TCPOLEN_TSTAMP_ALIGNED >> 2) #ifdef CONFIG_TCP_MD5SIG - + (TCPOLEN_MD5SIG_ALIGNED >> 2) + + (TCPOLEN_MD5SIG_ALIGNED >> 2) #endif ]; } rep; @@ -2333,8 +2333,8 @@ static void get_tcp4_sock(struct sock *sp, char *tmpbuf, int i) struct tcp_sock *tp = tcp_sk(sp); const struct inet_connection_sock *icsk = inet_csk(sp); struct inet_sock *inet = inet_sk(sp); - unsigned int dest = inet->daddr; - unsigned int src = inet->rcv_saddr; + __be32 dest = inet->daddr; + __be32 src = inet->rcv_saddr; __u16 destp = ntohs(inet->dport); __u16 srcp = ntohs(inet->sport); diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index 4a0ee901a88..383cb38461c 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c @@ -493,7 +493,7 @@ struct sock *tcp_check_req(struct sock *sk,struct sk_buff *skb, struct request_sock **prev) { struct tcphdr *th = skb->h.th; - u32 flg = tcp_flag_word(th) & (TCP_FLAG_RST|TCP_FLAG_SYN|TCP_FLAG_ACK); + __be32 flg = tcp_flag_word(th) & (TCP_FLAG_RST|TCP_FLAG_SYN|TCP_FLAG_ACK); int paws_reject = 0; struct tcp_options_received tmp_opt; struct sock *child; diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index fb09ade5897..3355c276b61 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c @@ -297,7 +297,7 @@ static void tcp_retransmit_timer(struct sock *sk) if (net_ratelimit()) { struct inet_sock *inet = inet_sk(sk); printk(KERN_DEBUG "TCP: Treason uncloaked! Peer %u.%u.%u.%u:%u/%u shrinks window %u:%u. Repaired.\n", - NIPQUAD(inet->daddr), htons(inet->dport), + NIPQUAD(inet->daddr), ntohs(inet->dport), inet->num, tp->snd_una, tp->snd_nxt); } #endif -- cgit v1.2.3 From 42d224aa170a4f7446cea6c972d9302d524545e5 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 14 Nov 2006 21:11:08 -0800 Subject: [NETFILTER]: More trivial annotations. Signed-off-by: Al Viro Signed-off-by: David S. Miller --- net/ipv4/netfilter/ip_conntrack_amanda.c | 2 +- net/ipv4/netfilter/ip_conntrack_helper_h323.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/netfilter/ip_conntrack_amanda.c b/net/ipv4/netfilter/ip_conntrack_amanda.c index 6c7383a8e42..7fca246615d 100644 --- a/net/ipv4/netfilter/ip_conntrack_amanda.c +++ b/net/ipv4/netfilter/ip_conntrack_amanda.c @@ -180,7 +180,7 @@ static struct ip_conntrack_helper amanda_helper = { .help = help, .name = "amanda", - .tuple = { .src = { .u = { __constant_htons(10080) } }, + .tuple = { .src = { .u = { .udp = {.port = __constant_htons(10080) } } }, .dst = { .protonum = IPPROTO_UDP }, }, .mask = { .src = { .u = { 0xFFFF } }, diff --git a/net/ipv4/netfilter/ip_conntrack_helper_h323.c b/net/ipv4/netfilter/ip_conntrack_helper_h323.c index 6cb9070cd0b..a06b340ea41 100644 --- a/net/ipv4/netfilter/ip_conntrack_helper_h323.c +++ b/net/ipv4/netfilter/ip_conntrack_helper_h323.c @@ -1153,7 +1153,7 @@ static struct ip_conntrack_helper ip_conntrack_helper_q931 = { .me = THIS_MODULE, .max_expected = H323_RTP_CHANNEL_MAX * 4 + 4 /* T.120 and H.245 */ , .timeout = 240, - .tuple = {.src = {.u = {__constant_htons(Q931_PORT)}}, + .tuple = {.src = {.u = {.tcp = {.port = __constant_htons(Q931_PORT)}}}, .dst = {.protonum = IPPROTO_TCP}}, .mask = {.src = {.u = {0xFFFF}}, .dst = {.protonum = 0xFF}}, @@ -1746,7 +1746,7 @@ static struct ip_conntrack_helper ip_conntrack_helper_ras = { .me = THIS_MODULE, .max_expected = 32, .timeout = 240, - .tuple = {.src = {.u = {__constant_htons(RAS_PORT)}}, + .tuple = {.src = {.u = {.tcp = {.port = __constant_htons(RAS_PORT)}}}, .dst = {.protonum = IPPROTO_UDP}}, .mask = {.src = {.u = {0xFFFE}}, .dst = {.protonum = 0xFF}}, -- cgit v1.2.3 From 75e7ce66ef044fa877a420f1b4febe416bbc09ad Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 14 Nov 2006 21:13:28 -0800 Subject: [IPVS]: Annotate ..._app_hashkey(). Signed-off-by: Al Viro Signed-off-by: David S. Miller --- net/ipv4/ipvs/ip_vs_proto_tcp.c | 8 +++++--- net/ipv4/ipvs/ip_vs_proto_udp.c | 8 +++++--- 2 files changed, 10 insertions(+), 6 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/ipvs/ip_vs_proto_tcp.c b/net/ipv4/ipvs/ip_vs_proto_tcp.c index 7de385267b3..b60a07910df 100644 --- a/net/ipv4/ipvs/ip_vs_proto_tcp.c +++ b/net/ipv4/ipvs/ip_vs_proto_tcp.c @@ -490,16 +490,18 @@ tcp_state_transition(struct ip_vs_conn *cp, int direction, static struct list_head tcp_apps[TCP_APP_TAB_SIZE]; static DEFINE_SPINLOCK(tcp_app_lock); -static inline __u16 tcp_app_hashkey(__u16 port) +static inline __u16 tcp_app_hashkey(__be16 port) { - return ((port >> TCP_APP_TAB_BITS) ^ port) & TCP_APP_TAB_MASK; + return (((__force u16)port >> TCP_APP_TAB_BITS) ^ (__force u16)port) + & TCP_APP_TAB_MASK; } static int tcp_register_app(struct ip_vs_app *inc) { struct ip_vs_app *i; - __u16 hash, port = inc->port; + __u16 hash; + __be16 port = inc->port; int ret = 0; hash = tcp_app_hashkey(port); diff --git a/net/ipv4/ipvs/ip_vs_proto_udp.c b/net/ipv4/ipvs/ip_vs_proto_udp.c index 452cb9c384b..261581e6a81 100644 --- a/net/ipv4/ipvs/ip_vs_proto_udp.c +++ b/net/ipv4/ipvs/ip_vs_proto_udp.c @@ -282,16 +282,18 @@ udp_csum_check(struct sk_buff *skb, struct ip_vs_protocol *pp) static struct list_head udp_apps[UDP_APP_TAB_SIZE]; static DEFINE_SPINLOCK(udp_app_lock); -static inline __u16 udp_app_hashkey(__u16 port) +static inline __u16 udp_app_hashkey(__be16 port) { - return ((port >> UDP_APP_TAB_BITS) ^ port) & UDP_APP_TAB_MASK; + return (((__force u16)port >> UDP_APP_TAB_BITS) ^ (__force u16)port) + & UDP_APP_TAB_MASK; } static int udp_register_app(struct ip_vs_app *inc) { struct ip_vs_app *i; - __u16 hash, port = inc->port; + __u16 hash; + __be16 port = inc->port; int ret = 0; hash = udp_app_hashkey(port); -- cgit v1.2.3 From d3bc23e7ee9db8023dff5a86bb3b0069ed018789 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 14 Nov 2006 21:24:49 -0800 Subject: [NET]: Annotate callers of csum_fold() in net/* Signed-off-by: Al Viro Signed-off-by: David S. Miller --- net/ipv4/icmp.c | 4 ++-- net/ipv4/igmp.c | 2 +- net/ipv4/ip_gre.c | 4 ++-- net/ipv4/ip_output.c | 2 +- net/ipv4/ipmr.c | 2 +- net/ipv4/ipvs/ip_vs_core.c | 2 +- net/ipv4/netfilter.c | 2 +- net/ipv4/tcp.c | 8 +++++--- 8 files changed, 14 insertions(+), 12 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index b39a37a4754..cb9da0842b7 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -356,7 +356,7 @@ static void icmp_push_reply(struct icmp_bxm *icmp_param, ip_flush_pending_frames(icmp_socket->sk); else if ((skb = skb_peek(&icmp_socket->sk->sk_write_queue)) != NULL) { struct icmphdr *icmph = skb->h.icmph; - unsigned int csum = 0; + __wsum csum = 0; struct sk_buff *skb1; skb_queue_walk(&icmp_socket->sk->sk_write_queue, skb1) { @@ -931,7 +931,7 @@ int icmp_rcv(struct sk_buff *skb) switch (skb->ip_summed) { case CHECKSUM_COMPLETE: - if (!(u16)csum_fold(skb->csum)) + if (!csum_fold(skb->csum)) break; /* fall through */ case CHECKSUM_NONE: diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index 6eee71647b7..0017ccb01d6 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -932,7 +932,7 @@ int igmp_rcv(struct sk_buff *skb) switch (skb->ip_summed) { case CHECKSUM_COMPLETE: - if (!(u16)csum_fold(skb->csum)) + if (!csum_fold(skb->csum)) break; /* fall through */ case CHECKSUM_NONE: diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 25221146deb..2bf54adee8c 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -557,7 +557,7 @@ static int ipgre_rcv(struct sk_buff *skb) struct iphdr *iph; u8 *h; __be16 flags; - u16 csum = 0; + __sum16 csum = 0; __be32 key = 0; u32 seqno = 0; struct ip_tunnel *tunnel; @@ -580,7 +580,7 @@ static int ipgre_rcv(struct sk_buff *skb) if (flags&GRE_CSUM) { switch (skb->ip_summed) { case CHECKSUM_COMPLETE: - csum = (u16)csum_fold(skb->csum); + csum = csum_fold(skb->csum); if (!csum) break; /* fall through */ diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 90942a384a4..5f3e35c0363 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -1384,7 +1384,7 @@ void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *ar &ipc, rt, MSG_DONTWAIT); if ((skb = skb_peek(&sk->sk_write_queue)) != NULL) { if (arg->csumoffset >= 0) - *((u16 *)skb->h.raw + arg->csumoffset) = csum_fold(csum_add(skb->csum, arg->csum)); + *((__sum16 *)skb->h.raw + arg->csumoffset) = csum_fold(csum_add(skb->csum, arg->csum)); skb->ip_summed = CHECKSUM_NONE; ip_push_pending_frames(sk); } diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 97cfa97c8ab..efcf45ecc81 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -1493,7 +1493,7 @@ static int pim_rcv(struct sk_buff * skb) if (pim->type != ((PIM_VERSION<<4)|(PIM_REGISTER)) || (pim->flags&PIM_NULL_REGISTER) || (ip_compute_csum((void *)pim, sizeof(*pim)) != 0 && - (u16)csum_fold(skb_checksum(skb, 0, skb->len, 0)))) + csum_fold(skb_checksum(skb, 0, skb->len, 0)))) goto drop; /* check if the inner packet is destined to mcast group */ diff --git a/net/ipv4/ipvs/ip_vs_core.c b/net/ipv4/ipvs/ip_vs_core.c index 1445bb47fea..fac2dffd667 100644 --- a/net/ipv4/ipvs/ip_vs_core.c +++ b/net/ipv4/ipvs/ip_vs_core.c @@ -538,7 +538,7 @@ static unsigned int ip_vs_post_routing(unsigned int hooknum, u16 ip_vs_checksum_complete(struct sk_buff *skb, int offset) { - return (u16) csum_fold(skb_checksum(skb, offset, skb->len - offset, 0)); + return csum_fold(skb_checksum(skb, offset, skb->len - offset, 0)); } static inline struct sk_buff * diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c index e49441ac357..b797a37c01c 100644 --- a/net/ipv4/netfilter.c +++ b/net/ipv4/netfilter.c @@ -172,7 +172,7 @@ unsigned int nf_ip_checksum(struct sk_buff *skb, unsigned int hook, case CHECKSUM_COMPLETE: if (hook != NF_IP_PRE_ROUTING && hook != NF_IP_LOCAL_IN) break; - if ((protocol == 0 && !(u16)csum_fold(skb->csum)) || + if ((protocol == 0 && !csum_fold(skb->csum)) || !csum_tcpudp_magic(iph->saddr, iph->daddr, skb->len - dataoff, protocol, skb->csum)) { diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index dadef867a3b..168f9de906b 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -2162,7 +2162,7 @@ struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int features) struct tcphdr *th; unsigned thlen; unsigned int seq; - unsigned int delta; + __be32 delta; unsigned int oldlen; unsigned int len; @@ -2215,7 +2215,8 @@ struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int features) do { th->fin = th->psh = 0; - th->check = ~csum_fold(th->check + delta); + th->check = ~csum_fold((__force __wsum)((__force u32)th->check + + (__force u32)delta)); if (skb->ip_summed != CHECKSUM_PARTIAL) th->check = csum_fold(csum_partial(skb->h.raw, thlen, skb->csum)); @@ -2229,7 +2230,8 @@ struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int features) } while (skb->next); delta = htonl(oldlen + (skb->tail - skb->h.raw) + skb->data_len); - th->check = ~csum_fold(th->check + delta); + th->check = ~csum_fold((__force __wsum)((__force u32)th->check + + (__force u32)delta)); if (skb->ip_summed != CHECKSUM_PARTIAL) th->check = csum_fold(csum_partial(skb->h.raw, thlen, skb->csum)); -- cgit v1.2.3 From 6b11687ef003ed595033da89643c8995676f929d Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 14 Nov 2006 21:28:24 -0800 Subject: [NET]: Annotate csum_tcpudp_magic() callers in net/* Signed-off-by: Al Viro Signed-off-by: David S. Miller --- net/ipv4/udp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net/ipv4') diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 98ba7509617..f9c4ed7207b 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -414,8 +414,9 @@ static void udp_flush_pending_frames(struct sock *sk) static void udp4_hwcsum_outgoing(struct sock *sk, struct sk_buff *skb, __be32 src, __be32 dst, int len ) { - unsigned int csum = 0, offset; + unsigned int offset; struct udphdr *uh = skb->h.uh; + __wsum csum = 0; if (skb_queue_len(&sk->sk_write_queue) == 1) { /* -- cgit v1.2.3 From 44bb93633f57a55979f3c2589b10fd6a2bfc7c08 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 14 Nov 2006 21:36:14 -0800 Subject: [NET]: Annotate csum_partial() callers in net/* Signed-off-by: Al Viro Signed-off-by: David S. Miller --- net/ipv4/ip_output.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 5f3e35c0363..f9194f7e39d 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -682,7 +682,7 @@ ip_generic_getfrag(void *from, char *to, int offset, int len, int odd, struct sk if (memcpy_fromiovecend(to, iov, offset, len) < 0) return -EFAULT; } else { - unsigned int csum = 0; + __wsum csum = 0; if (csum_partial_copy_fromiovecend(to, iov, offset, len, &csum) < 0) return -EFAULT; skb->csum = csum_block_add(skb->csum, csum, odd); @@ -690,11 +690,11 @@ ip_generic_getfrag(void *from, char *to, int offset, int len, int odd, struct sk return 0; } -static inline unsigned int +static inline __wsum csum_page(struct page *page, int offset, int copy) { char *kaddr; - unsigned int csum; + __wsum csum; kaddr = kmap(page); csum = csum_partial(kaddr + offset, copy, 0); kunmap(page); @@ -1166,7 +1166,7 @@ ssize_t ip_append_page(struct sock *sk, struct page *page, } if (skb->ip_summed == CHECKSUM_NONE) { - unsigned int csum; + __wsum csum; csum = csum_page(page, offset, len); skb->csum = csum_block_add(skb->csum, csum, skb->len); } -- cgit v1.2.3 From 5084205faf45384fff25c4cf77dd5c96279283ad Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 14 Nov 2006 21:36:34 -0800 Subject: [NET]: Annotate callers of csum_partial_copy_...() and csum_and_copy...() in net/* Signed-off-by: Al Viro Signed-off-by: David S. Miller --- net/ipv4/ip_output.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/ipv4') diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index f9194f7e39d..1da3d32f828 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -1314,7 +1314,7 @@ void ip_flush_pending_frames(struct sock *sk) static int ip_reply_glue_bits(void *dptr, char *to, int offset, int len, int odd, struct sk_buff *skb) { - unsigned int csum; + __wsum csum; csum = csum_partial_copy_nocheck(dptr+offset, to, len, 0); skb->csum = csum_block_add(skb->csum, csum, odd); -- cgit v1.2.3 From 5f92a7388a29594d6c365b23a48d4bb8299a3ea7 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 14 Nov 2006 21:36:54 -0800 Subject: [NET]: Annotate callers of the reset of checksum.h stuff. Signed-off-by: Al Viro Signed-off-by: David S. Miller --- net/ipv4/icmp.c | 2 +- net/ipv4/ip_gre.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index cb9da0842b7..40cf0d0e1b8 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -332,7 +332,7 @@ static int icmp_glue_bits(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb) { struct icmp_bxm *icmp_param = (struct icmp_bxm *)from; - unsigned int csum; + __wsum csum; csum = skb_copy_and_csum_bits(icmp_param->skb, icmp_param->offset + offset, diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 2bf54adee8c..476cb6084c7 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -877,7 +877,7 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) } if (tunnel->parms.o_flags&GRE_CSUM) { *ptr = 0; - *(__be16*)ptr = ip_compute_csum((void*)(iph+1), skb->len - sizeof(struct iphdr)); + *(__sum16*)ptr = ip_compute_csum((void*)(iph+1), skb->len - sizeof(struct iphdr)); } } -- cgit v1.2.3 From b1550f221255f7dd06048d832bf0f3d166840e1c Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 14 Nov 2006 21:37:50 -0800 Subject: [NET]: Annotate ip_vs_checksum_complete() and callers. Signed-off-by: Al Viro Signed-off-by: David S. Miller --- net/ipv4/ipvs/ip_vs_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/ipv4') diff --git a/net/ipv4/ipvs/ip_vs_core.c b/net/ipv4/ipvs/ip_vs_core.c index fac2dffd667..34257520a3a 100644 --- a/net/ipv4/ipvs/ip_vs_core.c +++ b/net/ipv4/ipvs/ip_vs_core.c @@ -536,7 +536,7 @@ static unsigned int ip_vs_post_routing(unsigned int hooknum, return NF_STOP; } -u16 ip_vs_checksum_complete(struct sk_buff *skb, int offset) +__sum16 ip_vs_checksum_complete(struct sk_buff *skb, int offset) { return csum_fold(skb_checksum(skb, offset, skb->len - offset, 0)); } -- cgit v1.2.3 From b51655b958dfb1176bfcf99466231fdbef8751ff Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 14 Nov 2006 21:40:42 -0800 Subject: [NET]: Annotate __skb_checksum_complete() and friends. Signed-off-by: Al Viro Signed-off-by: David S. Miller --- net/ipv4/netfilter.c | 4 ++-- net/ipv4/tcp_input.c | 4 ++-- net/ipv4/tcp_ipv4.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c index b797a37c01c..a68966059b5 100644 --- a/net/ipv4/netfilter.c +++ b/net/ipv4/netfilter.c @@ -162,11 +162,11 @@ static int nf_ip_reroute(struct sk_buff **pskb, const struct nf_info *info) return 0; } -unsigned int nf_ip_checksum(struct sk_buff *skb, unsigned int hook, +__sum16 nf_ip_checksum(struct sk_buff *skb, unsigned int hook, unsigned int dataoff, u_int8_t protocol) { struct iphdr *iph = skb->nh.iph; - unsigned int csum = 0; + __sum16 csum = 0; switch (skb->ip_summed) { case CHECKSUM_COMPLETE: diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 6ab3423674b..9304034c0c4 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -3790,9 +3790,9 @@ static int tcp_copy_to_iovec(struct sock *sk, struct sk_buff *skb, int hlen) return err; } -static int __tcp_checksum_complete_user(struct sock *sk, struct sk_buff *skb) +static __sum16 __tcp_checksum_complete_user(struct sock *sk, struct sk_buff *skb) { - int result; + __sum16 result; if (sock_owned_by_user(sk)) { local_bh_enable(); diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 0ca8dead03b..dadf8027241 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1544,7 +1544,7 @@ static struct sock *tcp_v4_hnd_req(struct sock *sk, struct sk_buff *skb) return sk; } -static int tcp_v4_checksum_init(struct sk_buff *skb) +static __sum16 tcp_v4_checksum_init(struct sk_buff *skb) { if (skb->ip_summed == CHECKSUM_COMPLETE) { if (!tcp_v4_check(skb->h.th, skb->len, skb->nh.iph->saddr, -- cgit v1.2.3 From f6ab028804bdc580fe0915494dbf31f5ea473ca7 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 16 Nov 2006 02:36:50 -0800 Subject: [NET]: Make mangling a checksum (0 -> 0xffff on the wire) explicit. Signed-off-by: Al Viro Signed-off-by: David S. Miller --- net/ipv4/ipvs/ip_vs_proto_udp.c | 6 +++--- net/ipv4/netfilter/ip_nat_helper.c | 2 +- net/ipv4/netfilter/ip_nat_proto_udp.c | 2 +- net/ipv4/udp.c | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/ipvs/ip_vs_proto_udp.c b/net/ipv4/ipvs/ip_vs_proto_udp.c index 261581e6a81..3647397e416 100644 --- a/net/ipv4/ipvs/ip_vs_proto_udp.c +++ b/net/ipv4/ipvs/ip_vs_proto_udp.c @@ -125,7 +125,7 @@ udp_fast_csum_update(struct udphdr *uhdr, __be32 oldip, __be32 newip, ip_vs_check_diff(oldport ^ htons(0xFFFF), newport, uhdr->check)); if (!uhdr->check) - uhdr->check = -1; + uhdr->check = CSUM_MANGLED_0; } static int @@ -173,7 +173,7 @@ udp_snat_handler(struct sk_buff **pskb, cp->protocol, (*pskb)->csum); if (udph->check == 0) - udph->check = -1; + udph->check = CSUM_MANGLED_0; IP_VS_DBG(11, "O-pkt: %s O-csum=%d (+%zd)\n", pp->name, udph->check, (char*)&(udph->check) - (char*)udph); @@ -228,7 +228,7 @@ udp_dnat_handler(struct sk_buff **pskb, cp->protocol, (*pskb)->csum); if (udph->check == 0) - udph->check = -1; + udph->check = CSUM_MANGLED_0; (*pskb)->ip_summed = CHECKSUM_UNNECESSARY; } return 1; diff --git a/net/ipv4/netfilter/ip_nat_helper.c b/net/ipv4/netfilter/ip_nat_helper.c index 3bf85848055..3e7fd64c216 100644 --- a/net/ipv4/netfilter/ip_nat_helper.c +++ b/net/ipv4/netfilter/ip_nat_helper.c @@ -264,7 +264,7 @@ ip_nat_mangle_udp_packet(struct sk_buff **pskb, csum_partial((char *)udph, datalen, 0)); if (!udph->check) - udph->check = -1; + udph->check = CSUM_MANGLED_0; } else udph->check = nf_proto_csum_update(*pskb, htons(oldlen) ^ htons(0xFFFF), diff --git a/net/ipv4/netfilter/ip_nat_proto_udp.c b/net/ipv4/netfilter/ip_nat_proto_udp.c index 4bbec7730d1..82f8a6ab07e 100644 --- a/net/ipv4/netfilter/ip_nat_proto_udp.c +++ b/net/ipv4/netfilter/ip_nat_proto_udp.c @@ -121,7 +121,7 @@ udp_manip_pkt(struct sk_buff **pskb, *portptr ^ htons(0xFFFF), newport, hdr->check, 0); if (!hdr->check) - hdr->check = -1; + hdr->check = CSUM_MANGLED_0; } *portptr = newport; return 1; diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index f9c4ed7207b..dc19ba1e73b 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -441,7 +441,7 @@ static void udp4_hwcsum_outgoing(struct sock *sk, struct sk_buff *skb, uh->check = csum_tcpudp_magic(src, dst, len, IPPROTO_UDP, csum); if (uh->check == 0) - uh->check = -1; + uh->check = CSUM_MANGLED_0; } } @@ -490,7 +490,7 @@ int udp_push_pending_frames(struct sock *sk, struct udp_sock *up) uh->check = csum_tcpudp_magic(fl->fl4_src, fl->fl4_dst, up->len, sk->sk_protocol, csum ); if (uh->check == 0) - uh->check = -1; + uh->check = CSUM_MANGLED_0; send: err = ip_push_pending_frames(sk); -- cgit v1.2.3 From f9214b2627fb8582af1986afc4aed5942086a535 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 16 Nov 2006 02:41:18 -0800 Subject: [NET]: ipvs checksum annotations. Signed-off-by: Al Viro Signed-off-by: David S. Miller --- net/ipv4/ipvs/ip_vs_proto_tcp.c | 6 +++--- net/ipv4/ipvs/ip_vs_proto_udp.c | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/ipvs/ip_vs_proto_tcp.c b/net/ipv4/ipvs/ip_vs_proto_tcp.c index b60a07910df..16a9ebee2fe 100644 --- a/net/ipv4/ipvs/ip_vs_proto_tcp.c +++ b/net/ipv4/ipvs/ip_vs_proto_tcp.c @@ -116,9 +116,9 @@ tcp_fast_csum_update(struct tcphdr *tcph, __be32 oldip, __be32 newip, __be16 oldport, __be16 newport) { tcph->check = - ip_vs_check_diff(~oldip, newip, - ip_vs_check_diff(oldport ^ htons(0xFFFF), - newport, tcph->check)); + csum_fold(ip_vs_check_diff4(oldip, newip, + ip_vs_check_diff2(oldport, newport, + ~csum_unfold(tcph->check)))); } diff --git a/net/ipv4/ipvs/ip_vs_proto_udp.c b/net/ipv4/ipvs/ip_vs_proto_udp.c index 3647397e416..03f0a414cfa 100644 --- a/net/ipv4/ipvs/ip_vs_proto_udp.c +++ b/net/ipv4/ipvs/ip_vs_proto_udp.c @@ -121,9 +121,9 @@ udp_fast_csum_update(struct udphdr *uhdr, __be32 oldip, __be32 newip, __be16 oldport, __be16 newport) { uhdr->check = - ip_vs_check_diff(~oldip, newip, - ip_vs_check_diff(oldport ^ htons(0xFFFF), - newport, uhdr->check)); + csum_fold(ip_vs_check_diff4(oldip, newip, + ip_vs_check_diff2(oldport, newport, + ~csum_unfold(uhdr->check)))); if (!uhdr->check) uhdr->check = CSUM_MANGLED_0; } -- cgit v1.2.3 From 43bc0ca7eadc024e9e5b935fa5e0892df4fec9eb Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 14 Nov 2006 21:43:23 -0800 Subject: [NET]: netfilter checksum annotations Signed-off-by: Al Viro Signed-off-by: David S. Miller --- net/ipv4/netfilter/ip_nat_core.c | 6 ++---- net/ipv4/netfilter/ip_nat_helper.c | 30 ++++++++++-------------------- net/ipv4/netfilter/ip_nat_proto_gre.c | 8 +++----- net/ipv4/netfilter/ip_nat_proto_icmp.c | 6 ++---- net/ipv4/netfilter/ip_nat_proto_tcp.c | 5 ++--- net/ipv4/netfilter/ip_nat_proto_udp.c | 7 ++----- net/ipv4/netfilter/ipt_ECN.c | 11 ++++------- net/ipv4/netfilter/ipt_TCPMSS.c | 24 ++++++++---------------- net/ipv4/netfilter/ipt_TOS.c | 5 ++--- net/ipv4/netfilter/ipt_TTL.c | 5 ++--- 10 files changed, 37 insertions(+), 70 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/netfilter/ip_nat_core.c b/net/ipv4/netfilter/ip_nat_core.c index 4b6260a9740..9d1a5175dcd 100644 --- a/net/ipv4/netfilter/ip_nat_core.c +++ b/net/ipv4/netfilter/ip_nat_core.c @@ -362,12 +362,10 @@ manip_pkt(u_int16_t proto, iph = (void *)(*pskb)->data + iphdroff; if (maniptype == IP_NAT_MANIP_SRC) { - iph->check = nf_csum_update(~iph->saddr, target->src.ip, - iph->check); + nf_csum_replace4(&iph->check, iph->saddr, target->src.ip); iph->saddr = target->src.ip; } else { - iph->check = nf_csum_update(~iph->daddr, target->dst.ip, - iph->check); + nf_csum_replace4(&iph->check, iph->daddr, target->dst.ip); iph->daddr = target->dst.ip; } return 1; diff --git a/net/ipv4/netfilter/ip_nat_helper.c b/net/ipv4/netfilter/ip_nat_helper.c index 3e7fd64c216..ee80feb4b2a 100644 --- a/net/ipv4/netfilter/ip_nat_helper.c +++ b/net/ipv4/netfilter/ip_nat_helper.c @@ -188,10 +188,8 @@ ip_nat_mangle_tcp_packet(struct sk_buff **pskb, csum_partial((char *)tcph, datalen, 0)); } else - tcph->check = nf_proto_csum_update(*pskb, - htons(oldlen) ^ htons(0xFFFF), - htons(datalen), - tcph->check, 1); + nf_proto_csum_replace2(&tcph->check, *pskb, + htons(oldlen), htons(datalen), 1); if (rep_len != match_len) { set_bit(IPS_SEQ_ADJUST_BIT, &ct->status); @@ -266,10 +264,8 @@ ip_nat_mangle_udp_packet(struct sk_buff **pskb, if (!udph->check) udph->check = CSUM_MANGLED_0; } else - udph->check = nf_proto_csum_update(*pskb, - htons(oldlen) ^ htons(0xFFFF), - htons(datalen), - udph->check, 1); + nf_proto_csum_replace2(&udph->check, *pskb, + htons(oldlen), htons(datalen), 1); return 1; } EXPORT_SYMBOL(ip_nat_mangle_udp_packet); @@ -307,14 +303,10 @@ sack_adjust(struct sk_buff *skb, ntohl(sack->start_seq), new_start_seq, ntohl(sack->end_seq), new_end_seq); - tcph->check = nf_proto_csum_update(skb, - ~sack->start_seq, - new_start_seq, - tcph->check, 0); - tcph->check = nf_proto_csum_update(skb, - ~sack->end_seq, - new_end_seq, - tcph->check, 0); + nf_proto_csum_replace4(&tcph->check, skb, + sack->start_seq, new_start_seq, 0); + nf_proto_csum_replace4(&tcph->check, skb, + sack->end_seq, new_end_seq, 0); sack->start_seq = new_start_seq; sack->end_seq = new_end_seq; sackoff += sizeof(*sack); @@ -397,10 +389,8 @@ ip_nat_seq_adjust(struct sk_buff **pskb, else newack = htonl(ntohl(tcph->ack_seq) - other_way->offset_before); - tcph->check = nf_proto_csum_update(*pskb, ~tcph->seq, newseq, - tcph->check, 0); - tcph->check = nf_proto_csum_update(*pskb, ~tcph->ack_seq, newack, - tcph->check, 0); + nf_proto_csum_replace4(&tcph->check, *pskb, tcph->seq, newseq, 0); + nf_proto_csum_replace4(&tcph->check, *pskb, tcph->ack_seq, newack, 0); DEBUGP("Adjusting sequence number from %u->%u, ack from %u->%u\n", ntohl(tcph->seq), ntohl(newseq), ntohl(tcph->ack_seq), diff --git a/net/ipv4/netfilter/ip_nat_proto_gre.c b/net/ipv4/netfilter/ip_nat_proto_gre.c index bf91f9312b3..95810202d84 100644 --- a/net/ipv4/netfilter/ip_nat_proto_gre.c +++ b/net/ipv4/netfilter/ip_nat_proto_gre.c @@ -129,11 +129,9 @@ gre_manip_pkt(struct sk_buff **pskb, } if (greh->csum) { /* FIXME: Never tested this code... */ - *(gre_csum(greh)) = - nf_proto_csum_update(*pskb, - ~*(gre_key(greh)), - tuple->dst.u.gre.key, - *(gre_csum(greh)), 0); + nf_proto_csum_replace4(gre_csum(greh), *pskb, + *(gre_key(greh)), + tuple->dst.u.gre.key, 0); } *(gre_key(greh)) = tuple->dst.u.gre.key; break; diff --git a/net/ipv4/netfilter/ip_nat_proto_icmp.c b/net/ipv4/netfilter/ip_nat_proto_icmp.c index 3f6efc13ac7..75266fe3e0f 100644 --- a/net/ipv4/netfilter/ip_nat_proto_icmp.c +++ b/net/ipv4/netfilter/ip_nat_proto_icmp.c @@ -66,10 +66,8 @@ icmp_manip_pkt(struct sk_buff **pskb, return 0; hdr = (struct icmphdr *)((*pskb)->data + hdroff); - hdr->checksum = nf_proto_csum_update(*pskb, - hdr->un.echo.id ^ htons(0xFFFF), - tuple->src.u.icmp.id, - hdr->checksum, 0); + nf_proto_csum_replace2(&hdr->checksum, *pskb, + hdr->un.echo.id, tuple->src.u.icmp.id, 0); hdr->un.echo.id = tuple->src.u.icmp.id; return 1; } diff --git a/net/ipv4/netfilter/ip_nat_proto_tcp.c b/net/ipv4/netfilter/ip_nat_proto_tcp.c index 12deb13b93b..b586d18b3fb 100644 --- a/net/ipv4/netfilter/ip_nat_proto_tcp.c +++ b/net/ipv4/netfilter/ip_nat_proto_tcp.c @@ -129,9 +129,8 @@ tcp_manip_pkt(struct sk_buff **pskb, if (hdrsize < sizeof(*hdr)) return 1; - hdr->check = nf_proto_csum_update(*pskb, ~oldip, newip, hdr->check, 1); - hdr->check = nf_proto_csum_update(*pskb, oldport ^ htons(0xFFFF), newport, - hdr->check, 0); + nf_proto_csum_replace4(&hdr->check, *pskb, oldip, newip, 1); + nf_proto_csum_replace2(&hdr->check, *pskb, oldport, newport, 0); return 1; } diff --git a/net/ipv4/netfilter/ip_nat_proto_udp.c b/net/ipv4/netfilter/ip_nat_proto_udp.c index 82f8a6ab07e..5ced0877b32 100644 --- a/net/ipv4/netfilter/ip_nat_proto_udp.c +++ b/net/ipv4/netfilter/ip_nat_proto_udp.c @@ -115,11 +115,8 @@ udp_manip_pkt(struct sk_buff **pskb, } if (hdr->check || (*pskb)->ip_summed == CHECKSUM_PARTIAL) { - hdr->check = nf_proto_csum_update(*pskb, ~oldip, newip, - hdr->check, 1); - hdr->check = nf_proto_csum_update(*pskb, - *portptr ^ htons(0xFFFF), newport, - hdr->check, 0); + nf_proto_csum_replace4(&hdr->check, *pskb, oldip, newip, 1); + nf_proto_csum_replace2(&hdr->check, *pskb, *portptr, newport, 0); if (!hdr->check) hdr->check = CSUM_MANGLED_0; } diff --git a/net/ipv4/netfilter/ipt_ECN.c b/net/ipv4/netfilter/ipt_ECN.c index 1aa4517fbcd..b55d670a24d 100644 --- a/net/ipv4/netfilter/ipt_ECN.c +++ b/net/ipv4/netfilter/ipt_ECN.c @@ -28,17 +28,16 @@ static inline int set_ect_ip(struct sk_buff **pskb, const struct ipt_ECN_info *einfo) { struct iphdr *iph = (*pskb)->nh.iph; - u_int16_t oldtos; if ((iph->tos & IPT_ECN_IP_MASK) != (einfo->ip_ect & IPT_ECN_IP_MASK)) { + __u8 oldtos; if (!skb_make_writable(pskb, sizeof(struct iphdr))) return 0; iph = (*pskb)->nh.iph; oldtos = iph->tos; iph->tos &= ~IPT_ECN_IP_MASK; iph->tos |= (einfo->ip_ect & IPT_ECN_IP_MASK); - iph->check = nf_csum_update(htons(oldtos) ^ htons(0xFFFF), - htons(iph->tos), iph->check); + nf_csum_replace2(&iph->check, htons(oldtos), htons(iph->tos)); } return 1; } @@ -72,10 +71,8 @@ set_ect_tcp(struct sk_buff **pskb, const struct ipt_ECN_info *einfo) if (einfo->operation & IPT_ECN_OP_SET_CWR) tcph->cwr = einfo->proto.tcp.cwr; - tcph->check = nf_proto_csum_update((*pskb), - oldval ^ htons(0xFFFF), - ((__be16 *)tcph)[6], - tcph->check, 0); + nf_proto_csum_replace2(&tcph->check, *pskb, + oldval, ((__be16 *)tcph)[6], 0); return 1; } diff --git a/net/ipv4/netfilter/ipt_TCPMSS.c b/net/ipv4/netfilter/ipt_TCPMSS.c index 108b6b76311..93eb5c3c188 100644 --- a/net/ipv4/netfilter/ipt_TCPMSS.c +++ b/net/ipv4/netfilter/ipt_TCPMSS.c @@ -97,10 +97,8 @@ ipt_tcpmss_target(struct sk_buff **pskb, opt[i+2] = (newmss & 0xff00) >> 8; opt[i+3] = (newmss & 0x00ff); - tcph->check = nf_proto_csum_update(*pskb, - htons(oldmss)^htons(0xFFFF), - htons(newmss), - tcph->check, 0); + nf_proto_csum_replace2(&tcph->check, *pskb, + htons(oldmss), htons(newmss), 0); return IPT_CONTINUE; } } @@ -126,28 +124,22 @@ ipt_tcpmss_target(struct sk_buff **pskb, opt = (u_int8_t *)tcph + sizeof(struct tcphdr); memmove(opt + TCPOLEN_MSS, opt, tcplen - sizeof(struct tcphdr)); - tcph->check = nf_proto_csum_update(*pskb, - htons(tcplen) ^ htons(0xFFFF), - htons(tcplen + TCPOLEN_MSS), - tcph->check, 1); + nf_proto_csum_replace2(&tcph->check, *pskb, + htons(tcplen), htons(tcplen + TCPOLEN_MSS), 1); opt[0] = TCPOPT_MSS; opt[1] = TCPOLEN_MSS; opt[2] = (newmss & 0xff00) >> 8; opt[3] = (newmss & 0x00ff); - tcph->check = nf_proto_csum_update(*pskb, htonl(~0), *((__be32 *)opt), - tcph->check, 0); + nf_proto_csum_replace4(&tcph->check, *pskb, 0, *((__be32 *)opt), 0); oldval = ((__be16 *)tcph)[6]; tcph->doff += TCPOLEN_MSS/4; - tcph->check = nf_proto_csum_update(*pskb, - oldval ^ htons(0xFFFF), - ((__be16 *)tcph)[6], - tcph->check, 0); + nf_proto_csum_replace2(&tcph->check, *pskb, + oldval, ((__be16 *)tcph)[6], 0); newtotlen = htons(ntohs(iph->tot_len) + TCPOLEN_MSS); - iph->check = nf_csum_update(iph->tot_len ^ htons(0xFFFF), - newtotlen, iph->check); + nf_csum_replace2(&iph->check, iph->tot_len, newtotlen); iph->tot_len = newtotlen; return IPT_CONTINUE; } diff --git a/net/ipv4/netfilter/ipt_TOS.c b/net/ipv4/netfilter/ipt_TOS.c index 83b80b3a5d2..18e74ac4d42 100644 --- a/net/ipv4/netfilter/ipt_TOS.c +++ b/net/ipv4/netfilter/ipt_TOS.c @@ -30,16 +30,15 @@ target(struct sk_buff **pskb, { const struct ipt_tos_target_info *tosinfo = targinfo; struct iphdr *iph = (*pskb)->nh.iph; - u_int16_t oldtos; if ((iph->tos & IPTOS_TOS_MASK) != tosinfo->tos) { + __u8 oldtos; if (!skb_make_writable(pskb, sizeof(struct iphdr))) return NF_DROP; iph = (*pskb)->nh.iph; oldtos = iph->tos; iph->tos = (iph->tos & IPTOS_PREC_MASK) | tosinfo->tos; - iph->check = nf_csum_update(htons(oldtos) ^ htons(0xFFFF), - htons(iph->tos), iph->check); + nf_csum_replace2(&iph->check, htons(oldtos), htons(iph->tos)); } return IPT_CONTINUE; } diff --git a/net/ipv4/netfilter/ipt_TTL.c b/net/ipv4/netfilter/ipt_TTL.c index ac9517d62af..fffe5ca82e9 100644 --- a/net/ipv4/netfilter/ipt_TTL.c +++ b/net/ipv4/netfilter/ipt_TTL.c @@ -54,9 +54,8 @@ ipt_ttl_target(struct sk_buff **pskb, } if (new_ttl != iph->ttl) { - iph->check = nf_csum_update(htons((iph->ttl << 8)) ^ htons(0xFFFF), - htons(new_ttl << 8), - iph->check); + nf_csum_replace2(&iph->check, htons(iph->ttl << 8), + htons(new_ttl << 8)); iph->ttl = new_ttl; } -- cgit v1.2.3 From 078250d68d883495f31d0e6ce8321292f2dc1cfa Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Wed, 15 Nov 2006 00:44:49 -0800 Subject: [NET/IPv4]: Make udp_push_pending_frames static udp_push_pending_frames is only referenced within net/ipv4/udp.c and hence can remain static. Signed-off-by: Gerrit Renker Signed-off-by: David S. Miller --- net/ipv4/udp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/ipv4') diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index dc19ba1e73b..7eb76fbf1b4 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -448,7 +448,7 @@ static void udp4_hwcsum_outgoing(struct sock *sk, struct sk_buff *skb, /* * Push out all pending data as one UDP datagram. Socket is locked. */ -int udp_push_pending_frames(struct sock *sk, struct udp_sock *up) +static int udp_push_pending_frames(struct sock *sk, struct udp_sock *up) { struct inet_sock *inet = inet_sk(sk); struct flowi *fl = &inet->cork.fl; -- cgit v1.2.3 From 7174259e6ced15bebee202983511d8fc950e929f Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 17 Nov 2006 10:57:30 -0200 Subject: [TCP_IPV4]: CodingStyle cleanups, no code change Mostly related to CONFIG_TCP_MD5SIG recent merge. Signed-off-by: Arnaldo Carvalho de Melo --- net/ipv4/tcp_ipv4.c | 143 +++++++++++++++++++++++++++------------------------- 1 file changed, 75 insertions(+), 68 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index dadf8027241..010dff442a1 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -93,16 +93,18 @@ static struct socket *tcp_socket; void tcp_v4_send_check(struct sock *sk, int len, struct sk_buff *skb); #ifdef CONFIG_TCP_MD5SIG -static struct tcp_md5sig_key *tcp_v4_md5_do_lookup(struct sock *sk, __be32 addr); +static struct tcp_md5sig_key *tcp_v4_md5_do_lookup(struct sock *sk, + __be32 addr); static int tcp_v4_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, - __be32 saddr, __be32 daddr, struct tcphdr *th, - int protocol, int tcplen); + __be32 saddr, __be32 daddr, + struct tcphdr *th, int protocol, + int tcplen); #endif struct inet_hashinfo __cacheline_aligned tcp_hashinfo = { - .lhash_lock = __RW_LOCK_UNLOCKED(tcp_hashinfo.lhash_lock), - .lhash_users = ATOMIC_INIT(0), - .lhash_wait = __WAIT_QUEUE_HEAD_INITIALIZER(tcp_hashinfo.lhash_wait), + .lhash_lock = __RW_LOCK_UNLOCKED(tcp_hashinfo.lhash_lock), + .lhash_users = ATOMIC_INIT(0), + .lhash_wait = __WAIT_QUEUE_HEAD_INITIALIZER(tcp_hashinfo.lhash_wait), }; static int tcp_v4_get_port(struct sock *sk, unsigned short snum) @@ -215,13 +217,14 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) if (tcp_death_row.sysctl_tw_recycle && !tp->rx_opt.ts_recent_stamp && rt->rt_dst == daddr) { struct inet_peer *peer = rt_get_peer(rt); - - /* VJ's idea. We save last timestamp seen from - * the destination in peer table, when entering state TIME-WAIT - * and initialize rx_opt.ts_recent from it, when trying new connection. + /* + * VJ's idea. We save last timestamp seen from + * the destination in peer table, when entering state + * TIME-WAIT * and initialize rx_opt.ts_recent from it, + * when trying new connection. */ - - if (peer && peer->tcp_ts_stamp + TCP_PAWS_MSL >= xtime.tv_sec) { + if (peer != NULL && + peer->tcp_ts_stamp + TCP_PAWS_MSL >= xtime.tv_sec) { tp->rx_opt.ts_recent_stamp = peer->tcp_ts_stamp; tp->rx_opt.ts_recent = peer->tcp_ts; } @@ -246,7 +249,8 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) if (err) goto failure; - err = ip_route_newports(&rt, IPPROTO_TCP, inet->sport, inet->dport, sk); + err = ip_route_newports(&rt, IPPROTO_TCP, + inet->sport, inet->dport, sk); if (err) goto failure; @@ -270,7 +274,10 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) return 0; failure: - /* This unhashes the socket and releases the local port, if necessary. */ + /* + * This unhashes the socket and releases the local port, + * if necessary. + */ tcp_set_state(sk, TCP_CLOSE); ip_rt_put(rt); sk->sk_route_caps = 0; @@ -495,7 +502,8 @@ void tcp_v4_send_check(struct sock *sk, int len, struct sk_buff *skb) struct tcphdr *th = skb->h.th; if (skb->ip_summed == CHECKSUM_PARTIAL) { - th->check = ~tcp_v4_check(th, len, inet->saddr, inet->daddr, 0); + th->check = ~tcp_v4_check(th, len, + inet->saddr, inet->daddr, 0); skb->csum = offsetof(struct tcphdr, check); } else { th->check = tcp_v4_check(th, len, inet->saddr, inet->daddr, @@ -572,7 +580,7 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb) skb->len - (th->doff << 2)); } - memset(&arg, 0, sizeof arg); + memset(&arg, 0, sizeof(arg)); arg.iov[0].iov_base = (unsigned char *)&rep; arg.iov[0].iov_len = sizeof(rep.th); @@ -595,9 +603,8 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb) arg.iov[0].iov_len); } #endif - arg.csum = csum_tcpudp_nofold(skb->nh.iph->daddr, - skb->nh.iph->saddr, /*XXX*/ + skb->nh.iph->saddr, /* XXX */ sizeof(struct tcphdr), IPPROTO_TCP, 0); arg.csumoffset = offsetof(struct tcphdr, check) / 2; @@ -631,7 +638,7 @@ static void tcp_v4_send_ack(struct tcp_timewait_sock *twsk, #endif memset(&rep.th, 0, sizeof(struct tcphdr)); - memset(&arg, 0, sizeof arg); + memset(&arg, 0, sizeof(arg)); arg.iov[0].iov_base = (unsigned char *)&rep; arg.iov[0].iov_len = sizeof(rep.th); @@ -668,9 +675,8 @@ static void tcp_v4_send_ack(struct tcp_timewait_sock *twsk, tw_key.key = twsk->tw_md5_key; tw_key.keylen = twsk->tw_md5_keylen; key = &tw_key; - } else { + } else key = NULL; - } if (key) { int offset = (ts) ? 3 : 0; @@ -690,9 +696,8 @@ static void tcp_v4_send_ack(struct tcp_timewait_sock *twsk, arg.iov[0].iov_len); } #endif - arg.csum = csum_tcpudp_nofold(skb->nh.iph->daddr, - skb->nh.iph->saddr, /*XXX*/ + skb->nh.iph->saddr, /* XXX */ arg.iov[0].iov_len, IPPROTO_TCP, 0); arg.csumoffset = offsetof(struct tcphdr, check) / 2; @@ -707,12 +712,14 @@ static void tcp_v4_timewait_ack(struct sock *sk, struct sk_buff *skb) struct tcp_timewait_sock *tcptw = tcp_twsk(sk); tcp_v4_send_ack(tcptw, skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt, - tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale, tcptw->tw_ts_recent); + tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale, + tcptw->tw_ts_recent); inet_twsk_put(tw); } -static void tcp_v4_reqsk_send_ack(struct sk_buff *skb, struct request_sock *req) +static void tcp_v4_reqsk_send_ack(struct sk_buff *skb, + struct request_sock *req) { tcp_v4_send_ack(NULL, skb, tcp_rsk(req)->snt_isn + 1, tcp_rsk(req)->rcv_isn + 1, req->rcv_wnd, @@ -809,7 +816,8 @@ static struct ip_options *tcp_v4_save_options(struct sock *sk, */ /* Find the Key structure for an address. */ -static struct tcp_md5sig_key *tcp_v4_md5_do_lookup(struct sock *sk, __be32 addr) +static struct tcp_md5sig_key * + tcp_v4_md5_do_lookup(struct sock *sk, __be32 addr) { struct tcp_sock *tp = tcp_sk(sk); int i; @@ -818,7 +826,8 @@ static struct tcp_md5sig_key *tcp_v4_md5_do_lookup(struct sock *sk, __be32 addr) return NULL; for (i = 0; i < tp->md5sig_info->entries4; i++) { if (tp->md5sig_info->keys4[i].addr == addr) - return (struct tcp_md5sig_key *)&tp->md5sig_info->keys4[i]; + return (struct tcp_md5sig_key *) + &tp->md5sig_info->keys4[i]; } return NULL; } @@ -915,13 +924,12 @@ int tcp_v4_md5_do_del(struct sock *sk, __be32 addr) if (tp->md5sig_info->entries4 == 0) { kfree(tp->md5sig_info->keys4); tp->md5sig_info->keys4 = NULL; - } else { + } else if (tp->md5sig_info->entries4 != i) { /* Need to do some manipulation */ - if (tp->md5sig_info->entries4 != i) - memcpy(&tp->md5sig_info->keys4[i], - &tp->md5sig_info->keys4[i+1], - (tp->md5sig_info->entries4 - i) - * sizeof (struct tcp4_md5sig_key)); + memcpy(&tp->md5sig_info->keys4[i], + &tp->md5sig_info->keys4[i+1], + (tp->md5sig_info->entries4 - i) * + sizeof(struct tcp4_md5sig_key)); } tcp_free_md5sig_pool(); return 0; @@ -932,7 +940,7 @@ int tcp_v4_md5_do_del(struct sock *sk, __be32 addr) EXPORT_SYMBOL(tcp_v4_md5_do_del); -static void tcp_v4_clear_md5_list (struct sock *sk) +static void tcp_v4_clear_md5_list(struct sock *sk) { struct tcp_sock *tp = tcp_sk(sk); @@ -954,8 +962,8 @@ static void tcp_v4_clear_md5_list (struct sock *sk) } } -static int tcp_v4_parse_md5_keys (struct sock *sk, char __user *optval, - int optlen) +static int tcp_v4_parse_md5_keys(struct sock *sk, char __user *optval, + int optlen) { struct tcp_md5sig cmd; struct sockaddr_in *sin = (struct sockaddr_in *)&cmd.tcpm_addr; @@ -964,7 +972,7 @@ static int tcp_v4_parse_md5_keys (struct sock *sk, char __user *optval, if (optlen < sizeof(cmd)) return -EINVAL; - if (copy_from_user (&cmd, optval, sizeof(cmd))) + if (copy_from_user(&cmd, optval, sizeof(cmd))) return -EFAULT; if (sin->sin_family != AF_INET) @@ -981,9 +989,8 @@ static int tcp_v4_parse_md5_keys (struct sock *sk, char __user *optval, if (!tcp_sk(sk)->md5sig_info) { struct tcp_sock *tp = tcp_sk(sk); - struct tcp_md5sig_info *p; + struct tcp_md5sig_info *p = kzalloc(sizeof(*p), GFP_KERNEL); - p = kzalloc(sizeof(struct tcp_md5sig_info), GFP_KERNEL); if (!p) return -EINVAL; @@ -1044,8 +1051,8 @@ static int tcp_v4_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, #ifdef CONFIG_TCP_MD5SIG_DEBUG printk("Calcuating hash for: "); - for (i = 0; i < sizeof (*bp); i++) - printk ("%02x ", (unsigned int)((unsigned char *)bp)[i]); + for (i = 0; i < sizeof(*bp); i++) + printk("%02x ", (unsigned int)((unsigned char *)bp)[i]); printk(" "); #endif @@ -1057,8 +1064,8 @@ static int tcp_v4_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, sg_set_buf(&sg[block++], th, sizeof(struct tcphdr)); nbytes += sizeof(struct tcphdr); #ifdef CONFIG_TCP_MD5SIG_DEBUG - for (i = 0; i < sizeof (struct tcphdr); i++) - printk (" %02x", (unsigned int)((unsigned char *)th)[i]); + for (i = 0; i < sizeof(struct tcphdr); i++) + printk(" %02x", (unsigned int)((unsigned char *)th)[i]); #endif /* 3. the TCP segment data (if any) */ data_len = tcplen - (th->doff << 2); @@ -1075,9 +1082,9 @@ static int tcp_v4_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, nbytes += key->keylen; #ifdef CONFIG_TCP_MD5SIG_DEBUG - printk (" and password: "); + printk(" and password: "); for (i = 0; i < key->keylen; i++) - printk ("%02x ", (unsigned int)key->key[i]); + printk("%02x ", (unsigned int)key->key[i]); #endif /* Now store the Hash into the packet */ @@ -1099,7 +1106,7 @@ out: #ifdef CONFIG_TCP_MD5SIG_DEBUG printk(" result:"); for (i = 0; i < 16; i++) - printk (" %02x", (unsigned int)(((u8*)md5_hash)[i])); + printk(" %02x", (unsigned int)(((u8*)md5_hash)[i])); printk("\n"); #endif return 0; @@ -1135,7 +1142,7 @@ int tcp_v4_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, EXPORT_SYMBOL(tcp_v4_calc_md5_hash); -static int tcp_v4_inbound_md5_hash (struct sock *sk, struct sk_buff *skb) +static int tcp_v4_inbound_md5_hash(struct sock *sk, struct sk_buff *skb) { /* * This gets called for each TCP segment that arrives @@ -1149,7 +1156,7 @@ static int tcp_v4_inbound_md5_hash (struct sock *sk, struct sk_buff *skb) struct tcp_md5sig_key *hash_expected; struct iphdr *iph = skb->nh.iph; struct tcphdr *th = skb->h.th; - int length = (th->doff << 2) - sizeof (struct tcphdr); + int length = (th->doff << 2) - sizeof(struct tcphdr); int genhash; unsigned char *ptr; unsigned char newhash[16]; @@ -1200,22 +1207,18 @@ done_opts: return 0; if (hash_expected && !hash_location) { - if (net_ratelimit()) { - printk(KERN_INFO "MD5 Hash NOT expected but found " + LIMIT_NETDEBUG(KERN_INFO "MD5 Hash NOT expected but found " "(" NIPQUAD_FMT ", %d)->(" NIPQUAD_FMT ", %d)\n", - NIPQUAD (iph->saddr), ntohs(th->source), - NIPQUAD (iph->daddr), ntohs(th->dest)); - } + NIPQUAD(iph->saddr), ntohs(th->source), + NIPQUAD(iph->daddr), ntohs(th->dest)); return 1; } if (!hash_expected && hash_location) { - if (net_ratelimit()) { - printk(KERN_INFO "MD5 Hash NOT expected but found " + LIMIT_NETDEBUG(KERN_INFO "MD5 Hash NOT expected but found " "(" NIPQUAD_FMT ", %d)->(" NIPQUAD_FMT ", %d)\n", - NIPQUAD (iph->saddr), ntohs(th->source), - NIPQUAD (iph->daddr), ntohs(th->dest)); - } + NIPQUAD(iph->saddr), ntohs(th->source), + NIPQUAD(iph->daddr), ntohs(th->dest)); return 1; } @@ -1232,15 +1235,16 @@ done_opts: if (net_ratelimit()) { printk(KERN_INFO "MD5 Hash failed for " "(" NIPQUAD_FMT ", %d)->(" NIPQUAD_FMT ", %d)%s\n", - NIPQUAD (iph->saddr), ntohs(th->source), - NIPQUAD (iph->daddr), ntohs(th->dest), + NIPQUAD(iph->saddr), ntohs(th->source), + NIPQUAD(iph->daddr), ntohs(th->dest), genhash ? " tcp_v4_calc_md5_hash failed" : ""); #ifdef CONFIG_TCP_MD5SIG_DEBUG do { int i; printk("Received: "); for (i = 0; i < 16; i++) - printk("%02x ", 0xff & (int)hash_location[i]); + printk("%02x ", + 0xff & (int)hash_location[i]); printk("\n"); printk("Calculated: "); for (i = 0; i < 16; i++) @@ -1582,7 +1586,7 @@ int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb) * o We're expecting an MD5'd packet and this is no MD5 tcp option * o There is an MD5 option and we're not expecting one */ - if (tcp_v4_inbound_md5_hash (sk, skb)) + if (tcp_v4_inbound_md5_hash(sk, skb)) goto discard; #endif @@ -2155,7 +2159,7 @@ static void *established_get_idx(struct seq_file *seq, loff_t pos) while (rc && pos) { rc = established_get_next(seq, rc); --pos; - } + } return rc; } @@ -2284,7 +2288,7 @@ int tcp_proc_register(struct tcp_seq_afinfo *afinfo) afinfo->seq_fops->read = seq_read; afinfo->seq_fops->llseek = seq_lseek; afinfo->seq_fops->release = seq_release_private; - + p = proc_net_fops_create(afinfo->name, S_IRUGO, afinfo->seq_fops); if (p) p->data = afinfo; @@ -2298,7 +2302,7 @@ void tcp_proc_unregister(struct tcp_seq_afinfo *afinfo) if (!afinfo) return; proc_net_remove(afinfo->name); - memset(afinfo->seq_fops, 0, sizeof(*afinfo->seq_fops)); + memset(afinfo->seq_fops, 0, sizeof(*afinfo->seq_fops)); } static void get_openreq4(struct sock *sk, struct request_sock *req, @@ -2356,7 +2360,8 @@ static void get_tcp4_sock(struct sock *sp, char *tmpbuf, int i) "%08X %5d %8d %lu %d %p %u %u %u %u %d", i, src, srcp, dest, destp, sp->sk_state, tp->write_seq - tp->snd_una, - (sp->sk_state == TCP_LISTEN) ? sp->sk_ack_backlog : (tp->rcv_nxt - tp->copied_seq), + sp->sk_state == TCP_LISTEN ? sp->sk_ack_backlog : + (tp->rcv_nxt - tp->copied_seq), timer_active, jiffies_to_clock_t(timer_expires - jiffies), icsk->icsk_retransmits, @@ -2371,7 +2376,8 @@ static void get_tcp4_sock(struct sock *sp, char *tmpbuf, int i) tp->snd_ssthresh >= 0xFFFF ? -1 : tp->snd_ssthresh); } -static void get_timewait4_sock(struct inet_timewait_sock *tw, char *tmpbuf, int i) +static void get_timewait4_sock(struct inet_timewait_sock *tw, + char *tmpbuf, int i) { __be32 dest, src; __u16 destp, srcp; @@ -2484,7 +2490,8 @@ struct proto tcp_prot = { void __init tcp_v4_init(struct net_proto_family *ops) { - if (inet_csk_ctl_sock_create(&tcp_socket, PF_INET, SOCK_RAW, IPPROTO_TCP) < 0) + if (inet_csk_ctl_sock_create(&tcp_socket, PF_INET, SOCK_RAW, + IPPROTO_TCP) < 0) panic("Failed to create the TCP control socket.\n"); } -- cgit v1.2.3 From f6685938f9181e95f814edfca287d4f04a925240 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 17 Nov 2006 11:06:01 -0200 Subject: [TCP_IPV4]: Use kmemdup where appropriate Also use a variable to avoid the longish tp->md5sig_info-> use in tcp_v4_md5_do_add. Code diff stats: [acme@newtoy net-2.6.20]$ codiff /tmp/tcp_ipv4.o.before /tmp/tcp_ipv4.o.after /pub/scm/linux/kernel/git/acme/net-2.6.20/net/ipv4/tcp_ipv4.c: tcp_v4_md5_do_add | -62 tcp_v4_syn_recv_sock | -32 tcp_v4_parse_md5_keys | -86 3 functions changed, 180 bytes removed [acme@newtoy net-2.6.20]$ Signed-off-by: Arnaldo Carvalho de Melo --- net/ipv4/tcp_ipv4.c | 49 +++++++++++++++++++++++++------------------------ 1 file changed, 25 insertions(+), 24 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 010dff442a1..b7d5522092e 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -855,15 +855,18 @@ int tcp_v4_md5_do_add(struct sock *sk, __be32 addr, struct tcp_sock *tp = tcp_sk(sk); struct tcp4_md5sig_key *keys; - key = (struct tcp4_md5sig_key *) tcp_v4_md5_do_lookup(sk, addr); + key = (struct tcp4_md5sig_key *)tcp_v4_md5_do_lookup(sk, addr); if (key) { /* Pre-existing entry - just update that one. */ - kfree (key->key); + kfree(key->key); key->key = newkey; key->keylen = newkeylen; } else { + struct tcp_md5sig_info *md5sig; + if (!tp->md5sig_info) { - tp->md5sig_info = kzalloc(sizeof(*tp->md5sig_info), GFP_ATOMIC); + tp->md5sig_info = kzalloc(sizeof(*tp->md5sig_info), + GFP_ATOMIC); if (!tp->md5sig_info) { kfree(newkey); return -ENOMEM; @@ -873,30 +876,31 @@ int tcp_v4_md5_do_add(struct sock *sk, __be32 addr, kfree(newkey); return -ENOMEM; } - if (tp->md5sig_info->alloced4 == tp->md5sig_info->entries4) { - keys = kmalloc((sizeof(struct tcp4_md5sig_key) * - (tp->md5sig_info->entries4 + 1)), GFP_ATOMIC); + md5sig = tp->md5sig_info; + + if (md5sig->alloced4 == md5sig->entries4) { + keys = kmalloc((sizeof(*keys) * + (md5sig->entries4 + 1)), GFP_ATOMIC); if (!keys) { kfree(newkey); tcp_free_md5sig_pool(); return -ENOMEM; } - if (tp->md5sig_info->entries4) - memcpy(keys, tp->md5sig_info->keys4, - (sizeof (struct tcp4_md5sig_key) * - tp->md5sig_info->entries4)); + if (md5sig->entries4) + memcpy(keys, md5sig->keys4, + sizeof(*keys) * md5sig->entries4); /* Free old key list, and reference new one */ - if (tp->md5sig_info->keys4) - kfree(tp->md5sig_info->keys4); - tp->md5sig_info->keys4 = keys; - tp->md5sig_info->alloced4++; + if (md5sig->keys4) + kfree(md5sig->keys4); + md5sig->keys4 = keys; + md5sig->alloced4++; } - tp->md5sig_info->entries4++; - tp->md5sig_info->keys4[tp->md5sig_info->entries4 - 1].addr = addr; - tp->md5sig_info->keys4[tp->md5sig_info->entries4 - 1].key = newkey; - tp->md5sig_info->keys4[tp->md5sig_info->entries4 - 1].keylen = newkeylen; + md5sig->entries4++; + md5sig->keys4[md5sig->entries4 - 1].addr = addr; + md5sig->keys4[md5sig->entries4 - 1].key = newkey; + md5sig->keys4[md5sig->entries4 - 1].keylen = newkeylen; } return 0; } @@ -998,10 +1002,9 @@ static int tcp_v4_parse_md5_keys(struct sock *sk, char __user *optval, } - newkey = kmalloc(cmd.tcpm_keylen, GFP_KERNEL); + newkey = kmemdup(cmd.tcpm_key, cmd.tcpm_keylen, GFP_KERNEL); if (!newkey) return -ENOMEM; - memcpy(newkey, cmd.tcpm_key, cmd.tcpm_keylen); return tcp_v4_md5_do_add(sk, sin->sin_addr.s_addr, newkey, cmd.tcpm_keylen); } @@ -1494,12 +1497,10 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb, * memory, then we end up not copying the key * across. Shucks. */ - char *newkey = kmalloc(key->keylen, GFP_ATOMIC); - if (newkey) { - memcpy(newkey, key->key, key->keylen); + char *newkey = kmemdup(key->key, key->keylen, GFP_ATOMIC); + if (newkey != NULL) tcp_v4_md5_do_add(newsk, inet_sk(sk)->daddr, newkey, key->keylen); - } } #endif -- cgit v1.2.3 From fac5d7315126f4b6745a8565c3a875617e02f8b8 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 17 Nov 2006 11:14:16 -0200 Subject: [NETLABEL]: Use kmemdup in cipso_ipv4.c Code diff stats: [acme@newtoy net-2.6.20]$ codiff /tmp/cipso_ipv4.o.before /tmp/cipso_ipv4.o.after /pub/scm/linux/kernel/git/acme/net-2.6.20/net/ipv4/cipso_ipv4.c: cipso_v4_cache_add | -46 1 function changed, 46 bytes removed [acme@newtoy net-2.6.20]$ Signed-off-by: Arnaldo Carvalho de Melo --- net/ipv4/cipso_ipv4.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c index c3a61ebbade..095038ad72a 100644 --- a/net/ipv4/cipso_ipv4.c +++ b/net/ipv4/cipso_ipv4.c @@ -377,12 +377,11 @@ int cipso_v4_cache_add(const struct sk_buff *skb, entry = kzalloc(sizeof(*entry), GFP_ATOMIC); if (entry == NULL) return -ENOMEM; - entry->key = kmalloc(cipso_ptr_len, GFP_ATOMIC); + entry->key = kmemdup(cipso_ptr, cipso_ptr_len, GFP_ATOMIC); if (entry->key == NULL) { ret_val = -ENOMEM; goto cache_add_failure; } - memcpy(entry->key, cipso_ptr, cipso_ptr_len); entry->key_len = cipso_ptr_len; entry->hash = cipso_v4_map_cache_hash(cipso_ptr, cipso_ptr_len); atomic_inc(&secattr->cache->refcount); -- cgit v1.2.3 From 42e5ea466c1897c4ac2e3b4fe0b33a28e9e3d5de Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 17 Nov 2006 11:18:20 -0200 Subject: [IPV4]: Use kmemdup in net/ipv4/devinet.c Code diff stats: [acme@newtoy net-2.6.20]$ codiff /tmp/devinet.o.before /tmp/devinet.o.after /pub/scm/linux/kernel/git/acme/net-2.6.20/net/ipv4/devinet.c: devinet_sysctl_register | -38 1 function changed, 38 bytes removed [acme@newtoy net-2.6.20]$ Signed-off-by: Arnaldo Carvalho de Melo --- net/ipv4/devinet.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index a1b356c8aa5..2fd899160f8 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -1564,12 +1564,12 @@ static void devinet_sysctl_register(struct in_device *in_dev, { int i; struct net_device *dev = in_dev ? in_dev->dev : NULL; - struct devinet_sysctl_table *t = kmalloc(sizeof(*t), GFP_KERNEL); + struct devinet_sysctl_table *t = kmemdup(&devinet_sysctl, sizeof(*t), + GFP_KERNEL); char *dev_name = NULL; if (!t) return; - memcpy(t, &devinet_sysctl, sizeof(*t)); for (i = 0; i < ARRAY_SIZE(t->devinet_vars) - 1; i++) { t->devinet_vars[i].data += (char *)p - (char *)&ipv4_devconf; t->devinet_vars[i].de = NULL; -- cgit v1.2.3 From c67862403e28dd67f38e896736f063d8dd522688 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 17 Nov 2006 11:25:49 -0200 Subject: [TCP] minisocks: Use kmemdup and LIMIT_NETDEBUG Code diff stats: [acme@newtoy net-2.6.20]$ codiff /tmp/tcp_minisocks.o.before /tmp/tcp_minisocks.o.after /pub/scm/linux/kernel/git/acme/net-2.6.20/net/ipv4/tcp_minisocks.c: tcp_check_req | -44 1 function changed, 44 bytes removed [acme@newtoy net-2.6.20]$ Signed-off-by: Arnaldo Carvalho de Melo --- net/ipv4/tcp_minisocks.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index 383cb38461c..6dddf59c1fb 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c @@ -351,8 +351,7 @@ void tcp_time_wait(struct sock *sk, int state, int timeo) * socket up. We've got bigger problems than * non-graceful socket closings. */ - if (net_ratelimit()) - printk(KERN_INFO "TCP: time wait bucket table overflow\n"); + LIMIT_NETDEBUG(KERN_INFO "TCP: time wait bucket table overflow\n"); } tcp_update_metrics(sk); @@ -667,11 +666,11 @@ struct sock *tcp_check_req(struct sock *sk,struct sk_buff *skb, * newsk structure. If we fail to get memory then we * end up not copying the key across. Shucks. */ - char *newkey = kmalloc(key->keylen, GFP_ATOMIC); + char *newkey = kmemdup(key->key, key->keylen, + GFP_ATOMIC); if (newkey) { if (!tcp_alloc_md5sig_pool()) BUG(); - memcpy(newkey, key->key, key->keylen); tp->af_specific->md5_add(child, child, newkey, key->keylen); -- cgit v1.2.3 From 352d48008b6f3e02d8ce77868432e329dd921cb1 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 17 Nov 2006 19:59:12 -0200 Subject: [TCP]: Tidy up skb_entail Heck, it even saves us some few bytes: [acme@newtoy net-2.6.20]$ codiff -f /tmp/tcp.o.before ../OUTPUT/qemu/net-2.6.20/net/ipv4/tcp.o /pub/scm/linux/kernel/git/acme/net-2.6.20/net/ipv4/tcp.c: tcp_sendpage | -7 tcp_sendmsg | -5 2 functions changed, 12 bytes removed [acme@newtoy net-2.6.20]$ Signed-off-by: Arnaldo Carvalho de Melo --- net/ipv4/tcp.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 168f9de906b..a6b228914b8 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -463,11 +463,12 @@ static inline int forced_push(struct tcp_sock *tp) static inline void skb_entail(struct sock *sk, struct tcp_sock *tp, struct sk_buff *skb) { - skb->csum = 0; - TCP_SKB_CB(skb)->seq = tp->write_seq; - TCP_SKB_CB(skb)->end_seq = tp->write_seq; - TCP_SKB_CB(skb)->flags = TCPCB_FLAG_ACK; - TCP_SKB_CB(skb)->sacked = 0; + struct tcp_skb_cb *tcb = TCP_SKB_CB(skb); + + skb->csum = 0; + tcb->seq = tcb->end_seq = tp->write_seq; + tcb->flags = TCPCB_FLAG_ACK; + tcb->sacked = 0; skb_header_release(skb); __skb_queue_tail(&sk->sk_write_queue, skb); sk_charge_skb(sk, skb); -- cgit v1.2.3 From 701a90bad99b8081a824cca52c178c8fc8f46bb2 Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Fri, 17 Nov 2006 17:38:46 -0500 Subject: NetLabel: make netlbl_lsm_secattr struct easier/quicker to understand The existing netlbl_lsm_secattr struct required the LSM to check all of the fields to determine if any security attributes were present resulting in a lot of work in the common case of no attributes. This patch adds a 'flags' field which is used to indicate which attributes are present in the structure; this should allow the LSM to do a quick comparison to determine if the structure holds any security attributes. Example: if (netlbl_lsm_secattr->flags) /* security attributes present */ else /* NO security attributes present */ Signed-off-by: Paul Moore Signed-off-by: James Morris --- net/ipv4/cipso_ipv4.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c index 095038ad72a..f0a0785047f 100644 --- a/net/ipv4/cipso_ipv4.c +++ b/net/ipv4/cipso_ipv4.c @@ -319,6 +319,7 @@ static int cipso_v4_cache_check(const unsigned char *key, entry->activity += 1; atomic_inc(&entry->lsm_data->refcount); secattr->cache = entry->lsm_data; + secattr->flags |= NETLBL_SECATTR_CACHE; if (prev_entry == NULL) { spin_unlock_bh(&cipso_v4_cache[bkt].lock); return 0; @@ -991,12 +992,15 @@ static int cipso_v4_gentag_rbm(const struct cipso_v4_doi *doi_def, unsigned char **buffer, u32 *buffer_len) { - int ret_val = -EPERM; + int ret_val; unsigned char *buf = NULL; u32 buf_len; u32 level; - if (secattr->mls_cat) { + if ((secattr->flags & NETLBL_SECATTR_MLS_LVL) == 0) + return -EPERM; + + if (secattr->flags & NETLBL_SECATTR_MLS_CAT) { buf = kzalloc(CIPSO_V4_HDR_LEN + 4 + CIPSO_V4_TAG1_CAT_LEN, GFP_ATOMIC); if (buf == NULL) @@ -1013,10 +1017,10 @@ static int cipso_v4_gentag_rbm(const struct cipso_v4_doi *doi_def, /* This will send packets using the "optimized" format when * possibile as specified in section 3.4.2.6 of the * CIPSO draft. */ - if (cipso_v4_rbm_optfmt && (ret_val > 0 && ret_val < 10)) - ret_val = 10; - - buf_len = 4 + ret_val; + if (cipso_v4_rbm_optfmt && ret_val > 0 && ret_val <= 10) + buf_len = 14; + else + buf_len = 4 + ret_val; } else { buf = kzalloc(CIPSO_V4_HDR_LEN + 4, GFP_ATOMIC); if (buf == NULL) @@ -1070,7 +1074,7 @@ static int cipso_v4_parsetag_rbm(const struct cipso_v4_doi *doi_def, if (ret_val != 0) return ret_val; secattr->mls_lvl = level; - secattr->mls_lvl_vld = 1; + secattr->flags |= NETLBL_SECATTR_MLS_LVL; if (tag_len > 4) { switch (doi_def->type) { @@ -1094,8 +1098,10 @@ static int cipso_v4_parsetag_rbm(const struct cipso_v4_doi *doi_def, if (ret_val < 0) { kfree(secattr->mls_cat); return ret_val; + } else if (ret_val > 0) { + secattr->mls_cat_len = ret_val; + secattr->flags |= NETLBL_SECATTR_MLS_CAT; } - secattr->mls_cat_len = ret_val; } return 0; -- cgit v1.2.3 From 05e00cbf5036929355020dab4837b637203a0742 Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Fri, 17 Nov 2006 17:38:47 -0500 Subject: NetLabel: check for a CIPSOv4 option before we do call into the CIPSOv4 layer Right now the NetLabel code always jumps into the CIPSOv4 layer to determine if a CIPSO IP option is present. However, we can do this check directly in the NetLabel code by making use of the CIPSO_V4_OPTEXIST() macro which should save us a function call in the common case of not having a CIPSOv4 option present. Signed-off-by: Paul Moore Signed-off-by: James Morris --- net/ipv4/cipso_ipv4.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c index f0a0785047f..fb5d913f581 100644 --- a/net/ipv4/cipso_ipv4.c +++ b/net/ipv4/cipso_ipv4.c @@ -1435,8 +1435,6 @@ int cipso_v4_skbuff_getattr(const struct sk_buff *skb, u32 doi; struct cipso_v4_doi *doi_def; - if (!CIPSO_V4_OPTEXIST(skb)) - return -ENOMSG; cipso_ptr = CIPSO_V4_OPTPTR(skb); if (cipso_v4_cache_check(cipso_ptr, cipso_ptr[1], secattr) == 0) return 0; -- cgit v1.2.3 From 6ce61a7c2678800cfe59a5f4a41ce8f785b9d355 Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Fri, 17 Nov 2006 17:38:48 -0500 Subject: NetLabel: add tag verification when adding new CIPSOv4 DOI definitions Currently the CIPSOv4 engine does not do any sort of checking when a new DOI definition is added. The tags are still verified but only as a side effect of normal NetLabel operation (packet processing, socket labeling, etc.) which would cause application errors due to the faulty configuration. This patch adds tag checking when new DOI definition are added allowing us to catch these configuration problems when they happen. Signed-off-by: Paul Moore Signed-off-by: James Morris --- net/ipv4/cipso_ipv4.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'net/ipv4') diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c index fb5d913f581..23a968f754b 100644 --- a/net/ipv4/cipso_ipv4.c +++ b/net/ipv4/cipso_ipv4.c @@ -447,8 +447,22 @@ static struct cipso_v4_doi *cipso_v4_doi_search(u32 doi) */ int cipso_v4_doi_add(struct cipso_v4_doi *doi_def) { + u32 iter; + if (doi_def == NULL || doi_def->doi == CIPSO_V4_DOI_UNKNOWN) return -EINVAL; + for (iter = 0; iter < CIPSO_V4_TAG_MAXCNT; iter++) { + switch (doi_def->tags[iter]) { + case CIPSO_V4_TAG_RBITMAP: + break; + case CIPSO_V4_TAG_INVALID: + if (iter == 0) + return -EINVAL; + break; + default: + return -EINVAL; + } + } doi_def->valid = 1; INIT_RCU_HEAD(&doi_def->rcu); -- cgit v1.2.3 From 91b1ed0afdbffbda88c472ef72af37e19b7876fb Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Fri, 17 Nov 2006 17:38:49 -0500 Subject: NetLabel: fixup the handling of CIPSOv4 tags to allow for multiple tag types While the original CIPSOv4 code had provisions for multiple tag types the implementation was not as great as it could be, pushing a lot of non-tag specific processing into the tag specific code blocks. This patch fixes that issue making it easier to support multiple tag types in the future. Signed-off-by: Paul Moore Signed-off-by: James Morris --- net/ipv4/cipso_ipv4.c | 113 +++++++++++++++++++++++--------------------------- 1 file changed, 53 insertions(+), 60 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c index 23a968f754b..a056278ad62 100644 --- a/net/ipv4/cipso_ipv4.c +++ b/net/ipv4/cipso_ipv4.c @@ -958,35 +958,28 @@ static int cipso_v4_map_cat_rbm_ntoh(const struct cipso_v4_doi *doi_def, * Protocol Handling Functions */ +#define CIPSO_V4_OPT_LEN_MAX 40 #define CIPSO_V4_HDR_LEN 6 /** * cipso_v4_gentag_hdr - Generate a CIPSO option header * @doi_def: the DOI definition - * @len: the total tag length in bytes + * @len: the total tag length in bytes, not including this header * @buf: the CIPSO option buffer * * Description: - * Write a CIPSO header into the beginning of @buffer. Return zero on success, - * negative values on failure. + * Write a CIPSO header into the beginning of @buffer. * */ -static int cipso_v4_gentag_hdr(const struct cipso_v4_doi *doi_def, - u32 len, - unsigned char *buf) +static void cipso_v4_gentag_hdr(const struct cipso_v4_doi *doi_def, + unsigned char *buf, + u32 len) { - if (CIPSO_V4_HDR_LEN + len > 40) - return -ENOSPC; - buf[0] = IPOPT_CIPSO; buf[1] = CIPSO_V4_HDR_LEN + len; *(__be32 *)&buf[2] = htonl(doi_def->doi); - - return 0; } -#define CIPSO_V4_TAG1_CAT_LEN 30 - /** * cipso_v4_gentag_rbm - Generate a CIPSO restricted bitmap tag (type #1) * @doi_def: the DOI definition @@ -997,71 +990,50 @@ static int cipso_v4_gentag_hdr(const struct cipso_v4_doi *doi_def, * Description: * Generate a CIPSO option using the restricted bitmap tag, tag type #1. The * actual buffer length may be larger than the indicated size due to - * translation between host and network category bitmaps. Returns zero on - * success, negative values on failure. + * translation between host and network category bitmaps. Returns the size of + * the tag on success, negative values on failure. * */ static int cipso_v4_gentag_rbm(const struct cipso_v4_doi *doi_def, const struct netlbl_lsm_secattr *secattr, - unsigned char **buffer, - u32 *buffer_len) + unsigned char *buffer, + u32 buffer_len) { int ret_val; - unsigned char *buf = NULL; - u32 buf_len; + u32 tag_len; u32 level; if ((secattr->flags & NETLBL_SECATTR_MLS_LVL) == 0) return -EPERM; - if (secattr->flags & NETLBL_SECATTR_MLS_CAT) { - buf = kzalloc(CIPSO_V4_HDR_LEN + 4 + CIPSO_V4_TAG1_CAT_LEN, - GFP_ATOMIC); - if (buf == NULL) - return -ENOMEM; + ret_val = cipso_v4_map_lvl_hton(doi_def, secattr->mls_lvl, &level); + if (ret_val != 0) + return ret_val; + if (secattr->flags & NETLBL_SECATTR_MLS_CAT) { ret_val = cipso_v4_map_cat_rbm_hton(doi_def, secattr->mls_cat, secattr->mls_cat_len, - &buf[CIPSO_V4_HDR_LEN + 4], - CIPSO_V4_TAG1_CAT_LEN); + &buffer[4], + buffer_len - 4); if (ret_val < 0) - goto gentag_failure; + return ret_val; /* This will send packets using the "optimized" format when * possibile as specified in section 3.4.2.6 of the * CIPSO draft. */ if (cipso_v4_rbm_optfmt && ret_val > 0 && ret_val <= 10) - buf_len = 14; + tag_len = 14; else - buf_len = 4 + ret_val; - } else { - buf = kzalloc(CIPSO_V4_HDR_LEN + 4, GFP_ATOMIC); - if (buf == NULL) - return -ENOMEM; - buf_len = 4; - } - - ret_val = cipso_v4_map_lvl_hton(doi_def, secattr->mls_lvl, &level); - if (ret_val != 0) - goto gentag_failure; - - ret_val = cipso_v4_gentag_hdr(doi_def, buf_len, buf); - if (ret_val != 0) - goto gentag_failure; - - buf[CIPSO_V4_HDR_LEN] = 0x01; - buf[CIPSO_V4_HDR_LEN + 1] = buf_len; - buf[CIPSO_V4_HDR_LEN + 3] = level; + tag_len = 4 + ret_val; + } else + tag_len = 4; - *buffer = buf; - *buffer_len = CIPSO_V4_HDR_LEN + buf_len; + buffer[0] = 0x01; + buffer[1] = tag_len; + buffer[3] = level; - return 0; - -gentag_failure: - kfree(buf); - return ret_val; + return tag_len; } /** @@ -1284,7 +1256,7 @@ int cipso_v4_socket_setattr(const struct socket *sock, { int ret_val = -EPERM; u32 iter; - unsigned char *buf = NULL; + unsigned char *buf; u32 buf_len = 0; u32 opt_len; struct ip_options *opt = NULL; @@ -1300,17 +1272,28 @@ int cipso_v4_socket_setattr(const struct socket *sock, if (sk == NULL) return 0; + /* We allocate the maximum CIPSO option size here so we are probably + * being a little wasteful, but it makes our life _much_ easier later + * on and after all we are only talking about 40 bytes. */ + buf_len = CIPSO_V4_OPT_LEN_MAX; + buf = kmalloc(buf_len, GFP_ATOMIC); + if (buf == NULL) { + ret_val = -ENOMEM; + goto socket_setattr_failure; + } + /* XXX - This code assumes only one tag per CIPSO option which isn't * really a good assumption to make but since we only support the MAC * tags right now it is a safe assumption. */ iter = 0; do { + memset(buf, 0, buf_len); switch (doi_def->tags[iter]) { case CIPSO_V4_TAG_RBITMAP: ret_val = cipso_v4_gentag_rbm(doi_def, - secattr, - &buf, - &buf_len); + secattr, + &buf[CIPSO_V4_HDR_LEN], + buf_len - CIPSO_V4_HDR_LEN); break; default: ret_val = -EPERM; @@ -1318,11 +1301,13 @@ int cipso_v4_socket_setattr(const struct socket *sock, } iter++; - } while (ret_val != 0 && + } while (ret_val < 0 && iter < CIPSO_V4_TAG_MAXCNT && doi_def->tags[iter] != CIPSO_V4_TAG_INVALID); - if (ret_val != 0) + if (ret_val < 0) goto socket_setattr_failure; + cipso_v4_gentag_hdr(doi_def, buf, ret_val); + buf_len = CIPSO_V4_HDR_LEN + ret_val; /* We can't use ip_options_get() directly because it makes a call to * ip_options_get_alloc() which allocates memory with GFP_KERNEL and @@ -1396,6 +1381,10 @@ int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr) rcu_read_unlock(); return -ENOMSG; } + + /* XXX - This code assumes only one tag per CIPSO option which isn't + * really a good assumption to make but since we only support the MAC + * tags right now it is a safe assumption. */ switch (cipso_ptr[6]) { case CIPSO_V4_TAG_RBITMAP: ret_val = cipso_v4_parsetag_rbm(doi_def, @@ -1458,6 +1447,10 @@ int cipso_v4_skbuff_getattr(const struct sk_buff *skb, doi_def = cipso_v4_doi_getdef(doi); if (doi_def == NULL) goto skbuff_getattr_return; + + /* XXX - This code assumes only one tag per CIPSO option which isn't + * really a good assumption to make but since we only support the MAC + * tags right now it is a safe assumption. */ switch (cipso_ptr[6]) { case CIPSO_V4_TAG_RBITMAP: ret_val = cipso_v4_parsetag_rbm(doi_def, -- cgit v1.2.3 From 9fade4bf8eed3db2fd1306968da4d51bc611aca3 Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Fri, 17 Nov 2006 17:38:50 -0500 Subject: NetLabel: return the correct error for translated CIPSOv4 tags The CIPSOv4 translated tag #1 mapping does not always return the correct error code if the desired mapping does not exist; instead of returning -EPERM it returns -ENOSPC indicating that the buffer is not large enough to hold the translated value. This was caused by failing to check a specific error condition. This patch fixes this so that unknown mappings return -EPERM which is consistent with the rest of the related CIPSOv4 code. Signed-off-by: Paul Moore Signed-off-by: James Morris --- net/ipv4/cipso_ipv4.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'net/ipv4') diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c index a056278ad62..c305de6fa20 100644 --- a/net/ipv4/cipso_ipv4.c +++ b/net/ipv4/cipso_ipv4.c @@ -867,6 +867,8 @@ static int cipso_v4_map_cat_rbm_hton(const struct cipso_v4_doi *doi_def, return -EPERM; net_spot = host_cat_array[host_spot]; + if (net_spot >= CIPSO_V4_INV_CAT) + return -EPERM; if (net_spot >= net_clen_bits) return -ENOSPC; cipso_v4_bitmap_setbit(net_cat, net_spot, 1); @@ -935,6 +937,8 @@ static int cipso_v4_map_cat_rbm_ntoh(const struct cipso_v4_doi *doi_def, return -EPERM; host_spot = net_cat_array[net_spot]; + if (host_spot >= CIPSO_V4_INV_CAT) + return -EPERM; if (host_spot >= host_clen_bits) return -ENOSPC; cipso_v4_bitmap_setbit(host_cat, host_spot, 1); -- cgit v1.2.3 From 9bb5fd2b05cb4dba229e225536faa59eaadd837d Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Fri, 17 Nov 2006 17:38:52 -0500 Subject: NetLabel: use cipso_v4_doi_search() for local CIPSOv4 functions The cipso_v4_doi_search() function behaves the same as cipso_v4_doi_getdef() but is a local, static function so use it whenever possibile in the CIPSOv4 code base. Signed-of-by: Paul Moore Signed-off-by: James Morris --- net/ipv4/cipso_ipv4.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c index c305de6fa20..a60af830407 100644 --- a/net/ipv4/cipso_ipv4.c +++ b/net/ipv4/cipso_ipv4.c @@ -1135,7 +1135,7 @@ int cipso_v4_validate(unsigned char **option) } rcu_read_lock(); - doi_def = cipso_v4_doi_getdef(ntohl(*((__be32 *)&opt[2]))); + doi_def = cipso_v4_doi_search(ntohl(*((u32 *)&opt[2]))); if (doi_def == NULL) { err_offset = 2; goto validate_return_locked; @@ -1380,7 +1380,7 @@ int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr) doi = ntohl(*(__be32 *)&cipso_ptr[2]); rcu_read_lock(); - doi_def = cipso_v4_doi_getdef(doi); + doi_def = cipso_v4_doi_search(doi); if (doi_def == NULL) { rcu_read_unlock(); return -ENOMSG; @@ -1448,7 +1448,7 @@ int cipso_v4_skbuff_getattr(const struct sk_buff *skb, doi = ntohl(*(__be32 *)&cipso_ptr[2]); rcu_read_lock(); - doi_def = cipso_v4_doi_getdef(doi); + doi_def = cipso_v4_doi_search(doi); if (doi_def == NULL) goto skbuff_getattr_return; -- cgit v1.2.3 From 8e5200f54062b8af0ed1d186ea0f113854786d89 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 20 Nov 2006 18:06:37 -0800 Subject: [NET]: Fix assorted misannotations (from md5 and udplite merges). Signed-off-by: Al Viro Signed-off-by: David S. Miller --- net/ipv4/tcp_ipv4.c | 2 +- net/ipv4/udp.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index b7d5522092e..e9d467124c4 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1020,7 +1020,7 @@ static int tcp_v4_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, #ifdef CONFIG_TCP_MD5SIG_DEBUG int i; #endif - __u16 old_checksum; + __sum16 old_checksum; struct tcp_md5sig_pool *hp; struct tcp4_pseudohdr *bp; struct hash_desc *desc; diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 7eb76fbf1b4..28e4cf662ce 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -114,7 +114,7 @@ DEFINE_RWLOCK(udp_hash_lock); static int udp_port_rover; -static inline int __udp_lib_lport_inuse(__be16 num, struct hlist_head udptable[]) +static inline int __udp_lib_lport_inuse(__u16 num, struct hlist_head udptable[]) { struct sock *sk; struct hlist_node *node; @@ -455,7 +455,7 @@ static int udp_push_pending_frames(struct sock *sk, struct udp_sock *up) struct sk_buff *skb; struct udphdr *uh; int err = 0; - u32 csum = 0; + __wsum csum = 0; /* Grab the skbuff where UDP header space exists. */ if ((skb = skb_peek(&sk->sk_write_queue)) == NULL) -- cgit v1.2.3 From 5b14027bf2132c0631ea9f3be11ced89a5057220 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 20 Nov 2006 18:06:59 -0800 Subject: [NETFILTER]: ip_nat_snmp_basic annotations. ... and switch the damn checksum update to something saner Signed-off-by: Al Viro Signed-off-by: David S. Miller --- net/ipv4/netfilter/ip_nat_snmp_basic.c | 85 ++++++++++++++-------------------- 1 file changed, 34 insertions(+), 51 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/netfilter/ip_nat_snmp_basic.c b/net/ipv4/netfilter/ip_nat_snmp_basic.c index 168f45fa189..c3d9f3b090c 100644 --- a/net/ipv4/netfilter/ip_nat_snmp_basic.c +++ b/net/ipv4/netfilter/ip_nat_snmp_basic.c @@ -64,7 +64,7 @@ MODULE_DESCRIPTION("Basic SNMP Application Layer Gateway"); #define SNMP_PORT 161 #define SNMP_TRAP_PORT 162 -#define NOCT1(n) (u_int8_t )((n) & 0xff) +#define NOCT1(n) (*(u8 *)n) static int debug; static DEFINE_SPINLOCK(snmp_lock); @@ -613,7 +613,7 @@ struct snmp_v1_trap static inline void mangle_address(unsigned char *begin, unsigned char *addr, const struct oct1_map *map, - u_int16_t *check); + __sum16 *check); struct snmp_cnv { unsigned int class; @@ -873,38 +873,24 @@ static unsigned char snmp_request_decode(struct asn1_ctx *ctx, * Fast checksum update for possibly oddly-aligned UDP byte, from the * code example in the draft. */ -static void fast_csum(unsigned char *csum, +static void fast_csum(__sum16 *csum, const unsigned char *optr, const unsigned char *nptr, - int odd) + int offset) { - long x, old, new; - - x = csum[0] * 256 + csum[1]; - - x =~ x & 0xFFFF; - - if (odd) old = optr[0] * 256; - else old = optr[0]; - - x -= old & 0xFFFF; - if (x <= 0) { - x--; - x &= 0xFFFF; - } - - if (odd) new = nptr[0] * 256; - else new = nptr[0]; - - x += new & 0xFFFF; - if (x & 0x10000) { - x++; - x &= 0xFFFF; + unsigned char s[4]; + + if (offset & 1) { + s[0] = s[2] = 0; + s[1] = ~*optr; + s[3] = *nptr; + } else { + s[1] = s[3] = 0; + s[0] = ~*optr; + s[2] = *nptr; } - - x =~ x & 0xFFFF; - csum[0] = x / 256; - csum[1] = x & 0xFF; + + *csum = csum_fold(csum_partial(s, 4, ~csum_unfold(*csum))); } /* @@ -915,9 +901,9 @@ static void fast_csum(unsigned char *csum, static inline void mangle_address(unsigned char *begin, unsigned char *addr, const struct oct1_map *map, - u_int16_t *check) + __sum16 *check) { - if (map->from == NOCT1(*addr)) { + if (map->from == NOCT1(addr)) { u_int32_t old; if (debug) @@ -927,11 +913,8 @@ static inline void mangle_address(unsigned char *begin, /* Update UDP checksum if being used */ if (*check) { - unsigned char odd = !((addr - begin) % 2); - - fast_csum((unsigned char *)check, - &map->from, &map->to, odd); - + fast_csum(check, + &map->from, &map->to, addr - begin); } if (debug) @@ -943,7 +926,7 @@ static inline void mangle_address(unsigned char *begin, static unsigned char snmp_trap_decode(struct asn1_ctx *ctx, struct snmp_v1_trap *trap, const struct oct1_map *map, - u_int16_t *check) + __sum16 *check) { unsigned int cls, con, tag, len; unsigned char *end; @@ -1037,7 +1020,7 @@ static void hex_dump(unsigned char *buf, size_t len) static int snmp_parse_mangle(unsigned char *msg, u_int16_t len, const struct oct1_map *map, - u_int16_t *check) + __sum16 *check) { unsigned char *eoc, *end; unsigned int cls, con, tag, vers, pdutype; @@ -1223,12 +1206,12 @@ static int snmp_translate(struct ip_conntrack *ct, */ if (dir == IP_CT_DIR_ORIGINAL) { /* SNAT traps */ - map.from = NOCT1(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip); - map.to = NOCT1(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip); + map.from = NOCT1(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip); + map.to = NOCT1(&ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip); } else { /* DNAT replies */ - map.from = NOCT1(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip); - map.to = NOCT1(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip); + map.from = NOCT1(&ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip); + map.to = NOCT1(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip); } if (map.from == map.to) @@ -1294,11 +1277,11 @@ static struct ip_conntrack_helper snmp_helper = { .help = help, .name = "snmp", - .tuple = { .src = { .u = { __constant_htons(SNMP_PORT) } }, - .dst = { .protonum = IPPROTO_UDP }, + .tuple = {.src = {.u = {.udp = {.port = __constant_htons(SNMP_PORT)}}}, + .dst = {.protonum = IPPROTO_UDP}, }, - .mask = { .src = { .u = { 0xFFFF } }, - .dst = { .protonum = 0xFF }, + .mask = {.src = {.u = {0xFFFF}}, + .dst = {.protonum = 0xFF}, }, }; @@ -1309,11 +1292,11 @@ static struct ip_conntrack_helper snmp_trap_helper = { .help = help, .name = "snmp_trap", - .tuple = { .src = { .u = { __constant_htons(SNMP_TRAP_PORT) } }, - .dst = { .protonum = IPPROTO_UDP }, + .tuple = {.src = {.u = {.udp = {.port = __constant_htons(SNMP_TRAP_PORT)}}}, + .dst = {.protonum = IPPROTO_UDP}, }, - .mask = { .src = { .u = { 0xFFFF } }, - .dst = { .protonum = 0xFF }, + .mask = {.src = {.u = {0xFFFF}}, + .dst = {.protonum = 0xFF}, }, }; -- cgit v1.2.3 From ff1dcadb1b55dbf471c5ed109dbbdf06bd19ef3b Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 20 Nov 2006 18:07:29 -0800 Subject: [NET]: Split skb->csum ... into anonymous union of __wsum and __u32 (csum and csum_offset resp.) Signed-off-by: Al Viro Signed-off-by: David S. Miller --- net/ipv4/tcp_ipv4.c | 4 ++-- net/ipv4/udp.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index e9d467124c4..4913f25e5ad 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -504,7 +504,7 @@ void tcp_v4_send_check(struct sock *sk, int len, struct sk_buff *skb) if (skb->ip_summed == CHECKSUM_PARTIAL) { th->check = ~tcp_v4_check(th, len, inet->saddr, inet->daddr, 0); - skb->csum = offsetof(struct tcphdr, check); + skb->csum_offset = offsetof(struct tcphdr, check); } else { th->check = tcp_v4_check(th, len, inet->saddr, inet->daddr, csum_partial((char *)th, @@ -526,7 +526,7 @@ int tcp_v4_gso_send_check(struct sk_buff *skb) th->check = 0; th->check = ~tcp_v4_check(th, skb->len, iph->saddr, iph->daddr, 0); - skb->csum = offsetof(struct tcphdr, check); + skb->csum_offset = offsetof(struct tcphdr, check); skb->ip_summed = CHECKSUM_PARTIAL; return 0; } diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 28e4cf662ce..1807a30694d 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -422,7 +422,7 @@ static void udp4_hwcsum_outgoing(struct sock *sk, struct sk_buff *skb, /* * Only one fragment on the socket. */ - skb->csum = offsetof(struct udphdr, check); + skb->csum_offset = offsetof(struct udphdr, check); uh->check = ~csum_tcpudp_magic(src, dst, len, IPPROTO_UDP, 0); } else { /* -- cgit v1.2.3 From 66625984ca94552f75836596e0e83f3e5594bd58 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 20 Nov 2006 18:08:37 -0800 Subject: [CIPSO]: Missing annotation in cipso_ipv4 update. Signed-off-by: Al Viro Signed-off-by: David S. Miller --- net/ipv4/cipso_ipv4.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/ipv4') diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c index a60af830407..f3957cfaed4 100644 --- a/net/ipv4/cipso_ipv4.c +++ b/net/ipv4/cipso_ipv4.c @@ -1135,7 +1135,7 @@ int cipso_v4_validate(unsigned char **option) } rcu_read_lock(); - doi_def = cipso_v4_doi_search(ntohl(*((u32 *)&opt[2]))); + doi_def = cipso_v4_doi_search(ntohl(*((__be32 *)&opt[2]))); if (doi_def == NULL) { err_offset = 2; goto validate_return_locked; -- cgit v1.2.3 From 8b2ed4bba45b7ca8e378d45f82f3f32f651e0a42 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 21 Nov 2006 01:17:18 -0200 Subject: [IPVS]: Use kmemdup where appropriate Signed-off-by: Arnaldo Carvalho de Melo --- net/ipv4/ipvs/ip_vs_app.c | 3 +-- net/ipv4/ipvs/ip_vs_proto.c | 8 +------- 2 files changed, 2 insertions(+), 9 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/ipvs/ip_vs_app.c b/net/ipv4/ipvs/ip_vs_app.c index e7752334d29..6c40899aa16 100644 --- a/net/ipv4/ipvs/ip_vs_app.c +++ b/net/ipv4/ipvs/ip_vs_app.c @@ -80,10 +80,9 @@ ip_vs_app_inc_new(struct ip_vs_app *app, __u16 proto, __u16 port) if (!pp->unregister_app) return -EOPNOTSUPP; - inc = kmalloc(sizeof(struct ip_vs_app), GFP_KERNEL); + inc = kmemdup(app, sizeof(*inc), GFP_KERNEL); if (!inc) return -ENOMEM; - memcpy(inc, app, sizeof(*inc)); INIT_LIST_HEAD(&inc->p_list); INIT_LIST_HEAD(&inc->incs_list); inc->app = app; diff --git a/net/ipv4/ipvs/ip_vs_proto.c b/net/ipv4/ipvs/ip_vs_proto.c index c4528b5c800..e844ddb82b9 100644 --- a/net/ipv4/ipvs/ip_vs_proto.c +++ b/net/ipv4/ipvs/ip_vs_proto.c @@ -118,13 +118,7 @@ void ip_vs_protocol_timeout_change(int flags) int * ip_vs_create_timeout_table(int *table, int size) { - int *t; - - t = kmalloc(size, GFP_ATOMIC); - if (t == NULL) - return NULL; - memcpy(t, table, size); - return t; + return kmemdup(table, size, GFP_ATOMIC); } -- cgit v1.2.3 From 4e9b82693542003b028c8494e9e3c49615b91ce7 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Mon, 27 Nov 2006 09:25:58 -0800 Subject: [NETLINK]: Remove unused dst_pid field in netlink_skb_parms The destination PID is passed directly to netlink_unicast() respectively netlink_multicast(). Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- net/ipv4/fib_frontend.c | 1 - net/ipv4/netfilter/ip_conntrack_netlink.c | 4 +--- 2 files changed, 1 insertion(+), 4 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index 14025345cc5..d47b72af89e 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -811,7 +811,6 @@ static void nl_fib_input(struct sock *sk, int len) pid = nlh->nlmsg_pid; /*pid of sending process */ NETLINK_CB(skb).pid = 0; /* from kernel */ - NETLINK_CB(skb).dst_pid = pid; NETLINK_CB(skb).dst_group = 0; /* unicast */ netlink_unicast(sk, skb, pid, MSG_DONTWAIT); } diff --git a/net/ipv4/netfilter/ip_conntrack_netlink.c b/net/ipv4/netfilter/ip_conntrack_netlink.c index 55f0ae64108..1bb8ed33c5b 100644 --- a/net/ipv4/netfilter/ip_conntrack_netlink.c +++ b/net/ipv4/netfilter/ip_conntrack_netlink.c @@ -743,7 +743,6 @@ ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb, ip_conntrack_put(ct); return -ENOMEM; } - NETLINK_CB(skb2).dst_pid = NETLINK_CB(skb).pid; err = ctnetlink_fill_info(skb2, NETLINK_CB(skb).pid, nlh->nlmsg_seq, IPCTNL_MSG_CT_NEW, 1, ct); @@ -1273,8 +1272,7 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb, skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); if (!skb2) goto out; - NETLINK_CB(skb2).dst_pid = NETLINK_CB(skb).pid; - + err = ctnetlink_exp_fill_info(skb2, NETLINK_CB(skb).pid, nlh->nlmsg_seq, IPCTNL_MSG_EXP_NEW, 1, exp); -- cgit v1.2.3 From e3703b3de1f049b38733ba520e5038f23063068e Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Mon, 27 Nov 2006 09:27:07 -0800 Subject: [RTNETLINK]: Add rtnl_put_cacheinfo() to unify some code IPv4, IPv6, and DECNet all use struct rta_cacheinfo in a similiar way, therefore rtnl_put_cacheinfo() is added to reuse code. Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- net/ipv4/route.c | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/route.c b/net/ipv4/route.c index ee00b6506ab..9f3924c4905 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -2629,7 +2629,8 @@ static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event, struct rtable *rt = (struct rtable*)skb->dst; struct rtmsg *r; struct nlmsghdr *nlh; - struct rta_cacheinfo ci; + long expires; + u32 id = 0, ts = 0, tsage = 0, error; nlh = nlmsg_put(skb, pid, seq, event, sizeof(*r), flags); if (nlh == NULL) @@ -2676,20 +2677,13 @@ static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event, if (rtnetlink_put_metrics(skb, rt->u.dst.metrics) < 0) goto nla_put_failure; - ci.rta_lastuse = jiffies_to_clock_t(jiffies - rt->u.dst.lastuse); - ci.rta_used = rt->u.dst.__use; - ci.rta_clntref = atomic_read(&rt->u.dst.__refcnt); - if (rt->u.dst.expires) - ci.rta_expires = jiffies_to_clock_t(rt->u.dst.expires - jiffies); - else - ci.rta_expires = 0; - ci.rta_error = rt->u.dst.error; - ci.rta_id = ci.rta_ts = ci.rta_tsage = 0; + error = rt->u.dst.error; + expires = rt->u.dst.expires ? rt->u.dst.expires - jiffies : 0; if (rt->peer) { - ci.rta_id = rt->peer->ip_id_count; + id = rt->peer->ip_id_count; if (rt->peer->tcp_ts_stamp) { - ci.rta_ts = rt->peer->tcp_ts; - ci.rta_tsage = xtime.tv_sec - rt->peer->tcp_ts_stamp; + ts = rt->peer->tcp_ts; + tsage = xtime.tv_sec - rt->peer->tcp_ts_stamp; } } @@ -2708,7 +2702,7 @@ static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event, } else { if (err == -EMSGSIZE) goto nla_put_failure; - ci.rta_error = err; + error = err; } } } else @@ -2716,7 +2710,9 @@ static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event, NLA_PUT_U32(skb, RTA_IIF, rt->fl.iif); } - NLA_PUT(skb, RTA_CACHEINFO, sizeof(ci), &ci); + if (rtnl_put_cacheinfo(skb, &rt->u.dst, id, ts, tsage, + expires, error) < 0) + goto nla_put_failure; return nlmsg_end(skb, nlh); -- cgit v1.2.3 From 4c0a6cb0db19de411c4bf7fcdc79d4c7c4ccafb1 Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Mon, 27 Nov 2006 09:29:59 -0800 Subject: [UDP(-Lite)]: consolidate v4 and v6 get|setsockopt code This patch consolidates set/getsockopt code between UDP(-Lite) v4 and 6. The justification is that UDP(-Lite) is a transport-layer protocol and therefore the socket option code (at least in theory) should be AF-independent. Furthermore, there is the following code reduplication: * do_udp{,v6}_getsockopt is 100% identical between v4 and v6 * do_udp{,v6}_setsockopt is identical up to the following differerence --v4 in contrast to v4 additionally allows the experimental encapsulation types UDP_ENCAP_ESPINUDP and UDP_ENCAP_ESPINUDP_NON_IKE --the remainder is identical between v4 and v6 I believe that this difference is of little relevance. The advantages in not duplicating twice almost completely identical code. The patch further simplifies the interface of udp{,v6}_push_pending_frames, since for the second argument (struct udp_sock *up) it always holds that up = udp_sk(sk); where sk is the first function argument. Signed-off-by: Gerrit Renker Signed-off-by: David S. Miller --- net/ipv4/udp.c | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 1807a30694d..035915fc9ed 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -448,8 +448,9 @@ static void udp4_hwcsum_outgoing(struct sock *sk, struct sk_buff *skb, /* * Push out all pending data as one UDP datagram. Socket is locked. */ -static int udp_push_pending_frames(struct sock *sk, struct udp_sock *up) +static int udp_push_pending_frames(struct sock *sk) { + struct udp_sock *up = udp_sk(sk); struct inet_sock *inet = inet_sk(sk); struct flowi *fl = &inet->cork.fl; struct sk_buff *skb; @@ -673,7 +674,7 @@ do_append_data: if (err) udp_flush_pending_frames(sk); else if (!corkreq) - err = udp_push_pending_frames(sk, up); + err = udp_push_pending_frames(sk); else if (unlikely(skb_queue_empty(&sk->sk_write_queue))) up->pending = 0; release_sock(sk); @@ -746,7 +747,7 @@ int udp_sendpage(struct sock *sk, struct page *page, int offset, up->len += size; if (!(up->corkflag || (flags&MSG_MORE))) - ret = udp_push_pending_frames(sk, up); + ret = udp_push_pending_frames(sk); if (!ret) ret = size; out: @@ -1299,8 +1300,9 @@ int udp_destroy_sock(struct sock *sk) /* * Socket option code for UDP */ -static int do_udp_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen) +int udp_lib_setsockopt(struct sock *sk, int level, int optname, + char __user *optval, int optlen, + int (*push_pending_frames)(struct sock *)) { struct udp_sock *up = udp_sk(sk); int val; @@ -1319,7 +1321,7 @@ static int do_udp_setsockopt(struct sock *sk, int level, int optname, } else { up->corkflag = 0; lock_sock(sk); - udp_push_pending_frames(sk, up); + (*push_pending_frames)(sk); release_sock(sk); } break; @@ -1375,7 +1377,8 @@ int udp_setsockopt(struct sock *sk, int level, int optname, char __user *optval, int optlen) { if (level == SOL_UDP || level == SOL_UDPLITE) - return do_udp_setsockopt(sk, level, optname, optval, optlen); + return udp_lib_setsockopt(sk, level, optname, optval, optlen, + udp_push_pending_frames); return ip_setsockopt(sk, level, optname, optval, optlen); } @@ -1384,13 +1387,14 @@ int compat_udp_setsockopt(struct sock *sk, int level, int optname, char __user *optval, int optlen) { if (level == SOL_UDP || level == SOL_UDPLITE) - return do_udp_setsockopt(sk, level, optname, optval, optlen); + return udp_lib_setsockopt(sk, level, optname, optval, optlen, + udp_push_pending_frames); return compat_ip_setsockopt(sk, level, optname, optval, optlen); } #endif -static int do_udp_getsockopt(struct sock *sk, int level, int optname, - char __user *optval, int __user *optlen) +int udp_lib_getsockopt(struct sock *sk, int level, int optname, + char __user *optval, int __user *optlen) { struct udp_sock *up = udp_sk(sk); int val, len; @@ -1437,7 +1441,7 @@ int udp_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen) { if (level == SOL_UDP || level == SOL_UDPLITE) - return do_udp_getsockopt(sk, level, optname, optval, optlen); + return udp_lib_getsockopt(sk, level, optname, optval, optlen); return ip_getsockopt(sk, level, optname, optval, optlen); } @@ -1446,7 +1450,7 @@ int compat_udp_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen) { if (level == SOL_UDP || level == SOL_UDPLITE) - return do_udp_getsockopt(sk, level, optname, optval, optlen); + return udp_lib_getsockopt(sk, level, optname, optval, optlen); return compat_ip_getsockopt(sk, level, optname, optval, optlen); } #endif @@ -1716,6 +1720,8 @@ EXPORT_SYMBOL(udp_ioctl); EXPORT_SYMBOL(udp_get_port); EXPORT_SYMBOL(udp_prot); EXPORT_SYMBOL(udp_sendmsg); +EXPORT_SYMBOL(udp_lib_getsockopt); +EXPORT_SYMBOL(udp_lib_setsockopt); EXPORT_SYMBOL(udp_poll); #ifdef CONFIG_PROC_FS -- cgit v1.2.3 From d2e4bdc8704b0e711c5046a430bfd1681b0bd5a9 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 28 Nov 2006 14:37:38 -0800 Subject: [TCP] Vegas: Increase default alpha to 2 and beta to 4. This helps Vegas cope better with delayed ACKs, see analysis at: http://www.cs.caltech.edu/%7Eweixl/technical/ns2linux/known_linux/index.html#vegas Signed-off-by: David S. Miller --- net/ipv4/tcp_vegas.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/tcp_vegas.c b/net/ipv4/tcp_vegas.c index a3b7aa015a2..ddc4bcc5785 100644 --- a/net/ipv4/tcp_vegas.c +++ b/net/ipv4/tcp_vegas.c @@ -42,8 +42,8 @@ * with V_PARAM_SHIFT bits to the right of the binary point. */ #define V_PARAM_SHIFT 1 -static int alpha = 1< Date: Wed, 29 Nov 2006 02:35:06 +0100 Subject: [NETFILTER]: nf_conntrack: rename struct nf_conntrack_protocol Rename 'struct nf_conntrack_protocol' to 'struct nf_conntrack_l4proto' in order to help distinguish it from 'struct nf_conntrack_l3proto'. It gets rather confusing with 'nf_conntrack_protocol'. Signed-off-by: Martin Josefsson Signed-off-by: Patrick McHardy --- net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c | 26 +++++++++++++------------- net/ipv4/netfilter/nf_conntrack_proto_icmp.c | 12 ++++++------ 2 files changed, 19 insertions(+), 19 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c index 0af803df82b..370df0fdb22 100644 --- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c +++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include #include @@ -429,9 +429,9 @@ struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv4 = { .me = THIS_MODULE, }; -extern struct nf_conntrack_protocol nf_conntrack_protocol_tcp4; -extern struct nf_conntrack_protocol nf_conntrack_protocol_udp4; -extern struct nf_conntrack_protocol nf_conntrack_protocol_icmp; +extern struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp4; +extern struct nf_conntrack_l4proto nf_conntrack_l4proto_udp4; +extern struct nf_conntrack_l4proto nf_conntrack_l4proto_icmp; MODULE_ALIAS("nf_conntrack-" __stringify(AF_INET)); MODULE_LICENSE("GPL"); @@ -448,19 +448,19 @@ static int __init nf_conntrack_l3proto_ipv4_init(void) return ret; } - ret = nf_conntrack_protocol_register(&nf_conntrack_protocol_tcp4); + ret = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_tcp4); if (ret < 0) { printk("nf_conntrack_ipv4: can't register tcp.\n"); goto cleanup_sockopt; } - ret = nf_conntrack_protocol_register(&nf_conntrack_protocol_udp4); + ret = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_udp4); if (ret < 0) { printk("nf_conntrack_ipv4: can't register udp.\n"); goto cleanup_tcp; } - ret = nf_conntrack_protocol_register(&nf_conntrack_protocol_icmp); + ret = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_icmp); if (ret < 0) { printk("nf_conntrack_ipv4: can't register icmp.\n"); goto cleanup_udp; @@ -495,11 +495,11 @@ static int __init nf_conntrack_l3proto_ipv4_init(void) cleanup_ipv4: nf_conntrack_l3proto_unregister(&nf_conntrack_l3proto_ipv4); cleanup_icmp: - nf_conntrack_protocol_unregister(&nf_conntrack_protocol_icmp); + nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_icmp); cleanup_udp: - nf_conntrack_protocol_unregister(&nf_conntrack_protocol_udp4); + nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_udp4); cleanup_tcp: - nf_conntrack_protocol_unregister(&nf_conntrack_protocol_tcp4); + nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_tcp4); cleanup_sockopt: nf_unregister_sockopt(&so_getorigdst); return ret; @@ -513,9 +513,9 @@ static void __exit nf_conntrack_l3proto_ipv4_fini(void) #endif nf_unregister_hooks(ipv4_conntrack_ops, ARRAY_SIZE(ipv4_conntrack_ops)); nf_conntrack_l3proto_unregister(&nf_conntrack_l3proto_ipv4); - nf_conntrack_protocol_unregister(&nf_conntrack_protocol_icmp); - nf_conntrack_protocol_unregister(&nf_conntrack_protocol_udp4); - nf_conntrack_protocol_unregister(&nf_conntrack_protocol_tcp4); + nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_icmp); + nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_udp4); + nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_tcp4); nf_unregister_sockopt(&so_getorigdst); } diff --git a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c index 790f00d500c..08223a57a44 100644 --- a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c +++ b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include unsigned long nf_ct_icmp_timeout __read_mostly = 30*HZ; @@ -152,7 +152,7 @@ icmp_error_message(struct sk_buff *skb, struct icmphdr icmp; struct iphdr ip; } _in, *inside; - struct nf_conntrack_protocol *innerproto; + struct nf_conntrack_l4proto *innerproto; struct nf_conntrack_tuple_hash *h; int dataoff; @@ -170,7 +170,7 @@ icmp_error_message(struct sk_buff *skb, return -NF_ACCEPT; } - innerproto = __nf_ct_proto_find(PF_INET, inside->ip.protocol); + innerproto = __nf_ct_l4proto_find(PF_INET, inside->ip.protocol); dataoff = skb->nh.iph->ihl*4 + sizeof(inside->icmp); /* Are they talking about one of our connections? */ if (!nf_ct_get_tuple(skb, dataoff, dataoff + inside->ip.ihl*4, PF_INET, @@ -321,11 +321,11 @@ static int icmp_nfattr_to_tuple(struct nfattr *tb[], } #endif -struct nf_conntrack_protocol nf_conntrack_protocol_icmp = +struct nf_conntrack_l4proto nf_conntrack_l4proto_icmp = { .list = { NULL, NULL }, .l3proto = PF_INET, - .proto = IPPROTO_ICMP, + .l4proto = IPPROTO_ICMP, .name = "icmp", .pkt_to_tuple = icmp_pkt_to_tuple, .invert_tuple = icmp_invert_tuple, @@ -343,4 +343,4 @@ struct nf_conntrack_protocol nf_conntrack_protocol_icmp = #endif }; -EXPORT_SYMBOL(nf_conntrack_protocol_icmp); +EXPORT_SYMBOL(nf_conntrack_l4proto_icmp); -- cgit v1.2.3 From 824621eddd2087b0e6f0b2e0da91e8d77e4919bf Mon Sep 17 00:00:00 2001 From: Martin Josefsson Date: Wed, 29 Nov 2006 02:35:11 +0100 Subject: [NETFILTER]: nf_conntrack: remove unused struct list_head from protocols Remove unused struct list_head from struct nf_conntrack_l3proto and nf_conntrack_l4proto as all protocols are kept in arrays, not linked lists. Signed-off-by: Martin Josefsson Signed-off-by: Patrick McHardy --- net/ipv4/netfilter/nf_conntrack_proto_icmp.c | 1 - 1 file changed, 1 deletion(-) (limited to 'net/ipv4') diff --git a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c index 08223a57a44..95fc22b4969 100644 --- a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c +++ b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c @@ -323,7 +323,6 @@ static int icmp_nfattr_to_tuple(struct nfattr *tb[], struct nf_conntrack_l4proto nf_conntrack_l4proto_icmp = { - .list = { NULL, NULL }, .l3proto = PF_INET, .l4proto = IPPROTO_ICMP, .name = "icmp", -- cgit v1.2.3 From f8eb24a89afa12b48fa7e39775faea6d64b8e538 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Wed, 29 Nov 2006 02:35:15 +0100 Subject: [NETFILTER]: nf_conntrack: move extern declaration to header files Using extern in a C file is a bad idea because the compiler can't catch type errors. Signed-off-by: Patrick McHardy --- net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c index 370df0fdb22..d1907082d7d 100644 --- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c +++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c @@ -38,8 +38,6 @@ #define DEBUGP(format, args...) #endif -DECLARE_PER_CPU(struct nf_conntrack_stat, nf_conntrack_stat); - static int ipv4_pkt_to_tuple(const struct sk_buff *skb, unsigned int nhoff, struct nf_conntrack_tuple *tuple) { @@ -429,10 +427,6 @@ struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv4 = { .me = THIS_MODULE, }; -extern struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp4; -extern struct nf_conntrack_l4proto nf_conntrack_l4proto_udp4; -extern struct nf_conntrack_l4proto nf_conntrack_l4proto_icmp; - MODULE_ALIAS("nf_conntrack-" __stringify(AF_INET)); MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 933a41e7e12b773d1dd026018f02b86b5d257a22 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Wed, 29 Nov 2006 02:35:18 +0100 Subject: [NETFILTER]: nf_conntrack: move conntrack protocol sysctls to individual modules Signed-off-by: Patrick McHardy --- net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c | 53 -------------------------- net/ipv4/netfilter/nf_conntrack_proto_icmp.c | 23 ++++++++++- 2 files changed, 22 insertions(+), 54 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c index d1907082d7d..786c4ce96cd 100644 --- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c +++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c @@ -266,44 +266,6 @@ static struct nf_hook_ops ipv4_conntrack_ops[] = { }, }; -#ifdef CONFIG_SYSCTL -/* From nf_conntrack_proto_icmp.c */ -extern unsigned int nf_ct_icmp_timeout; -static struct ctl_table_header *nf_ct_ipv4_sysctl_header; - -static ctl_table nf_ct_sysctl_table[] = { - { - .ctl_name = NET_NF_CONNTRACK_ICMP_TIMEOUT, - .procname = "nf_conntrack_icmp_timeout", - .data = &nf_ct_icmp_timeout, - .maxlen = sizeof(unsigned int), - .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, - }, - { .ctl_name = 0 } -}; - -static ctl_table nf_ct_netfilter_table[] = { - { - .ctl_name = NET_NETFILTER, - .procname = "netfilter", - .mode = 0555, - .child = nf_ct_sysctl_table, - }, - { .ctl_name = 0 } -}; - -static ctl_table nf_ct_net_table[] = { - { - .ctl_name = CTL_NET, - .procname = "net", - .mode = 0555, - .child = nf_ct_netfilter_table, - }, - { .ctl_name = 0 } -}; -#endif - /* Fast function for those who don't want to parse /proc (and I don't blame them). */ /* Reversing the socket's dst/src point of view gives us the reply @@ -472,20 +434,8 @@ static int __init nf_conntrack_l3proto_ipv4_init(void) printk("nf_conntrack_ipv4: can't register hooks.\n"); goto cleanup_ipv4; } -#ifdef CONFIG_SYSCTL - nf_ct_ipv4_sysctl_header = register_sysctl_table(nf_ct_net_table, 0); - if (nf_ct_ipv4_sysctl_header == NULL) { - printk("nf_conntrack: can't register to sysctl.\n"); - ret = -ENOMEM; - goto cleanup_hooks; - } -#endif return ret; -#ifdef CONFIG_SYSCTL - cleanup_hooks: - nf_unregister_hooks(ipv4_conntrack_ops, ARRAY_SIZE(ipv4_conntrack_ops)); -#endif cleanup_ipv4: nf_conntrack_l3proto_unregister(&nf_conntrack_l3proto_ipv4); cleanup_icmp: @@ -502,9 +452,6 @@ static int __init nf_conntrack_l3proto_ipv4_init(void) static void __exit nf_conntrack_l3proto_ipv4_fini(void) { synchronize_net(); -#ifdef CONFIG_SYSCTL - unregister_sysctl_table(nf_ct_ipv4_sysctl_header); -#endif nf_unregister_hooks(ipv4_conntrack_ops, ARRAY_SIZE(ipv4_conntrack_ops)); nf_conntrack_l3proto_unregister(&nf_conntrack_l3proto_ipv4); nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_icmp); diff --git a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c index 95fc22b4969..c59f28193a3 100644 --- a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c +++ b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c @@ -25,7 +25,7 @@ #include #include -unsigned long nf_ct_icmp_timeout __read_mostly = 30*HZ; +static unsigned long nf_ct_icmp_timeout __read_mostly = 30*HZ; #if 0 #define DEBUGP printk @@ -321,6 +321,23 @@ static int icmp_nfattr_to_tuple(struct nfattr *tb[], } #endif +#ifdef CONFIG_SYSCTL +static struct ctl_table_header *icmp_sysctl_header; +static struct ctl_table icmp_sysctl_table[] = { + { + .ctl_name = NET_NF_CONNTRACK_ICMP_TIMEOUT, + .procname = "nf_conntrack_icmp_timeout", + .data = &nf_ct_icmp_timeout, + .maxlen = sizeof(unsigned int), + .mode = 0644, + .proc_handler = &proc_dointvec_jiffies, + }, + { + .ctl_name = 0 + } +}; +#endif /* CONFIG_SYSCTL */ + struct nf_conntrack_l4proto nf_conntrack_l4proto_icmp = { .l3proto = PF_INET, @@ -340,6 +357,10 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_icmp = .tuple_to_nfattr = icmp_tuple_to_nfattr, .nfattr_to_tuple = icmp_nfattr_to_tuple, #endif +#ifdef CONFIG_SYSCTL + .ctl_table_header = &icmp_sysctl_header, + .ctl_table = icmp_sysctl_table, +#endif }; EXPORT_SYMBOL(nf_conntrack_l4proto_icmp); -- cgit v1.2.3 From a999e6837603e4b5a164333c93918a1292f074c8 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Wed, 29 Nov 2006 02:35:20 +0100 Subject: [NETFILTER]: nf_conntrack: sysctl compatibility with old connection tracking This patch adds an option to keep the connection tracking sysctls visible under their old names. Signed-off-by: Patrick McHardy --- net/ipv4/netfilter/Kconfig | 11 +++++ net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c | 58 ++++++++++++++++++++++++++ net/ipv4/netfilter/nf_conntrack_proto_icmp.c | 18 ++++++++ 3 files changed, 87 insertions(+) (limited to 'net/ipv4') diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index d88c292f118..4ac5b5c4678 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig @@ -19,6 +19,17 @@ config NF_CONNTRACK_IPV4 To compile it as a module, choose M here. If unsure, say N. +config NF_CONNTRACK_PROC_COMPAT + bool "proc/sysctl compatibility with old connection tracking" + depends on NF_CONNTRACK + default y + help + This option enables /proc and sysctl compatibility with the old + layer 3 dependant connection tracking. This is needed to keep + old programs that have not been adapted to the new names working. + + If unsure, say Y. + # connection tracking, helpers and protocols config IP_NF_CONNTRACK tristate "Connection tracking (required for masq/NAT)" diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c index 786c4ce96cd..bcec6822f2e 100644 --- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c +++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c @@ -266,6 +266,60 @@ static struct nf_hook_ops ipv4_conntrack_ops[] = { }, }; +#if defined(CONFIG_SYSCTL) && defined(CONFIG_NF_CONNTRACK_PROC_COMPAT) +static int log_invalid_proto_min = 0; +static int log_invalid_proto_max = 255; + +static ctl_table ip_ct_sysctl_table[] = { + { + .ctl_name = NET_IPV4_NF_CONNTRACK_MAX, + .procname = "ip_conntrack_max", + .data = &nf_conntrack_max, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = NET_IPV4_NF_CONNTRACK_COUNT, + .procname = "ip_conntrack_count", + .data = &nf_conntrack_count, + .maxlen = sizeof(int), + .mode = 0444, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = NET_IPV4_NF_CONNTRACK_BUCKETS, + .procname = "ip_conntrack_buckets", + .data = &nf_conntrack_htable_size, + .maxlen = sizeof(unsigned int), + .mode = 0444, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = NET_IPV4_NF_CONNTRACK_CHECKSUM, + .procname = "ip_conntrack_checksum", + .data = &nf_conntrack_checksum, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = NET_IPV4_NF_CONNTRACK_LOG_INVALID, + .procname = "ip_conntrack_log_invalid", + .data = &nf_ct_log_invalid, + .maxlen = sizeof(unsigned int), + .mode = 0644, + .proc_handler = &proc_dointvec_minmax, + .strategy = &sysctl_intvec, + .extra1 = &log_invalid_proto_min, + .extra2 = &log_invalid_proto_max, + }, + { + .ctl_name = 0 + } +}; +#endif /* CONFIG_SYSCTL && CONFIG_NF_CONNTRACK_PROC_COMPAT */ + /* Fast function for those who don't want to parse /proc (and I don't blame them). */ /* Reversing the socket's dst/src point of view gives us the reply @@ -385,6 +439,10 @@ struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv4 = { defined(CONFIG_NF_CT_NETLINK_MODULE) .tuple_to_nfattr = ipv4_tuple_to_nfattr, .nfattr_to_tuple = ipv4_nfattr_to_tuple, +#endif +#if defined(CONFIG_SYSCTL) && defined(CONFIG_NF_CONNTRACK_PROC_COMPAT) + .ctl_table_path = nf_net_ipv4_netfilter_sysctl_path, + .ctl_table = ip_ct_sysctl_table, #endif .me = THIS_MODULE, }; diff --git a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c index c59f28193a3..46aa44abc07 100644 --- a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c +++ b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c @@ -336,6 +336,21 @@ static struct ctl_table icmp_sysctl_table[] = { .ctl_name = 0 } }; +#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT +static struct ctl_table icmp_compat_sysctl_table[] = { + { + .ctl_name = NET_IPV4_NF_CONNTRACK_ICMP_TIMEOUT, + .procname = "ip_conntrack_icmp_timeout", + .data = &nf_ct_icmp_timeout, + .maxlen = sizeof(unsigned int), + .mode = 0644, + .proc_handler = &proc_dointvec_jiffies, + }, + { + .ctl_name = 0 + } +}; +#endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */ #endif /* CONFIG_SYSCTL */ struct nf_conntrack_l4proto nf_conntrack_l4proto_icmp = @@ -360,6 +375,9 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_icmp = #ifdef CONFIG_SYSCTL .ctl_table_header = &icmp_sysctl_header, .ctl_table = icmp_sysctl_table, +#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT + .ctl_compat_table = icmp_compat_sysctl_table, +#endif #endif }; -- cgit v1.2.3 From e4bd8bce3e8b53e2c0a0d5c9afbc29731e517f8d Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Wed, 29 Nov 2006 02:35:22 +0100 Subject: [NETFILTER]: nf_conntrack: /proc compatibility with old connection tracking This patch adds /proc/net/ip_conntrack, /proc/net/ip_conntrack_expect and /proc/net/stat/ip_conntrack files to keep old programs using them working. The /proc/net/ip_conntrack and /proc/net/ip_conntrack_expect files show only IPv4 entries, the /proc/net/stat/ip_conntrack shows global statistics. Signed-off-by: Patrick McHardy --- net/ipv4/netfilter/Makefile | 5 + net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c | 13 +- .../netfilter/nf_conntrack_l3proto_ipv4_compat.c | 412 +++++++++++++++++++++ 3 files changed, 429 insertions(+), 1 deletion(-) create mode 100644 net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c (limited to 'net/ipv4') diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index 09aaed1a806..4ce20ebc4d6 100644 --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile @@ -89,6 +89,11 @@ obj-$(CONFIG_IP_NF_QUEUE) += ip_queue.o # objects for l3 independent conntrack nf_conntrack_ipv4-objs := nf_conntrack_l3proto_ipv4.o nf_conntrack_proto_icmp.o +ifeq ($(CONFIG_NF_CONNTRACK_PROC_COMPAT),y) +ifeq ($(CONFIG_PROC_FS),y) +nf_conntrack_ipv4-objs += nf_conntrack_l3proto_ipv4_compat.o +endif +endif # l3 independent conntrack obj-$(CONFIG_NF_CONNTRACK_IPV4) += nf_conntrack_ipv4.o diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c index bcec6822f2e..f24e872d4b9 100644 --- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c +++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c @@ -492,8 +492,16 @@ static int __init nf_conntrack_l3proto_ipv4_init(void) printk("nf_conntrack_ipv4: can't register hooks.\n"); goto cleanup_ipv4; } +#if defined(CONFIG_PROC_FS) && defined(CONFIG_NF_CONNTRACK_PROC_COMPAT) + ret = nf_conntrack_ipv4_compat_init(); + if (ret < 0) + goto cleanup_hooks; +#endif return ret; - +#if defined(CONFIG_PROC_FS) && defined(CONFIG_NF_CONNTRACK_PROC_COMPAT) + cleanup_hooks: + nf_unregister_hooks(ipv4_conntrack_ops, ARRAY_SIZE(ipv4_conntrack_ops)); +#endif cleanup_ipv4: nf_conntrack_l3proto_unregister(&nf_conntrack_l3proto_ipv4); cleanup_icmp: @@ -510,6 +518,9 @@ static int __init nf_conntrack_l3proto_ipv4_init(void) static void __exit nf_conntrack_l3proto_ipv4_fini(void) { synchronize_net(); +#if defined(CONFIG_PROC_FS) && defined(CONFIG_NF_CONNTRACK_PROC_COMPAT) + nf_conntrack_ipv4_compat_fini(); +#endif nf_unregister_hooks(ipv4_conntrack_ops, ARRAY_SIZE(ipv4_conntrack_ops)); nf_conntrack_l3proto_unregister(&nf_conntrack_l3proto_ipv4); nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_icmp); diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c new file mode 100644 index 00000000000..3b31bc64960 --- /dev/null +++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c @@ -0,0 +1,412 @@ +/* ip_conntrack proc compat - based on ip_conntrack_standalone.c + * + * (C) 1999-2001 Paul `Rusty' Russell + * (C) 2002-2006 Netfilter Core Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(format, args...) +#endif + +#ifdef CONFIG_NF_CT_ACCT +static unsigned int +seq_print_counters(struct seq_file *s, + const struct ip_conntrack_counter *counter) +{ + return seq_printf(s, "packets=%llu bytes=%llu ", + (unsigned long long)counter->packets, + (unsigned long long)counter->bytes); +} +#else +#define seq_print_counters(x, y) 0 +#endif + +struct ct_iter_state { + unsigned int bucket; +}; + +static struct list_head *ct_get_first(struct seq_file *seq) +{ + struct ct_iter_state *st = seq->private; + + for (st->bucket = 0; + st->bucket < nf_conntrack_htable_size; + st->bucket++) { + if (!list_empty(&nf_conntrack_hash[st->bucket])) + return nf_conntrack_hash[st->bucket].next; + } + return NULL; +} + +static struct list_head *ct_get_next(struct seq_file *seq, struct list_head *head) +{ + struct ct_iter_state *st = seq->private; + + head = head->next; + while (head == &nf_conntrack_hash[st->bucket]) { + if (++st->bucket >= nf_conntrack_htable_size) + return NULL; + head = nf_conntrack_hash[st->bucket].next; + } + return head; +} + +static struct list_head *ct_get_idx(struct seq_file *seq, loff_t pos) +{ + struct list_head *head = ct_get_first(seq); + + if (head) + while (pos && (head = ct_get_next(seq, head))) + pos--; + return pos ? NULL : head; +} + +static void *ct_seq_start(struct seq_file *seq, loff_t *pos) +{ + read_lock_bh(&nf_conntrack_lock); + return ct_get_idx(seq, *pos); +} + +static void *ct_seq_next(struct seq_file *s, void *v, loff_t *pos) +{ + (*pos)++; + return ct_get_next(s, v); +} + +static void ct_seq_stop(struct seq_file *s, void *v) +{ + read_unlock_bh(&nf_conntrack_lock); +} + +static int ct_seq_show(struct seq_file *s, void *v) +{ + const struct nf_conntrack_tuple_hash *hash = v; + const struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(hash); + struct nf_conntrack_l3proto *l3proto; + struct nf_conntrack_l4proto *l4proto; + + NF_CT_ASSERT(ct); + + /* we only want to print DIR_ORIGINAL */ + if (NF_CT_DIRECTION(hash)) + return 0; + if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num != AF_INET) + return 0; + + l3proto = __nf_ct_l3proto_find(ct->tuplehash[IP_CT_DIR_ORIGINAL] + .tuple.src.l3num); + NF_CT_ASSERT(l3proto); + l4proto = __nf_ct_l4proto_find(ct->tuplehash[IP_CT_DIR_ORIGINAL] + .tuple.src.l3num, + ct->tuplehash[IP_CT_DIR_ORIGINAL] + .tuple.dst.protonum); + NF_CT_ASSERT(l4proto); + + if (seq_printf(s, "%-8s %u %ld ", + l4proto->name, + ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum, + timer_pending(&ct->timeout) + ? (long)(ct->timeout.expires - jiffies)/HZ : 0) != 0) + return -ENOSPC; + + if (l3proto->print_conntrack(s, ct)) + return -ENOSPC; + + if (l4proto->print_conntrack(s, ct)) + return -ENOSPC; + + if (print_tuple(s, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, + l3proto, l4proto)) + return -ENOSPC; + + if (seq_print_counters(s, &ct->counters[IP_CT_DIR_ORIGINAL])) + return -ENOSPC; + + if (!(test_bit(IPS_SEEN_REPLY_BIT, &ct->status))) + if (seq_printf(s, "[UNREPLIED] ")) + return -ENOSPC; + + if (print_tuple(s, &ct->tuplehash[IP_CT_DIR_REPLY].tuple, + l3proto, l4proto)) + return -ENOSPC; + + if (seq_print_counters(s, &ct->counters[IP_CT_DIR_REPLY])) + return -ENOSPC; + + if (test_bit(IPS_ASSURED_BIT, &ct->status)) + if (seq_printf(s, "[ASSURED] ")) + return -ENOSPC; + +#ifdef CONFIG_NF_CONNTRACK_MARK + if (seq_printf(s, "mark=%u ", ct->mark)) + return -ENOSPC; +#endif + +#ifdef CONFIG_NF_CONNTRACK_SECMARK + if (seq_printf(s, "secmark=%u ", ct->secmark)) + return -ENOSPC; +#endif + + if (seq_printf(s, "use=%u\n", atomic_read(&ct->ct_general.use))) + return -ENOSPC; + + return 0; +} + +static struct seq_operations ct_seq_ops = { + .start = ct_seq_start, + .next = ct_seq_next, + .stop = ct_seq_stop, + .show = ct_seq_show +}; + +static int ct_open(struct inode *inode, struct file *file) +{ + struct seq_file *seq; + struct ct_iter_state *st; + int ret; + + st = kmalloc(sizeof(struct ct_iter_state), GFP_KERNEL); + if (st == NULL) + return -ENOMEM; + ret = seq_open(file, &ct_seq_ops); + if (ret) + goto out_free; + seq = file->private_data; + seq->private = st; + memset(st, 0, sizeof(struct ct_iter_state)); + return ret; +out_free: + kfree(st); + return ret; +} + +static struct file_operations ct_file_ops = { + .owner = THIS_MODULE, + .open = ct_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release_private, +}; + +/* expects */ +static void *exp_seq_start(struct seq_file *s, loff_t *pos) +{ + struct list_head *e = &nf_conntrack_expect_list; + loff_t i; + + /* strange seq_file api calls stop even if we fail, + * thus we need to grab lock since stop unlocks */ + read_lock_bh(&nf_conntrack_lock); + + if (list_empty(e)) + return NULL; + + for (i = 0; i <= *pos; i++) { + e = e->next; + if (e == &nf_conntrack_expect_list) + return NULL; + } + return e; +} + +static void *exp_seq_next(struct seq_file *s, void *v, loff_t *pos) +{ + struct list_head *e = v; + + ++*pos; + e = e->next; + + if (e == &nf_conntrack_expect_list) + return NULL; + + return e; +} + +static void exp_seq_stop(struct seq_file *s, void *v) +{ + read_unlock_bh(&nf_conntrack_lock); +} + +static int exp_seq_show(struct seq_file *s, void *v) +{ + struct nf_conntrack_expect *exp = v; + + if (exp->tuple.src.l3num != AF_INET) + return 0; + + if (exp->timeout.function) + seq_printf(s, "%ld ", timer_pending(&exp->timeout) + ? (long)(exp->timeout.expires - jiffies)/HZ : 0); + else + seq_printf(s, "- "); + + seq_printf(s, "proto=%u ", exp->tuple.dst.protonum); + + print_tuple(s, &exp->tuple, + __nf_ct_l3proto_find(exp->tuple.src.l3num), + __nf_ct_l4proto_find(exp->tuple.src.l3num, + exp->tuple.dst.protonum)); + return seq_putc(s, '\n'); +} + +static struct seq_operations exp_seq_ops = { + .start = exp_seq_start, + .next = exp_seq_next, + .stop = exp_seq_stop, + .show = exp_seq_show +}; + +static int exp_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &exp_seq_ops); +} + +static struct file_operations ip_exp_file_ops = { + .owner = THIS_MODULE, + .open = exp_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release +}; + +static void *ct_cpu_seq_start(struct seq_file *seq, loff_t *pos) +{ + int cpu; + + if (*pos == 0) + return SEQ_START_TOKEN; + + for (cpu = *pos-1; cpu < NR_CPUS; ++cpu) { + if (!cpu_possible(cpu)) + continue; + *pos = cpu+1; + return &per_cpu(nf_conntrack_stat, cpu); + } + + return NULL; +} + +static void *ct_cpu_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + int cpu; + + for (cpu = *pos; cpu < NR_CPUS; ++cpu) { + if (!cpu_possible(cpu)) + continue; + *pos = cpu+1; + return &per_cpu(nf_conntrack_stat, cpu); + } + + return NULL; +} + +static void ct_cpu_seq_stop(struct seq_file *seq, void *v) +{ +} + +static int ct_cpu_seq_show(struct seq_file *seq, void *v) +{ + unsigned int nr_conntracks = atomic_read(&nf_conntrack_count); + struct ip_conntrack_stat *st = v; + + if (v == SEQ_START_TOKEN) { + seq_printf(seq, "entries searched found new invalid ignore delete delete_list insert insert_failed drop early_drop icmp_error expect_new expect_create expect_delete\n"); + return 0; + } + + seq_printf(seq, "%08x %08x %08x %08x %08x %08x %08x %08x " + "%08x %08x %08x %08x %08x %08x %08x %08x \n", + nr_conntracks, + st->searched, + st->found, + st->new, + st->invalid, + st->ignore, + st->delete, + st->delete_list, + st->insert, + st->insert_failed, + st->drop, + st->early_drop, + st->error, + + st->expect_new, + st->expect_create, + st->expect_delete + ); + return 0; +} + +static struct seq_operations ct_cpu_seq_ops = { + .start = ct_cpu_seq_start, + .next = ct_cpu_seq_next, + .stop = ct_cpu_seq_stop, + .show = ct_cpu_seq_show, +}; + +static int ct_cpu_seq_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &ct_cpu_seq_ops); +} + +static struct file_operations ct_cpu_seq_fops = { + .owner = THIS_MODULE, + .open = ct_cpu_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release_private, +}; + +int __init nf_conntrack_ipv4_compat_init(void) +{ + struct proc_dir_entry *proc, *proc_exp, *proc_stat; + + proc = proc_net_fops_create("ip_conntrack", 0440, &ct_file_ops); + if (!proc) + goto err1; + + proc_exp = proc_net_fops_create("ip_conntrack_expect", 0440, + &ip_exp_file_ops); + if (!proc_exp) + goto err2; + + proc_stat = create_proc_entry("ip_conntrack", S_IRUGO, proc_net_stat); + if (!proc_stat) + goto err3; + + proc_stat->proc_fops = &ct_cpu_seq_fops; + proc_stat->owner = THIS_MODULE; + + return 0; + +err3: + proc_net_remove("ip_conntrack_expect"); +err2: + proc_net_remove("ip_conntrack"); +err1: + return -ENOMEM; +} + +void __exit nf_conntrack_ipv4_compat_fini(void) +{ + remove_proc_entry("ip_conntrack", proc_net_stat); + proc_net_remove("ip_conntrack_expect"); + proc_net_remove("ip_conntrack"); +} -- cgit v1.2.3 From 468ec44bd5a863736d955f78b8c38896f26864a1 Mon Sep 17 00:00:00 2001 From: Yasuyuki Kozakai Date: Wed, 29 Nov 2006 02:35:23 +0100 Subject: [NETFILTER]: conntrack: add '_get' to {ip, nf}_conntrack_expect_find We usually uses 'xxx_find_get' for function which increments reference count. Signed-off-by: Yasuyuki Kozakai Signed-off-by: Patrick McHardy --- net/ipv4/netfilter/ip_conntrack_core.c | 2 +- net/ipv4/netfilter/ip_conntrack_helper_pptp.c | 4 ++-- net/ipv4/netfilter/ip_conntrack_netlink.c | 4 ++-- net/ipv4/netfilter/ip_conntrack_standalone.c | 2 +- net/ipv4/netfilter/ip_nat_helper_pptp.c | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/netfilter/ip_conntrack_core.c b/net/ipv4/netfilter/ip_conntrack_core.c index 8b848aa77bf..4d1f954d459 100644 --- a/net/ipv4/netfilter/ip_conntrack_core.c +++ b/net/ipv4/netfilter/ip_conntrack_core.c @@ -233,7 +233,7 @@ __ip_conntrack_expect_find(const struct ip_conntrack_tuple *tuple) /* Just find a expectation corresponding to a tuple. */ struct ip_conntrack_expect * -ip_conntrack_expect_find(const struct ip_conntrack_tuple *tuple) +ip_conntrack_expect_find_get(const struct ip_conntrack_tuple *tuple) { struct ip_conntrack_expect *i; diff --git a/net/ipv4/netfilter/ip_conntrack_helper_pptp.c b/net/ipv4/netfilter/ip_conntrack_helper_pptp.c index a2af5e0c7f9..a5c057bcecf 100644 --- a/net/ipv4/netfilter/ip_conntrack_helper_pptp.c +++ b/net/ipv4/netfilter/ip_conntrack_helper_pptp.c @@ -142,7 +142,7 @@ static void pptp_expectfn(struct ip_conntrack *ct, DEBUGP("trying to unexpect other dir: "); DUMP_TUPLE(&inv_t); - exp_other = ip_conntrack_expect_find(&inv_t); + exp_other = ip_conntrack_expect_find_get(&inv_t); if (exp_other) { /* delete other expectation. */ DEBUGP("found\n"); @@ -176,7 +176,7 @@ static int destroy_sibling_or_exp(const struct ip_conntrack_tuple *t) ip_conntrack_put(sibling); return 1; } else { - exp = ip_conntrack_expect_find(t); + exp = ip_conntrack_expect_find_get(t); if (exp) { DEBUGP("unexpect_related of expect %p\n", exp); ip_conntrack_unexpect_related(exp); diff --git a/net/ipv4/netfilter/ip_conntrack_netlink.c b/net/ipv4/netfilter/ip_conntrack_netlink.c index 1bb8ed33c5b..3d277aa869d 100644 --- a/net/ipv4/netfilter/ip_conntrack_netlink.c +++ b/net/ipv4/netfilter/ip_conntrack_netlink.c @@ -1256,7 +1256,7 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb, if (err < 0) return err; - exp = ip_conntrack_expect_find(&tuple); + exp = ip_conntrack_expect_find_get(&tuple); if (!exp) return -ENOENT; @@ -1309,7 +1309,7 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb, return err; /* bump usage count to 2 */ - exp = ip_conntrack_expect_find(&tuple); + exp = ip_conntrack_expect_find_get(&tuple); if (!exp) return -ENOENT; diff --git a/net/ipv4/netfilter/ip_conntrack_standalone.c b/net/ipv4/netfilter/ip_conntrack_standalone.c index 02135756562..2df67538ffb 100644 --- a/net/ipv4/netfilter/ip_conntrack_standalone.c +++ b/net/ipv4/netfilter/ip_conntrack_standalone.c @@ -926,7 +926,7 @@ EXPORT_SYMBOL(__ip_ct_refresh_acct); EXPORT_SYMBOL(ip_conntrack_expect_alloc); EXPORT_SYMBOL(ip_conntrack_expect_put); EXPORT_SYMBOL_GPL(__ip_conntrack_expect_find); -EXPORT_SYMBOL_GPL(ip_conntrack_expect_find); +EXPORT_SYMBOL_GPL(ip_conntrack_expect_find_get); EXPORT_SYMBOL(ip_conntrack_expect_related); EXPORT_SYMBOL(ip_conntrack_unexpect_related); EXPORT_SYMBOL_GPL(ip_conntrack_expect_list); diff --git a/net/ipv4/netfilter/ip_nat_helper_pptp.c b/net/ipv4/netfilter/ip_nat_helper_pptp.c index 329fdcd7d70..acf55d86310 100644 --- a/net/ipv4/netfilter/ip_nat_helper_pptp.c +++ b/net/ipv4/netfilter/ip_nat_helper_pptp.c @@ -101,7 +101,7 @@ static void pptp_nat_expected(struct ip_conntrack *ct, DEBUGP("trying to unexpect other dir: "); DUMP_TUPLE(&t); - other_exp = ip_conntrack_expect_find(&t); + other_exp = ip_conntrack_expect_find_get(&t); if (other_exp) { ip_conntrack_unexpect_related(other_exp); ip_conntrack_expect_put(other_exp); -- cgit v1.2.3 From 337fbc4166967a72c3cc71c597bdde7e6a8633ab Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Wed, 29 Nov 2006 02:35:25 +0100 Subject: [NETFILTER]: ip_conntrack: fix NAT helper unload races The NAT helpr hooks are protected by RCU, but all of the conntrack helpers test and use the global pointers instead of copying them first using rcu_dereference() Also replace synchronize_net() by synchronize_rcu() for clarity since sychronizing only with packet receive processing is insufficient to prevent races. Signed-off-by: Patrick McHardy --- net/ipv4/netfilter/ip_conntrack_amanda.c | 9 +- net/ipv4/netfilter/ip_conntrack_ftp.c | 8 +- net/ipv4/netfilter/ip_conntrack_helper_h323.c | 164 +++++++++++++++----------- net/ipv4/netfilter/ip_conntrack_helper_pptp.c | 29 +++-- net/ipv4/netfilter/ip_conntrack_irc.c | 12 +- net/ipv4/netfilter/ip_conntrack_sip.c | 12 +- net/ipv4/netfilter/ip_conntrack_tftp.c | 6 +- net/ipv4/netfilter/ip_nat_amanda.c | 9 +- net/ipv4/netfilter/ip_nat_ftp.c | 9 +- net/ipv4/netfilter/ip_nat_helper_h323.c | 58 ++++----- net/ipv4/netfilter/ip_nat_helper_pptp.c | 27 ++--- net/ipv4/netfilter/ip_nat_irc.c | 9 +- net/ipv4/netfilter/ip_nat_sip.c | 15 ++- net/ipv4/netfilter/ip_nat_tftp.c | 9 +- 14 files changed, 211 insertions(+), 165 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/netfilter/ip_conntrack_amanda.c b/net/ipv4/netfilter/ip_conntrack_amanda.c index 7fca246615d..ad246ba7790 100644 --- a/net/ipv4/netfilter/ip_conntrack_amanda.c +++ b/net/ipv4/netfilter/ip_conntrack_amanda.c @@ -92,6 +92,7 @@ static int help(struct sk_buff **pskb, char pbuf[sizeof("65535")], *tmp; u_int16_t port, len; int ret = NF_ACCEPT; + typeof(ip_nat_amanda_hook) ip_nat_amanda; /* Only look at packets from the Amanda server */ if (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) @@ -161,9 +162,11 @@ static int help(struct sk_buff **pskb, exp->mask.dst.protonum = 0xFF; exp->mask.dst.u.tcp.port = htons(0xFFFF); - if (ip_nat_amanda_hook) - ret = ip_nat_amanda_hook(pskb, ctinfo, off - dataoff, - len, exp); + /* RCU read locked by nf_hook_slow */ + ip_nat_amanda = rcu_dereference(ip_nat_amanda_hook); + if (ip_nat_amanda) + ret = ip_nat_amanda(pskb, ctinfo, off - dataoff, + len, exp); else if (ip_conntrack_expect_related(exp) != 0) ret = NF_DROP; ip_conntrack_expect_put(exp); diff --git a/net/ipv4/netfilter/ip_conntrack_ftp.c b/net/ipv4/netfilter/ip_conntrack_ftp.c index 93dcf960662..0410c99caca 100644 --- a/net/ipv4/netfilter/ip_conntrack_ftp.c +++ b/net/ipv4/netfilter/ip_conntrack_ftp.c @@ -310,6 +310,7 @@ static int help(struct sk_buff **pskb, struct ip_conntrack_expect *exp; unsigned int i; int found = 0, ends_in_nl; + typeof(ip_nat_ftp_hook) ip_nat_ftp; /* Until there's been traffic both ways, don't look in packets. */ if (ctinfo != IP_CT_ESTABLISHED @@ -433,9 +434,10 @@ static int help(struct sk_buff **pskb, /* Now, NAT might want to mangle the packet, and register the * (possibly changed) expectation itself. */ - if (ip_nat_ftp_hook) - ret = ip_nat_ftp_hook(pskb, ctinfo, search[dir][i].ftptype, - matchoff, matchlen, exp, &seq); + ip_nat_ftp = rcu_dereference(ip_nat_ftp_hook); + if (ip_nat_ftp) + ret = ip_nat_ftp(pskb, ctinfo, search[dir][i].ftptype, + matchoff, matchlen, exp, &seq); else { /* Can't expect this? Best to drop packet now. */ if (ip_conntrack_expect_related(exp) != 0) diff --git a/net/ipv4/netfilter/ip_conntrack_helper_h323.c b/net/ipv4/netfilter/ip_conntrack_helper_h323.c index a06b340ea41..aabfe1c0690 100644 --- a/net/ipv4/netfilter/ip_conntrack_helper_h323.c +++ b/net/ipv4/netfilter/ip_conntrack_helper_h323.c @@ -237,6 +237,7 @@ static int expect_rtp_rtcp(struct sk_buff **pskb, struct ip_conntrack *ct, u_int16_t rtp_port; struct ip_conntrack_expect *rtp_exp; struct ip_conntrack_expect *rtcp_exp; + typeof(nat_rtp_rtcp_hook) nat_rtp_rtcp; /* Read RTP or RTCP address */ if (!get_h245_addr(*data, addr, &ip, &port) || @@ -279,11 +280,11 @@ static int expect_rtp_rtcp(struct sk_buff **pskb, struct ip_conntrack *ct, rtcp_exp->flags = 0; if (ct->tuplehash[dir].tuple.src.ip != - ct->tuplehash[!dir].tuple.dst.ip && nat_rtp_rtcp_hook) { + ct->tuplehash[!dir].tuple.dst.ip && + (nat_rtp_rtcp = rcu_dereference(nat_rtp_rtcp_hook))) { /* NAT needed */ - ret = nat_rtp_rtcp_hook(pskb, ct, ctinfo, data, dataoff, - addr, port, rtp_port, rtp_exp, - rtcp_exp); + ret = nat_rtp_rtcp(pskb, ct, ctinfo, data, dataoff, + addr, port, rtp_port, rtp_exp, rtcp_exp); } else { /* Conntrack only */ rtp_exp->expectfn = NULL; rtcp_exp->expectfn = NULL; @@ -328,6 +329,7 @@ static int expect_t120(struct sk_buff **pskb, __be32 ip; u_int16_t port; struct ip_conntrack_expect *exp = NULL; + typeof(nat_t120_hook) nat_t120; /* Read T.120 address */ if (!get_h245_addr(*data, addr, &ip, &port) || @@ -350,10 +352,11 @@ static int expect_t120(struct sk_buff **pskb, exp->flags = IP_CT_EXPECT_PERMANENT; /* Accept multiple channels */ if (ct->tuplehash[dir].tuple.src.ip != - ct->tuplehash[!dir].tuple.dst.ip && nat_t120_hook) { + ct->tuplehash[!dir].tuple.dst.ip && + (nat_t120 = rcu_dereference(nat_t120_hook))) { /* NAT needed */ - ret = nat_t120_hook(pskb, ct, ctinfo, data, dataoff, addr, - port, exp); + ret = nat_t120(pskb, ct, ctinfo, data, dataoff, addr, + port, exp); } else { /* Conntrack only */ exp->expectfn = NULL; if (ip_conntrack_expect_related(exp) == 0) { @@ -651,6 +654,7 @@ static int expect_h245(struct sk_buff **pskb, struct ip_conntrack *ct, __be32 ip; u_int16_t port; struct ip_conntrack_expect *exp = NULL; + typeof(nat_h245_hook) nat_h245; /* Read h245Address */ if (!get_h225_addr(*data, addr, &ip, &port) || @@ -673,10 +677,11 @@ static int expect_h245(struct sk_buff **pskb, struct ip_conntrack *ct, exp->flags = 0; if (ct->tuplehash[dir].tuple.src.ip != - ct->tuplehash[!dir].tuple.dst.ip && nat_h245_hook) { + ct->tuplehash[!dir].tuple.dst.ip && + (nat_h245 = rcu_dereference(nat_h245_hook))) { /* NAT needed */ - ret = nat_h245_hook(pskb, ct, ctinfo, data, dataoff, addr, - port, exp); + ret = nat_h245(pskb, ct, ctinfo, data, dataoff, addr, + port, exp); } else { /* Conntrack only */ exp->expectfn = ip_conntrack_h245_expect; @@ -712,6 +717,7 @@ static int expect_callforwarding(struct sk_buff **pskb, __be32 ip; u_int16_t port; struct ip_conntrack_expect *exp = NULL; + typeof(nat_callforwarding_hook) nat_callforwarding; /* Read alternativeAddress */ if (!get_h225_addr(*data, addr, &ip, &port) || port == 0) @@ -759,10 +765,11 @@ static int expect_callforwarding(struct sk_buff **pskb, exp->flags = 0; if (ct->tuplehash[dir].tuple.src.ip != - ct->tuplehash[!dir].tuple.dst.ip && nat_callforwarding_hook) { + ct->tuplehash[!dir].tuple.dst.ip && + (nat_callforwarding = rcu_dereference(nat_callforwarding_hook))) { /* Need NAT */ - ret = nat_callforwarding_hook(pskb, ct, ctinfo, data, dataoff, - addr, port, exp); + ret = nat_callforwarding(pskb, ct, ctinfo, data, dataoff, + addr, port, exp); } else { /* Conntrack only */ exp->expectfn = ip_conntrack_q931_expect; @@ -793,6 +800,7 @@ static int process_setup(struct sk_buff **pskb, struct ip_conntrack *ct, int i; __be32 ip; u_int16_t port; + typeof(set_h225_addr_hook) set_h225_addr; DEBUGP("ip_ct_q931: Setup\n"); @@ -803,8 +811,10 @@ static int process_setup(struct sk_buff **pskb, struct ip_conntrack *ct, return -1; } + set_h225_addr = rcu_dereference(set_h225_addr_hook); + if ((setup->options & eSetup_UUIE_destCallSignalAddress) && - (set_h225_addr_hook) && + (set_h225_addr) && get_h225_addr(*data, &setup->destCallSignalAddress, &ip, &port) && ip != ct->tuplehash[!dir].tuple.src.ip) { DEBUGP("ip_ct_q931: set destCallSignalAddress " @@ -812,17 +822,17 @@ static int process_setup(struct sk_buff **pskb, struct ip_conntrack *ct, NIPQUAD(ip), port, NIPQUAD(ct->tuplehash[!dir].tuple.src.ip), ntohs(ct->tuplehash[!dir].tuple.src.u.tcp.port)); - ret = set_h225_addr_hook(pskb, data, dataoff, - &setup->destCallSignalAddress, - ct->tuplehash[!dir].tuple.src.ip, - ntohs(ct->tuplehash[!dir].tuple.src. - u.tcp.port)); + ret = set_h225_addr(pskb, data, dataoff, + &setup->destCallSignalAddress, + ct->tuplehash[!dir].tuple.src.ip, + ntohs(ct->tuplehash[!dir].tuple.src. + u.tcp.port)); if (ret < 0) return -1; } if ((setup->options & eSetup_UUIE_sourceCallSignalAddress) && - (set_h225_addr_hook) && + (set_h225_addr) && get_h225_addr(*data, &setup->sourceCallSignalAddress, &ip, &port) && ip != ct->tuplehash[!dir].tuple.dst.ip) { DEBUGP("ip_ct_q931: set sourceCallSignalAddress " @@ -830,11 +840,11 @@ static int process_setup(struct sk_buff **pskb, struct ip_conntrack *ct, NIPQUAD(ip), port, NIPQUAD(ct->tuplehash[!dir].tuple.dst.ip), ntohs(ct->tuplehash[!dir].tuple.dst.u.tcp.port)); - ret = set_h225_addr_hook(pskb, data, dataoff, - &setup->sourceCallSignalAddress, - ct->tuplehash[!dir].tuple.dst.ip, - ntohs(ct->tuplehash[!dir].tuple.dst. - u.tcp.port)); + ret = set_h225_addr(pskb, data, dataoff, + &setup->sourceCallSignalAddress, + ct->tuplehash[!dir].tuple.dst.ip, + ntohs(ct->tuplehash[!dir].tuple.dst. + u.tcp.port)); if (ret < 0) return -1; } @@ -1231,6 +1241,7 @@ static int expect_q931(struct sk_buff **pskb, struct ip_conntrack *ct, __be32 ip; u_int16_t port; struct ip_conntrack_expect *exp; + typeof(nat_q931_hook) nat_q931; /* Look for the first related address */ for (i = 0; i < count; i++) { @@ -1258,9 +1269,9 @@ static int expect_q931(struct sk_buff **pskb, struct ip_conntrack *ct, exp->mask.dst.protonum = 0xFF; exp->flags = IP_CT_EXPECT_PERMANENT; /* Accept multiple calls */ - if (nat_q931_hook) { /* Need NAT */ - ret = nat_q931_hook(pskb, ct, ctinfo, data, addr, i, - port, exp); + nat_q931 = rcu_dereference(nat_q931_hook); + if (nat_q931) { /* Need NAT */ + ret = nat_q931(pskb, ct, ctinfo, data, addr, i, port, exp); } else { /* Conntrack only */ exp->expectfn = ip_conntrack_q931_expect; @@ -1288,11 +1299,14 @@ static int process_grq(struct sk_buff **pskb, struct ip_conntrack *ct, enum ip_conntrack_info ctinfo, unsigned char **data, GatekeeperRequest * grq) { + typeof(set_ras_addr_hook) set_ras_addr; + DEBUGP("ip_ct_ras: GRQ\n"); - if (set_ras_addr_hook) /* NATed */ - return set_ras_addr_hook(pskb, ct, ctinfo, data, - &grq->rasAddress, 1); + set_ras_addr = rcu_dereference(set_ras_addr_hook); + if (set_ras_addr) /* NATed */ + return set_ras_addr(pskb, ct, ctinfo, data, + &grq->rasAddress, 1); return 0; } @@ -1362,6 +1376,7 @@ static int process_rrq(struct sk_buff **pskb, struct ip_conntrack *ct, { struct ip_ct_h323_master *info = &ct->help.ct_h323_info; int ret; + typeof(set_ras_addr_hook) set_ras_addr; DEBUGP("ip_ct_ras: RRQ\n"); @@ -1371,10 +1386,11 @@ static int process_rrq(struct sk_buff **pskb, struct ip_conntrack *ct, if (ret < 0) return -1; - if (set_ras_addr_hook) { - ret = set_ras_addr_hook(pskb, ct, ctinfo, data, - rrq->rasAddress.item, - rrq->rasAddress.count); + set_ras_addr = rcu_dereference(set_ras_addr_hook); + if (set_ras_addr) { + ret = set_ras_addr(pskb, ct, ctinfo, data, + rrq->rasAddress.item, + rrq->rasAddress.count); if (ret < 0) return -1; } @@ -1397,13 +1413,15 @@ static int process_rcf(struct sk_buff **pskb, struct ip_conntrack *ct, int dir = CTINFO2DIR(ctinfo); int ret; struct ip_conntrack_expect *exp; + typeof(set_sig_addr_hook) set_sig_addr; DEBUGP("ip_ct_ras: RCF\n"); - if (set_sig_addr_hook) { - ret = set_sig_addr_hook(pskb, ct, ctinfo, data, - rcf->callSignalAddress.item, - rcf->callSignalAddress.count); + set_sig_addr = rcu_dereference(set_sig_addr_hook); + if (set_sig_addr) { + ret = set_sig_addr(pskb, ct, ctinfo, data, + rcf->callSignalAddress.item, + rcf->callSignalAddress.count); if (ret < 0) return -1; } @@ -1448,13 +1466,15 @@ static int process_urq(struct sk_buff **pskb, struct ip_conntrack *ct, struct ip_ct_h323_master *info = &ct->help.ct_h323_info; int dir = CTINFO2DIR(ctinfo); int ret; + typeof(set_sig_addr_hook) set_sig_addr; DEBUGP("ip_ct_ras: URQ\n"); - if (set_sig_addr_hook) { - ret = set_sig_addr_hook(pskb, ct, ctinfo, data, - urq->callSignalAddress.item, - urq->callSignalAddress.count); + set_sig_addr = rcu_dereference(set_sig_addr_hook); + if (set_sig_addr) { + ret = set_sig_addr(pskb, ct, ctinfo, data, + urq->callSignalAddress.item, + urq->callSignalAddress.count); if (ret < 0) return -1; } @@ -1479,28 +1499,30 @@ static int process_arq(struct sk_buff **pskb, struct ip_conntrack *ct, int dir = CTINFO2DIR(ctinfo); __be32 ip; u_int16_t port; + typeof(set_h225_addr_hook) set_h225_addr; DEBUGP("ip_ct_ras: ARQ\n"); + set_h225_addr = rcu_dereference(set_h225_addr_hook); if ((arq->options & eAdmissionRequest_destCallSignalAddress) && get_h225_addr(*data, &arq->destCallSignalAddress, &ip, &port) && ip == ct->tuplehash[dir].tuple.src.ip && - port == info->sig_port[dir] && set_h225_addr_hook) { + port == info->sig_port[dir] && set_h225_addr) { /* Answering ARQ */ - return set_h225_addr_hook(pskb, data, 0, - &arq->destCallSignalAddress, - ct->tuplehash[!dir].tuple.dst.ip, - info->sig_port[!dir]); + return set_h225_addr(pskb, data, 0, + &arq->destCallSignalAddress, + ct->tuplehash[!dir].tuple.dst.ip, + info->sig_port[!dir]); } if ((arq->options & eAdmissionRequest_srcCallSignalAddress) && get_h225_addr(*data, &arq->srcCallSignalAddress, &ip, &port) && - ip == ct->tuplehash[dir].tuple.src.ip && set_h225_addr_hook) { + ip == ct->tuplehash[dir].tuple.src.ip && set_h225_addr) { /* Calling ARQ */ - return set_h225_addr_hook(pskb, data, 0, - &arq->srcCallSignalAddress, - ct->tuplehash[!dir].tuple.dst.ip, - port); + return set_h225_addr(pskb, data, 0, + &arq->srcCallSignalAddress, + ct->tuplehash[!dir].tuple.dst.ip, + port); } return 0; @@ -1516,6 +1538,7 @@ static int process_acf(struct sk_buff **pskb, struct ip_conntrack *ct, __be32 ip; u_int16_t port; struct ip_conntrack_expect *exp; + typeof(set_sig_addr_hook) set_sig_addr; DEBUGP("ip_ct_ras: ACF\n"); @@ -1523,10 +1546,10 @@ static int process_acf(struct sk_buff **pskb, struct ip_conntrack *ct, return 0; if (ip == ct->tuplehash[dir].tuple.dst.ip) { /* Answering ACF */ - if (set_sig_addr_hook) - return set_sig_addr_hook(pskb, ct, ctinfo, data, - &acf->destCallSignalAddress, - 1); + set_sig_addr = rcu_dereference(set_sig_addr_hook); + if (set_sig_addr) + return set_sig_addr(pskb, ct, ctinfo, data, + &acf->destCallSignalAddress, 1); return 0; } @@ -1566,11 +1589,14 @@ static int process_lrq(struct sk_buff **pskb, struct ip_conntrack *ct, enum ip_conntrack_info ctinfo, unsigned char **data, LocationRequest * lrq) { + typeof(set_ras_addr_hook) set_ras_addr; + DEBUGP("ip_ct_ras: LRQ\n"); - if (set_ras_addr_hook) - return set_ras_addr_hook(pskb, ct, ctinfo, data, - &lrq->replyAddress, 1); + set_ras_addr = rcu_dereference(set_ras_addr_hook); + if (set_ras_addr) + return set_ras_addr(pskb, ct, ctinfo, data, + &lrq->replyAddress, 1); return 0; } @@ -1629,20 +1655,24 @@ static int process_irr(struct sk_buff **pskb, struct ip_conntrack *ct, unsigned char **data, InfoRequestResponse * irr) { int ret; + typeof(set_ras_addr_hook) set_ras_addr; + typeof(set_sig_addr_hook) set_sig_addr; DEBUGP("ip_ct_ras: IRR\n"); - if (set_ras_addr_hook) { - ret = set_ras_addr_hook(pskb, ct, ctinfo, data, - &irr->rasAddress, 1); + set_ras_addr = rcu_dereference(set_ras_addr_hook); + if (set_ras_addr) { + ret = set_ras_addr(pskb, ct, ctinfo, data, + &irr->rasAddress, 1); if (ret < 0) return -1; } - if (set_sig_addr_hook) { - ret = set_sig_addr_hook(pskb, ct, ctinfo, data, - irr->callSignalAddress.item, - irr->callSignalAddress.count); + set_sig_addr = rcu_dereference(set_sig_addr_hook); + if (set_sig_addr) { + ret = set_sig_addr(pskb, ct, ctinfo, data, + irr->callSignalAddress.item, + irr->callSignalAddress.count); if (ret < 0) return -1; } diff --git a/net/ipv4/netfilter/ip_conntrack_helper_pptp.c b/net/ipv4/netfilter/ip_conntrack_helper_pptp.c index a5c057bcecf..4d19373bbf0 100644 --- a/net/ipv4/netfilter/ip_conntrack_helper_pptp.c +++ b/net/ipv4/netfilter/ip_conntrack_helper_pptp.c @@ -124,6 +124,8 @@ EXPORT_SYMBOL(pptp_msg_name); static void pptp_expectfn(struct ip_conntrack *ct, struct ip_conntrack_expect *exp) { + typeof(ip_nat_pptp_hook_expectfn) ip_nat_pptp_expectfn; + DEBUGP("increasing timeouts\n"); /* increase timeout of GRE data channel conntrack entry */ @@ -133,7 +135,9 @@ static void pptp_expectfn(struct ip_conntrack *ct, /* Can you see how rusty this code is, compared with the pre-2.6.11 * one? That's what happened to my shiny newnat of 2002 ;( -HW */ - if (!ip_nat_pptp_hook_expectfn) { + rcu_read_lock(); + ip_nat_pptp_expectfn = rcu_dereference(ip_nat_pptp_hook_expectfn); + if (!ip_nat_pptp_expectfn) { struct ip_conntrack_tuple inv_t; struct ip_conntrack_expect *exp_other; @@ -153,8 +157,9 @@ static void pptp_expectfn(struct ip_conntrack *ct, } } else { /* we need more than simple inversion */ - ip_nat_pptp_hook_expectfn(ct, exp); + ip_nat_pptp_expectfn(ct, exp); } + rcu_read_unlock(); } static int destroy_sibling_or_exp(const struct ip_conntrack_tuple *t) @@ -226,6 +231,7 @@ exp_gre(struct ip_conntrack *ct, { struct ip_conntrack_expect *exp_orig, *exp_reply; int ret = 1; + typeof(ip_nat_pptp_hook_exp_gre) ip_nat_pptp_exp_gre; exp_orig = ip_conntrack_expect_alloc(ct); if (exp_orig == NULL) @@ -262,8 +268,9 @@ exp_gre(struct ip_conntrack *ct, exp_reply->tuple.dst.u.gre.key = peer_callid; exp_reply->tuple.dst.protonum = IPPROTO_GRE; - if (ip_nat_pptp_hook_exp_gre) - ip_nat_pptp_hook_exp_gre(exp_orig, exp_reply); + ip_nat_pptp_exp_gre = rcu_dereference(ip_nat_pptp_hook_exp_gre); + if (ip_nat_pptp_exp_gre) + ip_nat_pptp_exp_gre(exp_orig, exp_reply); if (ip_conntrack_expect_related(exp_orig) != 0) goto out_put_both; if (ip_conntrack_expect_related(exp_reply) != 0) @@ -303,6 +310,7 @@ pptp_inbound_pkt(struct sk_buff **pskb, struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info; u_int16_t msg; __be16 cid = 0, pcid = 0; + typeof(ip_nat_pptp_hook_inbound) ip_nat_pptp_inbound; msg = ntohs(ctlh->messageType); DEBUGP("inbound control message %s\n", pptp_msg_name[msg]); @@ -402,9 +410,9 @@ pptp_inbound_pkt(struct sk_buff **pskb, goto invalid; } - if (ip_nat_pptp_hook_inbound) - return ip_nat_pptp_hook_inbound(pskb, ct, ctinfo, ctlh, - pptpReq); + ip_nat_pptp_inbound = rcu_dereference(ip_nat_pptp_hook_inbound); + if (ip_nat_pptp_inbound) + return ip_nat_pptp_inbound(pskb, ct, ctinfo, ctlh, pptpReq); return NF_ACCEPT; invalid: @@ -427,6 +435,7 @@ pptp_outbound_pkt(struct sk_buff **pskb, struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info; u_int16_t msg; __be16 cid = 0, pcid = 0; + typeof(ip_nat_pptp_hook_outbound) ip_nat_pptp_outbound; msg = ntohs(ctlh->messageType); DEBUGP("outbound control message %s\n", pptp_msg_name[msg]); @@ -492,9 +501,9 @@ pptp_outbound_pkt(struct sk_buff **pskb, goto invalid; } - if (ip_nat_pptp_hook_outbound) - return ip_nat_pptp_hook_outbound(pskb, ct, ctinfo, ctlh, - pptpReq); + ip_nat_pptp_outbound = rcu_dereference(ip_nat_pptp_hook_outbound); + if (ip_nat_pptp_outbound) + return ip_nat_pptp_outbound(pskb, ct, ctinfo, ctlh, pptpReq); return NF_ACCEPT; invalid: diff --git a/net/ipv4/netfilter/ip_conntrack_irc.c b/net/ipv4/netfilter/ip_conntrack_irc.c index 75f7c3db161..91832eca410 100644 --- a/net/ipv4/netfilter/ip_conntrack_irc.c +++ b/net/ipv4/netfilter/ip_conntrack_irc.c @@ -114,6 +114,7 @@ static int help(struct sk_buff **pskb, u_int16_t dcc_port; int i, ret = NF_ACCEPT; char *addr_beg_p, *addr_end_p; + typeof(ip_nat_irc_hook) ip_nat_irc; DEBUGP("entered\n"); @@ -222,11 +223,12 @@ static int help(struct sk_buff **pskb, { .tcp = { htons(0xFFFF) } }, 0xFF }}); exp->expectfn = NULL; exp->flags = 0; - if (ip_nat_irc_hook) - ret = ip_nat_irc_hook(pskb, ctinfo, - addr_beg_p - ib_ptr, - addr_end_p - addr_beg_p, - exp); + ip_nat_irc = rcu_dereference(ip_nat_irc_hook); + if (ip_nat_irc) + ret = ip_nat_irc(pskb, ctinfo, + addr_beg_p - ib_ptr, + addr_end_p - addr_beg_p, + exp); else if (ip_conntrack_expect_related(exp) != 0) ret = NF_DROP; ip_conntrack_expect_put(exp); diff --git a/net/ipv4/netfilter/ip_conntrack_sip.c b/net/ipv4/netfilter/ip_conntrack_sip.c index f4f75995a9e..bf423db4ed4 100644 --- a/net/ipv4/netfilter/ip_conntrack_sip.c +++ b/net/ipv4/netfilter/ip_conntrack_sip.c @@ -308,6 +308,7 @@ static int set_expected_rtp(struct sk_buff **pskb, struct ip_conntrack_expect *exp; enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); int ret; + typeof(ip_nat_sdp_hook) ip_nat_sdp; exp = ip_conntrack_expect_alloc(ct); if (exp == NULL) @@ -328,8 +329,9 @@ static int set_expected_rtp(struct sk_buff **pskb, exp->expectfn = NULL; exp->flags = 0; - if (ip_nat_sdp_hook) - ret = ip_nat_sdp_hook(pskb, ctinfo, exp, dptr); + ip_nat_sdp = rcu_dereference(ip_nat_sdp_hook); + if (ip_nat_sdp) + ret = ip_nat_sdp(pskb, ctinfo, exp, dptr); else { if (ip_conntrack_expect_related(exp) != 0) ret = NF_DROP; @@ -351,6 +353,7 @@ static int sip_help(struct sk_buff **pskb, int matchoff, matchlen; __be32 ipaddr; u_int16_t port; + typeof(ip_nat_sip_hook) ip_nat_sip; /* No Data ? */ dataoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr); @@ -368,8 +371,9 @@ static int sip_help(struct sk_buff **pskb, goto out; } - if (ip_nat_sip_hook) { - if (!ip_nat_sip_hook(pskb, ctinfo, ct, &dptr)) { + ip_nat_sip = rcu_dereference(ip_nat_sip_hook); + if (ip_nat_sip) { + if (!ip_nat_sip(pskb, ctinfo, ct, &dptr)) { ret = NF_DROP; goto out; } diff --git a/net/ipv4/netfilter/ip_conntrack_tftp.c b/net/ipv4/netfilter/ip_conntrack_tftp.c index fe0b634dd37..ef56de2eff0 100644 --- a/net/ipv4/netfilter/ip_conntrack_tftp.c +++ b/net/ipv4/netfilter/ip_conntrack_tftp.c @@ -50,6 +50,7 @@ static int tftp_help(struct sk_buff **pskb, struct tftphdr _tftph, *tfh; struct ip_conntrack_expect *exp; unsigned int ret = NF_ACCEPT; + typeof(ip_nat_tftp_hook) ip_nat_tftp; tfh = skb_header_pointer(*pskb, (*pskb)->nh.iph->ihl*4+sizeof(struct udphdr), @@ -81,8 +82,9 @@ static int tftp_help(struct sk_buff **pskb, DEBUGP("expect: "); DUMP_TUPLE(&exp->tuple); DUMP_TUPLE(&exp->mask); - if (ip_nat_tftp_hook) - ret = ip_nat_tftp_hook(pskb, ctinfo, exp); + ip_nat_tftp = rcu_dereference(ip_nat_tftp_hook); + if (ip_nat_tftp) + ret = ip_nat_tftp(pskb, ctinfo, exp); else if (ip_conntrack_expect_related(exp) != 0) ret = NF_DROP; ip_conntrack_expect_put(exp); diff --git a/net/ipv4/netfilter/ip_nat_amanda.c b/net/ipv4/netfilter/ip_nat_amanda.c index 3a888715bbf..85df1a9aed3 100644 --- a/net/ipv4/netfilter/ip_nat_amanda.c +++ b/net/ipv4/netfilter/ip_nat_amanda.c @@ -70,15 +70,14 @@ static unsigned int help(struct sk_buff **pskb, static void __exit ip_nat_amanda_fini(void) { - ip_nat_amanda_hook = NULL; - /* Make sure noone calls it, meanwhile. */ - synchronize_net(); + rcu_assign_pointer(ip_nat_amanda_hook, NULL); + synchronize_rcu(); } static int __init ip_nat_amanda_init(void) { - BUG_ON(ip_nat_amanda_hook); - ip_nat_amanda_hook = help; + BUG_ON(rcu_dereference(ip_nat_amanda_hook)); + rcu_assign_pointer(ip_nat_amanda_hook, help); return 0; } diff --git a/net/ipv4/netfilter/ip_nat_ftp.c b/net/ipv4/netfilter/ip_nat_ftp.c index a71c233d811..913960e1380 100644 --- a/net/ipv4/netfilter/ip_nat_ftp.c +++ b/net/ipv4/netfilter/ip_nat_ftp.c @@ -156,15 +156,14 @@ static unsigned int ip_nat_ftp(struct sk_buff **pskb, static void __exit ip_nat_ftp_fini(void) { - ip_nat_ftp_hook = NULL; - /* Make sure noone calls it, meanwhile. */ - synchronize_net(); + rcu_assign_pointer(ip_nat_ftp_hook, NULL); + synchronize_rcu(); } static int __init ip_nat_ftp_init(void) { - BUG_ON(ip_nat_ftp_hook); - ip_nat_ftp_hook = ip_nat_ftp; + BUG_ON(rcu_dereference(ip_nat_ftp_hook)); + rcu_assign_pointer(ip_nat_ftp_hook, ip_nat_ftp); return 0; } diff --git a/net/ipv4/netfilter/ip_nat_helper_h323.c b/net/ipv4/netfilter/ip_nat_helper_h323.c index 4a7d34466ee..bdc99ef6159 100644 --- a/net/ipv4/netfilter/ip_nat_helper_h323.c +++ b/net/ipv4/netfilter/ip_nat_helper_h323.c @@ -563,25 +563,25 @@ static int nat_callforwarding(struct sk_buff **pskb, struct ip_conntrack *ct, /****************************************************************************/ static int __init init(void) { - BUG_ON(set_h245_addr_hook != NULL); - BUG_ON(set_h225_addr_hook != NULL); - BUG_ON(set_sig_addr_hook != NULL); - BUG_ON(set_ras_addr_hook != NULL); - BUG_ON(nat_rtp_rtcp_hook != NULL); - BUG_ON(nat_t120_hook != NULL); - BUG_ON(nat_h245_hook != NULL); - BUG_ON(nat_callforwarding_hook != NULL); - BUG_ON(nat_q931_hook != NULL); - - set_h245_addr_hook = set_h245_addr; - set_h225_addr_hook = set_h225_addr; - set_sig_addr_hook = set_sig_addr; - set_ras_addr_hook = set_ras_addr; - nat_rtp_rtcp_hook = nat_rtp_rtcp; - nat_t120_hook = nat_t120; - nat_h245_hook = nat_h245; - nat_callforwarding_hook = nat_callforwarding; - nat_q931_hook = nat_q931; + BUG_ON(rcu_dereference(set_h245_addr_hook) != NULL); + BUG_ON(rcu_dereference(set_h225_addr_hook) != NULL); + BUG_ON(rcu_dereference(set_sig_addr_hook) != NULL); + BUG_ON(rcu_dereference(set_ras_addr_hook) != NULL); + BUG_ON(rcu_dereference(nat_rtp_rtcp_hook) != NULL); + BUG_ON(rcu_dereference(nat_t120_hook) != NULL); + BUG_ON(rcu_dereference(nat_h245_hook) != NULL); + BUG_ON(rcu_dereference(nat_callforwarding_hook) != NULL); + BUG_ON(rcu_dereference(nat_q931_hook) != NULL); + + rcu_assign_pointer(set_h245_addr_hook, set_h245_addr); + rcu_assign_pointer(set_h225_addr_hook, set_h225_addr); + rcu_assign_pointer(set_sig_addr_hook, set_sig_addr); + rcu_assign_pointer(set_ras_addr_hook, set_ras_addr); + rcu_assign_pointer(nat_rtp_rtcp_hook, nat_rtp_rtcp); + rcu_assign_pointer(nat_t120_hook, nat_t120); + rcu_assign_pointer(nat_h245_hook, nat_h245); + rcu_assign_pointer(nat_callforwarding_hook, nat_callforwarding); + rcu_assign_pointer(nat_q931_hook, nat_q931); DEBUGP("ip_nat_h323: init success\n"); return 0; @@ -590,16 +590,16 @@ static int __init init(void) /****************************************************************************/ static void __exit fini(void) { - set_h245_addr_hook = NULL; - set_h225_addr_hook = NULL; - set_sig_addr_hook = NULL; - set_ras_addr_hook = NULL; - nat_rtp_rtcp_hook = NULL; - nat_t120_hook = NULL; - nat_h245_hook = NULL; - nat_callforwarding_hook = NULL; - nat_q931_hook = NULL; - synchronize_net(); + rcu_assign_pointer(set_h245_addr_hook, NULL); + rcu_assign_pointer(set_h225_addr_hook, NULL); + rcu_assign_pointer(set_sig_addr_hook, NULL); + rcu_assign_pointer(set_ras_addr_hook, NULL); + rcu_assign_pointer(nat_rtp_rtcp_hook, NULL); + rcu_assign_pointer(nat_t120_hook, NULL); + rcu_assign_pointer(nat_h245_hook, NULL); + rcu_assign_pointer(nat_callforwarding_hook, NULL); + rcu_assign_pointer(nat_q931_hook, NULL); + synchronize_rcu(); } /****************************************************************************/ diff --git a/net/ipv4/netfilter/ip_nat_helper_pptp.c b/net/ipv4/netfilter/ip_nat_helper_pptp.c index acf55d86310..ec957bbb536 100644 --- a/net/ipv4/netfilter/ip_nat_helper_pptp.c +++ b/net/ipv4/netfilter/ip_nat_helper_pptp.c @@ -315,17 +315,17 @@ static int __init ip_nat_helper_pptp_init(void) if (ret < 0) return ret; - BUG_ON(ip_nat_pptp_hook_outbound); - ip_nat_pptp_hook_outbound = &pptp_outbound_pkt; + BUG_ON(rcu_dereference(ip_nat_pptp_hook_outbound)); + rcu_assign_pointer(ip_nat_pptp_hook_outbound, pptp_outbound_pkt); - BUG_ON(ip_nat_pptp_hook_inbound); - ip_nat_pptp_hook_inbound = &pptp_inbound_pkt; + BUG_ON(rcu_dereference(ip_nat_pptp_hook_inbound)); + rcu_assign_pointer(ip_nat_pptp_hook_inbound, pptp_inbound_pkt); - BUG_ON(ip_nat_pptp_hook_exp_gre); - ip_nat_pptp_hook_exp_gre = &pptp_exp_gre; + BUG_ON(rcu_dereference(ip_nat_pptp_hook_exp_gre)); + rcu_assign_pointer(ip_nat_pptp_hook_exp_gre, pptp_exp_gre); - BUG_ON(ip_nat_pptp_hook_expectfn); - ip_nat_pptp_hook_expectfn = &pptp_nat_expected; + BUG_ON(rcu_dereference(ip_nat_pptp_hook_expectfn)); + rcu_assign_pointer(ip_nat_pptp_hook_expectfn, pptp_nat_expected); printk("ip_nat_pptp version %s loaded\n", IP_NAT_PPTP_VERSION); return 0; @@ -335,14 +335,13 @@ static void __exit ip_nat_helper_pptp_fini(void) { DEBUGP("cleanup_module\n" ); - ip_nat_pptp_hook_expectfn = NULL; - ip_nat_pptp_hook_exp_gre = NULL; - ip_nat_pptp_hook_inbound = NULL; - ip_nat_pptp_hook_outbound = NULL; + rcu_assign_pointer(ip_nat_pptp_hook_expectfn, NULL); + rcu_assign_pointer(ip_nat_pptp_hook_exp_gre, NULL); + rcu_assign_pointer(ip_nat_pptp_hook_inbound, NULL); + rcu_assign_pointer(ip_nat_pptp_hook_outbound, NULL); + synchronize_rcu(); ip_nat_proto_gre_fini(); - /* Make sure noone calls it, meanwhile */ - synchronize_net(); printk("ip_nat_pptp version %s unloaded\n", IP_NAT_PPTP_VERSION); } diff --git a/net/ipv4/netfilter/ip_nat_irc.c b/net/ipv4/netfilter/ip_nat_irc.c index a767123e082..feb26b48f1d 100644 --- a/net/ipv4/netfilter/ip_nat_irc.c +++ b/net/ipv4/netfilter/ip_nat_irc.c @@ -98,15 +98,14 @@ static unsigned int help(struct sk_buff **pskb, static void __exit ip_nat_irc_fini(void) { - ip_nat_irc_hook = NULL; - /* Make sure noone calls it, meanwhile. */ - synchronize_net(); + rcu_assign_pointer(ip_nat_irc_hook, NULL); + synchronize_rcu(); } static int __init ip_nat_irc_init(void) { - BUG_ON(ip_nat_irc_hook); - ip_nat_irc_hook = help; + BUG_ON(rcu_dereference(ip_nat_irc_hook)); + rcu_assign_pointer(ip_nat_irc_hook, help); return 0; } diff --git a/net/ipv4/netfilter/ip_nat_sip.c b/net/ipv4/netfilter/ip_nat_sip.c index 71fc2730a00..9fad9809953 100644 --- a/net/ipv4/netfilter/ip_nat_sip.c +++ b/net/ipv4/netfilter/ip_nat_sip.c @@ -230,18 +230,17 @@ static unsigned int ip_nat_sdp(struct sk_buff **pskb, static void __exit fini(void) { - ip_nat_sip_hook = NULL; - ip_nat_sdp_hook = NULL; - /* Make sure noone calls it, meanwhile. */ - synchronize_net(); + rcu_assign_pointer(ip_nat_sip_hook, NULL); + rcu_assign_pointer(ip_nat_sdp_hook, NULL); + synchronize_rcu(); } static int __init init(void) { - BUG_ON(ip_nat_sip_hook); - BUG_ON(ip_nat_sdp_hook); - ip_nat_sip_hook = ip_nat_sip; - ip_nat_sdp_hook = ip_nat_sdp; + BUG_ON(rcu_dereference(ip_nat_sip_hook)); + BUG_ON(rcu_dereference(ip_nat_sdp_hook)); + rcu_assign_pointer(ip_nat_sip_hook, ip_nat_sip); + rcu_assign_pointer(ip_nat_sdp_hook, ip_nat_sdp); return 0; } diff --git a/net/ipv4/netfilter/ip_nat_tftp.c b/net/ipv4/netfilter/ip_nat_tftp.c index 94a78015451..604793536fc 100644 --- a/net/ipv4/netfilter/ip_nat_tftp.c +++ b/net/ipv4/netfilter/ip_nat_tftp.c @@ -55,15 +55,14 @@ static unsigned int help(struct sk_buff **pskb, static void __exit ip_nat_tftp_fini(void) { - ip_nat_tftp_hook = NULL; - /* Make sure noone calls it, meanwhile. */ - synchronize_net(); + rcu_assign_pointer(ip_nat_tftp_hook, NULL); + synchronize_rcu(); } static int __init ip_nat_tftp_init(void) { - BUG_ON(ip_nat_tftp_hook); - ip_nat_tftp_hook = help; + BUG_ON(rcu_dereference(ip_nat_tftp_hook)); + rcu_assign_pointer(ip_nat_tftp_hook, help); return 0; } -- cgit v1.2.3 From 9d5b8baa4e9ace9be113c6151aaeeb3c07a26fc8 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Wed, 29 Nov 2006 02:35:26 +0100 Subject: [NETFILTER]: sip conntrack: minor cleanup - Use enum for header field enumeration - Use numerical value instead of pointer to header info structure to identify headers, unexport ct_sip_hdrs - group SIP and SDP entries in header info structure - remove double forward declaration of ct_sip_get_info Signed-off-by: Patrick McHardy --- net/ipv4/netfilter/ip_conntrack_sip.c | 60 +++++++++++++++++++---------------- net/ipv4/netfilter/ip_nat_sip.c | 30 ++++++++---------- 2 files changed, 45 insertions(+), 45 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/netfilter/ip_conntrack_sip.c b/net/ipv4/netfilter/ip_conntrack_sip.c index bf423db4ed4..cc317658166 100644 --- a/net/ipv4/netfilter/ip_conntrack_sip.c +++ b/net/ipv4/netfilter/ip_conntrack_sip.c @@ -52,20 +52,32 @@ unsigned int (*ip_nat_sdp_hook)(struct sk_buff **pskb, const char *dptr); EXPORT_SYMBOL_GPL(ip_nat_sdp_hook); -int ct_sip_get_info(const char *dptr, size_t dlen, - unsigned int *matchoff, - unsigned int *matchlen, - struct sip_header_nfo *hnfo); -EXPORT_SYMBOL_GPL(ct_sip_get_info); - - static int digits_len(const char *dptr, const char *limit, int *shift); static int epaddr_len(const char *dptr, const char *limit, int *shift); static int skp_digits_len(const char *dptr, const char *limit, int *shift); static int skp_epaddr_len(const char *dptr, const char *limit, int *shift); -struct sip_header_nfo ct_sip_hdrs[] = { - { /* Via header */ +struct sip_header_nfo { + const char *lname; + const char *sname; + const char *ln_str; + size_t lnlen; + size_t snlen; + size_t ln_strlen; + int (*match_len)(const char *, const char *, int *); +}; + +static struct sip_header_nfo ct_sip_hdrs[] = { + [POS_REQ_HEADER] = { /* SIP Requests headers */ + .lname = "sip:", + .lnlen = sizeof("sip:") - 1, + .sname = "sip:", + .snlen = sizeof("sip:") - 1, /* yes, i know.. ;) */ + .ln_str = "@", + .ln_strlen = sizeof("@") - 1, + .match_len = epaddr_len + }, + [POS_VIA] = { /* SIP Via header */ .lname = "Via:", .lnlen = sizeof("Via:") - 1, .sname = "\r\nv:", @@ -74,7 +86,7 @@ struct sip_header_nfo ct_sip_hdrs[] = { .ln_strlen = sizeof("UDP ") - 1, .match_len = epaddr_len, }, - { /* Contact header */ + [POS_CONTACT] = { /* SIP Contact header */ .lname = "Contact:", .lnlen = sizeof("Contact:") - 1, .sname = "\r\nm:", @@ -83,7 +95,7 @@ struct sip_header_nfo ct_sip_hdrs[] = { .ln_strlen = sizeof("sip:") - 1, .match_len = skp_epaddr_len }, - { /* Content length header */ + [POS_CONTENT] = { /* SIP Content length header */ .lname = "Content-Length:", .lnlen = sizeof("Content-Length:") - 1, .sname = "\r\nl:", @@ -92,7 +104,7 @@ struct sip_header_nfo ct_sip_hdrs[] = { .ln_strlen = sizeof(":") - 1, .match_len = skp_digits_len }, - { /* SDP media info */ + [POS_MEDIA] = { /* SDP media info */ .lname = "\nm=", .lnlen = sizeof("\nm=") - 1, .sname = "\rm=", @@ -101,7 +113,7 @@ struct sip_header_nfo ct_sip_hdrs[] = { .ln_strlen = sizeof("audio ") - 1, .match_len = digits_len }, - { /* SDP owner address*/ + [POS_OWNER] = { /* SDP owner address*/ .lname = "\no=", .lnlen = sizeof("\no=") - 1, .sname = "\ro=", @@ -110,7 +122,7 @@ struct sip_header_nfo ct_sip_hdrs[] = { .ln_strlen = sizeof("IN IP4 ") - 1, .match_len = epaddr_len }, - { /* SDP connection info */ + [POS_CONNECTION] = { /* SDP connection info */ .lname = "\nc=", .lnlen = sizeof("\nc=") - 1, .sname = "\rc=", @@ -119,16 +131,7 @@ struct sip_header_nfo ct_sip_hdrs[] = { .ln_strlen = sizeof("IN IP4 ") - 1, .match_len = epaddr_len }, - { /* Requests headers */ - .lname = "sip:", - .lnlen = sizeof("sip:") - 1, - .sname = "sip:", - .snlen = sizeof("sip:") - 1, /* yes, i know.. ;) */ - .ln_str = "@", - .ln_strlen = sizeof("@") - 1, - .match_len = epaddr_len - }, - { /* SDP version header */ + [POS_SDP_HEADER] = { /* SDP version header */ .lname = "\nv=", .lnlen = sizeof("\nv=") - 1, .sname = "\rv=", @@ -138,7 +141,6 @@ struct sip_header_nfo ct_sip_hdrs[] = { .match_len = digits_len } }; -EXPORT_SYMBOL_GPL(ct_sip_hdrs); /* get line lenght until first CR or LF seen. */ int ct_sip_lnlen(const char *line, const char *limit) @@ -263,8 +265,9 @@ static int skp_epaddr_len(const char *dptr, const char *limit, int *shift) int ct_sip_get_info(const char *dptr, size_t dlen, unsigned int *matchoff, unsigned int *matchlen, - struct sip_header_nfo *hnfo) + enum sip_header_pos pos) { + struct sip_header_nfo *hnfo = &ct_sip_hdrs[pos]; const char *limit, *aux, *k = dptr; int shift = 0; @@ -298,6 +301,7 @@ int ct_sip_get_info(const char *dptr, size_t dlen, DEBUGP("%s header not found.\n", hnfo->lname); return 0; } +EXPORT_SYMBOL_GPL(ct_sip_get_info); static int set_expected_rtp(struct sk_buff **pskb, struct ip_conntrack *ct, @@ -393,7 +397,7 @@ static int sip_help(struct sk_buff **pskb, } /* Get ip and port address from SDP packet. */ if (ct_sip_get_info(dptr, datalen, &matchoff, &matchlen, - &ct_sip_hdrs[POS_CONNECTION]) > 0) { + POS_CONNECTION) > 0) { /* We'll drop only if there are parse problems. */ if (parse_ipaddr(dptr + matchoff, NULL, &ipaddr, @@ -402,7 +406,7 @@ static int sip_help(struct sk_buff **pskb, goto out; } if (ct_sip_get_info(dptr, datalen, &matchoff, &matchlen, - &ct_sip_hdrs[POS_MEDIA]) > 0) { + POS_MEDIA) > 0) { port = simple_strtoul(dptr + matchoff, NULL, 10); if (port < 1024) { diff --git a/net/ipv4/netfilter/ip_nat_sip.c b/net/ipv4/netfilter/ip_nat_sip.c index 9fad9809953..47097aac63d 100644 --- a/net/ipv4/netfilter/ip_nat_sip.c +++ b/net/ipv4/netfilter/ip_nat_sip.c @@ -29,18 +29,16 @@ MODULE_DESCRIPTION("SIP NAT helper"); #define DEBUGP(format, args...) #endif -extern struct sip_header_nfo ct_sip_hdrs[]; - static unsigned int mangle_sip_packet(struct sk_buff **pskb, enum ip_conntrack_info ctinfo, struct ip_conntrack *ct, const char **dptr, size_t dlen, char *buffer, int bufflen, - struct sip_header_nfo *hnfo) + enum sip_header_pos pos) { unsigned int matchlen, matchoff; - if (ct_sip_get_info(*dptr, dlen, &matchoff, &matchlen, hnfo) <= 0) + if (ct_sip_get_info(*dptr, dlen, &matchoff, &matchlen, pos) <= 0) return 0; if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo, @@ -80,14 +78,13 @@ static unsigned int ip_nat_sip(struct sk_buff **pskb, if ((ctinfo) < IP_CT_IS_REPLY) { mangle_sip_packet(pskb, ctinfo, ct, dptr, (*pskb)->len - dataoff, - buffer, bufflen, - &ct_sip_hdrs[POS_CONTACT]); + buffer, bufflen, POS_CONTACT); return 1; } if (!mangle_sip_packet(pskb, ctinfo, ct, dptr, (*pskb)->len - dataoff, - buffer, bufflen, &ct_sip_hdrs[POS_VIA])) + buffer, bufflen, POS_VIA)) return 0; /* This search should ignore case, but later.. */ @@ -102,25 +99,24 @@ static unsigned int ip_nat_sip(struct sk_buff **pskb, return mangle_sip_packet(pskb, ctinfo, ct, dptr, (*pskb)->len - dataoff, - buffer, bufflen, - &ct_sip_hdrs[POS_CONTACT]); + buffer, bufflen, POS_CONTACT); } if ((ctinfo) < IP_CT_IS_REPLY) { if (!mangle_sip_packet(pskb, ctinfo, ct, dptr, (*pskb)->len - dataoff, - buffer, bufflen, &ct_sip_hdrs[POS_VIA])) + buffer, bufflen, POS_VIA)) return 0; /* Mangle Contact if exists only. - watch udp_nat_mangle()! */ mangle_sip_packet(pskb, ctinfo, ct, dptr, (*pskb)->len - dataoff, - buffer, bufflen, &ct_sip_hdrs[POS_CONTACT]); + buffer, bufflen, POS_CONTACT); return 1; } /* This mangle requests headers. */ return mangle_sip_packet(pskb, ctinfo, ct, dptr, ct_sip_lnlen(*dptr, *dptr + (*pskb)->len - dataoff), - buffer, bufflen, &ct_sip_hdrs[POS_REQ_HEADER]); + buffer, bufflen, POS_REQ_HEADER); } static int mangle_content_len(struct sk_buff **pskb, @@ -136,7 +132,7 @@ static int mangle_content_len(struct sk_buff **pskb, /* Get actual SDP lenght */ if (ct_sip_get_info(dptr, (*pskb)->len - dataoff, &matchoff, - &matchlen, &ct_sip_hdrs[POS_SDP_HEADER]) > 0) { + &matchlen, POS_SDP_HEADER) > 0) { /* since ct_sip_get_info() give us a pointer passing 'v=' we need to add 2 bytes in this count. */ @@ -144,7 +140,7 @@ static int mangle_content_len(struct sk_buff **pskb, /* Now, update SDP lenght */ if (ct_sip_get_info(dptr, (*pskb)->len - dataoff, &matchoff, - &matchlen, &ct_sip_hdrs[POS_CONTENT]) > 0) { + &matchlen, POS_CONTENT) > 0) { bufflen = sprintf(buffer, "%u", c_len); @@ -170,17 +166,17 @@ static unsigned int mangle_sdp(struct sk_buff **pskb, /* Mangle owner and contact info. */ bufflen = sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(newip)); if (!mangle_sip_packet(pskb, ctinfo, ct, &dptr, (*pskb)->len - dataoff, - buffer, bufflen, &ct_sip_hdrs[POS_OWNER])) + buffer, bufflen, POS_OWNER)) return 0; if (!mangle_sip_packet(pskb, ctinfo, ct, &dptr, (*pskb)->len - dataoff, - buffer, bufflen, &ct_sip_hdrs[POS_CONNECTION])) + buffer, bufflen, POS_CONNECTION)) return 0; /* Mangle media port. */ bufflen = sprintf(buffer, "%u", port); if (!mangle_sip_packet(pskb, ctinfo, ct, &dptr, (*pskb)->len - dataoff, - buffer, bufflen, &ct_sip_hdrs[POS_MEDIA])) + buffer, bufflen, POS_MEDIA)) return 0; return mangle_content_len(pskb, ctinfo, ct, dptr); -- cgit v1.2.3 From 40883e8184947879f135605a05c0764c60656cc5 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Wed, 29 Nov 2006 02:35:27 +0100 Subject: [NETFILTER]: sip conntrack: do case insensitive SIP header search SIP headers are generally case-insensitive, only SDP headers are case sensitive. Signed-off-by: Patrick McHardy --- net/ipv4/netfilter/ip_conntrack_sip.c | 20 ++++++++++++++++---- net/ipv4/netfilter/ip_nat_sip.c | 7 ++++--- 2 files changed, 20 insertions(+), 7 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/netfilter/ip_conntrack_sip.c b/net/ipv4/netfilter/ip_conntrack_sip.c index cc317658166..a9c0d1d3e56 100644 --- a/net/ipv4/netfilter/ip_conntrack_sip.c +++ b/net/ipv4/netfilter/ip_conntrack_sip.c @@ -64,6 +64,7 @@ struct sip_header_nfo { size_t lnlen; size_t snlen; size_t ln_strlen; + int case_sensitive; int (*match_len)(const char *, const char *, int *); }; @@ -105,6 +106,7 @@ static struct sip_header_nfo ct_sip_hdrs[] = { .match_len = skp_digits_len }, [POS_MEDIA] = { /* SDP media info */ + .case_sensitive = 1, .lname = "\nm=", .lnlen = sizeof("\nm=") - 1, .sname = "\rm=", @@ -114,6 +116,7 @@ static struct sip_header_nfo ct_sip_hdrs[] = { .match_len = digits_len }, [POS_OWNER] = { /* SDP owner address*/ + .case_sensitive = 1, .lname = "\no=", .lnlen = sizeof("\no=") - 1, .sname = "\ro=", @@ -123,6 +126,7 @@ static struct sip_header_nfo ct_sip_hdrs[] = { .match_len = epaddr_len }, [POS_CONNECTION] = { /* SDP connection info */ + .case_sensitive = 1, .lname = "\nc=", .lnlen = sizeof("\nc=") - 1, .sname = "\rc=", @@ -132,6 +136,7 @@ static struct sip_header_nfo ct_sip_hdrs[] = { .match_len = epaddr_len }, [POS_SDP_HEADER] = { /* SDP version header */ + .case_sensitive = 1, .lname = "\nv=", .lnlen = sizeof("\nv=") - 1, .sname = "\rv=", @@ -161,13 +166,19 @@ EXPORT_SYMBOL_GPL(ct_sip_lnlen); /* Linear string search, case sensitive. */ const char *ct_sip_search(const char *needle, const char *haystack, - size_t needle_len, size_t haystack_len) + size_t needle_len, size_t haystack_len, + int case_sensitive) { const char *limit = haystack + (haystack_len - needle_len); while (haystack <= limit) { - if (memcmp(haystack, needle, needle_len) == 0) - return haystack; + if (case_sensitive) { + if (strncmp(haystack, needle, needle_len) == 0) + return haystack; + } else { + if (strnicmp(haystack, needle, needle_len) == 0) + return haystack; + } haystack++; } return NULL; @@ -280,7 +291,8 @@ int ct_sip_get_info(const char *dptr, size_t dlen, continue; } aux = ct_sip_search(hnfo->ln_str, dptr, hnfo->ln_strlen, - ct_sip_lnlen(dptr, limit)); + ct_sip_lnlen(dptr, limit), + hnfo->case_sensitive); if (!aux) { DEBUGP("'%s' not found in '%s'.\n", hnfo->ln_str, hnfo->lname); diff --git a/net/ipv4/netfilter/ip_nat_sip.c b/net/ipv4/netfilter/ip_nat_sip.c index 47097aac63d..e16604c4339 100644 --- a/net/ipv4/netfilter/ip_nat_sip.c +++ b/net/ipv4/netfilter/ip_nat_sip.c @@ -87,14 +87,15 @@ static unsigned int ip_nat_sip(struct sk_buff **pskb, buffer, bufflen, POS_VIA)) return 0; - /* This search should ignore case, but later.. */ aux = ct_sip_search("CSeq:", *dptr, sizeof("CSeq:") - 1, - (*pskb)->len - dataoff); + (*pskb)->len - dataoff, 0); if (!aux) return 0; if (!ct_sip_search("REGISTER", aux, sizeof("REGISTER"), - ct_sip_lnlen(aux, *dptr + (*pskb)->len - dataoff))) + ct_sip_lnlen(aux, + *dptr + (*pskb)->len - dataoff), + 1)) return 1; return mangle_sip_packet(pskb, ctinfo, ct, dptr, -- cgit v1.2.3 From 77a78dec48386ce958196bf69f192ee76537c07d Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Wed, 29 Nov 2006 02:35:28 +0100 Subject: [NETFILTER]: sip conntrack: make header shortcuts optional Not every header has a shortcut, so make them optional instead of searching for the same string twice. Signed-off-by: Patrick McHardy --- net/ipv4/netfilter/ip_conntrack_sip.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/netfilter/ip_conntrack_sip.c b/net/ipv4/netfilter/ip_conntrack_sip.c index a9c0d1d3e56..0a6a13c45b0 100644 --- a/net/ipv4/netfilter/ip_conntrack_sip.c +++ b/net/ipv4/netfilter/ip_conntrack_sip.c @@ -72,8 +72,6 @@ static struct sip_header_nfo ct_sip_hdrs[] = { [POS_REQ_HEADER] = { /* SIP Requests headers */ .lname = "sip:", .lnlen = sizeof("sip:") - 1, - .sname = "sip:", - .snlen = sizeof("sip:") - 1, /* yes, i know.. ;) */ .ln_str = "@", .ln_strlen = sizeof("@") - 1, .match_len = epaddr_len @@ -286,7 +284,8 @@ int ct_sip_get_info(const char *dptr, size_t dlen, while (dptr <= limit) { if ((strncmp(dptr, hnfo->lname, hnfo->lnlen) != 0) && - (strncmp(dptr, hnfo->sname, hnfo->snlen) != 0)) { + (hinfo->sname == NULL || + strncmp(dptr, hnfo->sname, hnfo->snlen) != 0)) { dptr++; continue; } -- cgit v1.2.3 From 1b683b551209ca46ae59b29572018001db5af078 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Wed, 29 Nov 2006 02:35:30 +0100 Subject: [NETFILTER]: sip conntrack: better NAT handling The NAT handling of the SIP helper has a few problems: - Request headers are only mangled in the reply direction, From/To headers not at all, which can lead to authentication failures with DNAT in case the authentication domain is the IP address - Contact headers in responses are only mangled for REGISTER responses - Headers may be mangled even though they contain addresses not participating in the connection, like alternative addresses - Packets are droppen when domain names are used where the helper expects IP addresses This patch takes a different approach, instead of fixed rules what field to mangle to what content, it adds symetric mapping of From/To/Via/Contact headers, which allows to deal properly with echoed addresses in responses and foreign addresses not belonging to the connection. Signed-off-by: Patrick McHardy --- net/ipv4/netfilter/ip_conntrack_sip.c | 29 +++++- net/ipv4/netfilter/ip_nat_sip.c | 171 +++++++++++++++++++++------------- 2 files changed, 131 insertions(+), 69 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/netfilter/ip_conntrack_sip.c b/net/ipv4/netfilter/ip_conntrack_sip.c index 0a6a13c45b0..3a26d63eed8 100644 --- a/net/ipv4/netfilter/ip_conntrack_sip.c +++ b/net/ipv4/netfilter/ip_conntrack_sip.c @@ -69,13 +69,38 @@ struct sip_header_nfo { }; static struct sip_header_nfo ct_sip_hdrs[] = { - [POS_REQ_HEADER] = { /* SIP Requests headers */ + [POS_REG_REQ_URI] = { /* SIP REGISTER request URI */ + .lname = "sip:", + .lnlen = sizeof("sip:") - 1, + .ln_str = ":", + .ln_strlen = sizeof(":") - 1, + .match_len = epaddr_len + }, + [POS_REQ_URI] = { /* SIP request URI */ .lname = "sip:", .lnlen = sizeof("sip:") - 1, .ln_str = "@", .ln_strlen = sizeof("@") - 1, .match_len = epaddr_len }, + [POS_FROM] = { /* SIP From header */ + .lname = "From:", + .lnlen = sizeof("From:") - 1, + .sname = "\r\nf:", + .snlen = sizeof("\r\nf:") - 1, + .ln_str = "sip:", + .ln_strlen = sizeof("sip:") - 1, + .match_len = skp_epaddr_len, + }, + [POS_TO] = { /* SIP To header */ + .lname = "To:", + .lnlen = sizeof("To:") - 1, + .sname = "\r\nt:", + .snlen = sizeof("\r\nt:") - 1, + .ln_str = "sip:", + .ln_strlen = sizeof("sip:") - 1, + .match_len = skp_epaddr_len, + }, [POS_VIA] = { /* SIP Via header */ .lname = "Via:", .lnlen = sizeof("Via:") - 1, @@ -284,7 +309,7 @@ int ct_sip_get_info(const char *dptr, size_t dlen, while (dptr <= limit) { if ((strncmp(dptr, hnfo->lname, hnfo->lnlen) != 0) && - (hinfo->sname == NULL || + (hnfo->sname == NULL || strncmp(dptr, hnfo->sname, hnfo->snlen) != 0)) { dptr++; continue; diff --git a/net/ipv4/netfilter/ip_nat_sip.c b/net/ipv4/netfilter/ip_nat_sip.c index e16604c4339..6223abc924f 100644 --- a/net/ipv4/netfilter/ip_nat_sip.c +++ b/net/ipv4/netfilter/ip_nat_sip.c @@ -29,25 +29,70 @@ MODULE_DESCRIPTION("SIP NAT helper"); #define DEBUGP(format, args...) #endif -static unsigned int mangle_sip_packet(struct sk_buff **pskb, - enum ip_conntrack_info ctinfo, - struct ip_conntrack *ct, - const char **dptr, size_t dlen, - char *buffer, int bufflen, - enum sip_header_pos pos) +struct addr_map { + struct { + char src[sizeof("nnn.nnn.nnn.nnn:nnnnn")]; + char dst[sizeof("nnn.nnn.nnn.nnn:nnnnn")]; + unsigned int srclen, srciplen; + unsigned int dstlen, dstiplen; + } addr[IP_CT_DIR_MAX]; +}; + +static void addr_map_init(struct ip_conntrack *ct, struct addr_map *map) { - unsigned int matchlen, matchoff; + struct ip_conntrack_tuple *t; + enum ip_conntrack_dir dir; + unsigned int n; + + for (dir = 0; dir < IP_CT_DIR_MAX; dir++) { + t = &ct->tuplehash[dir].tuple; + + n = sprintf(map->addr[dir].src, "%u.%u.%u.%u", + NIPQUAD(t->src.ip)); + map->addr[dir].srciplen = n; + n += sprintf(map->addr[dir].src + n, ":%u", + ntohs(t->src.u.udp.port)); + map->addr[dir].srclen = n; + + n = sprintf(map->addr[dir].dst, "%u.%u.%u.%u", + NIPQUAD(t->dst.ip)); + map->addr[dir].dstiplen = n; + n += sprintf(map->addr[dir].dst + n, ":%u", + ntohs(t->dst.u.udp.port)); + map->addr[dir].dstlen = n; + } +} + +static int map_sip_addr(struct sk_buff **pskb, enum ip_conntrack_info ctinfo, + struct ip_conntrack *ct, const char **dptr, size_t dlen, + enum sip_header_pos pos, struct addr_map *map) +{ + enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); + unsigned int matchlen, matchoff, addrlen; + char *addr; if (ct_sip_get_info(*dptr, dlen, &matchoff, &matchlen, pos) <= 0) - return 0; + return 1; + + if ((matchlen == map->addr[dir].srciplen || + matchlen == map->addr[dir].srclen) && + memcmp(*dptr + matchoff, map->addr[dir].src, matchlen) == 0) { + addr = map->addr[!dir].dst; + addrlen = map->addr[!dir].dstlen; + } else if ((matchlen == map->addr[dir].dstiplen || + matchlen == map->addr[dir].dstlen) && + memcmp(*dptr + matchoff, map->addr[dir].dst, matchlen) == 0) { + addr = map->addr[!dir].src; + addrlen = map->addr[!dir].srclen; + } else + return 1; if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo, - matchoff, matchlen, buffer, bufflen)) + matchoff, matchlen, addr, addrlen)) return 0; - - /* We need to reload this. Thanks Patrick. */ *dptr = (*pskb)->data + (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr); return 1; + } static unsigned int ip_nat_sip(struct sk_buff **pskb, @@ -55,69 +100,61 @@ static unsigned int ip_nat_sip(struct sk_buff **pskb, struct ip_conntrack *ct, const char **dptr) { - enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); - char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")]; - unsigned int bufflen, dataoff; - __be32 ip; - __be16 port; + enum sip_header_pos pos; + struct addr_map map; + int dataoff, datalen; dataoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr); + datalen = (*pskb)->len - dataoff; + if (datalen < sizeof("SIP/2.0") - 1) + return NF_DROP; + + addr_map_init(ct, &map); + + /* Basic rules: requests and responses. */ + if (strncmp(*dptr, "SIP/2.0", sizeof("SIP/2.0") - 1) != 0) { + /* 10.2: Constructing the REGISTER Request: + * + * The "userinfo" and "@" components of the SIP URI MUST NOT + * be present. + */ + if (datalen >= sizeof("REGISTER") - 1 && + strncmp(*dptr, "REGISTER", sizeof("REGISTER") - 1) == 0) + pos = POS_REG_REQ_URI; + else + pos = POS_REQ_URI; + + if (!map_sip_addr(pskb, ctinfo, ct, dptr, datalen, pos, &map)) + return NF_DROP; + } - ip = ct->tuplehash[!dir].tuple.dst.ip; - port = ct->tuplehash[!dir].tuple.dst.u.udp.port; - bufflen = sprintf(buffer, "%u.%u.%u.%u:%u", NIPQUAD(ip), ntohs(port)); + if (!map_sip_addr(pskb, ctinfo, ct, dptr, datalen, POS_FROM, &map) || + !map_sip_addr(pskb, ctinfo, ct, dptr, datalen, POS_TO, &map) || + !map_sip_addr(pskb, ctinfo, ct, dptr, datalen, POS_VIA, &map) || + !map_sip_addr(pskb, ctinfo, ct, dptr, datalen, POS_CONTACT, &map)) + return NF_DROP; + return NF_ACCEPT; +} + +static unsigned int mangle_sip_packet(struct sk_buff **pskb, + enum ip_conntrack_info ctinfo, + struct ip_conntrack *ct, + const char **dptr, size_t dlen, + char *buffer, int bufflen, + enum sip_header_pos pos) +{ + unsigned int matchlen, matchoff; - /* short packet ? */ - if (((*pskb)->len - dataoff) < (sizeof("SIP/2.0") - 1)) + if (ct_sip_get_info(*dptr, dlen, &matchoff, &matchlen, pos) <= 0) return 0; - /* Basic rules: requests and responses. */ - if (memcmp(*dptr, "SIP/2.0", sizeof("SIP/2.0") - 1) == 0) { - const char *aux; - - if ((ctinfo) < IP_CT_IS_REPLY) { - mangle_sip_packet(pskb, ctinfo, ct, dptr, - (*pskb)->len - dataoff, - buffer, bufflen, POS_CONTACT); - return 1; - } + if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo, + matchoff, matchlen, buffer, bufflen)) + return 0; - if (!mangle_sip_packet(pskb, ctinfo, ct, dptr, - (*pskb)->len - dataoff, - buffer, bufflen, POS_VIA)) - return 0; - - aux = ct_sip_search("CSeq:", *dptr, sizeof("CSeq:") - 1, - (*pskb)->len - dataoff, 0); - if (!aux) - return 0; - - if (!ct_sip_search("REGISTER", aux, sizeof("REGISTER"), - ct_sip_lnlen(aux, - *dptr + (*pskb)->len - dataoff), - 1)) - return 1; - - return mangle_sip_packet(pskb, ctinfo, ct, dptr, - (*pskb)->len - dataoff, - buffer, bufflen, POS_CONTACT); - } - if ((ctinfo) < IP_CT_IS_REPLY) { - if (!mangle_sip_packet(pskb, ctinfo, ct, dptr, - (*pskb)->len - dataoff, - buffer, bufflen, POS_VIA)) - return 0; - - /* Mangle Contact if exists only. - watch udp_nat_mangle()! */ - mangle_sip_packet(pskb, ctinfo, ct, dptr, (*pskb)->len - dataoff, - buffer, bufflen, POS_CONTACT); - return 1; - } - /* This mangle requests headers. */ - return mangle_sip_packet(pskb, ctinfo, ct, dptr, - ct_sip_lnlen(*dptr, - *dptr + (*pskb)->len - dataoff), - buffer, bufflen, POS_REQ_HEADER); + /* We need to reload this. Thanks Patrick. */ + *dptr = (*pskb)->data + (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr); + return 1; } static int mangle_content_len(struct sk_buff **pskb, -- cgit v1.2.3 From bbb3357d14f6becd156469220992ef7ab0f10e69 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 29 Nov 2006 02:35:31 +0100 Subject: [NETFILTER]: ctnetlink: check for status attribute existence on conntrack creation Check that status flags are available in the netlink message received to create a new conntrack. Signed-off-by: Pablo Neira Ayuso Signed-off-by: Patrick McHardy --- net/ipv4/netfilter/ip_conntrack_netlink.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/netfilter/ip_conntrack_netlink.c b/net/ipv4/netfilter/ip_conntrack_netlink.c index 3d277aa869d..d5d2efddba5 100644 --- a/net/ipv4/netfilter/ip_conntrack_netlink.c +++ b/net/ipv4/netfilter/ip_conntrack_netlink.c @@ -945,9 +945,11 @@ ctnetlink_create_conntrack(struct nfattr *cda[], ct->timeout.expires = jiffies + ct->timeout.expires * HZ; ct->status |= IPS_CONFIRMED; - err = ctnetlink_change_status(ct, cda); - if (err < 0) - goto err; + if (cda[CTA_STATUS-1]) { + err = ctnetlink_change_status(ct, cda); + if (err < 0) + goto err; + } if (cda[CTA_PROTOINFO-1]) { err = ctnetlink_change_protoinfo(ct, cda); -- cgit v1.2.3 From 7b621c1ea64a54f77b8a841b16dc4c9fee3ecf48 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 29 Nov 2006 02:35:32 +0100 Subject: [NETFILTER]: ctnetlink: rework conntrack fields dumping logic on events | NEW | UPDATE | DESTROY | ----------------------------------------| tuples | Y | Y | Y | status | Y | Y | N | timeout | Y | Y | N | protoinfo | S | S | N | helper | S | S | N | mark | S | S | N | counters | F | F | Y | Leyend: Y: yes N: no S: iif the field is set F: iif overflow This patch also replace IPCT_HELPINFO by IPCT_HELPER since we want to track the helper assignation process, not the changes in the private information held by the helper. Signed-off-by: Pablo Neira Ayuso Signed-off-by: Patrick McHardy --- net/ipv4/netfilter/ip_conntrack_netlink.c | 49 +++++++++++++++++-------------- 1 file changed, 27 insertions(+), 22 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/netfilter/ip_conntrack_netlink.c b/net/ipv4/netfilter/ip_conntrack_netlink.c index d5d2efddba5..5fcf91d617c 100644 --- a/net/ipv4/netfilter/ip_conntrack_netlink.c +++ b/net/ipv4/netfilter/ip_conntrack_netlink.c @@ -320,8 +320,6 @@ static int ctnetlink_conntrack_event(struct notifier_block *this, } else if (events & (IPCT_NEW | IPCT_RELATED)) { type = IPCTNL_MSG_CT_NEW; flags = NLM_F_CREATE|NLM_F_EXCL; - /* dump everything */ - events = ~0UL; group = NFNLGRP_CONNTRACK_NEW; } else if (events & (IPCT_STATUS | IPCT_PROTOINFO)) { type = IPCTNL_MSG_CT_NEW; @@ -356,28 +354,35 @@ static int ctnetlink_conntrack_event(struct notifier_block *this, if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_REPLY)) < 0) goto nfattr_failure; NFA_NEST_END(skb, nest_parms); - - /* NAT stuff is now a status flag */ - if ((events & IPCT_STATUS || events & IPCT_NATINFO) - && ctnetlink_dump_status(skb, ct) < 0) - goto nfattr_failure; - if (events & IPCT_REFRESH - && ctnetlink_dump_timeout(skb, ct) < 0) - goto nfattr_failure; - if (events & IPCT_PROTOINFO - && ctnetlink_dump_protoinfo(skb, ct) < 0) - goto nfattr_failure; - if (events & IPCT_HELPINFO - && ctnetlink_dump_helpinfo(skb, ct) < 0) - goto nfattr_failure; - if (ctnetlink_dump_counters(skb, ct, IP_CT_DIR_ORIGINAL) < 0 || - ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0) - goto nfattr_failure; + if (events & IPCT_DESTROY) { + if (ctnetlink_dump_counters(skb, ct, IP_CT_DIR_ORIGINAL) < 0 || + ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0) + goto nfattr_failure; + } else { + if (ctnetlink_dump_status(skb, ct) < 0) + goto nfattr_failure; - if (events & IPCT_MARK - && ctnetlink_dump_mark(skb, ct) < 0) - goto nfattr_failure; + if (ctnetlink_dump_timeout(skb, ct) < 0) + goto nfattr_failure; + + if (events & IPCT_PROTOINFO + && ctnetlink_dump_protoinfo(skb, ct) < 0) + goto nfattr_failure; + + if ((events & IPCT_HELPER || ct->helper) + && ctnetlink_dump_helpinfo(skb, ct) < 0) + goto nfattr_failure; + + if ((events & IPCT_MARK || ct->mark) + && ctnetlink_dump_mark(skb, ct) < 0) + goto nfattr_failure; + + if (events & IPCT_COUNTER_FILLING && + (ctnetlink_dump_counters(skb, ct, IP_CT_DIR_ORIGINAL) < 0 || + ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0)) + goto nfattr_failure; + } nlh->nlmsg_len = skb->tail - b; nfnetlink_send(skb, 0, group, 0); -- cgit v1.2.3 From 39b46fc6f0d1161a5585cd8af7b3a05e8118ab7e Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Wed, 29 Nov 2006 02:35:36 +0100 Subject: [NETFILTER]: x_tables: add port of hashlimit match for IPv4 and IPv6 Signed-off-by: Patrick McHardy --- net/ipv4/netfilter/Kconfig | 14 - net/ipv4/netfilter/Makefile | 1 - net/ipv4/netfilter/ipt_hashlimit.c | 733 ------------------------------------- 3 files changed, 748 deletions(-) delete mode 100644 net/ipv4/netfilter/ipt_hashlimit.c (limited to 'net/ipv4') diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index 4ac5b5c4678..bc298a3f236 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig @@ -326,20 +326,6 @@ config IP_NF_MATCH_ADDRTYPE If you want to compile it as a module, say M here and read . If unsure, say `N'. -config IP_NF_MATCH_HASHLIMIT - tristate 'hashlimit match support' - depends on IP_NF_IPTABLES - help - This option adds a new iptables `hashlimit' match. - - As opposed to `limit', this match dynamically creates a hash table - of limit buckets, based on your selection of source/destination - ip addresses and/or ports. - - It enables you to express policies like `10kpps for any given - destination IP' or `500pps from any given source IP' with a single - IPtables rule. - # `filter', generic and specific targets config IP_NF_FILTER tristate "Packet filtering" diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index 4ce20ebc4d6..21359d83f0c 100644 --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile @@ -53,7 +53,6 @@ obj-$(CONFIG_IP_NF_NAT) += iptable_nat.o obj-$(CONFIG_IP_NF_RAW) += iptable_raw.o # matches -obj-$(CONFIG_IP_NF_MATCH_HASHLIMIT) += ipt_hashlimit.o obj-$(CONFIG_IP_NF_MATCH_IPRANGE) += ipt_iprange.o obj-$(CONFIG_IP_NF_MATCH_OWNER) += ipt_owner.o obj-$(CONFIG_IP_NF_MATCH_TOS) += ipt_tos.o diff --git a/net/ipv4/netfilter/ipt_hashlimit.c b/net/ipv4/netfilter/ipt_hashlimit.c deleted file mode 100644 index 33ccdbf8e79..00000000000 --- a/net/ipv4/netfilter/ipt_hashlimit.c +++ /dev/null @@ -1,733 +0,0 @@ -/* iptables match extension to limit the number of packets per second - * seperately for each hashbucket (sourceip/sourceport/dstip/dstport) - * - * (C) 2003-2004 by Harald Welte - * - * $Id: ipt_hashlimit.c 3244 2004-10-20 16:24:29Z laforge@netfilter.org $ - * - * Development of this code was funded by Astaro AG, http://www.astaro.com/ - * - * based on ipt_limit.c by: - * Jérôme de Vivie - * Hervé Eychenne - * Rusty Russell - * - * The general idea is to create a hash table for every dstip and have a - * seperate limit counter per tuple. This way you can do something like 'limit - * the number of syn packets for each of my internal addresses. - * - * Ideally this would just be implemented as a general 'hash' match, which would - * allow us to attach any iptables target to it's hash buckets. But this is - * not possible in the current iptables architecture. As always, pkttables for - * 2.7.x will help ;) - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -/* FIXME: this is just for IP_NF_ASSERRT */ -#include -#include - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Harald Welte "); -MODULE_DESCRIPTION("iptables match for limiting per hash-bucket"); - -/* need to declare this at the top */ -static struct proc_dir_entry *hashlimit_procdir; -static struct file_operations dl_file_ops; - -/* hash table crap */ - -struct dsthash_dst { - __be32 src_ip; - __be32 dst_ip; - /* ports have to be consecutive !!! */ - __be16 src_port; - __be16 dst_port; -}; - -struct dsthash_ent { - /* static / read-only parts in the beginning */ - struct hlist_node node; - struct dsthash_dst dst; - - /* modified structure members in the end */ - unsigned long expires; /* precalculated expiry time */ - struct { - unsigned long prev; /* last modification */ - u_int32_t credit; - u_int32_t credit_cap, cost; - } rateinfo; -}; - -struct ipt_hashlimit_htable { - struct hlist_node node; /* global list of all htables */ - atomic_t use; - - struct hashlimit_cfg cfg; /* config */ - - /* used internally */ - spinlock_t lock; /* lock for list_head */ - u_int32_t rnd; /* random seed for hash */ - int rnd_initialized; - struct timer_list timer; /* timer for gc */ - atomic_t count; /* number entries in table */ - - /* seq_file stuff */ - struct proc_dir_entry *pde; - - struct hlist_head hash[0]; /* hashtable itself */ -}; - -static DEFINE_SPINLOCK(hashlimit_lock); /* protects htables list */ -static DEFINE_MUTEX(hlimit_mutex); /* additional checkentry protection */ -static HLIST_HEAD(hashlimit_htables); -static kmem_cache_t *hashlimit_cachep __read_mostly; - -static inline int dst_cmp(const struct dsthash_ent *ent, struct dsthash_dst *b) -{ - return (ent->dst.dst_ip == b->dst_ip - && ent->dst.dst_port == b->dst_port - && ent->dst.src_port == b->src_port - && ent->dst.src_ip == b->src_ip); -} - -static inline u_int32_t -hash_dst(const struct ipt_hashlimit_htable *ht, const struct dsthash_dst *dst) -{ - return (jhash_3words((__force u32)dst->dst_ip, - ((__force u32)dst->dst_port<<16 | - (__force u32)dst->src_port), - (__force u32)dst->src_ip, ht->rnd) % ht->cfg.size); -} - -static inline struct dsthash_ent * -__dsthash_find(const struct ipt_hashlimit_htable *ht, struct dsthash_dst *dst) -{ - struct dsthash_ent *ent; - struct hlist_node *pos; - u_int32_t hash = hash_dst(ht, dst); - - if (!hlist_empty(&ht->hash[hash])) - hlist_for_each_entry(ent, pos, &ht->hash[hash], node) { - if (dst_cmp(ent, dst)) { - return ent; - } - } - - return NULL; -} - -/* allocate dsthash_ent, initialize dst, put in htable and lock it */ -static struct dsthash_ent * -__dsthash_alloc_init(struct ipt_hashlimit_htable *ht, struct dsthash_dst *dst) -{ - struct dsthash_ent *ent; - - /* initialize hash with random val at the time we allocate - * the first hashtable entry */ - if (!ht->rnd_initialized) { - get_random_bytes(&ht->rnd, 4); - ht->rnd_initialized = 1; - } - - if (ht->cfg.max && - atomic_read(&ht->count) >= ht->cfg.max) { - /* FIXME: do something. question is what.. */ - if (net_ratelimit()) - printk(KERN_WARNING - "ipt_hashlimit: max count of %u reached\n", - ht->cfg.max); - return NULL; - } - - ent = kmem_cache_alloc(hashlimit_cachep, GFP_ATOMIC); - if (!ent) { - if (net_ratelimit()) - printk(KERN_ERR - "ipt_hashlimit: can't allocate dsthash_ent\n"); - return NULL; - } - - atomic_inc(&ht->count); - - ent->dst.dst_ip = dst->dst_ip; - ent->dst.dst_port = dst->dst_port; - ent->dst.src_ip = dst->src_ip; - ent->dst.src_port = dst->src_port; - - hlist_add_head(&ent->node, &ht->hash[hash_dst(ht, dst)]); - - return ent; -} - -static inline void -__dsthash_free(struct ipt_hashlimit_htable *ht, struct dsthash_ent *ent) -{ - hlist_del(&ent->node); - kmem_cache_free(hashlimit_cachep, ent); - atomic_dec(&ht->count); -} -static void htable_gc(unsigned long htlong); - -static int htable_create(struct ipt_hashlimit_info *minfo) -{ - int i; - unsigned int size; - struct ipt_hashlimit_htable *hinfo; - - if (minfo->cfg.size) - size = minfo->cfg.size; - else { - size = (((num_physpages << PAGE_SHIFT) / 16384) - / sizeof(struct list_head)); - if (num_physpages > (1024 * 1024 * 1024 / PAGE_SIZE)) - size = 8192; - if (size < 16) - size = 16; - } - /* FIXME: don't use vmalloc() here or anywhere else -HW */ - hinfo = vmalloc(sizeof(struct ipt_hashlimit_htable) - + (sizeof(struct list_head) * size)); - if (!hinfo) { - printk(KERN_ERR "ipt_hashlimit: Unable to create hashtable\n"); - return -1; - } - minfo->hinfo = hinfo; - - /* copy match config into hashtable config */ - memcpy(&hinfo->cfg, &minfo->cfg, sizeof(hinfo->cfg)); - hinfo->cfg.size = size; - if (!hinfo->cfg.max) - hinfo->cfg.max = 8 * hinfo->cfg.size; - else if (hinfo->cfg.max < hinfo->cfg.size) - hinfo->cfg.max = hinfo->cfg.size; - - for (i = 0; i < hinfo->cfg.size; i++) - INIT_HLIST_HEAD(&hinfo->hash[i]); - - atomic_set(&hinfo->count, 0); - atomic_set(&hinfo->use, 1); - hinfo->rnd_initialized = 0; - spin_lock_init(&hinfo->lock); - hinfo->pde = create_proc_entry(minfo->name, 0, hashlimit_procdir); - if (!hinfo->pde) { - vfree(hinfo); - return -1; - } - hinfo->pde->proc_fops = &dl_file_ops; - hinfo->pde->data = hinfo; - - init_timer(&hinfo->timer); - hinfo->timer.expires = jiffies + msecs_to_jiffies(hinfo->cfg.gc_interval); - hinfo->timer.data = (unsigned long )hinfo; - hinfo->timer.function = htable_gc; - add_timer(&hinfo->timer); - - spin_lock_bh(&hashlimit_lock); - hlist_add_head(&hinfo->node, &hashlimit_htables); - spin_unlock_bh(&hashlimit_lock); - - return 0; -} - -static int select_all(struct ipt_hashlimit_htable *ht, struct dsthash_ent *he) -{ - return 1; -} - -static int select_gc(struct ipt_hashlimit_htable *ht, struct dsthash_ent *he) -{ - return (jiffies >= he->expires); -} - -static void htable_selective_cleanup(struct ipt_hashlimit_htable *ht, - int (*select)(struct ipt_hashlimit_htable *ht, - struct dsthash_ent *he)) -{ - int i; - - IP_NF_ASSERT(ht->cfg.size && ht->cfg.max); - - /* lock hash table and iterate over it */ - spin_lock_bh(&ht->lock); - for (i = 0; i < ht->cfg.size; i++) { - struct dsthash_ent *dh; - struct hlist_node *pos, *n; - hlist_for_each_entry_safe(dh, pos, n, &ht->hash[i], node) { - if ((*select)(ht, dh)) - __dsthash_free(ht, dh); - } - } - spin_unlock_bh(&ht->lock); -} - -/* hash table garbage collector, run by timer */ -static void htable_gc(unsigned long htlong) -{ - struct ipt_hashlimit_htable *ht = (struct ipt_hashlimit_htable *)htlong; - - htable_selective_cleanup(ht, select_gc); - - /* re-add the timer accordingly */ - ht->timer.expires = jiffies + msecs_to_jiffies(ht->cfg.gc_interval); - add_timer(&ht->timer); -} - -static void htable_destroy(struct ipt_hashlimit_htable *hinfo) -{ - /* remove timer, if it is pending */ - if (timer_pending(&hinfo->timer)) - del_timer(&hinfo->timer); - - /* remove proc entry */ - remove_proc_entry(hinfo->pde->name, hashlimit_procdir); - - htable_selective_cleanup(hinfo, select_all); - vfree(hinfo); -} - -static struct ipt_hashlimit_htable *htable_find_get(char *name) -{ - struct ipt_hashlimit_htable *hinfo; - struct hlist_node *pos; - - spin_lock_bh(&hashlimit_lock); - hlist_for_each_entry(hinfo, pos, &hashlimit_htables, node) { - if (!strcmp(name, hinfo->pde->name)) { - atomic_inc(&hinfo->use); - spin_unlock_bh(&hashlimit_lock); - return hinfo; - } - } - spin_unlock_bh(&hashlimit_lock); - - return NULL; -} - -static void htable_put(struct ipt_hashlimit_htable *hinfo) -{ - if (atomic_dec_and_test(&hinfo->use)) { - spin_lock_bh(&hashlimit_lock); - hlist_del(&hinfo->node); - spin_unlock_bh(&hashlimit_lock); - htable_destroy(hinfo); - } -} - - -/* The algorithm used is the Simple Token Bucket Filter (TBF) - * see net/sched/sch_tbf.c in the linux source tree - */ - -/* Rusty: This is my (non-mathematically-inclined) understanding of - this algorithm. The `average rate' in jiffies becomes your initial - amount of credit `credit' and the most credit you can ever have - `credit_cap'. The `peak rate' becomes the cost of passing the - test, `cost'. - - `prev' tracks the last packet hit: you gain one credit per jiffy. - If you get credit balance more than this, the extra credit is - discarded. Every time the match passes, you lose `cost' credits; - if you don't have that many, the test fails. - - See Alexey's formal explanation in net/sched/sch_tbf.c. - - To get the maximum range, we multiply by this factor (ie. you get N - credits per jiffy). We want to allow a rate as low as 1 per day - (slowest userspace tool allows), which means - CREDITS_PER_JIFFY*HZ*60*60*24 < 2^32 ie. -*/ -#define MAX_CPJ (0xFFFFFFFF / (HZ*60*60*24)) - -/* Repeated shift and or gives us all 1s, final shift and add 1 gives - * us the power of 2 below the theoretical max, so GCC simply does a - * shift. */ -#define _POW2_BELOW2(x) ((x)|((x)>>1)) -#define _POW2_BELOW4(x) (_POW2_BELOW2(x)|_POW2_BELOW2((x)>>2)) -#define _POW2_BELOW8(x) (_POW2_BELOW4(x)|_POW2_BELOW4((x)>>4)) -#define _POW2_BELOW16(x) (_POW2_BELOW8(x)|_POW2_BELOW8((x)>>8)) -#define _POW2_BELOW32(x) (_POW2_BELOW16(x)|_POW2_BELOW16((x)>>16)) -#define POW2_BELOW32(x) ((_POW2_BELOW32(x)>>1) + 1) - -#define CREDITS_PER_JIFFY POW2_BELOW32(MAX_CPJ) - -/* Precision saver. */ -static inline u_int32_t -user2credits(u_int32_t user) -{ - /* If multiplying would overflow... */ - if (user > 0xFFFFFFFF / (HZ*CREDITS_PER_JIFFY)) - /* Divide first. */ - return (user / IPT_HASHLIMIT_SCALE) * HZ * CREDITS_PER_JIFFY; - - return (user * HZ * CREDITS_PER_JIFFY) / IPT_HASHLIMIT_SCALE; -} - -static inline void rateinfo_recalc(struct dsthash_ent *dh, unsigned long now) -{ - dh->rateinfo.credit += (now - xchg(&dh->rateinfo.prev, now)) - * CREDITS_PER_JIFFY; - if (dh->rateinfo.credit > dh->rateinfo.credit_cap) - dh->rateinfo.credit = dh->rateinfo.credit_cap; -} - -static int -hashlimit_match(const struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - const struct xt_match *match, - const void *matchinfo, - int offset, - unsigned int protoff, - int *hotdrop) -{ - struct ipt_hashlimit_info *r = - ((struct ipt_hashlimit_info *)matchinfo)->u.master; - struct ipt_hashlimit_htable *hinfo = r->hinfo; - unsigned long now = jiffies; - struct dsthash_ent *dh; - struct dsthash_dst dst; - - /* build 'dst' according to hinfo->cfg and current packet */ - memset(&dst, 0, sizeof(dst)); - if (hinfo->cfg.mode & IPT_HASHLIMIT_HASH_DIP) - dst.dst_ip = skb->nh.iph->daddr; - if (hinfo->cfg.mode & IPT_HASHLIMIT_HASH_SIP) - dst.src_ip = skb->nh.iph->saddr; - if (hinfo->cfg.mode & IPT_HASHLIMIT_HASH_DPT - ||hinfo->cfg.mode & IPT_HASHLIMIT_HASH_SPT) { - __be16 _ports[2], *ports; - - switch (skb->nh.iph->protocol) { - case IPPROTO_TCP: - case IPPROTO_UDP: - case IPPROTO_SCTP: - case IPPROTO_DCCP: - ports = skb_header_pointer(skb, skb->nh.iph->ihl*4, - sizeof(_ports), &_ports); - break; - default: - _ports[0] = _ports[1] = 0; - ports = _ports; - break; - } - if (!ports) { - /* We've been asked to examine this packet, and we - can't. Hence, no choice but to drop. */ - *hotdrop = 1; - return 0; - } - if (hinfo->cfg.mode & IPT_HASHLIMIT_HASH_SPT) - dst.src_port = ports[0]; - if (hinfo->cfg.mode & IPT_HASHLIMIT_HASH_DPT) - dst.dst_port = ports[1]; - } - - spin_lock_bh(&hinfo->lock); - dh = __dsthash_find(hinfo, &dst); - if (!dh) { - dh = __dsthash_alloc_init(hinfo, &dst); - - if (!dh) { - /* enomem... don't match == DROP */ - if (net_ratelimit()) - printk(KERN_ERR "%s: ENOMEM\n", __FUNCTION__); - spin_unlock_bh(&hinfo->lock); - return 0; - } - - dh->expires = jiffies + msecs_to_jiffies(hinfo->cfg.expire); - - dh->rateinfo.prev = jiffies; - dh->rateinfo.credit = user2credits(hinfo->cfg.avg * - hinfo->cfg.burst); - dh->rateinfo.credit_cap = user2credits(hinfo->cfg.avg * - hinfo->cfg.burst); - dh->rateinfo.cost = user2credits(hinfo->cfg.avg); - } else { - /* update expiration timeout */ - dh->expires = now + msecs_to_jiffies(hinfo->cfg.expire); - rateinfo_recalc(dh, now); - } - - if (dh->rateinfo.credit >= dh->rateinfo.cost) { - /* We're underlimit. */ - dh->rateinfo.credit -= dh->rateinfo.cost; - spin_unlock_bh(&hinfo->lock); - return 1; - } - - spin_unlock_bh(&hinfo->lock); - - /* default case: we're overlimit, thus don't match */ - return 0; -} - -static int -hashlimit_checkentry(const char *tablename, - const void *inf, - const struct xt_match *match, - void *matchinfo, - unsigned int hook_mask) -{ - struct ipt_hashlimit_info *r = matchinfo; - - /* Check for overflow. */ - if (r->cfg.burst == 0 - || user2credits(r->cfg.avg * r->cfg.burst) < - user2credits(r->cfg.avg)) { - printk(KERN_ERR "ipt_hashlimit: Overflow, try lower: %u/%u\n", - r->cfg.avg, r->cfg.burst); - return 0; - } - - if (r->cfg.mode == 0 - || r->cfg.mode > (IPT_HASHLIMIT_HASH_DPT - |IPT_HASHLIMIT_HASH_DIP - |IPT_HASHLIMIT_HASH_SIP - |IPT_HASHLIMIT_HASH_SPT)) - return 0; - - if (!r->cfg.gc_interval) - return 0; - - if (!r->cfg.expire) - return 0; - - if (r->name[sizeof(r->name) - 1] != '\0') - return 0; - - /* This is the best we've got: We cannot release and re-grab lock, - * since checkentry() is called before ip_tables.c grabs ipt_mutex. - * We also cannot grab the hashtable spinlock, since htable_create will - * call vmalloc, and that can sleep. And we cannot just re-search - * the list of htable's in htable_create(), since then we would - * create duplicate proc files. -HW */ - mutex_lock(&hlimit_mutex); - r->hinfo = htable_find_get(r->name); - if (!r->hinfo && (htable_create(r) != 0)) { - mutex_unlock(&hlimit_mutex); - return 0; - } - mutex_unlock(&hlimit_mutex); - - /* Ugly hack: For SMP, we only want to use one set */ - r->u.master = r; - - return 1; -} - -static void -hashlimit_destroy(const struct xt_match *match, void *matchinfo) -{ - struct ipt_hashlimit_info *r = matchinfo; - - htable_put(r->hinfo); -} - -#ifdef CONFIG_COMPAT -struct compat_ipt_hashlimit_info { - char name[IFNAMSIZ]; - struct hashlimit_cfg cfg; - compat_uptr_t hinfo; - compat_uptr_t master; -}; - -static void compat_from_user(void *dst, void *src) -{ - int off = offsetof(struct compat_ipt_hashlimit_info, hinfo); - - memcpy(dst, src, off); - memset(dst + off, 0, sizeof(struct compat_ipt_hashlimit_info) - off); -} - -static int compat_to_user(void __user *dst, void *src) -{ - int off = offsetof(struct compat_ipt_hashlimit_info, hinfo); - - return copy_to_user(dst, src, off) ? -EFAULT : 0; -} -#endif - -static struct ipt_match ipt_hashlimit = { - .name = "hashlimit", - .match = hashlimit_match, - .matchsize = sizeof(struct ipt_hashlimit_info), -#ifdef CONFIG_COMPAT - .compatsize = sizeof(struct compat_ipt_hashlimit_info), - .compat_from_user = compat_from_user, - .compat_to_user = compat_to_user, -#endif - .checkentry = hashlimit_checkentry, - .destroy = hashlimit_destroy, - .me = THIS_MODULE -}; - -/* PROC stuff */ - -static void *dl_seq_start(struct seq_file *s, loff_t *pos) -{ - struct proc_dir_entry *pde = s->private; - struct ipt_hashlimit_htable *htable = pde->data; - unsigned int *bucket; - - spin_lock_bh(&htable->lock); - if (*pos >= htable->cfg.size) - return NULL; - - bucket = kmalloc(sizeof(unsigned int), GFP_ATOMIC); - if (!bucket) - return ERR_PTR(-ENOMEM); - - *bucket = *pos; - return bucket; -} - -static void *dl_seq_next(struct seq_file *s, void *v, loff_t *pos) -{ - struct proc_dir_entry *pde = s->private; - struct ipt_hashlimit_htable *htable = pde->data; - unsigned int *bucket = (unsigned int *)v; - - *pos = ++(*bucket); - if (*pos >= htable->cfg.size) { - kfree(v); - return NULL; - } - return bucket; -} - -static void dl_seq_stop(struct seq_file *s, void *v) -{ - struct proc_dir_entry *pde = s->private; - struct ipt_hashlimit_htable *htable = pde->data; - unsigned int *bucket = (unsigned int *)v; - - kfree(bucket); - - spin_unlock_bh(&htable->lock); -} - -static inline int dl_seq_real_show(struct dsthash_ent *ent, struct seq_file *s) -{ - /* recalculate to show accurate numbers */ - rateinfo_recalc(ent, jiffies); - - return seq_printf(s, "%ld %u.%u.%u.%u:%u->%u.%u.%u.%u:%u %u %u %u\n", - (long)(ent->expires - jiffies)/HZ, - NIPQUAD(ent->dst.src_ip), ntohs(ent->dst.src_port), - NIPQUAD(ent->dst.dst_ip), ntohs(ent->dst.dst_port), - ent->rateinfo.credit, ent->rateinfo.credit_cap, - ent->rateinfo.cost); -} - -static int dl_seq_show(struct seq_file *s, void *v) -{ - struct proc_dir_entry *pde = s->private; - struct ipt_hashlimit_htable *htable = pde->data; - unsigned int *bucket = (unsigned int *)v; - struct dsthash_ent *ent; - struct hlist_node *pos; - - if (!hlist_empty(&htable->hash[*bucket])) - hlist_for_each_entry(ent, pos, &htable->hash[*bucket], node) { - if (dl_seq_real_show(ent, s)) { - /* buffer was filled and unable to print that tuple */ - return 1; - } - } - - return 0; -} - -static struct seq_operations dl_seq_ops = { - .start = dl_seq_start, - .next = dl_seq_next, - .stop = dl_seq_stop, - .show = dl_seq_show -}; - -static int dl_proc_open(struct inode *inode, struct file *file) -{ - int ret = seq_open(file, &dl_seq_ops); - - if (!ret) { - struct seq_file *sf = file->private_data; - sf->private = PDE(inode); - } - return ret; -} - -static struct file_operations dl_file_ops = { - .owner = THIS_MODULE, - .open = dl_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release -}; - -static int init_or_fini(int fini) -{ - int ret = 0; - - if (fini) - goto cleanup; - - if (ipt_register_match(&ipt_hashlimit)) { - ret = -EINVAL; - goto cleanup_nothing; - } - - hashlimit_cachep = kmem_cache_create("ipt_hashlimit", - sizeof(struct dsthash_ent), 0, - 0, NULL, NULL); - if (!hashlimit_cachep) { - printk(KERN_ERR "Unable to create ipt_hashlimit slab cache\n"); - ret = -ENOMEM; - goto cleanup_unreg_match; - } - - hashlimit_procdir = proc_mkdir("ipt_hashlimit", proc_net); - if (!hashlimit_procdir) { - printk(KERN_ERR "Unable to create proc dir entry\n"); - ret = -ENOMEM; - goto cleanup_free_slab; - } - - return ret; - -cleanup: - remove_proc_entry("ipt_hashlimit", proc_net); -cleanup_free_slab: - kmem_cache_destroy(hashlimit_cachep); -cleanup_unreg_match: - ipt_unregister_match(&ipt_hashlimit); -cleanup_nothing: - return ret; - -} - -static int __init ipt_hashlimit_init(void) -{ - return init_or_fini(0); -} - -static void __exit ipt_hashlimit_fini(void) -{ - init_or_fini(1); -} - -module_init(ipt_hashlimit_init); -module_exit(ipt_hashlimit_fini); -- cgit v1.2.3 From baf7b1e11282127e068d149825cccec002091d61 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Wed, 29 Nov 2006 02:35:38 +0100 Subject: [NETFILTER]: x_tables: add NFLOG target Add new NFLOG target to allow use of nfnetlink_log for both IPv4 and IPv6. Currently we have two (unsupported by userspace) hacks in the LOG and ULOG targets to optionally call to the nflog API. They lack a few features, namely the IPv4 and IPv6 LOG targets can not specify a number of arguments related to nfnetlink_log, while the ULOG target is only available for IPv4. Remove those hacks and add a clean way to use nfnetlink_log. Signed-off-by: Patrick McHardy --- net/ipv4/netfilter/ipt_LOG.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/netfilter/ipt_LOG.c b/net/ipv4/netfilter/ipt_LOG.c index 46eee64a11f..c96de16fefa 100644 --- a/net/ipv4/netfilter/ipt_LOG.c +++ b/net/ipv4/netfilter/ipt_LOG.c @@ -430,13 +430,8 @@ ipt_log_target(struct sk_buff **pskb, li.u.log.level = loginfo->level; li.u.log.logflags = loginfo->logflags; - if (loginfo->logflags & IPT_LOG_NFLOG) - nf_log_packet(PF_INET, hooknum, *pskb, in, out, &li, - "%s", loginfo->prefix); - else - ipt_log_packet(PF_INET, hooknum, *pskb, in, out, &li, - loginfo->prefix); - + ipt_log_packet(PF_INET, hooknum, *pskb, in, out, &li, + loginfo->prefix); return IPT_CONTINUE; } -- cgit v1.2.3 From 65195686ff2f088a73c1764f4d30be5c7e0eb089 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Wed, 29 Nov 2006 02:35:41 +0100 Subject: [NETFILTER]: remove remaining ASSERT_{READ,WRITE}_LOCK Signed-off-by: Patrick McHardy --- net/ipv4/netfilter/ip_conntrack_core.c | 6 ------ net/ipv4/netfilter/ip_conntrack_proto_gre.c | 2 -- net/ipv4/netfilter/ip_conntrack_standalone.c | 4 ---- net/ipv4/netfilter/ipt_CLUSTERIP.c | 3 --- 4 files changed, 15 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/netfilter/ip_conntrack_core.c b/net/ipv4/netfilter/ip_conntrack_core.c index 4d1f954d459..f4b0e68a16d 100644 --- a/net/ipv4/netfilter/ip_conntrack_core.c +++ b/net/ipv4/netfilter/ip_conntrack_core.c @@ -40,9 +40,6 @@ /* ip_conntrack_lock protects the main hash table, protocol/helper/expected registrations, conntrack timers*/ -#define ASSERT_READ_LOCK(x) -#define ASSERT_WRITE_LOCK(x) - #include #include #include @@ -201,7 +198,6 @@ ip_ct_invert_tuple(struct ip_conntrack_tuple *inverse, /* ip_conntrack_expect helper functions */ void ip_ct_unlink_expect(struct ip_conntrack_expect *exp) { - ASSERT_WRITE_LOCK(&ip_conntrack_lock); IP_NF_ASSERT(!timer_pending(&exp->timeout)); list_del(&exp->list); CONNTRACK_STAT_INC(expect_delete); @@ -294,7 +290,6 @@ static void clean_from_lists(struct ip_conntrack *ct) { DEBUGP("clean_from_lists(%p)\n", ct); - ASSERT_WRITE_LOCK(&ip_conntrack_lock); list_del(&ct->tuplehash[IP_CT_DIR_ORIGINAL].list); list_del(&ct->tuplehash[IP_CT_DIR_REPLY].list); @@ -373,7 +368,6 @@ __ip_conntrack_find(const struct ip_conntrack_tuple *tuple, struct ip_conntrack_tuple_hash *h; unsigned int hash = hash_conntrack(tuple); - ASSERT_READ_LOCK(&ip_conntrack_lock); list_for_each_entry(h, &ip_conntrack_hash[hash], list) { if (tuplehash_to_ctrack(h) != ignored_conntrack && ip_ct_tuple_equal(tuple, &h->tuple)) { diff --git a/net/ipv4/netfilter/ip_conntrack_proto_gre.c b/net/ipv4/netfilter/ip_conntrack_proto_gre.c index 5fe026f467d..ac1c49ef36a 100644 --- a/net/ipv4/netfilter/ip_conntrack_proto_gre.c +++ b/net/ipv4/netfilter/ip_conntrack_proto_gre.c @@ -34,8 +34,6 @@ #include static DEFINE_RWLOCK(ip_ct_gre_lock); -#define ASSERT_READ_LOCK(x) -#define ASSERT_WRITE_LOCK(x) #include #include diff --git a/net/ipv4/netfilter/ip_conntrack_standalone.c b/net/ipv4/netfilter/ip_conntrack_standalone.c index 2df67538ffb..86efb544967 100644 --- a/net/ipv4/netfilter/ip_conntrack_standalone.c +++ b/net/ipv4/netfilter/ip_conntrack_standalone.c @@ -28,9 +28,6 @@ #include #include -#define ASSERT_READ_LOCK(x) -#define ASSERT_WRITE_LOCK(x) - #include #include #include @@ -139,7 +136,6 @@ static int ct_seq_show(struct seq_file *s, void *v) const struct ip_conntrack *conntrack = tuplehash_to_ctrack(hash); struct ip_conntrack_protocol *proto; - ASSERT_READ_LOCK(&ip_conntrack_lock); IP_NF_ASSERT(conntrack); /* we only want to print DIR_ORIGINAL */ diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c index 7a29d6e7baa..5d43a63e565 100644 --- a/net/ipv4/netfilter/ipt_CLUSTERIP.c +++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c @@ -40,8 +40,6 @@ #define DEBUGP #endif -#define ASSERT_READ_LOCK(x) - MODULE_LICENSE("GPL"); MODULE_AUTHOR("Harald Welte "); MODULE_DESCRIPTION("iptables target for CLUSTERIP"); @@ -123,7 +121,6 @@ __clusterip_config_find(__be32 clusterip) { struct list_head *pos; - ASSERT_READ_LOCK(&clusterip_lock); list_for_each(pos, &clusterip_configs) { struct clusterip_config *c = list_entry(pos, struct clusterip_config, list); -- cgit v1.2.3 From 76592584be7828cd314bc8d5dc7773ff1692fb99 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Wed, 29 Nov 2006 02:35:42 +0100 Subject: [NETFILTER]: Fix PROC_FS=n warnings Fix some unused function/variable warnings. Signed-off-by: Patrick McHardy --- net/ipv4/netfilter/ipt_CLUSTERIP.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c index 5d43a63e565..09836506223 100644 --- a/net/ipv4/netfilter/ipt_CLUSTERIP.c +++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c @@ -167,7 +167,6 @@ clusterip_config_init(struct ipt_clusterip_tgt_info *i, __be32 ip, struct net_device *dev) { struct clusterip_config *c; - char buffer[16]; c = kzalloc(sizeof(*c), GFP_ATOMIC); if (!c) @@ -184,12 +183,17 @@ clusterip_config_init(struct ipt_clusterip_tgt_info *i, __be32 ip, atomic_set(&c->entries, 1); #ifdef CONFIG_PROC_FS - /* create proc dir entry */ - sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(ip)); - c->pde = create_proc_entry(buffer, S_IWUSR|S_IRUSR, clusterip_procdir); - if (!c->pde) { - kfree(c); - return NULL; + { + char buffer[16]; + + /* create proc dir entry */ + sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(ip)); + c->pde = create_proc_entry(buffer, S_IWUSR|S_IRUSR, + clusterip_procdir); + if (!c->pde) { + kfree(c); + return NULL; + } } c->pde->proc_fops = &clusterip_proc_fops; c->pde->data = c; @@ -202,6 +206,7 @@ clusterip_config_init(struct ipt_clusterip_tgt_info *i, __be32 ip, return c; } +#ifdef CONFIG_PROC_FS static int clusterip_add_node(struct clusterip_config *c, u_int16_t nodenum) { @@ -229,6 +234,7 @@ clusterip_del_node(struct clusterip_config *c, u_int16_t nodenum) return 1; } +#endif static inline u_int32_t clusterip_hashfn(struct sk_buff *skb, struct clusterip_config *config) @@ -734,8 +740,10 @@ static int __init ipt_clusterip_init(void) CLUSTERIP_VERSION); return 0; +#ifdef CONFIG_PROC_FS cleanup_hook: nf_unregister_hook(&cip_arp_ops); +#endif /* CONFIG_PROC_FS */ cleanup_target: ipt_unregister_target(&clusterip_tgt); return ret; -- cgit v1.2.3 From 02752760359db6b00a3ffb1acfc13ef8d9eb1e3f Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Wed, 29 Nov 2006 13:18:18 -0500 Subject: NetLabel: convert to an extensibile/sparse category bitmap The original NetLabel category bitmap was a straight char bitmap which worked fine for the initial release as it only supported 240 bits due to limitations in the CIPSO restricted bitmap tag (tag type 0x01). This patch converts that straight char bitmap into an extensibile/sparse bitmap in order to lay the foundation for other CIPSO tag types and protocols. This patch also has a nice side effect in that all of the security attributes passed by NetLabel into the LSM are now in a format which is in the host's native byte/bit ordering which makes the LSM specific code much simpler; look at the changes in security/selinux/ss/ebitmap.c as an example. Signed-off-by: Paul Moore Signed-off-by: James Morris --- net/ipv4/cipso_ipv4.c | 168 +++++++++++++++++++++----------------------------- 1 file changed, 69 insertions(+), 99 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c index f3957cfaed4..08144f8fc91 100644 --- a/net/ipv4/cipso_ipv4.c +++ b/net/ipv4/cipso_ipv4.c @@ -819,8 +819,7 @@ static int cipso_v4_map_cat_rbm_valid(const struct cipso_v4_doi *doi_def, /** * cipso_v4_map_cat_rbm_hton - Perform a category mapping from host to network * @doi_def: the DOI definition - * @host_cat: the category bitmap in host format - * @host_cat_len: the length of the host's category bitmap in bytes + * @secattr: the security attributes * @net_cat: the zero'd out category bitmap in network/CIPSO format * @net_cat_len: the length of the CIPSO bitmap in bytes * @@ -831,61 +830,51 @@ static int cipso_v4_map_cat_rbm_valid(const struct cipso_v4_doi *doi_def, * */ static int cipso_v4_map_cat_rbm_hton(const struct cipso_v4_doi *doi_def, - const unsigned char *host_cat, - u32 host_cat_len, + const struct netlbl_lsm_secattr *secattr, unsigned char *net_cat, u32 net_cat_len) { int host_spot = -1; - u32 net_spot; + u32 net_spot = CIPSO_V4_INV_CAT; u32 net_spot_max = 0; - u32 host_clen_bits = host_cat_len * 8; u32 net_clen_bits = net_cat_len * 8; - u32 host_cat_size; - u32 *host_cat_array; + u32 host_cat_size = 0; + u32 *host_cat_array = NULL; - switch (doi_def->type) { - case CIPSO_V4_MAP_PASS: - net_spot_max = host_cat_len; - while (net_spot_max > 0 && host_cat[net_spot_max - 1] == 0) - net_spot_max--; - if (net_spot_max > net_cat_len) - return -EINVAL; - memcpy(net_cat, host_cat, net_spot_max); - return net_spot_max; - case CIPSO_V4_MAP_STD: + if (doi_def->type == CIPSO_V4_MAP_STD) { host_cat_size = doi_def->map.std->cat.local_size; host_cat_array = doi_def->map.std->cat.local; - for (;;) { - host_spot = cipso_v4_bitmap_walk(host_cat, - host_clen_bits, - host_spot + 1, - 1); - if (host_spot < 0) - break; + } + + for (;;) { + host_spot = netlbl_secattr_catmap_walk(secattr->mls_cat, + host_spot + 1); + if (host_spot < 0) + break; + + switch (doi_def->type) { + case CIPSO_V4_MAP_PASS: + net_spot = host_spot; + break; + case CIPSO_V4_MAP_STD: if (host_spot >= host_cat_size) return -EPERM; - net_spot = host_cat_array[host_spot]; if (net_spot >= CIPSO_V4_INV_CAT) return -EPERM; - if (net_spot >= net_clen_bits) - return -ENOSPC; - cipso_v4_bitmap_setbit(net_cat, net_spot, 1); - - if (net_spot > net_spot_max) - net_spot_max = net_spot; + break; } + if (net_spot >= net_clen_bits) + return -ENOSPC; + cipso_v4_bitmap_setbit(net_cat, net_spot, 1); - if (host_spot == -2) - return -EFAULT; - - if (++net_spot_max % 8) - return net_spot_max / 8 + 1; - return net_spot_max / 8; + if (net_spot > net_spot_max) + net_spot_max = net_spot; } - return -EINVAL; + if (++net_spot_max % 8) + return net_spot_max / 8 + 1; + return net_spot_max / 8; } /** @@ -893,66 +882,59 @@ static int cipso_v4_map_cat_rbm_hton(const struct cipso_v4_doi *doi_def, * @doi_def: the DOI definition * @net_cat: the category bitmap in network/CIPSO format * @net_cat_len: the length of the CIPSO bitmap in bytes - * @host_cat: the zero'd out category bitmap in host format - * @host_cat_len: the length of the host's category bitmap in bytes + * @secattr: the security attributes * * Description: * Perform a label mapping to translate a CIPSO bitmap to the correct local - * MLS category bitmap using the given DOI definition. Returns the minimum - * size in bytes of the host bitmap on success, negative values otherwise. + * MLS category bitmap using the given DOI definition. Returns zero on + * success, negative values on failure. * */ static int cipso_v4_map_cat_rbm_ntoh(const struct cipso_v4_doi *doi_def, const unsigned char *net_cat, u32 net_cat_len, - unsigned char *host_cat, - u32 host_cat_len) + struct netlbl_lsm_secattr *secattr) { - u32 host_spot; - u32 host_spot_max = 0; + int ret_val; int net_spot = -1; + u32 host_spot = CIPSO_V4_INV_CAT; u32 net_clen_bits = net_cat_len * 8; - u32 host_clen_bits = host_cat_len * 8; - u32 net_cat_size; - u32 *net_cat_array; + u32 net_cat_size = 0; + u32 *net_cat_array = NULL; - switch (doi_def->type) { - case CIPSO_V4_MAP_PASS: - if (net_cat_len > host_cat_len) - return -EINVAL; - memcpy(host_cat, net_cat, net_cat_len); - return net_cat_len; - case CIPSO_V4_MAP_STD: + if (doi_def->type == CIPSO_V4_MAP_STD) { net_cat_size = doi_def->map.std->cat.cipso_size; net_cat_array = doi_def->map.std->cat.cipso; - for (;;) { - net_spot = cipso_v4_bitmap_walk(net_cat, - net_clen_bits, - net_spot + 1, - 1); - if (net_spot < 0) - break; - if (net_spot >= net_cat_size || - net_cat_array[net_spot] >= CIPSO_V4_INV_CAT) - return -EPERM; + } + for (;;) { + net_spot = cipso_v4_bitmap_walk(net_cat, + net_clen_bits, + net_spot + 1, + 1); + if (net_spot < 0) { + if (net_spot == -2) + return -EFAULT; + return 0; + } + + switch (doi_def->type) { + case CIPSO_V4_MAP_PASS: + host_spot = net_spot; + break; + case CIPSO_V4_MAP_STD: + if (net_spot >= net_cat_size) + return -EPERM; host_spot = net_cat_array[net_spot]; if (host_spot >= CIPSO_V4_INV_CAT) return -EPERM; - if (host_spot >= host_clen_bits) - return -ENOSPC; - cipso_v4_bitmap_setbit(host_cat, host_spot, 1); - - if (host_spot > host_spot_max) - host_spot_max = host_spot; + break; } - - if (net_spot == -2) - return -EFAULT; - - if (++host_spot_max % 8) - return host_spot_max / 8 + 1; - return host_spot_max / 8; + ret_val = netlbl_secattr_catmap_setbit(secattr->mls_cat, + host_spot, + GFP_ATOMIC); + if (ret_val != 0) + return ret_val; } return -EINVAL; @@ -1016,8 +998,7 @@ static int cipso_v4_gentag_rbm(const struct cipso_v4_doi *doi_def, if (secattr->flags & NETLBL_SECATTR_MLS_CAT) { ret_val = cipso_v4_map_cat_rbm_hton(doi_def, - secattr->mls_cat, - secattr->mls_cat_len, + secattr, &buffer[4], buffer_len - 4); if (ret_val < 0) @@ -1067,31 +1048,20 @@ static int cipso_v4_parsetag_rbm(const struct cipso_v4_doi *doi_def, secattr->flags |= NETLBL_SECATTR_MLS_LVL; if (tag_len > 4) { - switch (doi_def->type) { - case CIPSO_V4_MAP_PASS: - secattr->mls_cat_len = tag_len - 4; - break; - case CIPSO_V4_MAP_STD: - secattr->mls_cat_len = - doi_def->map.std->cat.local_size; - break; - } - secattr->mls_cat = kzalloc(secattr->mls_cat_len, GFP_ATOMIC); + secattr->mls_cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC); if (secattr->mls_cat == NULL) return -ENOMEM; ret_val = cipso_v4_map_cat_rbm_ntoh(doi_def, &tag[4], tag_len - 4, - secattr->mls_cat, - secattr->mls_cat_len); - if (ret_val < 0) { - kfree(secattr->mls_cat); + secattr); + if (ret_val != 0) { + netlbl_secattr_catmap_free(secattr->mls_cat); return ret_val; - } else if (ret_val > 0) { - secattr->mls_cat_len = ret_val; - secattr->flags |= NETLBL_SECATTR_MLS_CAT; } + + secattr->flags |= NETLBL_SECATTR_MLS_CAT; } return 0; -- cgit v1.2.3 From 654bbc2a2b87185630d05b79cc0db0e9364bb7e0 Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Wed, 29 Nov 2006 13:18:19 -0500 Subject: NetLabel: add the enumerated tag to the CIPSOv4 protocol Add support for the enumerated tag (tag type #2) to the CIPSOv4 protocol. The enumerated tag allows for 15 categories to be specified in a CIPSO option, where each category is an unsigned 16 bit field with a maximum value of 65534. See Documentation/netlabel/draft-ietf-cipso-ipsecurity-01.txt for more details. Signed-off-by: Paul Moore Signed-off-by: James Morris --- net/ipv4/cipso_ipv4.c | 233 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 233 insertions(+) (limited to 'net/ipv4') diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c index 08144f8fc91..70858dccaca 100644 --- a/net/ipv4/cipso_ipv4.c +++ b/net/ipv4/cipso_ipv4.c @@ -459,6 +459,10 @@ int cipso_v4_doi_add(struct cipso_v4_doi *doi_def) if (iter == 0) return -EINVAL; break; + case CIPSO_V4_TAG_ENUM: + if (doi_def->type != CIPSO_V4_MAP_PASS) + return -EINVAL; + break; default: return -EINVAL; } @@ -940,6 +944,107 @@ static int cipso_v4_map_cat_rbm_ntoh(const struct cipso_v4_doi *doi_def, return -EINVAL; } +/** + * cipso_v4_map_cat_enum_valid - Checks to see if the categories are valid + * @doi_def: the DOI definition + * @enumcat: category list + * @enumcat_len: length of the category list in bytes + * + * Description: + * Checks the given categories against the given DOI definition and returns a + * negative value if any of the categories do not have a valid mapping and a + * zero value if all of the categories are valid. + * + */ +static int cipso_v4_map_cat_enum_valid(const struct cipso_v4_doi *doi_def, + const unsigned char *enumcat, + u32 enumcat_len) +{ + u16 cat; + int cat_prev = -1; + u32 iter; + + if (doi_def->type != CIPSO_V4_MAP_PASS || enumcat_len & 0x01) + return -EFAULT; + + for (iter = 0; iter < enumcat_len; iter += 2) { + cat = ntohs(*((__be16 *)&enumcat[iter])); + if (cat <= cat_prev) + return -EFAULT; + cat_prev = cat; + } + + return 0; +} + +/** + * cipso_v4_map_cat_enum_hton - Perform a category mapping from host to network + * @doi_def: the DOI definition + * @secattr: the security attributes + * @net_cat: the zero'd out category list in network/CIPSO format + * @net_cat_len: the length of the CIPSO category list in bytes + * + * Description: + * Perform a label mapping to translate a local MLS category bitmap to the + * correct CIPSO category list using the given DOI definition. Returns the + * size in bytes of the network category bitmap on success, negative values + * otherwise. + * + */ +static int cipso_v4_map_cat_enum_hton(const struct cipso_v4_doi *doi_def, + const struct netlbl_lsm_secattr *secattr, + unsigned char *net_cat, + u32 net_cat_len) +{ + int cat = -1; + u32 cat_iter = 0; + + for (;;) { + cat = netlbl_secattr_catmap_walk(secattr->mls_cat, cat + 1); + if (cat < 0) + break; + if ((cat_iter + 2) > net_cat_len) + return -ENOSPC; + + *((__be16 *)&net_cat[cat_iter]) = htons(cat); + cat_iter += 2; + } + + return cat_iter; +} + +/** + * cipso_v4_map_cat_enum_ntoh - Perform a category mapping from network to host + * @doi_def: the DOI definition + * @net_cat: the category list in network/CIPSO format + * @net_cat_len: the length of the CIPSO bitmap in bytes + * @secattr: the security attributes + * + * Description: + * Perform a label mapping to translate a CIPSO category list to the correct + * local MLS category bitmap using the given DOI definition. Returns zero on + * success, negative values on failure. + * + */ +static int cipso_v4_map_cat_enum_ntoh(const struct cipso_v4_doi *doi_def, + const unsigned char *net_cat, + u32 net_cat_len, + struct netlbl_lsm_secattr *secattr) +{ + int ret_val; + u32 iter; + + for (iter = 0; iter < net_cat_len; iter += 2) { + ret_val = netlbl_secattr_catmap_setbit(secattr->mls_cat, + ntohs(*((__be16 *)&net_cat[iter])), + GFP_ATOMIC); + if (ret_val != 0) + return ret_val; + } + + return 0; +} + /* * Protocol Handling Functions */ @@ -1067,6 +1172,99 @@ static int cipso_v4_parsetag_rbm(const struct cipso_v4_doi *doi_def, return 0; } +/** + * cipso_v4_gentag_enum - Generate a CIPSO enumerated tag (type #2) + * @doi_def: the DOI definition + * @secattr: the security attributes + * @buffer: the option buffer + * @buffer_len: length of buffer in bytes + * + * Description: + * Generate a CIPSO option using the enumerated tag, tag type #2. Returns the + * size of the tag on success, negative values on failure. + * + */ +static int cipso_v4_gentag_enum(const struct cipso_v4_doi *doi_def, + const struct netlbl_lsm_secattr *secattr, + unsigned char *buffer, + u32 buffer_len) +{ + int ret_val; + u32 tag_len; + u32 level; + + if (!(secattr->flags & NETLBL_SECATTR_MLS_LVL)) + return -EPERM; + + ret_val = cipso_v4_map_lvl_hton(doi_def, secattr->mls_lvl, &level); + if (ret_val != 0) + return ret_val; + + if (secattr->flags & NETLBL_SECATTR_MLS_CAT) { + ret_val = cipso_v4_map_cat_enum_hton(doi_def, + secattr, + &buffer[4], + buffer_len - 4); + if (ret_val < 0) + return ret_val; + + tag_len = 4 + ret_val; + } else + tag_len = 4; + + buffer[0] = 0x02; + buffer[1] = tag_len; + buffer[3] = level; + + return tag_len; +} + +/** + * cipso_v4_parsetag_enum - Parse a CIPSO enumerated tag + * @doi_def: the DOI definition + * @tag: the CIPSO tag + * @secattr: the security attributes + * + * Description: + * Parse a CIPSO enumerated tag (tag type #2) and return the security + * attributes in @secattr. Return zero on success, negatives values on + * failure. + * + */ +static int cipso_v4_parsetag_enum(const struct cipso_v4_doi *doi_def, + const unsigned char *tag, + struct netlbl_lsm_secattr *secattr) +{ + int ret_val; + u8 tag_len = tag[1]; + u32 level; + + ret_val = cipso_v4_map_lvl_ntoh(doi_def, tag[3], &level); + if (ret_val != 0) + return ret_val; + secattr->mls_lvl = level; + secattr->flags |= NETLBL_SECATTR_MLS_LVL; + + if (tag_len > 4) { + secattr->mls_cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC); + if (secattr->mls_cat == NULL) + return -ENOMEM; + + ret_val = cipso_v4_map_cat_enum_ntoh(doi_def, + &tag[4], + tag_len - 4, + secattr); + if (ret_val != 0) { + netlbl_secattr_catmap_free(secattr->mls_cat); + return ret_val; + } + + secattr->flags |= NETLBL_SECATTR_MLS_CAT; + } + + return 0; +} + /** * cipso_v4_validate - Validate a CIPSO option * @option: the start of the option, on error it is set to point to the error @@ -1156,6 +1354,25 @@ int cipso_v4_validate(unsigned char **option) } } break; + case CIPSO_V4_TAG_ENUM: + if (tag_len < 4) { + err_offset = opt_iter + 1; + goto validate_return_locked; + } + + if (cipso_v4_map_lvl_valid(doi_def, + tag[3]) < 0) { + err_offset = opt_iter + 3; + goto validate_return_locked; + } + if (tag_len > 4 && + cipso_v4_map_cat_enum_valid(doi_def, + &tag[4], + tag_len - 4) < 0) { + err_offset = opt_iter + 4; + goto validate_return_locked; + } + break; default: err_offset = opt_iter; goto validate_return_locked; @@ -1269,6 +1486,12 @@ int cipso_v4_socket_setattr(const struct socket *sock, &buf[CIPSO_V4_HDR_LEN], buf_len - CIPSO_V4_HDR_LEN); break; + case CIPSO_V4_TAG_ENUM: + ret_val = cipso_v4_gentag_enum(doi_def, + secattr, + &buf[CIPSO_V4_HDR_LEN], + buf_len - CIPSO_V4_HDR_LEN); + break; default: ret_val = -EPERM; goto socket_setattr_failure; @@ -1365,6 +1588,11 @@ int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr) &cipso_ptr[6], secattr); break; + case CIPSO_V4_TAG_ENUM: + ret_val = cipso_v4_parsetag_enum(doi_def, + &cipso_ptr[6], + secattr); + break; } rcu_read_unlock(); @@ -1431,6 +1659,11 @@ int cipso_v4_skbuff_getattr(const struct sk_buff *skb, &cipso_ptr[6], secattr); break; + case CIPSO_V4_TAG_ENUM: + ret_val = cipso_v4_parsetag_enum(doi_def, + &cipso_ptr[6], + secattr); + break; } skbuff_getattr_return: -- cgit v1.2.3 From 484b366932be0b73a22c74a82748ca10a721643e Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Wed, 29 Nov 2006 13:18:20 -0500 Subject: NetLabel: add the ranged tag to the CIPSOv4 protocol Add support for the ranged tag (tag type #5) to the CIPSOv4 protocol. The ranged tag allows for seven, or eight if zero is the lowest category, category ranges to be specified in a CIPSO option. Each range is specified by two unsigned 16 bit fields, each with a maximum value of 65534. The two values specify the start and end of the category range; if the start of the category range is zero then it is omitted. See Documentation/netlabel/draft-ietf-cipso-ipsecurity-01.txt for more details. Signed-off-by: Paul Moore Signed-off-by: James Morris --- net/ipv4/cipso_ipv4.c | 268 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 268 insertions(+) (limited to 'net/ipv4') diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c index 70858dccaca..60aafb4a8ad 100644 --- a/net/ipv4/cipso_ipv4.c +++ b/net/ipv4/cipso_ipv4.c @@ -455,6 +455,10 @@ int cipso_v4_doi_add(struct cipso_v4_doi *doi_def) switch (doi_def->tags[iter]) { case CIPSO_V4_TAG_RBITMAP: break; + case CIPSO_V4_TAG_RANGE: + if (doi_def->type != CIPSO_V4_MAP_PASS) + return -EINVAL; + break; case CIPSO_V4_TAG_INVALID: if (iter == 0) return -EINVAL; @@ -1045,6 +1049,148 @@ static int cipso_v4_map_cat_enum_ntoh(const struct cipso_v4_doi *doi_def, return 0; } +/** + * cipso_v4_map_cat_rng_valid - Checks to see if the categories are valid + * @doi_def: the DOI definition + * @rngcat: category list + * @rngcat_len: length of the category list in bytes + * + * Description: + * Checks the given categories against the given DOI definition and returns a + * negative value if any of the categories do not have a valid mapping and a + * zero value if all of the categories are valid. + * + */ +static int cipso_v4_map_cat_rng_valid(const struct cipso_v4_doi *doi_def, + const unsigned char *rngcat, + u32 rngcat_len) +{ + u16 cat_high; + u16 cat_low; + u32 cat_prev = CIPSO_V4_MAX_REM_CATS + 1; + u32 iter; + + if (doi_def->type != CIPSO_V4_MAP_PASS || rngcat_len & 0x01) + return -EFAULT; + + for (iter = 0; iter < rngcat_len; iter += 4) { + cat_high = ntohs(*((__be16 *)&rngcat[iter])); + if ((iter + 4) <= rngcat_len) + cat_low = ntohs(*((__be16 *)&rngcat[iter + 2])); + else + cat_low = 0; + + if (cat_high > cat_prev) + return -EFAULT; + + cat_prev = cat_low; + } + + return 0; +} + +/** + * cipso_v4_map_cat_rng_hton - Perform a category mapping from host to network + * @doi_def: the DOI definition + * @secattr: the security attributes + * @net_cat: the zero'd out category list in network/CIPSO format + * @net_cat_len: the length of the CIPSO category list in bytes + * + * Description: + * Perform a label mapping to translate a local MLS category bitmap to the + * correct CIPSO category list using the given DOI definition. Returns the + * size in bytes of the network category bitmap on success, negative values + * otherwise. + * + */ +static int cipso_v4_map_cat_rng_hton(const struct cipso_v4_doi *doi_def, + const struct netlbl_lsm_secattr *secattr, + unsigned char *net_cat, + u32 net_cat_len) +{ + /* The constant '16' is not random, it is the maximum number of + * high/low category range pairs as permitted by the CIPSO draft based + * on a maximum IPv4 header length of 60 bytes - the BUG_ON() assertion + * does a sanity check to make sure we don't overflow the array. */ + int iter = -1; + u16 array[16]; + u32 array_cnt = 0; + u32 cat_size = 0; + + BUG_ON(net_cat_len > 30); + + for (;;) { + iter = netlbl_secattr_catmap_walk(secattr->mls_cat, iter + 1); + if (iter < 0) + break; + cat_size += (iter == 0 ? 0 : sizeof(u16)); + if (cat_size > net_cat_len) + return -ENOSPC; + array[array_cnt++] = iter; + + iter = netlbl_secattr_catmap_walk_rng(secattr->mls_cat, iter); + if (iter < 0) + return -EFAULT; + cat_size += sizeof(u16); + if (cat_size > net_cat_len) + return -ENOSPC; + array[array_cnt++] = iter; + } + + for (iter = 0; array_cnt > 0;) { + *((__be16 *)&net_cat[iter]) = htons(array[--array_cnt]); + iter += 2; + array_cnt--; + if (array[array_cnt] != 0) { + *((__be16 *)&net_cat[iter]) = htons(array[array_cnt]); + iter += 2; + } + } + + return cat_size; +} + +/** + * cipso_v4_map_cat_rng_ntoh - Perform a category mapping from network to host + * @doi_def: the DOI definition + * @net_cat: the category list in network/CIPSO format + * @net_cat_len: the length of the CIPSO bitmap in bytes + * @secattr: the security attributes + * + * Description: + * Perform a label mapping to translate a CIPSO category list to the correct + * local MLS category bitmap using the given DOI definition. Returns zero on + * success, negative values on failure. + * + */ +static int cipso_v4_map_cat_rng_ntoh(const struct cipso_v4_doi *doi_def, + const unsigned char *net_cat, + u32 net_cat_len, + struct netlbl_lsm_secattr *secattr) +{ + int ret_val; + u32 net_iter; + u16 cat_low; + u16 cat_high; + + for(net_iter = 0; net_iter < net_cat_len; net_iter += 4) { + cat_high = ntohs(*((__be16 *)&net_cat[net_iter])); + if ((net_iter + 4) <= net_cat_len) + cat_low = ntohs(*((__be16 *)&net_cat[net_iter + 2])); + else + cat_low = 0; + + ret_val = netlbl_secattr_catmap_setrng(secattr->mls_cat, + cat_low, + cat_high, + GFP_ATOMIC); + if (ret_val != 0) + return ret_val; + } + + return 0; +} + /* * Protocol Handling Functions */ @@ -1265,6 +1411,98 @@ static int cipso_v4_parsetag_enum(const struct cipso_v4_doi *doi_def, return 0; } +/** + * cipso_v4_gentag_rng - Generate a CIPSO ranged tag (type #5) + * @doi_def: the DOI definition + * @secattr: the security attributes + * @buffer: the option buffer + * @buffer_len: length of buffer in bytes + * + * Description: + * Generate a CIPSO option using the ranged tag, tag type #5. Returns the + * size of the tag on success, negative values on failure. + * + */ +static int cipso_v4_gentag_rng(const struct cipso_v4_doi *doi_def, + const struct netlbl_lsm_secattr *secattr, + unsigned char *buffer, + u32 buffer_len) +{ + int ret_val; + u32 tag_len; + u32 level; + + if (!(secattr->flags & NETLBL_SECATTR_MLS_LVL)) + return -EPERM; + + ret_val = cipso_v4_map_lvl_hton(doi_def, secattr->mls_lvl, &level); + if (ret_val != 0) + return ret_val; + + if (secattr->flags & NETLBL_SECATTR_MLS_CAT) { + ret_val = cipso_v4_map_cat_rng_hton(doi_def, + secattr, + &buffer[4], + buffer_len - 4); + if (ret_val < 0) + return ret_val; + + tag_len = 4 + ret_val; + } else + tag_len = 4; + + buffer[0] = 0x05; + buffer[1] = tag_len; + buffer[3] = level; + + return tag_len; +} + +/** + * cipso_v4_parsetag_rng - Parse a CIPSO ranged tag + * @doi_def: the DOI definition + * @tag: the CIPSO tag + * @secattr: the security attributes + * + * Description: + * Parse a CIPSO ranged tag (tag type #5) and return the security attributes + * in @secattr. Return zero on success, negatives values on failure. + * + */ +static int cipso_v4_parsetag_rng(const struct cipso_v4_doi *doi_def, + const unsigned char *tag, + struct netlbl_lsm_secattr *secattr) +{ + int ret_val; + u8 tag_len = tag[1]; + u32 level; + + ret_val = cipso_v4_map_lvl_ntoh(doi_def, tag[3], &level); + if (ret_val != 0) + return ret_val; + secattr->mls_lvl = level; + secattr->flags |= NETLBL_SECATTR_MLS_LVL; + + if (tag_len > 4) { + secattr->mls_cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC); + if (secattr->mls_cat == NULL) + return -ENOMEM; + + ret_val = cipso_v4_map_cat_rng_ntoh(doi_def, + &tag[4], + tag_len - 4, + secattr); + if (ret_val != 0) { + netlbl_secattr_catmap_free(secattr->mls_cat); + return ret_val; + } + + secattr->flags |= NETLBL_SECATTR_MLS_CAT; + } + + return 0; +} + /** * cipso_v4_validate - Validate a CIPSO option * @option: the start of the option, on error it is set to point to the error @@ -1373,6 +1611,25 @@ int cipso_v4_validate(unsigned char **option) goto validate_return_locked; } break; + case CIPSO_V4_TAG_RANGE: + if (tag_len < 4) { + err_offset = opt_iter + 1; + goto validate_return_locked; + } + + if (cipso_v4_map_lvl_valid(doi_def, + tag[3]) < 0) { + err_offset = opt_iter + 3; + goto validate_return_locked; + } + if (tag_len > 4 && + cipso_v4_map_cat_rng_valid(doi_def, + &tag[4], + tag_len - 4) < 0) { + err_offset = opt_iter + 4; + goto validate_return_locked; + } + break; default: err_offset = opt_iter; goto validate_return_locked; @@ -1492,6 +1749,12 @@ int cipso_v4_socket_setattr(const struct socket *sock, &buf[CIPSO_V4_HDR_LEN], buf_len - CIPSO_V4_HDR_LEN); break; + case CIPSO_V4_TAG_RANGE: + ret_val = cipso_v4_gentag_rng(doi_def, + secattr, + &buf[CIPSO_V4_HDR_LEN], + buf_len - CIPSO_V4_HDR_LEN); + break; default: ret_val = -EPERM; goto socket_setattr_failure; @@ -1593,6 +1856,11 @@ int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr) &cipso_ptr[6], secattr); break; + case CIPSO_V4_TAG_RANGE: + ret_val = cipso_v4_parsetag_rng(doi_def, + &cipso_ptr[6], + secattr); + break; } rcu_read_unlock(); -- cgit v1.2.3 From 08dd1a506bbc4528db60dfdfff61423a1608ed3f Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 30 Nov 2006 16:35:01 -0800 Subject: [TCP] MD5SIG: Kill CONFIG_TCP_MD5SIG_DEBUG. It just obfuscates the code and adds limited value. And as Adrian Bunk noticed, it lacked Kconfig help text too, so just kill it. Signed-off-by: David S. Miller --- net/ipv4/Kconfig | 4 ---- net/ipv4/tcp_ipv4.c | 41 +---------------------------------------- 2 files changed, 1 insertion(+), 44 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig index 39e0cb76358..503e7059e31 100644 --- a/net/ipv4/Kconfig +++ b/net/ipv4/Kconfig @@ -630,9 +630,5 @@ config TCP_MD5SIG If unsure, say N. -config TCP_MD5SIG_DEBUG - bool "TCP: MD5 Signature Option debugging" - depends on TCP_MD5SIG - source "net/ipv4/ipvs/Kconfig" diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 4913f25e5ad..dd3509a59fe 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1017,9 +1017,6 @@ static int tcp_v4_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, struct scatterlist sg[4]; __u16 data_len; int block = 0; -#ifdef CONFIG_TCP_MD5SIG_DEBUG - int i; -#endif __sum16 old_checksum; struct tcp_md5sig_pool *hp; struct tcp4_pseudohdr *bp; @@ -1052,13 +1049,6 @@ static int tcp_v4_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, sg_set_buf(&sg[block++], bp, sizeof(*bp)); nbytes += sizeof(*bp); -#ifdef CONFIG_TCP_MD5SIG_DEBUG - printk("Calcuating hash for: "); - for (i = 0; i < sizeof(*bp); i++) - printk("%02x ", (unsigned int)((unsigned char *)bp)[i]); - printk(" "); -#endif - /* 2. the TCP header, excluding options, and assuming a * checksum of zero/ */ @@ -1066,10 +1056,7 @@ static int tcp_v4_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, th->check = 0; sg_set_buf(&sg[block++], th, sizeof(struct tcphdr)); nbytes += sizeof(struct tcphdr); -#ifdef CONFIG_TCP_MD5SIG_DEBUG - for (i = 0; i < sizeof(struct tcphdr); i++) - printk(" %02x", (unsigned int)((unsigned char *)th)[i]); -#endif + /* 3. the TCP segment data (if any) */ data_len = tcplen - (th->doff << 2); if (data_len > 0) { @@ -1084,12 +1071,6 @@ static int tcp_v4_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, sg_set_buf(&sg[block++], key->key, key->keylen); nbytes += key->keylen; -#ifdef CONFIG_TCP_MD5SIG_DEBUG - printk(" and password: "); - for (i = 0; i < key->keylen; i++) - printk("%02x ", (unsigned int)key->key[i]); -#endif - /* Now store the Hash into the packet */ err = crypto_hash_init(desc); if (err) @@ -1106,12 +1087,6 @@ static int tcp_v4_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, th->check = old_checksum; out: -#ifdef CONFIG_TCP_MD5SIG_DEBUG - printk(" result:"); - for (i = 0; i < 16; i++) - printk(" %02x", (unsigned int)(((u8*)md5_hash)[i])); - printk("\n"); -#endif return 0; clear_hash: tcp_put_md5sig_pool(); @@ -1241,20 +1216,6 @@ done_opts: NIPQUAD(iph->saddr), ntohs(th->source), NIPQUAD(iph->daddr), ntohs(th->dest), genhash ? " tcp_v4_calc_md5_hash failed" : ""); -#ifdef CONFIG_TCP_MD5SIG_DEBUG - do { - int i; - printk("Received: "); - for (i = 0; i < 16; i++) - printk("%02x ", - 0xff & (int)hash_location[i]); - printk("\n"); - printk("Calculated: "); - for (i = 0; i < 16; i++) - printk("%02x ", 0xff & (int)newhash[i]); - printk("\n"); - } while(0); -#endif } return 1; } -- cgit v1.2.3 From f5b99bcdddfb2338227faad3489c24907f37ee8e Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Thu, 30 Nov 2006 17:22:29 -0800 Subject: [NET]: Possible cleanups. This patch contains the following possible cleanups: - make the following needlessly global functions statis: - ipv4/tcp.c: __tcp_alloc_md5sig_pool() - ipv4/tcp_ipv4.c: tcp_v4_reqsk_md5_lookup() - ipv4/udplite.c: udplite_rcv() - ipv4/udplite.c: udplite_err() - make the following needlessly global structs static: - ipv4/tcp_ipv4.c: tcp_request_sock_ipv4_ops - ipv4/tcp_ipv4.c: tcp_sock_ipv4_specific - ipv6/tcp_ipv6.c: tcp_request_sock_ipv6_ops - net/ipv{4,6}/udplite.c: remove inline's from static functions (gcc should know best when to inline them) Signed-off-by: Adrian Bunk Signed-off-by: David S. Miller --- net/ipv4/tcp.c | 2 +- net/ipv4/tcp_ipv4.c | 8 ++++---- net/ipv4/udplite.c | 10 +++++----- 3 files changed, 10 insertions(+), 10 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index a6b228914b8..090c690627e 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -2278,7 +2278,7 @@ void tcp_free_md5sig_pool(void) EXPORT_SYMBOL(tcp_free_md5sig_pool); -struct tcp_md5sig_pool **__tcp_alloc_md5sig_pool(void) +static struct tcp_md5sig_pool **__tcp_alloc_md5sig_pool(void) { int cpu; struct tcp_md5sig_pool **pool; diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index dd3509a59fe..7684297d80a 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -840,8 +840,8 @@ struct tcp_md5sig_key *tcp_v4_md5_lookup(struct sock *sk, EXPORT_SYMBOL(tcp_v4_md5_lookup); -struct tcp_md5sig_key *tcp_v4_reqsk_md5_lookup(struct sock *sk, - struct request_sock *req) +static struct tcp_md5sig_key *tcp_v4_reqsk_md5_lookup(struct sock *sk, + struct request_sock *req) { return tcp_v4_md5_do_lookup(sk, inet_rsk(req)->rmt_addr); } @@ -1233,7 +1233,7 @@ struct request_sock_ops tcp_request_sock_ops __read_mostly = { .send_reset = tcp_v4_send_reset, }; -struct tcp_request_sock_ops tcp_request_sock_ipv4_ops = { +static struct tcp_request_sock_ops tcp_request_sock_ipv4_ops = { #ifdef CONFIG_TCP_MD5SIG .md5_lookup = tcp_v4_reqsk_md5_lookup, #endif @@ -1820,7 +1820,7 @@ struct inet_connection_sock_af_ops ipv4_specific = { #endif }; -struct tcp_sock_af_ops tcp_sock_ipv4_specific = { +static struct tcp_sock_af_ops tcp_sock_ipv4_specific = { #ifdef CONFIG_TCP_MD5SIG .md5_lookup = tcp_v4_md5_lookup, .calc_md5_hash = tcp_v4_calc_md5_hash, diff --git a/net/ipv4/udplite.c b/net/ipv4/udplite.c index 561de6d8c73..b28fe1edf98 100644 --- a/net/ipv4/udplite.c +++ b/net/ipv4/udplite.c @@ -18,23 +18,23 @@ DEFINE_SNMP_STAT(struct udp_mib, udplite_statistics) __read_mostly; struct hlist_head udplite_hash[UDP_HTABLE_SIZE]; static int udplite_port_rover; -__inline__ int udplite_get_port(struct sock *sk, unsigned short p, - int (*c)(const struct sock *, const struct sock *)) +int udplite_get_port(struct sock *sk, unsigned short p, + int (*c)(const struct sock *, const struct sock *)) { return __udp_lib_get_port(sk, p, udplite_hash, &udplite_port_rover, c); } -static __inline__ int udplite_v4_get_port(struct sock *sk, unsigned short snum) +static int udplite_v4_get_port(struct sock *sk, unsigned short snum) { return udplite_get_port(sk, snum, ipv4_rcv_saddr_equal); } -__inline__ int udplite_rcv(struct sk_buff *skb) +static int udplite_rcv(struct sk_buff *skb) { return __udp4_lib_rcv(skb, udplite_hash, 1); } -__inline__ void udplite_err(struct sk_buff *skb, u32 info) +static void udplite_err(struct sk_buff *skb, u32 info) { return __udp4_lib_err(skb, info, udplite_hash); } -- cgit v1.2.3 From b6332e6cf9c9198c0f3b0fe37c2c57514dafe1b8 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Thu, 30 Nov 2006 19:16:28 -0800 Subject: [TCP]: Fix warnings with TCP_MD5SIG disabled. Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- net/ipv4/tcp_ipv4.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 7684297d80a..a1222d6968c 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1233,11 +1233,11 @@ struct request_sock_ops tcp_request_sock_ops __read_mostly = { .send_reset = tcp_v4_send_reset, }; -static struct tcp_request_sock_ops tcp_request_sock_ipv4_ops = { #ifdef CONFIG_TCP_MD5SIG +static struct tcp_request_sock_ops tcp_request_sock_ipv4_ops = { .md5_lookup = tcp_v4_reqsk_md5_lookup, -#endif }; +#endif static struct timewait_sock_ops tcp_timewait_sock_ops = { .twsk_obj_size = sizeof(struct tcp_timewait_sock), @@ -1820,14 +1820,14 @@ struct inet_connection_sock_af_ops ipv4_specific = { #endif }; -static struct tcp_sock_af_ops tcp_sock_ipv4_specific = { #ifdef CONFIG_TCP_MD5SIG +static struct tcp_sock_af_ops tcp_sock_ipv4_specific = { .md5_lookup = tcp_v4_md5_lookup, .calc_md5_hash = tcp_v4_calc_md5_hash, .md5_add = tcp_v4_md5_add_func, .md5_parse = tcp_v4_parse_md5_keys, -#endif }; +#endif /* NOTE: A lot of things set to zero explicitly by call to * sk_alloc() so need not be done here. -- cgit v1.2.3 From 0c4ca1bd8638d04796553b6e678063c4fadb92cc Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Sat, 2 Dec 2006 22:04:24 -0800 Subject: [NETFILTER]: nf_conntrack: fix NF_CONNTRACK_PROC_COMPAT dependency NF_CONNTRACK_PROC_COMPAT depends on NF_CONNTRACK_IPV4, not NF_CONNTRACK. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/ipv4/netfilter/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/ipv4') diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index bc298a3f236..06fec80a008 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig @@ -21,7 +21,7 @@ config NF_CONNTRACK_IPV4 config NF_CONNTRACK_PROC_COMPAT bool "proc/sysctl compatibility with old connection tracking" - depends on NF_CONNTRACK + depends on NF_CONNTRACK_IPV4 default y help This option enables /proc and sysctl compatibility with the old -- cgit v1.2.3 From bff9a89bcac5b68ac0a1ea856b1726a35ae1eabb Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Sat, 2 Dec 2006 22:05:08 -0800 Subject: [NETFILTER]: nf_conntrack: endian annotations Resync with Al Viro's ip_conntrack annotations and fix a missed spot in ip_nat_proto_icmp.c. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/ipv4/netfilter/ip_nat_proto_icmp.c | 4 ++-- net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c | 8 +++----- net/ipv4/netfilter/nf_conntrack_proto_icmp.c | 2 +- 3 files changed, 6 insertions(+), 8 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/netfilter/ip_nat_proto_icmp.c b/net/ipv4/netfilter/ip_nat_proto_icmp.c index 75266fe3e0f..fb716edd5bc 100644 --- a/net/ipv4/netfilter/ip_nat_proto_icmp.c +++ b/net/ipv4/netfilter/ip_nat_proto_icmp.c @@ -24,8 +24,8 @@ icmp_in_range(const struct ip_conntrack_tuple *tuple, const union ip_conntrack_manip_proto *min, const union ip_conntrack_manip_proto *max) { - return (tuple->src.u.icmp.id >= min->icmp.id - && tuple->src.u.icmp.id <= max->icmp.id); + return ntohs(tuple->src.u.icmp.id) >= ntohs(min->icmp.id) && + ntohs(tuple->src.u.icmp.id) <= ntohs(max->icmp.id); } static int diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c index f24e872d4b9..2b73e3edd94 100644 --- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c +++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c @@ -41,7 +41,7 @@ static int ipv4_pkt_to_tuple(const struct sk_buff *skb, unsigned int nhoff, struct nf_conntrack_tuple *tuple) { - u_int32_t _addrs[2], *ap; + __be32 _addrs[2], *ap; ap = skb_header_pointer(skb, nhoff + offsetof(struct iphdr, saddr), sizeof(u_int32_t) * 2, _addrs); if (ap == NULL) @@ -410,10 +410,8 @@ static int ipv4_nfattr_to_tuple(struct nfattr *tb[], if (nfattr_bad_size(tb, CTA_IP_MAX, cta_min_ip)) return -EINVAL; - t->src.u3.ip = - *(u_int32_t *)NFA_DATA(tb[CTA_IP_V4_SRC-1]); - t->dst.u3.ip = - *(u_int32_t *)NFA_DATA(tb[CTA_IP_V4_DST-1]); + t->src.u3.ip = *(__be32 *)NFA_DATA(tb[CTA_IP_V4_SRC-1]); + t->dst.u3.ip = *(__be32 *)NFA_DATA(tb[CTA_IP_V4_DST-1]); return 0; } diff --git a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c index 46aa44abc07..d25002fb817 100644 --- a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c +++ b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c @@ -311,7 +311,7 @@ static int icmp_nfattr_to_tuple(struct nfattr *tb[], tuple->dst.u.icmp.code = *(u_int8_t *)NFA_DATA(tb[CTA_PROTO_ICMP_CODE-1]); tuple->src.u.icmp.id = - *(u_int16_t *)NFA_DATA(tb[CTA_PROTO_ICMP_ID-1]); + *(__be16 *)NFA_DATA(tb[CTA_PROTO_ICMP_ID-1]); if (tuple->dst.u.icmp.type >= sizeof(invmap) || !invmap[tuple->dst.u.icmp.type]) -- cgit v1.2.3 From b321e14425c0234dd9cd07a5327a179507956c7c Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Sat, 2 Dec 2006 22:05:46 -0800 Subject: [NETFILTER]: Kconfig: improve conntrack selection Improve the connection tracking selection (well, the user experience, not really the aesthetics) by offering one option to enable connection tracking and a choice between the implementations. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/ipv4/netfilter/Kconfig | 14 -------------- 1 file changed, 14 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index 06fec80a008..71485276b81 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig @@ -31,20 +31,6 @@ config NF_CONNTRACK_PROC_COMPAT If unsure, say Y. # connection tracking, helpers and protocols -config IP_NF_CONNTRACK - tristate "Connection tracking (required for masq/NAT)" - ---help--- - Connection tracking keeps a record of what packets have passed - through your machine, in order to figure out how they are related - into connections. - - This is required to do Masquerading or other kinds of Network - Address Translation (except for Fast NAT). It can also be used to - enhance packet filtering (see `Connection state match support' - below). - - To compile it as a module, choose M here. If unsure, say N. - config IP_NF_CT_ACCT bool "Connection tracking flow accounting" depends on IP_NF_CONNTRACK -- cgit v1.2.3 From d2483ddefd38b06053cdce7206382ca61f6282b1 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Sat, 2 Dec 2006 22:06:05 -0800 Subject: [NETFILTER]: nf_conntrack: add module aliases to IPv4 conntrack names Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c | 1 + 1 file changed, 1 insertion(+) (limited to 'net/ipv4') diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c index 2b73e3edd94..653f57b8a10 100644 --- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c +++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c @@ -446,6 +446,7 @@ struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv4 = { }; MODULE_ALIAS("nf_conntrack-" __stringify(AF_INET)); +MODULE_ALIAS("ip_conntrack"); MODULE_LICENSE("GPL"); static int __init nf_conntrack_l3proto_ipv4_init(void) -- cgit v1.2.3 From 5b1158e909ecbe1a052203e0d8df15633f829930 Mon Sep 17 00:00:00 2001 From: Jozsef Kadlecsik Date: Sat, 2 Dec 2006 22:07:13 -0800 Subject: [NETFILTER]: Add NAT support for nf_conntrack Add NAT support for nf_conntrack. Joint work of Jozsef Kadlecsik, Yasuyuki Kozakai, Martin Josefsson and myself. Signed-off-by: Jozsef Kadlecsik Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/ipv4/netfilter/Kconfig | 30 +- net/ipv4/netfilter/Makefile | 7 + net/ipv4/netfilter/ip_nat_standalone.c | 6 - net/ipv4/netfilter/ipt_MASQUERADE.c | 29 +- net/ipv4/netfilter/ipt_NETMAP.c | 4 + net/ipv4/netfilter/ipt_REDIRECT.c | 6 +- net/ipv4/netfilter/ipt_SAME.c | 12 +- net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c | 7 +- net/ipv4/netfilter/nf_nat_core.c | 647 +++++++++++++++++++++++++ net/ipv4/netfilter/nf_nat_helper.c | 433 +++++++++++++++++ net/ipv4/netfilter/nf_nat_proto_icmp.c | 86 ++++ net/ipv4/netfilter/nf_nat_proto_tcp.c | 148 ++++++ net/ipv4/netfilter/nf_nat_proto_udp.c | 138 ++++++ net/ipv4/netfilter/nf_nat_proto_unknown.c | 54 +++ net/ipv4/netfilter/nf_nat_rule.c | 343 +++++++++++++ net/ipv4/netfilter/nf_nat_standalone.c | 406 ++++++++++++++++ 16 files changed, 2337 insertions(+), 19 deletions(-) create mode 100644 net/ipv4/netfilter/nf_nat_core.c create mode 100644 net/ipv4/netfilter/nf_nat_helper.c create mode 100644 net/ipv4/netfilter/nf_nat_proto_icmp.c create mode 100644 net/ipv4/netfilter/nf_nat_proto_tcp.c create mode 100644 net/ipv4/netfilter/nf_nat_proto_udp.c create mode 100644 net/ipv4/netfilter/nf_nat_proto_unknown.c create mode 100644 net/ipv4/netfilter/nf_nat_rule.c create mode 100644 net/ipv4/netfilter/nf_nat_standalone.c (limited to 'net/ipv4') diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index 71485276b81..01789aeaeb5 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig @@ -6,7 +6,7 @@ menu "IP: Netfilter Configuration" depends on INET && NETFILTER config NF_CONNTRACK_IPV4 - tristate "IPv4 support for new connection tracking (EXPERIMENTAL)" + tristate "IPv4 support for new connection tracking (required for NAT) (EXPERIMENTAL)" depends on EXPERIMENTAL && NF_CONNTRACK ---help--- Connection tracking keeps a record of what packets have passed @@ -387,7 +387,7 @@ config IP_NF_TARGET_TCPMSS To compile it as a module, choose M here. If unsure, say N. -# NAT + specific targets +# NAT + specific targets: ip_conntrack config IP_NF_NAT tristate "Full NAT" depends on IP_NF_IPTABLES && IP_NF_CONNTRACK @@ -398,14 +398,30 @@ config IP_NF_NAT To compile it as a module, choose M here. If unsure, say N. +# NAT + specific targets: nf_conntrack +config NF_NAT + tristate "Full NAT" + depends on IP_NF_IPTABLES && NF_CONNTRACK + help + The Full NAT option allows masquerading, port forwarding and other + forms of full Network Address Port Translation. It is controlled by + the `nat' table in iptables: see the man page for iptables(8). + + To compile it as a module, choose M here. If unsure, say N. + config IP_NF_NAT_NEEDED bool - depends on IP_NF_NAT != n + depends on IP_NF_NAT + default y + +config NF_NAT_NEEDED + bool + depends on NF_NAT default y config IP_NF_TARGET_MASQUERADE tristate "MASQUERADE target support" - depends on IP_NF_NAT + depends on (NF_NAT || IP_NF_NAT) help Masquerading is a special case of NAT: all outgoing connections are changed to seem to come from a particular interface's address, and @@ -417,7 +433,7 @@ config IP_NF_TARGET_MASQUERADE config IP_NF_TARGET_REDIRECT tristate "REDIRECT target support" - depends on IP_NF_NAT + depends on (NF_NAT || IP_NF_NAT) help REDIRECT is a special case of NAT: all incoming connections are mapped onto the incoming interface's address, causing the packets to @@ -428,7 +444,7 @@ config IP_NF_TARGET_REDIRECT config IP_NF_TARGET_NETMAP tristate "NETMAP target support" - depends on IP_NF_NAT + depends on (NF_NAT || IP_NF_NAT) help NETMAP is an implementation of static 1:1 NAT mapping of network addresses. It maps the network address part, while keeping the host @@ -439,7 +455,7 @@ config IP_NF_TARGET_NETMAP config IP_NF_TARGET_SAME tristate "SAME target support" - depends on IP_NF_NAT + depends on (NF_NAT || IP_NF_NAT) help This option adds a `SAME' target, which works like the standard SNAT target, but attempts to give clients the same IP for all connections. diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index 21359d83f0c..ec31690764a 100644 --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile @@ -5,7 +5,12 @@ # objects for the standalone - connection tracking / NAT ip_conntrack-objs := ip_conntrack_standalone.o ip_conntrack_core.o ip_conntrack_proto_generic.o ip_conntrack_proto_tcp.o ip_conntrack_proto_udp.o ip_conntrack_proto_icmp.o ip_nat-objs := ip_nat_core.o ip_nat_helper.o ip_nat_proto_unknown.o ip_nat_proto_tcp.o ip_nat_proto_udp.o ip_nat_proto_icmp.o +nf_nat-objs := nf_nat_core.o nf_nat_helper.o nf_nat_proto_unknown.o nf_nat_proto_tcp.o nf_nat_proto_udp.o nf_nat_proto_icmp.o +ifneq ($(CONFIG_NF_NAT),) +iptable_nat-objs := nf_nat_rule.o nf_nat_standalone.o +else iptable_nat-objs := ip_nat_rule.o ip_nat_standalone.o +endif ip_conntrack_pptp-objs := ip_conntrack_helper_pptp.o ip_conntrack_proto_gre.o ip_nat_pptp-objs := ip_nat_helper_pptp.o ip_nat_proto_gre.o @@ -16,6 +21,7 @@ ip_nat_h323-objs := ip_nat_helper_h323.o # connection tracking obj-$(CONFIG_IP_NF_CONNTRACK) += ip_conntrack.o obj-$(CONFIG_IP_NF_NAT) += ip_nat.o +obj-$(CONFIG_NF_NAT) += nf_nat.o # conntrack netlink interface obj-$(CONFIG_IP_NF_CONNTRACK_NETLINK) += ip_conntrack_netlink.o @@ -50,6 +56,7 @@ obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o obj-$(CONFIG_IP_NF_FILTER) += iptable_filter.o obj-$(CONFIG_IP_NF_MANGLE) += iptable_mangle.o obj-$(CONFIG_IP_NF_NAT) += iptable_nat.o +obj-$(CONFIG_NF_NAT) += iptable_nat.o obj-$(CONFIG_IP_NF_RAW) += iptable_raw.o # matches diff --git a/net/ipv4/netfilter/ip_nat_standalone.c b/net/ipv4/netfilter/ip_nat_standalone.c index d85d2de5044..ad66328baa5 100644 --- a/net/ipv4/netfilter/ip_nat_standalone.c +++ b/net/ipv4/netfilter/ip_nat_standalone.c @@ -44,12 +44,6 @@ #define DEBUGP(format, args...) #endif -#define HOOKNAME(hooknum) ((hooknum) == NF_IP_POST_ROUTING ? "POST_ROUTING" \ - : ((hooknum) == NF_IP_PRE_ROUTING ? "PRE_ROUTING" \ - : ((hooknum) == NF_IP_LOCAL_OUT ? "LOCAL_OUT" \ - : ((hooknum) == NF_IP_LOCAL_IN ? "LOCAL_IN" \ - : "*ERROR*"))) - #ifdef CONFIG_XFRM static void nat_decode_session(struct sk_buff *skb, struct flowi *fl) { diff --git a/net/ipv4/netfilter/ipt_MASQUERADE.c b/net/ipv4/netfilter/ipt_MASQUERADE.c index 3dbfcfac8a8..28b9233956b 100644 --- a/net/ipv4/netfilter/ipt_MASQUERADE.c +++ b/net/ipv4/netfilter/ipt_MASQUERADE.c @@ -2,7 +2,7 @@ (depending on route). */ /* (C) 1999-2001 Paul `Rusty' Russell - * (C) 2002-2004 Netfilter Core Team + * (C) 2002-2006 Netfilter Core Team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -20,7 +20,11 @@ #include #include #include +#ifdef CONFIG_NF_NAT_NEEDED +#include +#else #include +#endif #include MODULE_LICENSE("GPL"); @@ -65,23 +69,33 @@ masquerade_target(struct sk_buff **pskb, const struct xt_target *target, const void *targinfo) { +#ifdef CONFIG_NF_NAT_NEEDED + struct nf_conn_nat *nat; +#endif struct ip_conntrack *ct; enum ip_conntrack_info ctinfo; - const struct ip_nat_multi_range_compat *mr; struct ip_nat_range newrange; + const struct ip_nat_multi_range_compat *mr; struct rtable *rt; __be32 newsrc; IP_NF_ASSERT(hooknum == NF_IP_POST_ROUTING); ct = ip_conntrack_get(*pskb, &ctinfo); +#ifdef CONFIG_NF_NAT_NEEDED + nat = nfct_nat(ct); +#endif IP_NF_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED || ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY)); /* Source address is 0.0.0.0 - locally generated packet that is * probably not supposed to be masqueraded. */ +#ifdef CONFIG_NF_NAT_NEEDED + if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip == 0) +#else if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip == 0) +#endif return NF_ACCEPT; mr = targinfo; @@ -93,7 +107,11 @@ masquerade_target(struct sk_buff **pskb, } write_lock_bh(&masq_lock); +#ifdef CONFIG_NF_NAT_NEEDED + nat->masq_index = out->ifindex; +#else ct->nat.masq_index = out->ifindex; +#endif write_unlock_bh(&masq_lock); /* Transfer from original range. */ @@ -109,10 +127,17 @@ masquerade_target(struct sk_buff **pskb, static inline int device_cmp(struct ip_conntrack *i, void *ifindex) { +#ifdef CONFIG_NF_NAT_NEEDED + struct nf_conn_nat *nat = nfct_nat(i); +#endif int ret; read_lock_bh(&masq_lock); +#ifdef CONFIG_NF_NAT_NEEDED + ret = (nat->masq_index == (int)(long)ifindex); +#else ret = (i->nat.masq_index == (int)(long)ifindex); +#endif read_unlock_bh(&masq_lock); return ret; diff --git a/net/ipv4/netfilter/ipt_NETMAP.c b/net/ipv4/netfilter/ipt_NETMAP.c index 58a88f22710..9390e90f2b2 100644 --- a/net/ipv4/netfilter/ipt_NETMAP.c +++ b/net/ipv4/netfilter/ipt_NETMAP.c @@ -15,7 +15,11 @@ #include #include #include +#ifdef CONFIG_NF_NAT_NEEDED +#include +#else #include +#endif #define MODULENAME "NETMAP" MODULE_LICENSE("GPL"); diff --git a/net/ipv4/netfilter/ipt_REDIRECT.c b/net/ipv4/netfilter/ipt_REDIRECT.c index c0dcfe9d610..462eceb3a1b 100644 --- a/net/ipv4/netfilter/ipt_REDIRECT.c +++ b/net/ipv4/netfilter/ipt_REDIRECT.c @@ -1,6 +1,6 @@ /* Redirect. Simple mapping which alters dst to a local IP address. */ /* (C) 1999-2001 Paul `Rusty' Russell - * (C) 2002-2004 Netfilter Core Team + * (C) 2002-2006 Netfilter Core Team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -18,7 +18,11 @@ #include #include #include +#ifdef CONFIG_NF_NAT_NEEDED +#include +#else #include +#endif MODULE_LICENSE("GPL"); MODULE_AUTHOR("Netfilter Core Team "); diff --git a/net/ipv4/netfilter/ipt_SAME.c b/net/ipv4/netfilter/ipt_SAME.c index b38b13328d7..3dcf2941133 100644 --- a/net/ipv4/netfilter/ipt_SAME.c +++ b/net/ipv4/netfilter/ipt_SAME.c @@ -34,7 +34,11 @@ #include #include #include +#ifdef CONFIG_NF_NAT_NEEDED +#include +#else #include +#endif #include MODULE_LICENSE("GPL"); @@ -152,11 +156,17 @@ same_target(struct sk_buff **pskb, Here we calculate the index in same->iparray which holds the ipaddress we should use */ +#ifdef CONFIG_NF_NAT_NEEDED + tmpip = ntohl(t->src.u3.ip); + + if (!(same->info & IPT_SAME_NODST)) + tmpip += ntohl(t->dst.u3.ip); +#else tmpip = ntohl(t->src.ip); if (!(same->info & IPT_SAME_NODST)) tmpip += ntohl(t->dst.ip); - +#endif aindex = tmpip % same->ipnum; new_ip = htonl(same->iparray[aindex]); diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c index 653f57b8a10..5655109dcaf 100644 --- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c +++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c @@ -111,10 +111,10 @@ ipv4_prepare(struct sk_buff **pskb, unsigned int hooknum, unsigned int *dataoff, return NF_ACCEPT; } -int nat_module_is_loaded = 0; +int nf_nat_module_is_loaded = 0; static u_int32_t ipv4_get_features(const struct nf_conntrack_tuple *tuple) { - if (nat_module_is_loaded) + if (nf_nat_module_is_loaded) return NF_CT_F_NAT; return NF_CT_F_BASIC; @@ -532,3 +532,6 @@ module_init(nf_conntrack_l3proto_ipv4_init); module_exit(nf_conntrack_l3proto_ipv4_fini); EXPORT_SYMBOL(nf_ct_ipv4_gather_frags); +#ifdef CONFIG_NF_NAT_NEEDED +EXPORT_SYMBOL(nf_nat_module_is_loaded); +#endif diff --git a/net/ipv4/netfilter/nf_nat_core.c b/net/ipv4/netfilter/nf_nat_core.c new file mode 100644 index 00000000000..86a92272b05 --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_core.c @@ -0,0 +1,647 @@ +/* NAT for netfilter; shared with compatibility layer. */ + +/* (C) 1999-2001 Paul `Rusty' Russell + * (C) 2002-2006 Netfilter Core Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include /* For tcp_prot in getorigdst */ +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(format, args...) +#endif + +static DEFINE_RWLOCK(nf_nat_lock); + +static struct nf_conntrack_l3proto *l3proto = NULL; + +/* Calculated at init based on memory size */ +static unsigned int nf_nat_htable_size; + +static struct list_head *bysource; + +#define MAX_IP_NAT_PROTO 256 +static struct nf_nat_protocol *nf_nat_protos[MAX_IP_NAT_PROTO]; + +static inline struct nf_nat_protocol * +__nf_nat_proto_find(u_int8_t protonum) +{ + return nf_nat_protos[protonum]; +} + +struct nf_nat_protocol * +nf_nat_proto_find_get(u_int8_t protonum) +{ + struct nf_nat_protocol *p; + + /* we need to disable preemption to make sure 'p' doesn't get + * removed until we've grabbed the reference */ + preempt_disable(); + p = __nf_nat_proto_find(protonum); + if (!try_module_get(p->me)) + p = &nf_nat_unknown_protocol; + preempt_enable(); + + return p; +} +EXPORT_SYMBOL_GPL(nf_nat_proto_find_get); + +void +nf_nat_proto_put(struct nf_nat_protocol *p) +{ + module_put(p->me); +} +EXPORT_SYMBOL_GPL(nf_nat_proto_put); + +/* We keep an extra hash for each conntrack, for fast searching. */ +static inline unsigned int +hash_by_src(const struct nf_conntrack_tuple *tuple) +{ + /* Original src, to ensure we map it consistently if poss. */ + return jhash_3words((__force u32)tuple->src.u3.ip, tuple->src.u.all, + tuple->dst.protonum, 0) % nf_nat_htable_size; +} + +/* Noone using conntrack by the time this called. */ +static void nf_nat_cleanup_conntrack(struct nf_conn *conn) +{ + struct nf_conn_nat *nat; + if (!(conn->status & IPS_NAT_DONE_MASK)) + return; + + nat = nfct_nat(conn); + write_lock_bh(&nf_nat_lock); + list_del(&nat->info.bysource); + write_unlock_bh(&nf_nat_lock); +} + +/* Is this tuple already taken? (not by us) */ +int +nf_nat_used_tuple(const struct nf_conntrack_tuple *tuple, + const struct nf_conn *ignored_conntrack) +{ + /* Conntrack tracking doesn't keep track of outgoing tuples; only + incoming ones. NAT means they don't have a fixed mapping, + so we invert the tuple and look for the incoming reply. + + We could keep a separate hash if this proves too slow. */ + struct nf_conntrack_tuple reply; + + nf_ct_invert_tuplepr(&reply, tuple); + return nf_conntrack_tuple_taken(&reply, ignored_conntrack); +} +EXPORT_SYMBOL(nf_nat_used_tuple); + +/* If we source map this tuple so reply looks like reply_tuple, will + * that meet the constraints of range. */ +static int +in_range(const struct nf_conntrack_tuple *tuple, + const struct nf_nat_range *range) +{ + struct nf_nat_protocol *proto; + + proto = __nf_nat_proto_find(tuple->dst.protonum); + /* If we are supposed to map IPs, then we must be in the + range specified, otherwise let this drag us onto a new src IP. */ + if (range->flags & IP_NAT_RANGE_MAP_IPS) { + if (ntohl(tuple->src.u3.ip) < ntohl(range->min_ip) || + ntohl(tuple->src.u3.ip) > ntohl(range->max_ip)) + return 0; + } + + if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED) || + proto->in_range(tuple, IP_NAT_MANIP_SRC, + &range->min, &range->max)) + return 1; + + return 0; +} + +static inline int +same_src(const struct nf_conn *ct, + const struct nf_conntrack_tuple *tuple) +{ + const struct nf_conntrack_tuple *t; + + t = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; + return (t->dst.protonum == tuple->dst.protonum && + t->src.u3.ip == tuple->src.u3.ip && + t->src.u.all == tuple->src.u.all); +} + +/* Only called for SRC manip */ +static int +find_appropriate_src(const struct nf_conntrack_tuple *tuple, + struct nf_conntrack_tuple *result, + const struct nf_nat_range *range) +{ + unsigned int h = hash_by_src(tuple); + struct nf_conn_nat *nat; + struct nf_conn *ct; + + read_lock_bh(&nf_nat_lock); + list_for_each_entry(nat, &bysource[h], info.bysource) { + ct = (struct nf_conn *)((char *)nat - offsetof(struct nf_conn, data)); + if (same_src(ct, tuple)) { + /* Copy source part from reply tuple. */ + nf_ct_invert_tuplepr(result, + &ct->tuplehash[IP_CT_DIR_REPLY].tuple); + result->dst = tuple->dst; + + if (in_range(result, range)) { + read_unlock_bh(&nf_nat_lock); + return 1; + } + } + } + read_unlock_bh(&nf_nat_lock); + return 0; +} + +/* For [FUTURE] fragmentation handling, we want the least-used + src-ip/dst-ip/proto triple. Fairness doesn't come into it. Thus + if the range specifies 1.2.3.4 ports 10000-10005 and 1.2.3.5 ports + 1-65535, we don't do pro-rata allocation based on ports; we choose + the ip with the lowest src-ip/dst-ip/proto usage. +*/ +static void +find_best_ips_proto(struct nf_conntrack_tuple *tuple, + const struct nf_nat_range *range, + const struct nf_conn *ct, + enum nf_nat_manip_type maniptype) +{ + __be32 *var_ipp; + /* Host order */ + u_int32_t minip, maxip, j; + + /* No IP mapping? Do nothing. */ + if (!(range->flags & IP_NAT_RANGE_MAP_IPS)) + return; + + if (maniptype == IP_NAT_MANIP_SRC) + var_ipp = &tuple->src.u3.ip; + else + var_ipp = &tuple->dst.u3.ip; + + /* Fast path: only one choice. */ + if (range->min_ip == range->max_ip) { + *var_ipp = range->min_ip; + return; + } + + /* Hashing source and destination IPs gives a fairly even + * spread in practice (if there are a small number of IPs + * involved, there usually aren't that many connections + * anyway). The consistency means that servers see the same + * client coming from the same IP (some Internet Banking sites + * like this), even across reboots. */ + minip = ntohl(range->min_ip); + maxip = ntohl(range->max_ip); + j = jhash_2words((__force u32)tuple->src.u3.ip, + (__force u32)tuple->dst.u3.ip, 0); + *var_ipp = htonl(minip + j % (maxip - minip + 1)); +} + +/* Manipulate the tuple into the range given. For NF_IP_POST_ROUTING, + * we change the source to map into the range. For NF_IP_PRE_ROUTING + * and NF_IP_LOCAL_OUT, we change the destination to map into the + * range. It might not be possible to get a unique tuple, but we try. + * At worst (or if we race), we will end up with a final duplicate in + * __ip_conntrack_confirm and drop the packet. */ +static void +get_unique_tuple(struct nf_conntrack_tuple *tuple, + const struct nf_conntrack_tuple *orig_tuple, + const struct nf_nat_range *range, + struct nf_conn *ct, + enum nf_nat_manip_type maniptype) +{ + struct nf_nat_protocol *proto; + + /* 1) If this srcip/proto/src-proto-part is currently mapped, + and that same mapping gives a unique tuple within the given + range, use that. + + This is only required for source (ie. NAT/masq) mappings. + So far, we don't do local source mappings, so multiple + manips not an issue. */ + if (maniptype == IP_NAT_MANIP_SRC) { + if (find_appropriate_src(orig_tuple, tuple, range)) { + DEBUGP("get_unique_tuple: Found current src map\n"); + if (!nf_nat_used_tuple(tuple, ct)) + return; + } + } + + /* 2) Select the least-used IP/proto combination in the given + range. */ + *tuple = *orig_tuple; + find_best_ips_proto(tuple, range, ct, maniptype); + + /* 3) The per-protocol part of the manip is made to map into + the range to make a unique tuple. */ + + proto = nf_nat_proto_find_get(orig_tuple->dst.protonum); + + /* Only bother mapping if it's not already in range and unique */ + if ((!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED) || + proto->in_range(tuple, maniptype, &range->min, &range->max)) && + !nf_nat_used_tuple(tuple, ct)) { + nf_nat_proto_put(proto); + return; + } + + /* Last change: get protocol to try to obtain unique tuple. */ + proto->unique_tuple(tuple, range, maniptype, ct); + + nf_nat_proto_put(proto); +} + +unsigned int +nf_nat_setup_info(struct nf_conn *ct, + const struct nf_nat_range *range, + unsigned int hooknum) +{ + struct nf_conntrack_tuple curr_tuple, new_tuple; + struct nf_conn_nat *nat = nfct_nat(ct); + struct nf_nat_info *info = &nat->info; + int have_to_hash = !(ct->status & IPS_NAT_DONE_MASK); + enum nf_nat_manip_type maniptype = HOOK2MANIP(hooknum); + + NF_CT_ASSERT(hooknum == NF_IP_PRE_ROUTING || + hooknum == NF_IP_POST_ROUTING || + hooknum == NF_IP_LOCAL_IN || + hooknum == NF_IP_LOCAL_OUT); + BUG_ON(nf_nat_initialized(ct, maniptype)); + + /* What we've got will look like inverse of reply. Normally + this is what is in the conntrack, except for prior + manipulations (future optimization: if num_manips == 0, + orig_tp = + conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple) */ + nf_ct_invert_tuplepr(&curr_tuple, + &ct->tuplehash[IP_CT_DIR_REPLY].tuple); + + get_unique_tuple(&new_tuple, &curr_tuple, range, ct, maniptype); + + if (!nf_ct_tuple_equal(&new_tuple, &curr_tuple)) { + struct nf_conntrack_tuple reply; + + /* Alter conntrack table so will recognize replies. */ + nf_ct_invert_tuplepr(&reply, &new_tuple); + nf_conntrack_alter_reply(ct, &reply); + + /* Non-atomic: we own this at the moment. */ + if (maniptype == IP_NAT_MANIP_SRC) + ct->status |= IPS_SRC_NAT; + else + ct->status |= IPS_DST_NAT; + } + + /* Place in source hash if this is the first time. */ + if (have_to_hash) { + unsigned int srchash; + + srchash = hash_by_src(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); + write_lock_bh(&nf_nat_lock); + list_add(&info->bysource, &bysource[srchash]); + write_unlock_bh(&nf_nat_lock); + } + + /* It's done. */ + if (maniptype == IP_NAT_MANIP_DST) + set_bit(IPS_DST_NAT_DONE_BIT, &ct->status); + else + set_bit(IPS_SRC_NAT_DONE_BIT, &ct->status); + + return NF_ACCEPT; +} +EXPORT_SYMBOL(nf_nat_setup_info); + +/* Returns true if succeeded. */ +static int +manip_pkt(u_int16_t proto, + struct sk_buff **pskb, + unsigned int iphdroff, + const struct nf_conntrack_tuple *target, + enum nf_nat_manip_type maniptype) +{ + struct iphdr *iph; + struct nf_nat_protocol *p; + + if (!skb_make_writable(pskb, iphdroff + sizeof(*iph))) + return 0; + + iph = (void *)(*pskb)->data + iphdroff; + + /* Manipulate protcol part. */ + p = nf_nat_proto_find_get(proto); + if (!p->manip_pkt(pskb, iphdroff, target, maniptype)) { + nf_nat_proto_put(p); + return 0; + } + nf_nat_proto_put(p); + + iph = (void *)(*pskb)->data + iphdroff; + + if (maniptype == IP_NAT_MANIP_SRC) { + nf_csum_replace4(&iph->check, iph->saddr, target->src.u3.ip); + iph->saddr = target->src.u3.ip; + } else { + nf_csum_replace4(&iph->check, iph->daddr, target->dst.u3.ip); + iph->daddr = target->dst.u3.ip; + } + return 1; +} + +/* Do packet manipulations according to nf_nat_setup_info. */ +unsigned int nf_nat_packet(struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned int hooknum, + struct sk_buff **pskb) +{ + enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); + unsigned long statusbit; + enum nf_nat_manip_type mtype = HOOK2MANIP(hooknum); + + if (mtype == IP_NAT_MANIP_SRC) + statusbit = IPS_SRC_NAT; + else + statusbit = IPS_DST_NAT; + + /* Invert if this is reply dir. */ + if (dir == IP_CT_DIR_REPLY) + statusbit ^= IPS_NAT_MASK; + + /* Non-atomic: these bits don't change. */ + if (ct->status & statusbit) { + struct nf_conntrack_tuple target; + + /* We are aiming to look like inverse of other direction. */ + nf_ct_invert_tuplepr(&target, &ct->tuplehash[!dir].tuple); + + if (!manip_pkt(target.dst.protonum, pskb, 0, &target, mtype)) + return NF_DROP; + } + return NF_ACCEPT; +} +EXPORT_SYMBOL_GPL(nf_nat_packet); + +/* Dir is direction ICMP is coming from (opposite to packet it contains) */ +int nf_nat_icmp_reply_translation(struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned int hooknum, + struct sk_buff **pskb) +{ + struct { + struct icmphdr icmp; + struct iphdr ip; + } *inside; + struct nf_conntrack_tuple inner, target; + int hdrlen = (*pskb)->nh.iph->ihl * 4; + enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); + unsigned long statusbit; + enum nf_nat_manip_type manip = HOOK2MANIP(hooknum); + + if (!skb_make_writable(pskb, hdrlen + sizeof(*inside))) + return 0; + + inside = (void *)(*pskb)->data + (*pskb)->nh.iph->ihl*4; + + /* We're actually going to mangle it beyond trivial checksum + adjustment, so make sure the current checksum is correct. */ + if (nf_ip_checksum(*pskb, hooknum, hdrlen, 0)) + return 0; + + /* Must be RELATED */ + NF_CT_ASSERT((*pskb)->nfctinfo == IP_CT_RELATED || + (*pskb)->nfctinfo == IP_CT_RELATED+IP_CT_IS_REPLY); + + /* Redirects on non-null nats must be dropped, else they'll + start talking to each other without our translation, and be + confused... --RR */ + if (inside->icmp.type == ICMP_REDIRECT) { + /* If NAT isn't finished, assume it and drop. */ + if ((ct->status & IPS_NAT_DONE_MASK) != IPS_NAT_DONE_MASK) + return 0; + + if (ct->status & IPS_NAT_MASK) + return 0; + } + + DEBUGP("icmp_reply_translation: translating error %p manp %u dir %s\n", + *pskb, manip, dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY"); + + if (!nf_ct_get_tuple(*pskb, + (*pskb)->nh.iph->ihl*4 + sizeof(struct icmphdr), + (*pskb)->nh.iph->ihl*4 + + sizeof(struct icmphdr) + inside->ip.ihl*4, + (u_int16_t)AF_INET, + inside->ip.protocol, + &inner, + l3proto, + __nf_ct_l4proto_find((u_int16_t)PF_INET, + inside->ip.protocol))) + return 0; + + /* Change inner back to look like incoming packet. We do the + opposite manip on this hook to normal, because it might not + pass all hooks (locally-generated ICMP). Consider incoming + packet: PREROUTING (DST manip), routing produces ICMP, goes + through POSTROUTING (which must correct the DST manip). */ + if (!manip_pkt(inside->ip.protocol, pskb, + (*pskb)->nh.iph->ihl*4 + sizeof(inside->icmp), + &ct->tuplehash[!dir].tuple, + !manip)) + return 0; + + if ((*pskb)->ip_summed != CHECKSUM_PARTIAL) { + /* Reloading "inside" here since manip_pkt inner. */ + inside = (void *)(*pskb)->data + (*pskb)->nh.iph->ihl*4; + inside->icmp.checksum = 0; + inside->icmp.checksum = + csum_fold(skb_checksum(*pskb, hdrlen, + (*pskb)->len - hdrlen, 0)); + } + + /* Change outer to look the reply to an incoming packet + * (proto 0 means don't invert per-proto part). */ + if (manip == IP_NAT_MANIP_SRC) + statusbit = IPS_SRC_NAT; + else + statusbit = IPS_DST_NAT; + + /* Invert if this is reply dir. */ + if (dir == IP_CT_DIR_REPLY) + statusbit ^= IPS_NAT_MASK; + + if (ct->status & statusbit) { + nf_ct_invert_tuplepr(&target, &ct->tuplehash[!dir].tuple); + if (!manip_pkt(0, pskb, 0, &target, manip)) + return 0; + } + + return 1; +} +EXPORT_SYMBOL_GPL(nf_nat_icmp_reply_translation); + +/* Protocol registration. */ +int nf_nat_protocol_register(struct nf_nat_protocol *proto) +{ + int ret = 0; + + write_lock_bh(&nf_nat_lock); + if (nf_nat_protos[proto->protonum] != &nf_nat_unknown_protocol) { + ret = -EBUSY; + goto out; + } + nf_nat_protos[proto->protonum] = proto; + out: + write_unlock_bh(&nf_nat_lock); + return ret; +} +EXPORT_SYMBOL(nf_nat_protocol_register); + +/* Noone stores the protocol anywhere; simply delete it. */ +void nf_nat_protocol_unregister(struct nf_nat_protocol *proto) +{ + write_lock_bh(&nf_nat_lock); + nf_nat_protos[proto->protonum] = &nf_nat_unknown_protocol; + write_unlock_bh(&nf_nat_lock); + + /* Someone could be still looking at the proto in a bh. */ + synchronize_net(); +} +EXPORT_SYMBOL(nf_nat_protocol_unregister); + +#if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \ + defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE) +int +nf_nat_port_range_to_nfattr(struct sk_buff *skb, + const struct nf_nat_range *range) +{ + NFA_PUT(skb, CTA_PROTONAT_PORT_MIN, sizeof(__be16), + &range->min.tcp.port); + NFA_PUT(skb, CTA_PROTONAT_PORT_MAX, sizeof(__be16), + &range->max.tcp.port); + + return 0; + +nfattr_failure: + return -1; +} +EXPORT_SYMBOL_GPL(nf_nat_port_nfattr_to_range); + +int +nf_nat_port_nfattr_to_range(struct nfattr *tb[], struct nf_nat_range *range) +{ + int ret = 0; + + /* we have to return whether we actually parsed something or not */ + + if (tb[CTA_PROTONAT_PORT_MIN-1]) { + ret = 1; + range->min.tcp.port = + *(__be16 *)NFA_DATA(tb[CTA_PROTONAT_PORT_MIN-1]); + } + + if (!tb[CTA_PROTONAT_PORT_MAX-1]) { + if (ret) + range->max.tcp.port = range->min.tcp.port; + } else { + ret = 1; + range->max.tcp.port = + *(__be16 *)NFA_DATA(tb[CTA_PROTONAT_PORT_MAX-1]); + } + + return ret; +} +EXPORT_SYMBOL_GPL(nf_nat_port_range_to_nfattr); +#endif + +static int __init nf_nat_init(void) +{ + size_t i; + + /* Leave them the same for the moment. */ + nf_nat_htable_size = nf_conntrack_htable_size; + + /* One vmalloc for both hash tables */ + bysource = vmalloc(sizeof(struct list_head) * nf_nat_htable_size); + if (!bysource) + return -ENOMEM; + + /* Sew in builtin protocols. */ + write_lock_bh(&nf_nat_lock); + for (i = 0; i < MAX_IP_NAT_PROTO; i++) + nf_nat_protos[i] = &nf_nat_unknown_protocol; + nf_nat_protos[IPPROTO_TCP] = &nf_nat_protocol_tcp; + nf_nat_protos[IPPROTO_UDP] = &nf_nat_protocol_udp; + nf_nat_protos[IPPROTO_ICMP] = &nf_nat_protocol_icmp; + write_unlock_bh(&nf_nat_lock); + + for (i = 0; i < nf_nat_htable_size; i++) { + INIT_LIST_HEAD(&bysource[i]); + } + + /* FIXME: Man, this is a hack. */ + NF_CT_ASSERT(nf_conntrack_destroyed == NULL); + nf_conntrack_destroyed = &nf_nat_cleanup_conntrack; + + /* Initialize fake conntrack so that NAT will skip it */ + nf_conntrack_untracked.status |= IPS_NAT_DONE_MASK; + + l3proto = nf_ct_l3proto_find_get((u_int16_t)AF_INET); + return 0; +} + +/* Clear NAT section of all conntracks, in case we're loaded again. */ +static int clean_nat(struct nf_conn *i, void *data) +{ + struct nf_conn_nat *nat = nfct_nat(i); + + if (!nat) + return 0; + memset(nat, 0, sizeof(nat)); + i->status &= ~(IPS_NAT_MASK | IPS_NAT_DONE_MASK | IPS_SEQ_ADJUST); + return 0; +} + +static void __exit nf_nat_cleanup(void) +{ + nf_ct_iterate_cleanup(&clean_nat, NULL); + nf_conntrack_destroyed = NULL; + vfree(bysource); + nf_ct_l3proto_put(l3proto); +} + +MODULE_LICENSE("GPL"); + +module_init(nf_nat_init); +module_exit(nf_nat_cleanup); diff --git a/net/ipv4/netfilter/nf_nat_helper.c b/net/ipv4/netfilter/nf_nat_helper.c new file mode 100644 index 00000000000..98fbfc84d18 --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_helper.c @@ -0,0 +1,433 @@ +/* ip_nat_helper.c - generic support functions for NAT helpers + * + * (C) 2000-2002 Harald Welte + * (C) 2003-2006 Netfilter Core Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#if 0 +#define DEBUGP printk +#define DUMP_OFFSET(x) printk("offset_before=%d, offset_after=%d, correction_pos=%u\n", x->offset_before, x->offset_after, x->correction_pos); +#else +#define DEBUGP(format, args...) +#define DUMP_OFFSET(x) +#endif + +static DEFINE_SPINLOCK(nf_nat_seqofs_lock); + +/* Setup TCP sequence correction given this change at this sequence */ +static inline void +adjust_tcp_sequence(u32 seq, + int sizediff, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo) +{ + int dir; + struct nf_nat_seq *this_way, *other_way; + struct nf_conn_nat *nat = nfct_nat(ct); + + DEBUGP("nf_nat_resize_packet: old_size = %u, new_size = %u\n", + (*skb)->len, new_size); + + dir = CTINFO2DIR(ctinfo); + + this_way = &nat->info.seq[dir]; + other_way = &nat->info.seq[!dir]; + + DEBUGP("nf_nat_resize_packet: Seq_offset before: "); + DUMP_OFFSET(this_way); + + spin_lock_bh(&nf_nat_seqofs_lock); + + /* SYN adjust. If it's uninitialized, or this is after last + * correction, record it: we don't handle more than one + * adjustment in the window, but do deal with common case of a + * retransmit */ + if (this_way->offset_before == this_way->offset_after || + before(this_way->correction_pos, seq)) { + this_way->correction_pos = seq; + this_way->offset_before = this_way->offset_after; + this_way->offset_after += sizediff; + } + spin_unlock_bh(&nf_nat_seqofs_lock); + + DEBUGP("nf_nat_resize_packet: Seq_offset after: "); + DUMP_OFFSET(this_way); +} + +/* Frobs data inside this packet, which is linear. */ +static void mangle_contents(struct sk_buff *skb, + unsigned int dataoff, + unsigned int match_offset, + unsigned int match_len, + const char *rep_buffer, + unsigned int rep_len) +{ + unsigned char *data; + + BUG_ON(skb_is_nonlinear(skb)); + data = (unsigned char *)skb->nh.iph + dataoff; + + /* move post-replacement */ + memmove(data + match_offset + rep_len, + data + match_offset + match_len, + skb->tail - (data + match_offset + match_len)); + + /* insert data from buffer */ + memcpy(data + match_offset, rep_buffer, rep_len); + + /* update skb info */ + if (rep_len > match_len) { + DEBUGP("nf_nat_mangle_packet: Extending packet by " + "%u from %u bytes\n", rep_len - match_len, + skb->len); + skb_put(skb, rep_len - match_len); + } else { + DEBUGP("nf_nat_mangle_packet: Shrinking packet from " + "%u from %u bytes\n", match_len - rep_len, + skb->len); + __skb_trim(skb, skb->len + rep_len - match_len); + } + + /* fix IP hdr checksum information */ + skb->nh.iph->tot_len = htons(skb->len); + ip_send_check(skb->nh.iph); +} + +/* Unusual, but possible case. */ +static int enlarge_skb(struct sk_buff **pskb, unsigned int extra) +{ + struct sk_buff *nskb; + + if ((*pskb)->len + extra > 65535) + return 0; + + nskb = skb_copy_expand(*pskb, skb_headroom(*pskb), extra, GFP_ATOMIC); + if (!nskb) + return 0; + + /* Transfer socket to new skb. */ + if ((*pskb)->sk) + skb_set_owner_w(nskb, (*pskb)->sk); + kfree_skb(*pskb); + *pskb = nskb; + return 1; +} + +/* Generic function for mangling variable-length address changes inside + * NATed TCP connections (like the PORT XXX,XXX,XXX,XXX,XXX,XXX + * command in FTP). + * + * Takes care about all the nasty sequence number changes, checksumming, + * skb enlargement, ... + * + * */ +int +nf_nat_mangle_tcp_packet(struct sk_buff **pskb, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned int match_offset, + unsigned int match_len, + const char *rep_buffer, + unsigned int rep_len) +{ + struct iphdr *iph; + struct tcphdr *tcph; + int oldlen, datalen; + + if (!skb_make_writable(pskb, (*pskb)->len)) + return 0; + + if (rep_len > match_len && + rep_len - match_len > skb_tailroom(*pskb) && + !enlarge_skb(pskb, rep_len - match_len)) + return 0; + + SKB_LINEAR_ASSERT(*pskb); + + iph = (*pskb)->nh.iph; + tcph = (void *)iph + iph->ihl*4; + + oldlen = (*pskb)->len - iph->ihl*4; + mangle_contents(*pskb, iph->ihl*4 + tcph->doff*4, + match_offset, match_len, rep_buffer, rep_len); + + datalen = (*pskb)->len - iph->ihl*4; + if ((*pskb)->ip_summed != CHECKSUM_PARTIAL) { + tcph->check = 0; + tcph->check = tcp_v4_check(tcph, datalen, + iph->saddr, iph->daddr, + csum_partial((char *)tcph, + datalen, 0)); + } else + nf_proto_csum_replace2(&tcph->check, *pskb, + htons(oldlen), htons(datalen), 1); + + if (rep_len != match_len) { + set_bit(IPS_SEQ_ADJUST_BIT, &ct->status); + adjust_tcp_sequence(ntohl(tcph->seq), + (int)rep_len - (int)match_len, + ct, ctinfo); + /* Tell TCP window tracking about seq change */ + nf_conntrack_tcp_update(*pskb, (*pskb)->nh.iph->ihl*4, + ct, CTINFO2DIR(ctinfo)); + } + return 1; +} +EXPORT_SYMBOL(nf_nat_mangle_tcp_packet); + +/* Generic function for mangling variable-length address changes inside + * NATed UDP connections (like the CONNECT DATA XXXXX MESG XXXXX INDEX XXXXX + * command in the Amanda protocol) + * + * Takes care about all the nasty sequence number changes, checksumming, + * skb enlargement, ... + * + * XXX - This function could be merged with nf_nat_mangle_tcp_packet which + * should be fairly easy to do. + */ +int +nf_nat_mangle_udp_packet(struct sk_buff **pskb, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned int match_offset, + unsigned int match_len, + const char *rep_buffer, + unsigned int rep_len) +{ + struct iphdr *iph; + struct udphdr *udph; + int datalen, oldlen; + + /* UDP helpers might accidentally mangle the wrong packet */ + iph = (*pskb)->nh.iph; + if ((*pskb)->len < iph->ihl*4 + sizeof(*udph) + + match_offset + match_len) + return 0; + + if (!skb_make_writable(pskb, (*pskb)->len)) + return 0; + + if (rep_len > match_len && + rep_len - match_len > skb_tailroom(*pskb) && + !enlarge_skb(pskb, rep_len - match_len)) + return 0; + + iph = (*pskb)->nh.iph; + udph = (void *)iph + iph->ihl*4; + + oldlen = (*pskb)->len - iph->ihl*4; + mangle_contents(*pskb, iph->ihl*4 + sizeof(*udph), + match_offset, match_len, rep_buffer, rep_len); + + /* update the length of the UDP packet */ + datalen = (*pskb)->len - iph->ihl*4; + udph->len = htons(datalen); + + /* fix udp checksum if udp checksum was previously calculated */ + if (!udph->check && (*pskb)->ip_summed != CHECKSUM_PARTIAL) + return 1; + + if ((*pskb)->ip_summed != CHECKSUM_PARTIAL) { + udph->check = 0; + udph->check = csum_tcpudp_magic(iph->saddr, iph->daddr, + datalen, IPPROTO_UDP, + csum_partial((char *)udph, + datalen, 0)); + if (!udph->check) + udph->check = CSUM_MANGLED_0; + } else + nf_proto_csum_replace2(&udph->check, *pskb, + htons(oldlen), htons(datalen), 1); + + return 1; +} +EXPORT_SYMBOL(nf_nat_mangle_udp_packet); + +/* Adjust one found SACK option including checksum correction */ +static void +sack_adjust(struct sk_buff *skb, + struct tcphdr *tcph, + unsigned int sackoff, + unsigned int sackend, + struct nf_nat_seq *natseq) +{ + while (sackoff < sackend) { + struct tcp_sack_block_wire *sack; + __be32 new_start_seq, new_end_seq; + + sack = (void *)skb->data + sackoff; + if (after(ntohl(sack->start_seq) - natseq->offset_before, + natseq->correction_pos)) + new_start_seq = htonl(ntohl(sack->start_seq) + - natseq->offset_after); + else + new_start_seq = htonl(ntohl(sack->start_seq) + - natseq->offset_before); + + if (after(ntohl(sack->end_seq) - natseq->offset_before, + natseq->correction_pos)) + new_end_seq = htonl(ntohl(sack->end_seq) + - natseq->offset_after); + else + new_end_seq = htonl(ntohl(sack->end_seq) + - natseq->offset_before); + + DEBUGP("sack_adjust: start_seq: %d->%d, end_seq: %d->%d\n", + ntohl(sack->start_seq), new_start_seq, + ntohl(sack->end_seq), new_end_seq); + + nf_proto_csum_replace4(&tcph->check, skb, + sack->start_seq, new_start_seq, 0); + nf_proto_csum_replace4(&tcph->check, skb, + sack->end_seq, new_end_seq, 0); + sack->start_seq = new_start_seq; + sack->end_seq = new_end_seq; + sackoff += sizeof(*sack); + } +} + +/* TCP SACK sequence number adjustment */ +static inline unsigned int +nf_nat_sack_adjust(struct sk_buff **pskb, + struct tcphdr *tcph, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo) +{ + unsigned int dir, optoff, optend; + struct nf_conn_nat *nat = nfct_nat(ct); + + optoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct tcphdr); + optend = (*pskb)->nh.iph->ihl*4 + tcph->doff*4; + + if (!skb_make_writable(pskb, optend)) + return 0; + + dir = CTINFO2DIR(ctinfo); + + while (optoff < optend) { + /* Usually: option, length. */ + unsigned char *op = (*pskb)->data + optoff; + + switch (op[0]) { + case TCPOPT_EOL: + return 1; + case TCPOPT_NOP: + optoff++; + continue; + default: + /* no partial options */ + if (optoff + 1 == optend || + optoff + op[1] > optend || + op[1] < 2) + return 0; + if (op[0] == TCPOPT_SACK && + op[1] >= 2+TCPOLEN_SACK_PERBLOCK && + ((op[1] - 2) % TCPOLEN_SACK_PERBLOCK) == 0) + sack_adjust(*pskb, tcph, optoff+2, + optoff+op[1], + &nat->info.seq[!dir]); + optoff += op[1]; + } + } + return 1; +} + +/* TCP sequence number adjustment. Returns 1 on success, 0 on failure */ +int +nf_nat_seq_adjust(struct sk_buff **pskb, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo) +{ + struct tcphdr *tcph; + int dir; + __be32 newseq, newack; + struct nf_conn_nat *nat = nfct_nat(ct); + struct nf_nat_seq *this_way, *other_way; + + dir = CTINFO2DIR(ctinfo); + + this_way = &nat->info.seq[dir]; + other_way = &nat->info.seq[!dir]; + + if (!skb_make_writable(pskb, (*pskb)->nh.iph->ihl*4+sizeof(*tcph))) + return 0; + + tcph = (void *)(*pskb)->data + (*pskb)->nh.iph->ihl*4; + if (after(ntohl(tcph->seq), this_way->correction_pos)) + newseq = htonl(ntohl(tcph->seq) + this_way->offset_after); + else + newseq = htonl(ntohl(tcph->seq) + this_way->offset_before); + + if (after(ntohl(tcph->ack_seq) - other_way->offset_before, + other_way->correction_pos)) + newack = htonl(ntohl(tcph->ack_seq) - other_way->offset_after); + else + newack = htonl(ntohl(tcph->ack_seq) - other_way->offset_before); + + nf_proto_csum_replace4(&tcph->check, *pskb, tcph->seq, newseq, 0); + nf_proto_csum_replace4(&tcph->check, *pskb, tcph->ack_seq, newack, 0); + + DEBUGP("Adjusting sequence number from %u->%u, ack from %u->%u\n", + ntohl(tcph->seq), ntohl(newseq), ntohl(tcph->ack_seq), + ntohl(newack)); + + tcph->seq = newseq; + tcph->ack_seq = newack; + + if (!nf_nat_sack_adjust(pskb, tcph, ct, ctinfo)) + return 0; + + nf_conntrack_tcp_update(*pskb, (*pskb)->nh.iph->ihl*4, ct, dir); + + return 1; +} +EXPORT_SYMBOL(nf_nat_seq_adjust); + +/* Setup NAT on this expected conntrack so it follows master. */ +/* If we fail to get a free NAT slot, we'll get dropped on confirm */ +void nf_nat_follow_master(struct nf_conn *ct, + struct nf_conntrack_expect *exp) +{ + struct nf_nat_range range; + + /* This must be a fresh one. */ + BUG_ON(ct->status & IPS_NAT_DONE_MASK); + + /* Change src to where master sends to */ + range.flags = IP_NAT_RANGE_MAP_IPS; + range.min_ip = range.max_ip + = ct->master->tuplehash[!exp->dir].tuple.dst.u3.ip; + /* hook doesn't matter, but it has to do source manip */ + nf_nat_setup_info(ct, &range, NF_IP_POST_ROUTING); + + /* For DST manip, map port here to where it's expected. */ + range.flags = (IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED); + range.min = range.max = exp->saved_proto; + range.min_ip = range.max_ip + = ct->master->tuplehash[!exp->dir].tuple.src.u3.ip; + /* hook doesn't matter, but it has to do destination manip */ + nf_nat_setup_info(ct, &range, NF_IP_PRE_ROUTING); +} +EXPORT_SYMBOL(nf_nat_follow_master); diff --git a/net/ipv4/netfilter/nf_nat_proto_icmp.c b/net/ipv4/netfilter/nf_nat_proto_icmp.c new file mode 100644 index 00000000000..dcfd772972d --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_proto_icmp.c @@ -0,0 +1,86 @@ +/* (C) 1999-2001 Paul `Rusty' Russell + * (C) 2002-2006 Netfilter Core Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +static int +icmp_in_range(const struct nf_conntrack_tuple *tuple, + enum nf_nat_manip_type maniptype, + const union nf_conntrack_man_proto *min, + const union nf_conntrack_man_proto *max) +{ + return ntohs(tuple->src.u.icmp.id) >= ntohs(min->icmp.id) && + ntohs(tuple->src.u.icmp.id) <= ntohs(max->icmp.id); +} + +static int +icmp_unique_tuple(struct nf_conntrack_tuple *tuple, + const struct nf_nat_range *range, + enum nf_nat_manip_type maniptype, + const struct nf_conn *ct) +{ + static u_int16_t id; + unsigned int range_size; + unsigned int i; + + range_size = ntohs(range->max.icmp.id) - ntohs(range->min.icmp.id) + 1; + /* If no range specified... */ + if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) + range_size = 0xFFFF; + + for (i = 0; i < range_size; i++, id++) { + tuple->src.u.icmp.id = htons(ntohs(range->min.icmp.id) + + (id % range_size)); + if (!nf_nat_used_tuple(tuple, ct)) + return 1; + } + return 0; +} + +static int +icmp_manip_pkt(struct sk_buff **pskb, + unsigned int iphdroff, + const struct nf_conntrack_tuple *tuple, + enum nf_nat_manip_type maniptype) +{ + struct iphdr *iph = (struct iphdr *)((*pskb)->data + iphdroff); + struct icmphdr *hdr; + unsigned int hdroff = iphdroff + iph->ihl*4; + + if (!skb_make_writable(pskb, hdroff + sizeof(*hdr))) + return 0; + + hdr = (struct icmphdr *)((*pskb)->data + hdroff); + nf_proto_csum_replace2(&hdr->checksum, *pskb, + hdr->un.echo.id, tuple->src.u.icmp.id, 0); + hdr->un.echo.id = tuple->src.u.icmp.id; + return 1; +} + +struct nf_nat_protocol nf_nat_protocol_icmp = { + .name = "ICMP", + .protonum = IPPROTO_ICMP, + .me = THIS_MODULE, + .manip_pkt = icmp_manip_pkt, + .in_range = icmp_in_range, + .unique_tuple = icmp_unique_tuple, +#if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \ + defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE) + .range_to_nfattr = nf_nat_port_range_to_nfattr, + .nfattr_to_range = nf_nat_port_nfattr_to_range, +#endif +}; diff --git a/net/ipv4/netfilter/nf_nat_proto_tcp.c b/net/ipv4/netfilter/nf_nat_proto_tcp.c new file mode 100644 index 00000000000..7e26a7e9bee --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_proto_tcp.c @@ -0,0 +1,148 @@ +/* (C) 1999-2001 Paul `Rusty' Russell + * (C) 2002-2006 Netfilter Core Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +static int +tcp_in_range(const struct nf_conntrack_tuple *tuple, + enum nf_nat_manip_type maniptype, + const union nf_conntrack_man_proto *min, + const union nf_conntrack_man_proto *max) +{ + __be16 port; + + if (maniptype == IP_NAT_MANIP_SRC) + port = tuple->src.u.tcp.port; + else + port = tuple->dst.u.tcp.port; + + return ntohs(port) >= ntohs(min->tcp.port) && + ntohs(port) <= ntohs(max->tcp.port); +} + +static int +tcp_unique_tuple(struct nf_conntrack_tuple *tuple, + const struct nf_nat_range *range, + enum nf_nat_manip_type maniptype, + const struct nf_conn *ct) +{ + static u_int16_t port; + __be16 *portptr; + unsigned int range_size, min, i; + + if (maniptype == IP_NAT_MANIP_SRC) + portptr = &tuple->src.u.tcp.port; + else + portptr = &tuple->dst.u.tcp.port; + + /* If no range specified... */ + if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) { + /* If it's dst rewrite, can't change port */ + if (maniptype == IP_NAT_MANIP_DST) + return 0; + + /* Map privileged onto privileged. */ + if (ntohs(*portptr) < 1024) { + /* Loose convention: >> 512 is credential passing */ + if (ntohs(*portptr)<512) { + min = 1; + range_size = 511 - min + 1; + } else { + min = 600; + range_size = 1023 - min + 1; + } + } else { + min = 1024; + range_size = 65535 - 1024 + 1; + } + } else { + min = ntohs(range->min.tcp.port); + range_size = ntohs(range->max.tcp.port) - min + 1; + } + + for (i = 0; i < range_size; i++, port++) { + *portptr = htons(min + port % range_size); + if (!nf_nat_used_tuple(tuple, ct)) + return 1; + } + return 0; +} + +static int +tcp_manip_pkt(struct sk_buff **pskb, + unsigned int iphdroff, + const struct nf_conntrack_tuple *tuple, + enum nf_nat_manip_type maniptype) +{ + struct iphdr *iph = (struct iphdr *)((*pskb)->data + iphdroff); + struct tcphdr *hdr; + unsigned int hdroff = iphdroff + iph->ihl*4; + __be32 oldip, newip; + __be16 *portptr, newport, oldport; + int hdrsize = 8; /* TCP connection tracking guarantees this much */ + + /* this could be a inner header returned in icmp packet; in such + cases we cannot update the checksum field since it is outside of + the 8 bytes of transport layer headers we are guaranteed */ + if ((*pskb)->len >= hdroff + sizeof(struct tcphdr)) + hdrsize = sizeof(struct tcphdr); + + if (!skb_make_writable(pskb, hdroff + hdrsize)) + return 0; + + iph = (struct iphdr *)((*pskb)->data + iphdroff); + hdr = (struct tcphdr *)((*pskb)->data + hdroff); + + if (maniptype == IP_NAT_MANIP_SRC) { + /* Get rid of src ip and src pt */ + oldip = iph->saddr; + newip = tuple->src.u3.ip; + newport = tuple->src.u.tcp.port; + portptr = &hdr->source; + } else { + /* Get rid of dst ip and dst pt */ + oldip = iph->daddr; + newip = tuple->dst.u3.ip; + newport = tuple->dst.u.tcp.port; + portptr = &hdr->dest; + } + + oldport = *portptr; + *portptr = newport; + + if (hdrsize < sizeof(*hdr)) + return 1; + + nf_proto_csum_replace4(&hdr->check, *pskb, oldip, newip, 1); + nf_proto_csum_replace2(&hdr->check, *pskb, oldport, newport, 0); + return 1; +} + +struct nf_nat_protocol nf_nat_protocol_tcp = { + .name = "TCP", + .protonum = IPPROTO_TCP, + .me = THIS_MODULE, + .manip_pkt = tcp_manip_pkt, + .in_range = tcp_in_range, + .unique_tuple = tcp_unique_tuple, +#if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \ + defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE) + .range_to_nfattr = nf_nat_port_range_to_nfattr, + .nfattr_to_range = nf_nat_port_nfattr_to_range, +#endif +}; diff --git a/net/ipv4/netfilter/nf_nat_proto_udp.c b/net/ipv4/netfilter/nf_nat_proto_udp.c new file mode 100644 index 00000000000..ab0ce4c8699 --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_proto_udp.c @@ -0,0 +1,138 @@ +/* (C) 1999-2001 Paul `Rusty' Russell + * (C) 2002-2006 Netfilter Core Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +static int +udp_in_range(const struct nf_conntrack_tuple *tuple, + enum nf_nat_manip_type maniptype, + const union nf_conntrack_man_proto *min, + const union nf_conntrack_man_proto *max) +{ + __be16 port; + + if (maniptype == IP_NAT_MANIP_SRC) + port = tuple->src.u.udp.port; + else + port = tuple->dst.u.udp.port; + + return ntohs(port) >= ntohs(min->udp.port) && + ntohs(port) <= ntohs(max->udp.port); +} + +static int +udp_unique_tuple(struct nf_conntrack_tuple *tuple, + const struct nf_nat_range *range, + enum nf_nat_manip_type maniptype, + const struct nf_conn *ct) +{ + static u_int16_t port; + __be16 *portptr; + unsigned int range_size, min, i; + + if (maniptype == IP_NAT_MANIP_SRC) + portptr = &tuple->src.u.udp.port; + else + portptr = &tuple->dst.u.udp.port; + + /* If no range specified... */ + if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) { + /* If it's dst rewrite, can't change port */ + if (maniptype == IP_NAT_MANIP_DST) + return 0; + + if (ntohs(*portptr) < 1024) { + /* Loose convention: >> 512 is credential passing */ + if (ntohs(*portptr)<512) { + min = 1; + range_size = 511 - min + 1; + } else { + min = 600; + range_size = 1023 - min + 1; + } + } else { + min = 1024; + range_size = 65535 - 1024 + 1; + } + } else { + min = ntohs(range->min.udp.port); + range_size = ntohs(range->max.udp.port) - min + 1; + } + + for (i = 0; i < range_size; i++, port++) { + *portptr = htons(min + port % range_size); + if (!nf_nat_used_tuple(tuple, ct)) + return 1; + } + return 0; +} + +static int +udp_manip_pkt(struct sk_buff **pskb, + unsigned int iphdroff, + const struct nf_conntrack_tuple *tuple, + enum nf_nat_manip_type maniptype) +{ + struct iphdr *iph = (struct iphdr *)((*pskb)->data + iphdroff); + struct udphdr *hdr; + unsigned int hdroff = iphdroff + iph->ihl*4; + __be32 oldip, newip; + __be16 *portptr, newport; + + if (!skb_make_writable(pskb, hdroff + sizeof(*hdr))) + return 0; + + iph = (struct iphdr *)((*pskb)->data + iphdroff); + hdr = (struct udphdr *)((*pskb)->data + hdroff); + + if (maniptype == IP_NAT_MANIP_SRC) { + /* Get rid of src ip and src pt */ + oldip = iph->saddr; + newip = tuple->src.u3.ip; + newport = tuple->src.u.udp.port; + portptr = &hdr->source; + } else { + /* Get rid of dst ip and dst pt */ + oldip = iph->daddr; + newip = tuple->dst.u3.ip; + newport = tuple->dst.u.udp.port; + portptr = &hdr->dest; + } + if (hdr->check || (*pskb)->ip_summed == CHECKSUM_PARTIAL) { + nf_proto_csum_replace4(&hdr->check, *pskb, oldip, newip, 1); + nf_proto_csum_replace2(&hdr->check, *pskb, *portptr, newport, + 0); + if (!hdr->check) + hdr->check = CSUM_MANGLED_0; + } + *portptr = newport; + return 1; +} + +struct nf_nat_protocol nf_nat_protocol_udp = { + .name = "UDP", + .protonum = IPPROTO_UDP, + .me = THIS_MODULE, + .manip_pkt = udp_manip_pkt, + .in_range = udp_in_range, + .unique_tuple = udp_unique_tuple, +#if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \ + defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE) + .range_to_nfattr = nf_nat_port_range_to_nfattr, + .nfattr_to_range = nf_nat_port_nfattr_to_range, +#endif +}; diff --git a/net/ipv4/netfilter/nf_nat_proto_unknown.c b/net/ipv4/netfilter/nf_nat_proto_unknown.c new file mode 100644 index 00000000000..f50d0203f9c --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_proto_unknown.c @@ -0,0 +1,54 @@ +/* The "unknown" protocol. This is what is used for protocols we + * don't understand. It's returned by ip_ct_find_proto(). + */ + +/* (C) 1999-2001 Paul `Rusty' Russell + * (C) 2002-2006 Netfilter Core Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include + +#include +#include +#include +#include + +static int unknown_in_range(const struct nf_conntrack_tuple *tuple, + enum nf_nat_manip_type manip_type, + const union nf_conntrack_man_proto *min, + const union nf_conntrack_man_proto *max) +{ + return 1; +} + +static int unknown_unique_tuple(struct nf_conntrack_tuple *tuple, + const struct nf_nat_range *range, + enum nf_nat_manip_type maniptype, + const struct nf_conn *ct) +{ + /* Sorry: we can't help you; if it's not unique, we can't frob + anything. */ + return 0; +} + +static int +unknown_manip_pkt(struct sk_buff **pskb, + unsigned int iphdroff, + const struct nf_conntrack_tuple *tuple, + enum nf_nat_manip_type maniptype) +{ + return 1; +} + +struct nf_nat_protocol nf_nat_unknown_protocol = { + .name = "unknown", + /* .me isn't set: getting a ref to this cannot fail. */ + .manip_pkt = unknown_manip_pkt, + .in_range = unknown_in_range, + .unique_tuple = unknown_unique_tuple, +}; diff --git a/net/ipv4/netfilter/nf_nat_rule.c b/net/ipv4/netfilter/nf_nat_rule.c new file mode 100644 index 00000000000..b868ee0195d --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_rule.c @@ -0,0 +1,343 @@ +/* (C) 1999-2001 Paul `Rusty' Russell + * (C) 2002-2006 Netfilter Core Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* Everything about the rules for NAT. */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(format, args...) +#endif + +#define NAT_VALID_HOOKS ((1<range[0], hooknum); +} + +/* Before 2.6.11 we did implicit source NAT if required. Warn about change. */ +static void warn_if_extra_mangle(__be32 dstip, __be32 srcip) +{ + static int warned = 0; + struct flowi fl = { .nl_u = { .ip4_u = { .daddr = dstip } } }; + struct rtable *rt; + + if (ip_route_output_key(&rt, &fl) != 0) + return; + + if (rt->rt_src != srcip && !warned) { + printk("NAT: no longer support implicit source local NAT\n"); + printk("NAT: packet src %u.%u.%u.%u -> dst %u.%u.%u.%u\n", + NIPQUAD(srcip), NIPQUAD(dstip)); + warned = 1; + } + ip_rt_put(rt); +} + +static unsigned int ipt_dnat_target(struct sk_buff **pskb, + const struct net_device *in, + const struct net_device *out, + unsigned int hooknum, + const struct xt_target *target, + const void *targinfo) +{ + struct nf_conn *ct; + enum ip_conntrack_info ctinfo; + const struct nf_nat_multi_range_compat *mr = targinfo; + + NF_CT_ASSERT(hooknum == NF_IP_PRE_ROUTING || + hooknum == NF_IP_LOCAL_OUT); + + ct = nf_ct_get(*pskb, &ctinfo); + + /* Connection must be valid and new. */ + NF_CT_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED)); + + if (hooknum == NF_IP_LOCAL_OUT && + mr->range[0].flags & IP_NAT_RANGE_MAP_IPS) + warn_if_extra_mangle((*pskb)->nh.iph->daddr, + mr->range[0].min_ip); + + return nf_nat_setup_info(ct, &mr->range[0], hooknum); +} + +static int ipt_snat_checkentry(const char *tablename, + const void *entry, + const struct xt_target *target, + void *targinfo, + unsigned int hook_mask) +{ + struct nf_nat_multi_range_compat *mr = targinfo; + + /* Must be a valid range */ + if (mr->rangesize != 1) { + printk("SNAT: multiple ranges no longer supported\n"); + return 0; + } + return 1; +} + +static int ipt_dnat_checkentry(const char *tablename, + const void *entry, + const struct xt_target *target, + void *targinfo, + unsigned int hook_mask) +{ + struct nf_nat_multi_range_compat *mr = targinfo; + + /* Must be a valid range */ + if (mr->rangesize != 1) { + printk("DNAT: multiple ranges no longer supported\n"); + return 0; + } + return 1; +} + +inline unsigned int +alloc_null_binding(struct nf_conn *ct, + struct nf_nat_info *info, + unsigned int hooknum) +{ + /* Force range to this IP; let proto decide mapping for + per-proto parts (hence not IP_NAT_RANGE_PROTO_SPECIFIED). + Use reply in case it's already been mangled (eg local packet). + */ + __be32 ip + = (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC + ? ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip + : ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip); + struct nf_nat_range range + = { IP_NAT_RANGE_MAP_IPS, ip, ip, { 0 }, { 0 } }; + + DEBUGP("Allocating NULL binding for %p (%u.%u.%u.%u)\n", + ct, NIPQUAD(ip)); + return nf_nat_setup_info(ct, &range, hooknum); +} + +unsigned int +alloc_null_binding_confirmed(struct nf_conn *ct, + struct nf_nat_info *info, + unsigned int hooknum) +{ + __be32 ip + = (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC + ? ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip + : ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip); + u_int16_t all + = (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC + ? ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.all + : ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u.all); + struct nf_nat_range range + = { IP_NAT_RANGE_MAP_IPS, ip, ip, { all }, { all } }; + + DEBUGP("Allocating NULL binding for confirmed %p (%u.%u.%u.%u)\n", + ct, NIPQUAD(ip)); + return nf_nat_setup_info(ct, &range, hooknum); +} + +int nf_nat_rule_find(struct sk_buff **pskb, + unsigned int hooknum, + const struct net_device *in, + const struct net_device *out, + struct nf_conn *ct, + struct nf_nat_info *info) +{ + int ret; + + ret = ipt_do_table(pskb, hooknum, in, out, &nat_table); + + if (ret == NF_ACCEPT) { + if (!nf_nat_initialized(ct, HOOK2MANIP(hooknum))) + /* NUL mapping */ + ret = alloc_null_binding(ct, info, hooknum); + } + return ret; +} + +static struct ipt_target ipt_snat_reg = { + .name = "SNAT", + .target = ipt_snat_target, + .targetsize = sizeof(struct nf_nat_multi_range_compat), + .table = "nat", + .hooks = 1 << NF_IP_POST_ROUTING, + .checkentry = ipt_snat_checkentry, + .family = AF_INET, +}; + +static struct xt_target ipt_dnat_reg = { + .name = "DNAT", + .target = ipt_dnat_target, + .targetsize = sizeof(struct nf_nat_multi_range_compat), + .table = "nat", + .hooks = (1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_OUT), + .checkentry = ipt_dnat_checkentry, + .family = AF_INET, +}; + +int __init nf_nat_rule_init(void) +{ + int ret; + + ret = ipt_register_table(&nat_table, &nat_initial_table.repl); + if (ret != 0) + return ret; + ret = xt_register_target(&ipt_snat_reg); + if (ret != 0) + goto unregister_table; + + ret = xt_register_target(&ipt_dnat_reg); + if (ret != 0) + goto unregister_snat; + + return ret; + + unregister_snat: + xt_unregister_target(&ipt_snat_reg); + unregister_table: + ipt_unregister_table(&nat_table); + + return ret; +} + +void nf_nat_rule_cleanup(void) +{ + xt_unregister_target(&ipt_dnat_reg); + xt_unregister_target(&ipt_snat_reg); + ipt_unregister_table(&nat_table); +} diff --git a/net/ipv4/netfilter/nf_nat_standalone.c b/net/ipv4/netfilter/nf_nat_standalone.c new file mode 100644 index 00000000000..730a7a44c88 --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_standalone.c @@ -0,0 +1,406 @@ +/* (C) 1999-2001 Paul `Rusty' Russell + * (C) 2002-2006 Netfilter Core Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(format, args...) +#endif + +#define HOOKNAME(hooknum) ((hooknum) == NF_IP_POST_ROUTING ? "POST_ROUTING" \ + : ((hooknum) == NF_IP_PRE_ROUTING ? "PRE_ROUTING" \ + : ((hooknum) == NF_IP_LOCAL_OUT ? "LOCAL_OUT" \ + : ((hooknum) == NF_IP_LOCAL_IN ? "LOCAL_IN" \ + : "*ERROR*"))) + +#ifdef CONFIG_XFRM +static void nat_decode_session(struct sk_buff *skb, struct flowi *fl) +{ + struct nf_conn *ct; + struct nf_conntrack_tuple *t; + enum ip_conntrack_info ctinfo; + enum ip_conntrack_dir dir; + unsigned long statusbit; + + ct = nf_ct_get(skb, &ctinfo); + if (ct == NULL) + return; + dir = CTINFO2DIR(ctinfo); + t = &ct->tuplehash[dir].tuple; + + if (dir == IP_CT_DIR_ORIGINAL) + statusbit = IPS_DST_NAT; + else + statusbit = IPS_SRC_NAT; + + if (ct->status & statusbit) { + fl->fl4_dst = t->dst.u3.ip; + if (t->dst.protonum == IPPROTO_TCP || + t->dst.protonum == IPPROTO_UDP) + fl->fl_ip_dport = t->dst.u.tcp.port; + } + + statusbit ^= IPS_NAT_MASK; + + if (ct->status & statusbit) { + fl->fl4_src = t->src.u3.ip; + if (t->dst.protonum == IPPROTO_TCP || + t->dst.protonum == IPPROTO_UDP) + fl->fl_ip_sport = t->src.u.tcp.port; + } +} +#endif + +static unsigned int +nf_nat_fn(unsigned int hooknum, + struct sk_buff **pskb, + const struct net_device *in, + const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ + struct nf_conn *ct; + enum ip_conntrack_info ctinfo; + struct nf_conn_nat *nat; + struct nf_nat_info *info; + /* maniptype == SRC for postrouting. */ + enum nf_nat_manip_type maniptype = HOOK2MANIP(hooknum); + + /* We never see fragments: conntrack defrags on pre-routing + and local-out, and nf_nat_out protects post-routing. */ + NF_CT_ASSERT(!((*pskb)->nh.iph->frag_off + & htons(IP_MF|IP_OFFSET))); + + ct = nf_ct_get(*pskb, &ctinfo); + /* Can't track? It's not due to stress, or conntrack would + have dropped it. Hence it's the user's responsibilty to + packet filter it out, or implement conntrack/NAT for that + protocol. 8) --RR */ + if (!ct) { + /* Exception: ICMP redirect to new connection (not in + hash table yet). We must not let this through, in + case we're doing NAT to the same network. */ + if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP) { + struct icmphdr _hdr, *hp; + + hp = skb_header_pointer(*pskb, + (*pskb)->nh.iph->ihl*4, + sizeof(_hdr), &_hdr); + if (hp != NULL && + hp->type == ICMP_REDIRECT) + return NF_DROP; + } + return NF_ACCEPT; + } + + /* Don't try to NAT if this packet is not conntracked */ + if (ct == &nf_conntrack_untracked) + return NF_ACCEPT; + + nat = nfct_nat(ct); + if (!nat) + return NF_DROP; + + switch (ctinfo) { + case IP_CT_RELATED: + case IP_CT_RELATED+IP_CT_IS_REPLY: + if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP) { + if (!nf_nat_icmp_reply_translation(ct, ctinfo, + hooknum, pskb)) + return NF_DROP; + else + return NF_ACCEPT; + } + /* Fall thru... (Only ICMPs can be IP_CT_IS_REPLY) */ + case IP_CT_NEW: + info = &nat->info; + + /* Seen it before? This can happen for loopback, retrans, + or local packets.. */ + if (!nf_nat_initialized(ct, maniptype)) { + unsigned int ret; + + if (unlikely(nf_ct_is_confirmed(ct))) + /* NAT module was loaded late */ + ret = alloc_null_binding_confirmed(ct, info, + hooknum); + else if (hooknum == NF_IP_LOCAL_IN) + /* LOCAL_IN hook doesn't have a chain! */ + ret = alloc_null_binding(ct, info, hooknum); + else + ret = nf_nat_rule_find(pskb, hooknum, in, out, + ct, info); + + if (ret != NF_ACCEPT) { + return ret; + } + } else + DEBUGP("Already setup manip %s for ct %p\n", + maniptype == IP_NAT_MANIP_SRC ? "SRC" : "DST", + ct); + break; + + default: + /* ESTABLISHED */ + NF_CT_ASSERT(ctinfo == IP_CT_ESTABLISHED || + ctinfo == (IP_CT_ESTABLISHED+IP_CT_IS_REPLY)); + info = &nat->info; + } + + NF_CT_ASSERT(info); + return nf_nat_packet(ct, ctinfo, hooknum, pskb); +} + +static unsigned int +nf_nat_in(unsigned int hooknum, + struct sk_buff **pskb, + const struct net_device *in, + const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ + unsigned int ret; + __be32 daddr = (*pskb)->nh.iph->daddr; + + ret = nf_nat_fn(hooknum, pskb, in, out, okfn); + if (ret != NF_DROP && ret != NF_STOLEN && + daddr != (*pskb)->nh.iph->daddr) { + dst_release((*pskb)->dst); + (*pskb)->dst = NULL; + } + return ret; +} + +static unsigned int +nf_nat_out(unsigned int hooknum, + struct sk_buff **pskb, + const struct net_device *in, + const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ +#ifdef CONFIG_XFRM + struct nf_conn *ct; + enum ip_conntrack_info ctinfo; +#endif + unsigned int ret; + + /* root is playing with raw sockets. */ + if ((*pskb)->len < sizeof(struct iphdr) || + (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr)) + return NF_ACCEPT; + + ret = nf_nat_fn(hooknum, pskb, in, out, okfn); +#ifdef CONFIG_XFRM + if (ret != NF_DROP && ret != NF_STOLEN && + (ct = nf_ct_get(*pskb, &ctinfo)) != NULL) { + enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); + + if (ct->tuplehash[dir].tuple.src.u3.ip != + ct->tuplehash[!dir].tuple.dst.u3.ip + || ct->tuplehash[dir].tuple.src.u.all != + ct->tuplehash[!dir].tuple.dst.u.all + ) + return ip_xfrm_me_harder(pskb) == 0 ? ret : NF_DROP; + } +#endif + return ret; +} + +static unsigned int +nf_nat_local_fn(unsigned int hooknum, + struct sk_buff **pskb, + const struct net_device *in, + const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ + struct nf_conn *ct; + enum ip_conntrack_info ctinfo; + unsigned int ret; + + /* root is playing with raw sockets. */ + if ((*pskb)->len < sizeof(struct iphdr) || + (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr)) + return NF_ACCEPT; + + ret = nf_nat_fn(hooknum, pskb, in, out, okfn); + if (ret != NF_DROP && ret != NF_STOLEN && + (ct = nf_ct_get(*pskb, &ctinfo)) != NULL) { + enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); + + if (ct->tuplehash[dir].tuple.dst.u3.ip != + ct->tuplehash[!dir].tuple.src.u3.ip +#ifdef CONFIG_XFRM + || ct->tuplehash[dir].tuple.dst.u.all != + ct->tuplehash[!dir].tuple.src.u.all +#endif + ) + if (ip_route_me_harder(pskb, RTN_UNSPEC)) + ret = NF_DROP; + } + return ret; +} + +static unsigned int +nf_nat_adjust(unsigned int hooknum, + struct sk_buff **pskb, + const struct net_device *in, + const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ + struct nf_conn *ct; + enum ip_conntrack_info ctinfo; + + ct = nf_ct_get(*pskb, &ctinfo); + if (ct && test_bit(IPS_SEQ_ADJUST_BIT, &ct->status)) { + DEBUGP("nf_nat_standalone: adjusting sequence number\n"); + if (!nf_nat_seq_adjust(pskb, ct, ctinfo)) + return NF_DROP; + } + return NF_ACCEPT; +} + +/* We must be after connection tracking and before packet filtering. */ + +static struct nf_hook_ops nf_nat_ops[] = { + /* Before packet filtering, change destination */ + { + .hook = nf_nat_in, + .owner = THIS_MODULE, + .pf = PF_INET, + .hooknum = NF_IP_PRE_ROUTING, + .priority = NF_IP_PRI_NAT_DST, + }, + /* After packet filtering, change source */ + { + .hook = nf_nat_out, + .owner = THIS_MODULE, + .pf = PF_INET, + .hooknum = NF_IP_POST_ROUTING, + .priority = NF_IP_PRI_NAT_SRC, + }, + /* After conntrack, adjust sequence number */ + { + .hook = nf_nat_adjust, + .owner = THIS_MODULE, + .pf = PF_INET, + .hooknum = NF_IP_POST_ROUTING, + .priority = NF_IP_PRI_NAT_SEQ_ADJUST, + }, + /* Before packet filtering, change destination */ + { + .hook = nf_nat_local_fn, + .owner = THIS_MODULE, + .pf = PF_INET, + .hooknum = NF_IP_LOCAL_OUT, + .priority = NF_IP_PRI_NAT_DST, + }, + /* After packet filtering, change source */ + { + .hook = nf_nat_fn, + .owner = THIS_MODULE, + .pf = PF_INET, + .hooknum = NF_IP_LOCAL_IN, + .priority = NF_IP_PRI_NAT_SRC, + }, + /* After conntrack, adjust sequence number */ + { + .hook = nf_nat_adjust, + .owner = THIS_MODULE, + .pf = PF_INET, + .hooknum = NF_IP_LOCAL_IN, + .priority = NF_IP_PRI_NAT_SEQ_ADJUST, + }, +}; + +static int __init nf_nat_standalone_init(void) +{ + int size, ret = 0; + + need_conntrack(); + + size = ALIGN(sizeof(struct nf_conn), __alignof__(struct nf_conn_nat)) + + sizeof(struct nf_conn_nat); + ret = nf_conntrack_register_cache(NF_CT_F_NAT, "nf_nat:base", size); + if (ret < 0) { + printk(KERN_ERR "nf_nat_init: Unable to create slab cache\n"); + return ret; + } + + size = ALIGN(size, __alignof__(struct nf_conn_help)) + + sizeof(struct nf_conn_help); + ret = nf_conntrack_register_cache(NF_CT_F_NAT|NF_CT_F_HELP, + "nf_nat:help", size); + if (ret < 0) { + printk(KERN_ERR "nf_nat_init: Unable to create slab cache\n"); + goto cleanup_register_cache; + } +#ifdef CONFIG_XFRM + BUG_ON(ip_nat_decode_session != NULL); + ip_nat_decode_session = nat_decode_session; +#endif + ret = nf_nat_rule_init(); + if (ret < 0) { + printk("nf_nat_init: can't setup rules.\n"); + goto cleanup_decode_session; + } + ret = nf_register_hooks(nf_nat_ops, ARRAY_SIZE(nf_nat_ops)); + if (ret < 0) { + printk("nf_nat_init: can't register hooks.\n"); + goto cleanup_rule_init; + } + nf_nat_module_is_loaded = 1; + return ret; + + cleanup_rule_init: + nf_nat_rule_cleanup(); + cleanup_decode_session: +#ifdef CONFIG_XFRM + ip_nat_decode_session = NULL; + synchronize_net(); +#endif + nf_conntrack_unregister_cache(NF_CT_F_NAT|NF_CT_F_HELP); + cleanup_register_cache: + nf_conntrack_unregister_cache(NF_CT_F_NAT); + return ret; +} + +static void __exit nf_nat_standalone_fini(void) +{ + nf_unregister_hooks(nf_nat_ops, ARRAY_SIZE(nf_nat_ops)); + nf_nat_rule_cleanup(); + nf_nat_module_is_loaded = 0; +#ifdef CONFIG_XFRM + ip_nat_decode_session = NULL; + synchronize_net(); +#endif + /* Conntrack caches are unregistered in nf_conntrack_cleanup */ +} + +module_init(nf_nat_standalone_init); +module_exit(nf_nat_standalone_fini); + +MODULE_LICENSE("GPL"); +MODULE_ALIAS("ip_nat"); -- cgit v1.2.3 From 55a733247d6d2883d9bb77825fafac3dfca13fc2 Mon Sep 17 00:00:00 2001 From: Jozsef Kadlecsik Date: Sat, 2 Dec 2006 22:07:44 -0800 Subject: [NETFILTER]: nf_nat: add FTP NAT helper port Add FTP NAT helper. Split out from Jozsef's big nf_nat patch with a few small fixes by myself. Signed-off-by: Jozsef Kadlecsik Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/ipv4/netfilter/Kconfig | 25 ++++-- net/ipv4/netfilter/Makefile | 5 +- net/ipv4/netfilter/nf_nat_ftp.c | 179 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 200 insertions(+), 9 deletions(-) create mode 100644 net/ipv4/netfilter/nf_nat_ftp.c (limited to 'net/ipv4') diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index 01789aeaeb5..52f876db68f 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig @@ -477,20 +477,29 @@ config IP_NF_NAT_SNMP_BASIC To compile it as a module, choose M here. If unsure, say N. +# If they want FTP, set to $CONFIG_IP_NF_NAT (m or y), +# or $CONFIG_IP_NF_FTP (m or y), whichever is weaker. +# From kconfig-language.txt: +# +# '&&' (6) +# +# (6) Returns the result of min(/expr/, /expr/). +config IP_NF_NAT_FTP + tristate + depends on IP_NF_IPTABLES && IP_NF_CONNTRACK && IP_NF_NAT + default IP_NF_NAT && IP_NF_FTP + +config NF_NAT_FTP + tristate + depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT + default NF_NAT && NF_CONNTRACK_FTP + config IP_NF_NAT_IRC tristate depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n default IP_NF_NAT if IP_NF_IRC=y default m if IP_NF_IRC=m -# If they want FTP, set to $CONFIG_IP_NF_NAT (m or y), -# or $CONFIG_IP_NF_FTP (m or y), whichever is weaker. Argh. -config IP_NF_NAT_FTP - tristate - depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n - default IP_NF_NAT if IP_NF_FTP=y - default m if IP_NF_FTP=m - config IP_NF_NAT_TFTP tristate depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index ec31690764a..c0c6194bb27 100644 --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile @@ -40,7 +40,7 @@ obj-$(CONFIG_IP_NF_IRC) += ip_conntrack_irc.o obj-$(CONFIG_IP_NF_SIP) += ip_conntrack_sip.o obj-$(CONFIG_IP_NF_NETBIOS_NS) += ip_conntrack_netbios_ns.o -# NAT helpers +# NAT helpers (ip_conntrack) obj-$(CONFIG_IP_NF_NAT_H323) += ip_nat_h323.o obj-$(CONFIG_IP_NF_NAT_PPTP) += ip_nat_pptp.o obj-$(CONFIG_IP_NF_NAT_AMANDA) += ip_nat_amanda.o @@ -49,6 +49,9 @@ obj-$(CONFIG_IP_NF_NAT_FTP) += ip_nat_ftp.o obj-$(CONFIG_IP_NF_NAT_IRC) += ip_nat_irc.o obj-$(CONFIG_IP_NF_NAT_SIP) += ip_nat_sip.o +# NAT helpers (nf_conntrack) +obj-$(CONFIG_NF_NAT_FTP) += nf_nat_ftp.o + # generic IP tables obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o diff --git a/net/ipv4/netfilter/nf_nat_ftp.c b/net/ipv4/netfilter/nf_nat_ftp.c new file mode 100644 index 00000000000..751b5980175 --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_ftp.c @@ -0,0 +1,179 @@ +/* FTP extension for TCP NAT alteration. */ + +/* (C) 1999-2001 Paul `Rusty' Russell + * (C) 2002-2006 Netfilter Core Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Rusty Russell "); +MODULE_DESCRIPTION("ftp NAT helper"); +MODULE_ALIAS("ip_nat_ftp"); + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(format, args...) +#endif + +/* FIXME: Time out? --RR */ + +static int +mangle_rfc959_packet(struct sk_buff **pskb, + __be32 newip, + u_int16_t port, + unsigned int matchoff, + unsigned int matchlen, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + u32 *seq) +{ + char buffer[sizeof("nnn,nnn,nnn,nnn,nnn,nnn")]; + + sprintf(buffer, "%u,%u,%u,%u,%u,%u", + NIPQUAD(newip), port>>8, port&0xFF); + + DEBUGP("calling nf_nat_mangle_tcp_packet\n"); + + *seq += strlen(buffer) - matchlen; + return nf_nat_mangle_tcp_packet(pskb, ct, ctinfo, matchoff, + matchlen, buffer, strlen(buffer)); +} + +/* |1|132.235.1.2|6275| */ +static int +mangle_eprt_packet(struct sk_buff **pskb, + __be32 newip, + u_int16_t port, + unsigned int matchoff, + unsigned int matchlen, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + u32 *seq) +{ + char buffer[sizeof("|1|255.255.255.255|65535|")]; + + sprintf(buffer, "|1|%u.%u.%u.%u|%u|", NIPQUAD(newip), port); + + DEBUGP("calling nf_nat_mangle_tcp_packet\n"); + + *seq += strlen(buffer) - matchlen; + return nf_nat_mangle_tcp_packet(pskb, ct, ctinfo, matchoff, + matchlen, buffer, strlen(buffer)); +} + +/* |1|132.235.1.2|6275| */ +static int +mangle_epsv_packet(struct sk_buff **pskb, + __be32 newip, + u_int16_t port, + unsigned int matchoff, + unsigned int matchlen, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + u32 *seq) +{ + char buffer[sizeof("|||65535|")]; + + sprintf(buffer, "|||%u|", port); + + DEBUGP("calling nf_nat_mangle_tcp_packet\n"); + + *seq += strlen(buffer) - matchlen; + return nf_nat_mangle_tcp_packet(pskb, ct, ctinfo, matchoff, + matchlen, buffer, strlen(buffer)); +} + +static int (*mangle[])(struct sk_buff **, __be32, u_int16_t, + unsigned int, unsigned int, struct nf_conn *, + enum ip_conntrack_info, u32 *seq) += { + [NF_CT_FTP_PORT] = mangle_rfc959_packet, + [NF_CT_FTP_PASV] = mangle_rfc959_packet, + [NF_CT_FTP_EPRT] = mangle_eprt_packet, + [NF_CT_FTP_EPSV] = mangle_epsv_packet +}; + +/* So, this packet has hit the connection tracking matching code. + Mangle it, and change the expectation to match the new version. */ +static unsigned int nf_nat_ftp(struct sk_buff **pskb, + enum ip_conntrack_info ctinfo, + enum nf_ct_ftp_type type, + unsigned int matchoff, + unsigned int matchlen, + struct nf_conntrack_expect *exp, + u32 *seq) +{ + __be32 newip; + u_int16_t port; + int dir = CTINFO2DIR(ctinfo); + struct nf_conn *ct = exp->master; + + DEBUGP("FTP_NAT: type %i, off %u len %u\n", type, matchoff, matchlen); + + /* Connection will come from wherever this packet goes, hence !dir */ + newip = ct->tuplehash[!dir].tuple.dst.u3.ip; + exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port; + exp->dir = !dir; + + /* When you see the packet, we need to NAT it the same as the + * this one. */ + exp->expectfn = nf_nat_follow_master; + + /* Try to get same port: if not, try to change it. */ + for (port = ntohs(exp->saved_proto.tcp.port); port != 0; port++) { + exp->tuple.dst.u.tcp.port = htons(port); + if (nf_conntrack_expect_related(exp) == 0) + break; + } + + if (port == 0) + return NF_DROP; + + if (!mangle[type](pskb, newip, port, matchoff, matchlen, ct, ctinfo, + seq)) { + nf_conntrack_unexpect_related(exp); + return NF_DROP; + } + return NF_ACCEPT; +} + +static void __exit nf_nat_ftp_fini(void) +{ + rcu_assign_pointer(nf_nat_ftp_hook, NULL); + synchronize_rcu(); +} + +static int __init nf_nat_ftp_init(void) +{ + BUG_ON(rcu_dereference(nf_nat_ftp_hook)); + rcu_assign_pointer(nf_nat_ftp_hook, nf_nat_ftp); + return 0; +} + +/* Prior to 2.6.11, we had a ports param. No longer, but don't break users. */ +static int warn_set(const char *val, struct kernel_param *kp) +{ + printk(KERN_INFO KBUILD_MODNAME + ": kernel >= 2.6.10 only uses 'ports' for conntrack modules\n"); + return 0; +} +module_param_call(ports, warn_set, NULL, NULL, 0); + +module_init(nf_nat_ftp_init); +module_exit(nf_nat_ftp_fini); -- cgit v1.2.3 From 16958900578b94585c2ab9a2d20d837b4d5e3ba6 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Sat, 2 Dec 2006 22:08:26 -0800 Subject: [NETFILTER]: nf_conntrack/nf_nat: add amanda helper port Add IPv4 and IPv6 capable nf_conntrack port of the Amanda conntrack/NAT helper. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/ipv4/netfilter/Kconfig | 5 +++ net/ipv4/netfilter/Makefile | 1 + net/ipv4/netfilter/nf_nat_amanda.c | 78 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 84 insertions(+) create mode 100644 net/ipv4/netfilter/nf_nat_amanda.c (limited to 'net/ipv4') diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index 52f876db68f..6993ec53dc0 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig @@ -512,6 +512,11 @@ config IP_NF_NAT_AMANDA default IP_NF_NAT if IP_NF_AMANDA=y default m if IP_NF_AMANDA=m +config NF_NAT_AMANDA + tristate + depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT + default NF_NAT && NF_CONNTRACK_AMANDA + config IP_NF_NAT_PPTP tristate depends on IP_NF_NAT!=n && IP_NF_PPTP!=n diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index c0c6194bb27..8893249bbe9 100644 --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile @@ -50,6 +50,7 @@ obj-$(CONFIG_IP_NF_NAT_IRC) += ip_nat_irc.o obj-$(CONFIG_IP_NF_NAT_SIP) += ip_nat_sip.o # NAT helpers (nf_conntrack) +obj-$(CONFIG_NF_NAT_AMANDA) += nf_nat_amanda.o obj-$(CONFIG_NF_NAT_FTP) += nf_nat_ftp.o # generic IP tables diff --git a/net/ipv4/netfilter/nf_nat_amanda.c b/net/ipv4/netfilter/nf_nat_amanda.c new file mode 100644 index 00000000000..0f17098917b --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_amanda.c @@ -0,0 +1,78 @@ +/* Amanda extension for TCP NAT alteration. + * (C) 2002 by Brian J. Murrell + * based on a copy of HW's ip_nat_irc.c as well as other modules + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Brian J. Murrell "); +MODULE_DESCRIPTION("Amanda NAT helper"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("ip_nat_amanda"); + +static unsigned int help(struct sk_buff **pskb, + enum ip_conntrack_info ctinfo, + unsigned int matchoff, + unsigned int matchlen, + struct nf_conntrack_expect *exp) +{ + char buffer[sizeof("65535")]; + u_int16_t port; + unsigned int ret; + + /* Connection comes from client. */ + exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port; + exp->dir = IP_CT_DIR_ORIGINAL; + + /* When you see the packet, we need to NAT it the same as the + * this one (ie. same IP: it will be TCP and master is UDP). */ + exp->expectfn = nf_nat_follow_master; + + /* Try to get same port: if not, try to change it. */ + for (port = ntohs(exp->saved_proto.tcp.port); port != 0; port++) { + exp->tuple.dst.u.tcp.port = htons(port); + if (nf_conntrack_expect_related(exp) == 0) + break; + } + + if (port == 0) + return NF_DROP; + + sprintf(buffer, "%u", port); + ret = nf_nat_mangle_udp_packet(pskb, exp->master, ctinfo, + matchoff, matchlen, + buffer, strlen(buffer)); + if (ret != NF_ACCEPT) + nf_conntrack_unexpect_related(exp); + return ret; +} + +static void __exit nf_nat_amanda_fini(void) +{ + rcu_assign_pointer(nf_nat_amanda_hook, NULL); + synchronize_rcu(); +} + +static int __init nf_nat_amanda_init(void) +{ + BUG_ON(rcu_dereference(nf_nat_amanda_hook)); + rcu_assign_pointer(nf_nat_amanda_hook, help); + return 0; +} + +module_init(nf_nat_amanda_init); +module_exit(nf_nat_amanda_fini); -- cgit v1.2.3 From f587de0e2feb9eb9b94f98d0a7b7437e4d6617b4 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Sat, 2 Dec 2006 22:08:46 -0800 Subject: [NETFILTER]: nf_conntrack/nf_nat: add H.323 helper port Add IPv4 and IPv6 capable nf_conntrack port of the H.323 conntrack/NAT helper. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/ipv4/netfilter/Kconfig | 5 + net/ipv4/netfilter/Makefile | 3 +- net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.c | 874 --------- .../netfilter/ip_conntrack_helper_h323_types.c | 1926 -------------------- net/ipv4/netfilter/nf_nat_h323.c | 596 ++++++ 5 files changed, 603 insertions(+), 2801 deletions(-) delete mode 100644 net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.c delete mode 100644 net/ipv4/netfilter/ip_conntrack_helper_h323_types.c create mode 100644 net/ipv4/netfilter/nf_nat_h323.c (limited to 'net/ipv4') diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index 6993ec53dc0..e14156d1122 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig @@ -529,6 +529,11 @@ config IP_NF_NAT_H323 default IP_NF_NAT if IP_NF_H323=y default m if IP_NF_H323=m +config NF_NAT_H323 + tristate + depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT + default NF_NAT && NF_CONNTRACK_H323 + config IP_NF_NAT_SIP tristate depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index 8893249bbe9..bdaba4700e3 100644 --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile @@ -15,7 +15,7 @@ endif ip_conntrack_pptp-objs := ip_conntrack_helper_pptp.o ip_conntrack_proto_gre.o ip_nat_pptp-objs := ip_nat_helper_pptp.o ip_nat_proto_gre.o -ip_conntrack_h323-objs := ip_conntrack_helper_h323.o ip_conntrack_helper_h323_asn1.o +ip_conntrack_h323-objs := ip_conntrack_helper_h323.o ../../netfilter/nf_conntrack_h323_asn1.o ip_nat_h323-objs := ip_nat_helper_h323.o # connection tracking @@ -52,6 +52,7 @@ obj-$(CONFIG_IP_NF_NAT_SIP) += ip_nat_sip.o # NAT helpers (nf_conntrack) obj-$(CONFIG_NF_NAT_AMANDA) += nf_nat_amanda.o obj-$(CONFIG_NF_NAT_FTP) += nf_nat_ftp.o +obj-$(CONFIG_NF_NAT_H323) += nf_nat_h323.o # generic IP tables obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o diff --git a/net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.c b/net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.c deleted file mode 100644 index 26dfecadb33..00000000000 --- a/net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.c +++ /dev/null @@ -1,874 +0,0 @@ -/**************************************************************************** - * ip_conntrack_helper_h323_asn1.c - BER and PER decoding library for H.323 - * conntrack/NAT module. - * - * Copyright (c) 2006 by Jing Min Zhao - * - * This source code is licensed under General Public License version 2. - * - * See ip_conntrack_helper_h323_asn1.h for details. - * - ****************************************************************************/ - -#ifdef __KERNEL__ -#include -#else -#include -#endif -#include - -/* Trace Flag */ -#ifndef H323_TRACE -#define H323_TRACE 0 -#endif - -#if H323_TRACE -#define TAB_SIZE 4 -#define IFTHEN(cond, act) if(cond){act;} -#ifdef __KERNEL__ -#define PRINT printk -#else -#define PRINT printf -#endif -#define FNAME(name) name, -#else -#define IFTHEN(cond, act) -#define PRINT(fmt, args...) -#define FNAME(name) -#endif - -/* ASN.1 Types */ -#define NUL 0 -#define BOOL 1 -#define OID 2 -#define INT 3 -#define ENUM 4 -#define BITSTR 5 -#define NUMSTR 6 -#define NUMDGT 6 -#define TBCDSTR 6 -#define OCTSTR 7 -#define PRTSTR 7 -#define IA5STR 7 -#define GENSTR 7 -#define BMPSTR 8 -#define SEQ 9 -#define SET 9 -#define SEQOF 10 -#define SETOF 10 -#define CHOICE 11 - -/* Constraint Types */ -#define FIXD 0 -/* #define BITS 1-8 */ -#define BYTE 9 -#define WORD 10 -#define CONS 11 -#define SEMI 12 -#define UNCO 13 - -/* ASN.1 Type Attributes */ -#define SKIP 0 -#define STOP 1 -#define DECODE 2 -#define EXT 4 -#define OPEN 8 -#define OPT 16 - - -/* ASN.1 Field Structure */ -typedef struct field_t { -#if H323_TRACE - char *name; -#endif - unsigned char type; - unsigned char sz; - unsigned char lb; - unsigned char ub; - unsigned short attr; - unsigned short offset; - struct field_t *fields; -} field_t; - -/* Bit Stream */ -typedef struct { - unsigned char *buf; - unsigned char *beg; - unsigned char *end; - unsigned char *cur; - unsigned bit; -} bitstr_t; - -/* Tool Functions */ -#define INC_BIT(bs) if((++bs->bit)>7){bs->cur++;bs->bit=0;} -#define INC_BITS(bs,b) if((bs->bit+=b)>7){bs->cur+=bs->bit>>3;bs->bit&=7;} -#define BYTE_ALIGN(bs) if(bs->bit){bs->cur++;bs->bit=0;} -#define CHECK_BOUND(bs,n) if(bs->cur+(n)>bs->end)return(H323_ERROR_BOUND) -static unsigned get_len(bitstr_t * bs); -static unsigned get_bit(bitstr_t * bs); -static unsigned get_bits(bitstr_t * bs, unsigned b); -static unsigned get_bitmap(bitstr_t * bs, unsigned b); -static unsigned get_uint(bitstr_t * bs, int b); - -/* Decoder Functions */ -static int decode_nul(bitstr_t * bs, field_t * f, char *base, int level); -static int decode_bool(bitstr_t * bs, field_t * f, char *base, int level); -static int decode_oid(bitstr_t * bs, field_t * f, char *base, int level); -static int decode_int(bitstr_t * bs, field_t * f, char *base, int level); -static int decode_enum(bitstr_t * bs, field_t * f, char *base, int level); -static int decode_bitstr(bitstr_t * bs, field_t * f, char *base, int level); -static int decode_numstr(bitstr_t * bs, field_t * f, char *base, int level); -static int decode_octstr(bitstr_t * bs, field_t * f, char *base, int level); -static int decode_bmpstr(bitstr_t * bs, field_t * f, char *base, int level); -static int decode_seq(bitstr_t * bs, field_t * f, char *base, int level); -static int decode_seqof(bitstr_t * bs, field_t * f, char *base, int level); -static int decode_choice(bitstr_t * bs, field_t * f, char *base, int level); - -/* Decoder Functions Vector */ -typedef int (*decoder_t) (bitstr_t *, field_t *, char *, int); -static decoder_t Decoders[] = { - decode_nul, - decode_bool, - decode_oid, - decode_int, - decode_enum, - decode_bitstr, - decode_numstr, - decode_octstr, - decode_bmpstr, - decode_seq, - decode_seqof, - decode_choice, -}; - -/**************************************************************************** - * H.323 Types - ****************************************************************************/ -#include "ip_conntrack_helper_h323_types.c" - -/**************************************************************************** - * Functions - ****************************************************************************/ -/* Assume bs is aligned && v < 16384 */ -unsigned get_len(bitstr_t * bs) -{ - unsigned v; - - v = *bs->cur++; - - if (v & 0x80) { - v &= 0x3f; - v <<= 8; - v += *bs->cur++; - } - - return v; -} - -/****************************************************************************/ -unsigned get_bit(bitstr_t * bs) -{ - unsigned b = (*bs->cur) & (0x80 >> bs->bit); - - INC_BIT(bs); - - return b; -} - -/****************************************************************************/ -/* Assume b <= 8 */ -unsigned get_bits(bitstr_t * bs, unsigned b) -{ - unsigned v, l; - - v = (*bs->cur) & (0xffU >> bs->bit); - l = b + bs->bit; - - if (l < 8) { - v >>= 8 - l; - bs->bit = l; - } else if (l == 8) { - bs->cur++; - bs->bit = 0; - } else { /* l > 8 */ - - v <<= 8; - v += *(++bs->cur); - v >>= 16 - l; - bs->bit = l - 8; - } - - return v; -} - -/****************************************************************************/ -/* Assume b <= 32 */ -unsigned get_bitmap(bitstr_t * bs, unsigned b) -{ - unsigned v, l, shift, bytes; - - if (!b) - return 0; - - l = bs->bit + b; - - if (l < 8) { - v = (unsigned) (*bs->cur) << (bs->bit + 24); - bs->bit = l; - } else if (l == 8) { - v = (unsigned) (*bs->cur++) << (bs->bit + 24); - bs->bit = 0; - } else { - for (bytes = l >> 3, shift = 24, v = 0; bytes; - bytes--, shift -= 8) - v |= (unsigned) (*bs->cur++) << shift; - - if (l < 32) { - v |= (unsigned) (*bs->cur) << shift; - v <<= bs->bit; - } else if (l > 32) { - v <<= bs->bit; - v |= (*bs->cur) >> (8 - bs->bit); - } - - bs->bit = l & 0x7; - } - - v &= 0xffffffff << (32 - b); - - return v; -} - -/**************************************************************************** - * Assume bs is aligned and sizeof(unsigned int) == 4 - ****************************************************************************/ -unsigned get_uint(bitstr_t * bs, int b) -{ - unsigned v = 0; - - switch (b) { - case 4: - v |= *bs->cur++; - v <<= 8; - case 3: - v |= *bs->cur++; - v <<= 8; - case 2: - v |= *bs->cur++; - v <<= 8; - case 1: - v |= *bs->cur++; - break; - } - return v; -} - -/****************************************************************************/ -int decode_nul(bitstr_t * bs, field_t * f, char *base, int level) -{ - PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); - - return H323_ERROR_NONE; -} - -/****************************************************************************/ -int decode_bool(bitstr_t * bs, field_t * f, char *base, int level) -{ - PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); - - INC_BIT(bs); - - CHECK_BOUND(bs, 0); - return H323_ERROR_NONE; -} - -/****************************************************************************/ -int decode_oid(bitstr_t * bs, field_t * f, char *base, int level) -{ - int len; - - PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); - - BYTE_ALIGN(bs); - CHECK_BOUND(bs, 1); - len = *bs->cur++; - bs->cur += len; - - CHECK_BOUND(bs, 0); - return H323_ERROR_NONE; -} - -/****************************************************************************/ -int decode_int(bitstr_t * bs, field_t * f, char *base, int level) -{ - unsigned len; - - PRINT("%*.s%s", level * TAB_SIZE, " ", f->name); - - switch (f->sz) { - case BYTE: /* Range == 256 */ - BYTE_ALIGN(bs); - bs->cur++; - break; - case WORD: /* 257 <= Range <= 64K */ - BYTE_ALIGN(bs); - bs->cur += 2; - break; - case CONS: /* 64K < Range < 4G */ - len = get_bits(bs, 2) + 1; - BYTE_ALIGN(bs); - if (base && (f->attr & DECODE)) { /* timeToLive */ - unsigned v = get_uint(bs, len) + f->lb; - PRINT(" = %u", v); - *((unsigned *) (base + f->offset)) = v; - } - bs->cur += len; - break; - case UNCO: - BYTE_ALIGN(bs); - CHECK_BOUND(bs, 2); - len = get_len(bs); - bs->cur += len; - break; - default: /* 2 <= Range <= 255 */ - INC_BITS(bs, f->sz); - break; - } - - PRINT("\n"); - - CHECK_BOUND(bs, 0); - return H323_ERROR_NONE; -} - -/****************************************************************************/ -int decode_enum(bitstr_t * bs, field_t * f, char *base, int level) -{ - PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); - - if ((f->attr & EXT) && get_bit(bs)) { - INC_BITS(bs, 7); - } else { - INC_BITS(bs, f->sz); - } - - CHECK_BOUND(bs, 0); - return H323_ERROR_NONE; -} - -/****************************************************************************/ -int decode_bitstr(bitstr_t * bs, field_t * f, char *base, int level) -{ - unsigned len; - - PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); - - BYTE_ALIGN(bs); - switch (f->sz) { - case FIXD: /* fixed length > 16 */ - len = f->lb; - break; - case WORD: /* 2-byte length */ - CHECK_BOUND(bs, 2); - len = (*bs->cur++) << 8; - len += (*bs->cur++) + f->lb; - break; - case SEMI: - CHECK_BOUND(bs, 2); - len = get_len(bs); - break; - default: - len = 0; - break; - } - - bs->cur += len >> 3; - bs->bit = len & 7; - - CHECK_BOUND(bs, 0); - return H323_ERROR_NONE; -} - -/****************************************************************************/ -int decode_numstr(bitstr_t * bs, field_t * f, char *base, int level) -{ - unsigned len; - - PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); - - /* 2 <= Range <= 255 */ - len = get_bits(bs, f->sz) + f->lb; - - BYTE_ALIGN(bs); - INC_BITS(bs, (len << 2)); - - CHECK_BOUND(bs, 0); - return H323_ERROR_NONE; -} - -/****************************************************************************/ -int decode_octstr(bitstr_t * bs, field_t * f, char *base, int level) -{ - unsigned len; - - PRINT("%*.s%s", level * TAB_SIZE, " ", f->name); - - switch (f->sz) { - case FIXD: /* Range == 1 */ - if (f->lb > 2) { - BYTE_ALIGN(bs); - if (base && (f->attr & DECODE)) { - /* The IP Address */ - IFTHEN(f->lb == 4, - PRINT(" = %d.%d.%d.%d:%d", - bs->cur[0], bs->cur[1], - bs->cur[2], bs->cur[3], - bs->cur[4] * 256 + bs->cur[5])); - *((unsigned *) (base + f->offset)) = - bs->cur - bs->buf; - } - } - len = f->lb; - break; - case BYTE: /* Range == 256 */ - BYTE_ALIGN(bs); - CHECK_BOUND(bs, 1); - len = (*bs->cur++) + f->lb; - break; - case SEMI: - BYTE_ALIGN(bs); - CHECK_BOUND(bs, 2); - len = get_len(bs) + f->lb; - break; - default: /* 2 <= Range <= 255 */ - len = get_bits(bs, f->sz) + f->lb; - BYTE_ALIGN(bs); - break; - } - - bs->cur += len; - - PRINT("\n"); - - CHECK_BOUND(bs, 0); - return H323_ERROR_NONE; -} - -/****************************************************************************/ -int decode_bmpstr(bitstr_t * bs, field_t * f, char *base, int level) -{ - unsigned len; - - PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); - - switch (f->sz) { - case BYTE: /* Range == 256 */ - BYTE_ALIGN(bs); - CHECK_BOUND(bs, 1); - len = (*bs->cur++) + f->lb; - break; - default: /* 2 <= Range <= 255 */ - len = get_bits(bs, f->sz) + f->lb; - BYTE_ALIGN(bs); - break; - } - - bs->cur += len << 1; - - CHECK_BOUND(bs, 0); - return H323_ERROR_NONE; -} - -/****************************************************************************/ -int decode_seq(bitstr_t * bs, field_t * f, char *base, int level) -{ - unsigned ext, bmp, i, opt, len = 0, bmp2, bmp2_len; - int err; - field_t *son; - unsigned char *beg = NULL; - - PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); - - /* Decode? */ - base = (base && (f->attr & DECODE)) ? base + f->offset : NULL; - - /* Extensible? */ - ext = (f->attr & EXT) ? get_bit(bs) : 0; - - /* Get fields bitmap */ - bmp = get_bitmap(bs, f->sz); - if (base) - *(unsigned *) base = bmp; - - /* Decode the root components */ - for (i = opt = 0, son = f->fields; i < f->lb; i++, son++) { - if (son->attr & STOP) { - PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, " ", - son->name); - return H323_ERROR_STOP; - } - - if (son->attr & OPT) { /* Optional component */ - if (!((0x80000000U >> (opt++)) & bmp)) /* Not exist */ - continue; - } - - /* Decode */ - if (son->attr & OPEN) { /* Open field */ - CHECK_BOUND(bs, 2); - len = get_len(bs); - CHECK_BOUND(bs, len); - if (!base) { - PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, - " ", son->name); - bs->cur += len; - continue; - } - beg = bs->cur; - - /* Decode */ - if ((err = (Decoders[son->type]) (bs, son, base, - level + 1)) < - H323_ERROR_NONE) - return err; - - bs->cur = beg + len; - bs->bit = 0; - } else if ((err = (Decoders[son->type]) (bs, son, base, - level + 1)) < - H323_ERROR_NONE) - return err; - } - - /* No extension? */ - if (!ext) - return H323_ERROR_NONE; - - /* Get the extension bitmap */ - bmp2_len = get_bits(bs, 7) + 1; - CHECK_BOUND(bs, (bmp2_len + 7) >> 3); - bmp2 = get_bitmap(bs, bmp2_len); - bmp |= bmp2 >> f->sz; - if (base) - *(unsigned *) base = bmp; - BYTE_ALIGN(bs); - - /* Decode the extension components */ - for (opt = 0; opt < bmp2_len; opt++, i++, son++) { - if (i < f->ub && son->attr & STOP) { - PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, " ", - son->name); - return H323_ERROR_STOP; - } - - if (!((0x80000000 >> opt) & bmp2)) /* Not present */ - continue; - - /* Check Range */ - if (i >= f->ub) { /* Newer Version? */ - CHECK_BOUND(bs, 2); - len = get_len(bs); - CHECK_BOUND(bs, len); - bs->cur += len; - continue; - } - - CHECK_BOUND(bs, 2); - len = get_len(bs); - CHECK_BOUND(bs, len); - if (!base || !(son->attr & DECODE)) { - PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, " ", - son->name); - bs->cur += len; - continue; - } - beg = bs->cur; - - if ((err = (Decoders[son->type]) (bs, son, base, - level + 1)) < - H323_ERROR_NONE) - return err; - - bs->cur = beg + len; - bs->bit = 0; - } - return H323_ERROR_NONE; -} - -/****************************************************************************/ -int decode_seqof(bitstr_t * bs, field_t * f, char *base, int level) -{ - unsigned count, effective_count = 0, i, len = 0; - int err; - field_t *son; - unsigned char *beg = NULL; - - PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); - - /* Decode? */ - base = (base && (f->attr & DECODE)) ? base + f->offset : NULL; - - /* Decode item count */ - switch (f->sz) { - case BYTE: - BYTE_ALIGN(bs); - CHECK_BOUND(bs, 1); - count = *bs->cur++; - break; - case WORD: - BYTE_ALIGN(bs); - CHECK_BOUND(bs, 2); - count = *bs->cur++; - count <<= 8; - count = *bs->cur++; - break; - case SEMI: - BYTE_ALIGN(bs); - CHECK_BOUND(bs, 2); - count = get_len(bs); - break; - default: - count = get_bits(bs, f->sz); - break; - } - count += f->lb; - - /* Write Count */ - if (base) { - effective_count = count > f->ub ? f->ub : count; - *(unsigned *) base = effective_count; - base += sizeof(unsigned); - } - - /* Decode nested field */ - son = f->fields; - if (base) - base -= son->offset; - for (i = 0; i < count; i++) { - if (son->attr & OPEN) { - BYTE_ALIGN(bs); - len = get_len(bs); - CHECK_BOUND(bs, len); - if (!base || !(son->attr & DECODE)) { - PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, - " ", son->name); - bs->cur += len; - continue; - } - beg = bs->cur; - - if ((err = (Decoders[son->type]) (bs, son, - i < - effective_count ? - base : NULL, - level + 1)) < - H323_ERROR_NONE) - return err; - - bs->cur = beg + len; - bs->bit = 0; - } else - if ((err = (Decoders[son->type]) (bs, son, - i < - effective_count ? - base : NULL, - level + 1)) < - H323_ERROR_NONE) - return err; - - if (base) - base += son->offset; - } - - return H323_ERROR_NONE; -} - - -/****************************************************************************/ -int decode_choice(bitstr_t * bs, field_t * f, char *base, int level) -{ - unsigned type, ext, len = 0; - int err; - field_t *son; - unsigned char *beg = NULL; - - PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); - - /* Decode? */ - base = (base && (f->attr & DECODE)) ? base + f->offset : NULL; - - /* Decode the choice index number */ - if ((f->attr & EXT) && get_bit(bs)) { - ext = 1; - type = get_bits(bs, 7) + f->lb; - } else { - ext = 0; - type = get_bits(bs, f->sz); - } - - /* Write Type */ - if (base) - *(unsigned *) base = type; - - /* Check Range */ - if (type >= f->ub) { /* Newer version? */ - BYTE_ALIGN(bs); - len = get_len(bs); - CHECK_BOUND(bs, len); - bs->cur += len; - return H323_ERROR_NONE; - } - - /* Transfer to son level */ - son = &f->fields[type]; - if (son->attr & STOP) { - PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, " ", son->name); - return H323_ERROR_STOP; - } - - if (ext || (son->attr & OPEN)) { - BYTE_ALIGN(bs); - len = get_len(bs); - CHECK_BOUND(bs, len); - if (!base || !(son->attr & DECODE)) { - PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, " ", - son->name); - bs->cur += len; - return H323_ERROR_NONE; - } - beg = bs->cur; - - if ((err = (Decoders[son->type]) (bs, son, base, level + 1)) < - H323_ERROR_NONE) - return err; - - bs->cur = beg + len; - bs->bit = 0; - } else if ((err = (Decoders[son->type]) (bs, son, base, level + 1)) < - H323_ERROR_NONE) - return err; - - return H323_ERROR_NONE; -} - -/****************************************************************************/ -int DecodeRasMessage(unsigned char *buf, size_t sz, RasMessage * ras) -{ - static field_t ras_message = { - FNAME("RasMessage") CHOICE, 5, 24, 32, DECODE | EXT, - 0, _RasMessage - }; - bitstr_t bs; - - bs.buf = bs.beg = bs.cur = buf; - bs.end = buf + sz; - bs.bit = 0; - - return decode_choice(&bs, &ras_message, (char *) ras, 0); -} - -/****************************************************************************/ -static int DecodeH323_UserInformation(unsigned char *buf, unsigned char *beg, - size_t sz, H323_UserInformation * uuie) -{ - static field_t h323_userinformation = { - FNAME("H323-UserInformation") SEQ, 1, 2, 2, DECODE | EXT, - 0, _H323_UserInformation - }; - bitstr_t bs; - - bs.buf = buf; - bs.beg = bs.cur = beg; - bs.end = beg + sz; - bs.bit = 0; - - return decode_seq(&bs, &h323_userinformation, (char *) uuie, 0); -} - -/****************************************************************************/ -int DecodeMultimediaSystemControlMessage(unsigned char *buf, size_t sz, - MultimediaSystemControlMessage * - mscm) -{ - static field_t multimediasystemcontrolmessage = { - FNAME("MultimediaSystemControlMessage") CHOICE, 2, 4, 4, - DECODE | EXT, 0, _MultimediaSystemControlMessage - }; - bitstr_t bs; - - bs.buf = bs.beg = bs.cur = buf; - bs.end = buf + sz; - bs.bit = 0; - - return decode_choice(&bs, &multimediasystemcontrolmessage, - (char *) mscm, 0); -} - -/****************************************************************************/ -int DecodeQ931(unsigned char *buf, size_t sz, Q931 * q931) -{ - unsigned char *p = buf; - int len; - - if (!p || sz < 1) - return H323_ERROR_BOUND; - - /* Protocol Discriminator */ - if (*p != 0x08) { - PRINT("Unknown Protocol Discriminator\n"); - return H323_ERROR_RANGE; - } - p++; - sz--; - - /* CallReferenceValue */ - if (sz < 1) - return H323_ERROR_BOUND; - len = *p++; - sz--; - if (sz < len) - return H323_ERROR_BOUND; - p += len; - sz -= len; - - /* Message Type */ - if (sz < 1) - return H323_ERROR_BOUND; - q931->MessageType = *p++; - PRINT("MessageType = %02X\n", q931->MessageType); - if (*p & 0x80) { - p++; - sz--; - } - - /* Decode Information Elements */ - while (sz > 0) { - if (*p == 0x7e) { /* UserUserIE */ - if (sz < 3) - break; - p++; - len = *p++ << 8; - len |= *p++; - sz -= 3; - if (sz < len) - break; - p++; - len--; - return DecodeH323_UserInformation(buf, p, len, - &q931->UUIE); - } - p++; - sz--; - if (sz < 1) - break; - len = *p++; - if (sz < len) - break; - p += len; - sz -= len; - } - - PRINT("Q.931 UUIE not found\n"); - - return H323_ERROR_BOUND; -} diff --git a/net/ipv4/netfilter/ip_conntrack_helper_h323_types.c b/net/ipv4/netfilter/ip_conntrack_helper_h323_types.c deleted file mode 100644 index 4b359618bed..00000000000 --- a/net/ipv4/netfilter/ip_conntrack_helper_h323_types.c +++ /dev/null @@ -1,1926 +0,0 @@ -/* Generated by Jing Min Zhao's ASN.1 parser, Apr 20 2006 - * - * Copyright (c) 2006 Jing Min Zhao - * - * This source code is licensed under General Public License version 2. - */ - -static field_t _TransportAddress_ipAddress[] = { /* SEQUENCE */ - {FNAME("ip") OCTSTR, FIXD, 4, 0, DECODE, - offsetof(TransportAddress_ipAddress, ip), NULL}, - {FNAME("port") INT, WORD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _TransportAddress_ipSourceRoute_route[] = { /* SEQUENCE OF */ - {FNAME("item") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL}, -}; - -static field_t _TransportAddress_ipSourceRoute_routing[] = { /* CHOICE */ - {FNAME("strict") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("loose") NUL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _TransportAddress_ipSourceRoute[] = { /* SEQUENCE */ - {FNAME("ip") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL}, - {FNAME("port") INT, WORD, 0, 0, SKIP, 0, NULL}, - {FNAME("route") SEQOF, SEMI, 0, 0, SKIP, 0, - _TransportAddress_ipSourceRoute_route}, - {FNAME("routing") CHOICE, 1, 2, 2, SKIP | EXT, 0, - _TransportAddress_ipSourceRoute_routing}, -}; - -static field_t _TransportAddress_ipxAddress[] = { /* SEQUENCE */ - {FNAME("node") OCTSTR, FIXD, 6, 0, SKIP, 0, NULL}, - {FNAME("netnum") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL}, - {FNAME("port") OCTSTR, FIXD, 2, 0, SKIP, 0, NULL}, -}; - -static field_t _TransportAddress_ip6Address[] = { /* SEQUENCE */ - {FNAME("ip") OCTSTR, FIXD, 16, 0, SKIP, 0, NULL}, - {FNAME("port") INT, WORD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _H221NonStandard[] = { /* SEQUENCE */ - {FNAME("t35CountryCode") INT, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("t35Extension") INT, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("manufacturerCode") INT, WORD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _NonStandardIdentifier[] = { /* CHOICE */ - {FNAME("object") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("h221NonStandard") SEQ, 0, 3, 3, SKIP | EXT, 0, - _H221NonStandard}, -}; - -static field_t _NonStandardParameter[] = { /* SEQUENCE */ - {FNAME("nonStandardIdentifier") CHOICE, 1, 2, 2, SKIP | EXT, 0, - _NonStandardIdentifier}, - {FNAME("data") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _TransportAddress[] = { /* CHOICE */ - {FNAME("ipAddress") SEQ, 0, 2, 2, DECODE, - offsetof(TransportAddress, ipAddress), _TransportAddress_ipAddress}, - {FNAME("ipSourceRoute") SEQ, 0, 4, 4, SKIP | EXT, 0, - _TransportAddress_ipSourceRoute}, - {FNAME("ipxAddress") SEQ, 0, 3, 3, SKIP, 0, - _TransportAddress_ipxAddress}, - {FNAME("ip6Address") SEQ, 0, 2, 2, SKIP | EXT, 0, - _TransportAddress_ip6Address}, - {FNAME("netBios") OCTSTR, FIXD, 16, 0, SKIP, 0, NULL}, - {FNAME("nsap") OCTSTR, 5, 1, 0, SKIP, 0, NULL}, - {FNAME("nonStandardAddress") SEQ, 0, 2, 2, SKIP, 0, - _NonStandardParameter}, -}; - -static field_t _AliasAddress[] = { /* CHOICE */ - {FNAME("dialedDigits") NUMDGT, 7, 1, 0, SKIP, 0, NULL}, - {FNAME("h323-ID") BMPSTR, BYTE, 1, 0, SKIP, 0, NULL}, - {FNAME("url-ID") IA5STR, WORD, 1, 0, SKIP, 0, NULL}, - {FNAME("transportID") CHOICE, 3, 7, 7, SKIP | EXT, 0, NULL}, - {FNAME("email-ID") IA5STR, WORD, 1, 0, SKIP, 0, NULL}, - {FNAME("partyNumber") CHOICE, 3, 5, 5, SKIP | EXT, 0, NULL}, - {FNAME("mobileUIM") CHOICE, 1, 2, 2, SKIP | EXT, 0, NULL}, -}; - -static field_t _Setup_UUIE_sourceAddress[] = { /* SEQUENCE OF */ - {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, -}; - -static field_t _VendorIdentifier[] = { /* SEQUENCE */ - {FNAME("vendor") SEQ, 0, 3, 3, SKIP | EXT, 0, _H221NonStandard}, - {FNAME("productId") OCTSTR, BYTE, 1, 0, SKIP | OPT, 0, NULL}, - {FNAME("versionId") OCTSTR, BYTE, 1, 0, SKIP | OPT, 0, NULL}, -}; - -static field_t _GatekeeperInfo[] = { /* SEQUENCE */ - {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, - _NonStandardParameter}, -}; - -static field_t _H310Caps[] = { /* SEQUENCE */ - {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, - _NonStandardParameter}, - {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _H320Caps[] = { /* SEQUENCE */ - {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, - _NonStandardParameter}, - {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _H321Caps[] = { /* SEQUENCE */ - {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, - _NonStandardParameter}, - {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _H322Caps[] = { /* SEQUENCE */ - {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, - _NonStandardParameter}, - {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _H323Caps[] = { /* SEQUENCE */ - {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, - _NonStandardParameter}, - {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _H324Caps[] = { /* SEQUENCE */ - {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, - _NonStandardParameter}, - {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _VoiceCaps[] = { /* SEQUENCE */ - {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, - _NonStandardParameter}, - {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _T120OnlyCaps[] = { /* SEQUENCE */ - {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, - _NonStandardParameter}, - {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _SupportedProtocols[] = { /* CHOICE */ - {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP, 0, - _NonStandardParameter}, - {FNAME("h310") SEQ, 1, 1, 3, SKIP | EXT, 0, _H310Caps}, - {FNAME("h320") SEQ, 1, 1, 3, SKIP | EXT, 0, _H320Caps}, - {FNAME("h321") SEQ, 1, 1, 3, SKIP | EXT, 0, _H321Caps}, - {FNAME("h322") SEQ, 1, 1, 3, SKIP | EXT, 0, _H322Caps}, - {FNAME("h323") SEQ, 1, 1, 3, SKIP | EXT, 0, _H323Caps}, - {FNAME("h324") SEQ, 1, 1, 3, SKIP | EXT, 0, _H324Caps}, - {FNAME("voice") SEQ, 1, 1, 3, SKIP | EXT, 0, _VoiceCaps}, - {FNAME("t120-only") SEQ, 1, 1, 3, SKIP | EXT, 0, _T120OnlyCaps}, - {FNAME("nonStandardProtocol") SEQ, 2, 3, 3, SKIP | EXT, 0, NULL}, - {FNAME("t38FaxAnnexbOnly") SEQ, 2, 5, 5, SKIP | EXT, 0, NULL}, -}; - -static field_t _GatewayInfo_protocol[] = { /* SEQUENCE OF */ - {FNAME("item") CHOICE, 4, 9, 11, SKIP | EXT, 0, _SupportedProtocols}, -}; - -static field_t _GatewayInfo[] = { /* SEQUENCE */ - {FNAME("protocol") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, - _GatewayInfo_protocol}, - {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, - _NonStandardParameter}, -}; - -static field_t _McuInfo[] = { /* SEQUENCE */ - {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, - _NonStandardParameter}, - {FNAME("protocol") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, -}; - -static field_t _TerminalInfo[] = { /* SEQUENCE */ - {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, - _NonStandardParameter}, -}; - -static field_t _EndpointType[] = { /* SEQUENCE */ - {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, - _NonStandardParameter}, - {FNAME("vendor") SEQ, 2, 3, 3, SKIP | EXT | OPT, 0, - _VendorIdentifier}, - {FNAME("gatekeeper") SEQ, 1, 1, 1, SKIP | EXT | OPT, 0, - _GatekeeperInfo}, - {FNAME("gateway") SEQ, 2, 2, 2, SKIP | EXT | OPT, 0, _GatewayInfo}, - {FNAME("mcu") SEQ, 1, 1, 2, SKIP | EXT | OPT, 0, _McuInfo}, - {FNAME("terminal") SEQ, 1, 1, 1, SKIP | EXT | OPT, 0, _TerminalInfo}, - {FNAME("mc") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("undefinedNode") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("set") BITSTR, FIXD, 32, 0, SKIP | OPT, 0, NULL}, - {FNAME("supportedTunnelledProtocols") SEQOF, SEMI, 0, 0, SKIP | OPT, - 0, NULL}, -}; - -static field_t _Setup_UUIE_destinationAddress[] = { /* SEQUENCE OF */ - {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, -}; - -static field_t _Setup_UUIE_destExtraCallInfo[] = { /* SEQUENCE OF */ - {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, -}; - -static field_t _Setup_UUIE_destExtraCRV[] = { /* SEQUENCE OF */ - {FNAME("item") INT, WORD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _Setup_UUIE_conferenceGoal[] = { /* CHOICE */ - {FNAME("create") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("join") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("invite") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("capability-negotiation") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("callIndependentSupplementaryService") NUL, FIXD, 0, 0, SKIP, - 0, NULL}, -}; - -static field_t _Q954Details[] = { /* SEQUENCE */ - {FNAME("conferenceCalling") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("threePartyService") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _QseriesOptions[] = { /* SEQUENCE */ - {FNAME("q932Full") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("q951Full") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("q952Full") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("q953Full") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("q955Full") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("q956Full") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("q957Full") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("q954Info") SEQ, 0, 2, 2, SKIP | EXT, 0, _Q954Details}, -}; - -static field_t _CallType[] = { /* CHOICE */ - {FNAME("pointToPoint") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("oneToN") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("nToOne") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("nToN") NUL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _H245_NonStandardIdentifier_h221NonStandard[] = { /* SEQUENCE */ - {FNAME("t35CountryCode") INT, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("t35Extension") INT, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("manufacturerCode") INT, WORD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _H245_NonStandardIdentifier[] = { /* CHOICE */ - {FNAME("object") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("h221NonStandard") SEQ, 0, 3, 3, SKIP, 0, - _H245_NonStandardIdentifier_h221NonStandard}, -}; - -static field_t _H245_NonStandardParameter[] = { /* SEQUENCE */ - {FNAME("nonStandardIdentifier") CHOICE, 1, 2, 2, SKIP, 0, - _H245_NonStandardIdentifier}, - {FNAME("data") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _H261VideoCapability[] = { /* SEQUENCE */ - {FNAME("qcifMPI") INT, 2, 1, 0, SKIP | OPT, 0, NULL}, - {FNAME("cifMPI") INT, 2, 1, 0, SKIP | OPT, 0, NULL}, - {FNAME("temporalSpatialTradeOffCapability") BOOL, FIXD, 0, 0, SKIP, 0, - NULL}, - {FNAME("maxBitRate") INT, WORD, 1, 0, SKIP, 0, NULL}, - {FNAME("stillImageTransmission") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("videoBadMBsCap") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _H262VideoCapability[] = { /* SEQUENCE */ - {FNAME("profileAndLevel-SPatML") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("profileAndLevel-MPatLL") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("profileAndLevel-MPatML") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("profileAndLevel-MPatH-14") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("profileAndLevel-MPatHL") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("profileAndLevel-SNRatLL") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("profileAndLevel-SNRatML") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("profileAndLevel-SpatialatH-14") BOOL, FIXD, 0, 0, SKIP, 0, - NULL}, - {FNAME("profileAndLevel-HPatML") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("profileAndLevel-HPatH-14") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("profileAndLevel-HPatHL") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("videoBitRate") INT, CONS, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("vbvBufferSize") INT, CONS, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("samplesPerLine") INT, WORD, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("linesPerFrame") INT, WORD, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("framesPerSecond") INT, 4, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("luminanceSampleRate") INT, CONS, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("videoBadMBsCap") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _H263VideoCapability[] = { /* SEQUENCE */ - {FNAME("sqcifMPI") INT, 5, 1, 0, SKIP | OPT, 0, NULL}, - {FNAME("qcifMPI") INT, 5, 1, 0, SKIP | OPT, 0, NULL}, - {FNAME("cifMPI") INT, 5, 1, 0, SKIP | OPT, 0, NULL}, - {FNAME("cif4MPI") INT, 5, 1, 0, SKIP | OPT, 0, NULL}, - {FNAME("cif16MPI") INT, 5, 1, 0, SKIP | OPT, 0, NULL}, - {FNAME("maxBitRate") INT, CONS, 1, 0, SKIP, 0, NULL}, - {FNAME("unrestrictedVector") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("arithmeticCoding") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("advancedPrediction") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("pbFrames") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("temporalSpatialTradeOffCapability") BOOL, FIXD, 0, 0, SKIP, 0, - NULL}, - {FNAME("hrd-B") INT, CONS, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("bppMaxKb") INT, WORD, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("slowSqcifMPI") INT, WORD, 1, 0, SKIP | OPT, 0, NULL}, - {FNAME("slowQcifMPI") INT, WORD, 1, 0, SKIP | OPT, 0, NULL}, - {FNAME("slowCifMPI") INT, WORD, 1, 0, SKIP | OPT, 0, NULL}, - {FNAME("slowCif4MPI") INT, WORD, 1, 0, SKIP | OPT, 0, NULL}, - {FNAME("slowCif16MPI") INT, WORD, 1, 0, SKIP | OPT, 0, NULL}, - {FNAME("errorCompensation") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("enhancementLayerInfo") SEQ, 3, 4, 4, SKIP | EXT | OPT, 0, - NULL}, - {FNAME("h263Options") SEQ, 5, 29, 31, SKIP | EXT | OPT, 0, NULL}, -}; - -static field_t _IS11172VideoCapability[] = { /* SEQUENCE */ - {FNAME("constrainedBitstream") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("videoBitRate") INT, CONS, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("vbvBufferSize") INT, CONS, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("samplesPerLine") INT, WORD, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("linesPerFrame") INT, WORD, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("pictureRate") INT, 4, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("luminanceSampleRate") INT, CONS, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("videoBadMBsCap") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _VideoCapability[] = { /* CHOICE */ - {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0, - _H245_NonStandardParameter}, - {FNAME("h261VideoCapability") SEQ, 2, 5, 6, SKIP | EXT, 0, - _H261VideoCapability}, - {FNAME("h262VideoCapability") SEQ, 6, 17, 18, SKIP | EXT, 0, - _H262VideoCapability}, - {FNAME("h263VideoCapability") SEQ, 7, 13, 21, SKIP | EXT, 0, - _H263VideoCapability}, - {FNAME("is11172VideoCapability") SEQ, 6, 7, 8, SKIP | EXT, 0, - _IS11172VideoCapability}, - {FNAME("genericVideoCapability") SEQ, 5, 6, 6, SKIP | EXT, 0, NULL}, -}; - -static field_t _AudioCapability_g7231[] = { /* SEQUENCE */ - {FNAME("maxAl-sduAudioFrames") INT, BYTE, 1, 0, SKIP, 0, NULL}, - {FNAME("silenceSuppression") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _IS11172AudioCapability[] = { /* SEQUENCE */ - {FNAME("audioLayer1") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("audioLayer2") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("audioLayer3") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("audioSampling32k") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("audioSampling44k1") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("audioSampling48k") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("singleChannel") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("twoChannels") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("bitRate") INT, WORD, 1, 0, SKIP, 0, NULL}, -}; - -static field_t _IS13818AudioCapability[] = { /* SEQUENCE */ - {FNAME("audioLayer1") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("audioLayer2") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("audioLayer3") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("audioSampling16k") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("audioSampling22k05") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("audioSampling24k") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("audioSampling32k") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("audioSampling44k1") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("audioSampling48k") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("singleChannel") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("twoChannels") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("threeChannels2-1") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("threeChannels3-0") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("fourChannels2-0-2-0") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("fourChannels2-2") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("fourChannels3-1") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("fiveChannels3-0-2-0") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("fiveChannels3-2") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("lowFrequencyEnhancement") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("multilingual") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("bitRate") INT, WORD, 1, 0, SKIP, 0, NULL}, -}; - -static field_t _AudioCapability[] = { /* CHOICE */ - {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0, - _H245_NonStandardParameter}, - {FNAME("g711Alaw64k") INT, BYTE, 1, 0, SKIP, 0, NULL}, - {FNAME("g711Alaw56k") INT, BYTE, 1, 0, SKIP, 0, NULL}, - {FNAME("g711Ulaw64k") INT, BYTE, 1, 0, SKIP, 0, NULL}, - {FNAME("g711Ulaw56k") INT, BYTE, 1, 0, SKIP, 0, NULL}, - {FNAME("g722-64k") INT, BYTE, 1, 0, SKIP, 0, NULL}, - {FNAME("g722-56k") INT, BYTE, 1, 0, SKIP, 0, NULL}, - {FNAME("g722-48k") INT, BYTE, 1, 0, SKIP, 0, NULL}, - {FNAME("g7231") SEQ, 0, 2, 2, SKIP, 0, _AudioCapability_g7231}, - {FNAME("g728") INT, BYTE, 1, 0, SKIP, 0, NULL}, - {FNAME("g729") INT, BYTE, 1, 0, SKIP, 0, NULL}, - {FNAME("g729AnnexA") INT, BYTE, 1, 0, SKIP, 0, NULL}, - {FNAME("is11172AudioCapability") SEQ, 0, 9, 9, SKIP | EXT, 0, - _IS11172AudioCapability}, - {FNAME("is13818AudioCapability") SEQ, 0, 21, 21, SKIP | EXT, 0, - _IS13818AudioCapability}, - {FNAME("g729wAnnexB") INT, BYTE, 1, 0, SKIP, 0, NULL}, - {FNAME("g729AnnexAwAnnexB") INT, BYTE, 1, 0, SKIP, 0, NULL}, - {FNAME("g7231AnnexCCapability") SEQ, 1, 3, 3, SKIP | EXT, 0, NULL}, - {FNAME("gsmFullRate") SEQ, 0, 3, 3, SKIP | EXT, 0, NULL}, - {FNAME("gsmHalfRate") SEQ, 0, 3, 3, SKIP | EXT, 0, NULL}, - {FNAME("gsmEnhancedFullRate") SEQ, 0, 3, 3, SKIP | EXT, 0, NULL}, - {FNAME("genericAudioCapability") SEQ, 5, 6, 6, SKIP | EXT, 0, NULL}, - {FNAME("g729Extensions") SEQ, 1, 8, 8, SKIP | EXT, 0, NULL}, -}; - -static field_t _DataProtocolCapability[] = { /* CHOICE */ - {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0, - _H245_NonStandardParameter}, - {FNAME("v14buffered") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("v42lapm") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("hdlcFrameTunnelling") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("h310SeparateVCStack") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("h310SingleVCStack") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("transparent") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("segmentationAndReassembly") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("hdlcFrameTunnelingwSAR") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("v120") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("separateLANStack") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("v76wCompression") CHOICE, 2, 3, 3, SKIP | EXT, 0, NULL}, - {FNAME("tcp") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("udp") NUL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _T84Profile_t84Restricted[] = { /* SEQUENCE */ - {FNAME("qcif") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("cif") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("ccir601Seq") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("ccir601Prog") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("hdtvSeq") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("hdtvProg") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("g3FacsMH200x100") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("g3FacsMH200x200") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("g4FacsMMR200x100") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("g4FacsMMR200x200") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("jbig200x200Seq") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("jbig200x200Prog") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("jbig300x300Seq") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("jbig300x300Prog") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("digPhotoLow") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("digPhotoMedSeq") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("digPhotoMedProg") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("digPhotoHighSeq") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("digPhotoHighProg") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _T84Profile[] = { /* CHOICE */ - {FNAME("t84Unrestricted") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("t84Restricted") SEQ, 0, 19, 19, SKIP | EXT, 0, - _T84Profile_t84Restricted}, -}; - -static field_t _DataApplicationCapability_application_t84[] = { /* SEQUENCE */ - {FNAME("t84Protocol") CHOICE, 3, 7, 14, SKIP | EXT, 0, - _DataProtocolCapability}, - {FNAME("t84Profile") CHOICE, 1, 2, 2, SKIP, 0, _T84Profile}, -}; - -static field_t _DataApplicationCapability_application_nlpid[] = { /* SEQUENCE */ - {FNAME("nlpidProtocol") CHOICE, 3, 7, 14, SKIP | EXT, 0, - _DataProtocolCapability}, - {FNAME("nlpidData") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _DataApplicationCapability_application[] = { /* CHOICE */ - {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0, - _H245_NonStandardParameter}, - {FNAME("t120") CHOICE, 3, 7, 14, DECODE | EXT, - offsetof(DataApplicationCapability_application, t120), - _DataProtocolCapability}, - {FNAME("dsm-cc") CHOICE, 3, 7, 14, SKIP | EXT, 0, - _DataProtocolCapability}, - {FNAME("userData") CHOICE, 3, 7, 14, SKIP | EXT, 0, - _DataProtocolCapability}, - {FNAME("t84") SEQ, 0, 2, 2, SKIP, 0, - _DataApplicationCapability_application_t84}, - {FNAME("t434") CHOICE, 3, 7, 14, SKIP | EXT, 0, - _DataProtocolCapability}, - {FNAME("h224") CHOICE, 3, 7, 14, SKIP | EXT, 0, - _DataProtocolCapability}, - {FNAME("nlpid") SEQ, 0, 2, 2, SKIP, 0, - _DataApplicationCapability_application_nlpid}, - {FNAME("dsvdControl") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("h222DataPartitioning") CHOICE, 3, 7, 14, SKIP | EXT, 0, - _DataProtocolCapability}, - {FNAME("t30fax") CHOICE, 3, 7, 14, SKIP | EXT, 0, NULL}, - {FNAME("t140") CHOICE, 3, 7, 14, SKIP | EXT, 0, NULL}, - {FNAME("t38fax") SEQ, 0, 2, 2, SKIP, 0, NULL}, - {FNAME("genericDataCapability") SEQ, 5, 6, 6, SKIP | EXT, 0, NULL}, -}; - -static field_t _DataApplicationCapability[] = { /* SEQUENCE */ - {FNAME("application") CHOICE, 4, 10, 14, DECODE | EXT, - offsetof(DataApplicationCapability, application), - _DataApplicationCapability_application}, - {FNAME("maxBitRate") INT, CONS, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _EncryptionMode[] = { /* CHOICE */ - {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0, - _H245_NonStandardParameter}, - {FNAME("h233Encryption") NUL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _DataType[] = { /* CHOICE */ - {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0, - _H245_NonStandardParameter}, - {FNAME("nullData") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("videoData") CHOICE, 3, 5, 6, SKIP | EXT, 0, _VideoCapability}, - {FNAME("audioData") CHOICE, 4, 14, 22, SKIP | EXT, 0, - _AudioCapability}, - {FNAME("data") SEQ, 0, 2, 2, DECODE | EXT, offsetof(DataType, data), - _DataApplicationCapability}, - {FNAME("encryptionData") CHOICE, 1, 2, 2, SKIP | EXT, 0, - _EncryptionMode}, - {FNAME("h235Control") SEQ, 0, 2, 2, SKIP, 0, NULL}, - {FNAME("h235Media") SEQ, 0, 2, 2, SKIP | EXT, 0, NULL}, - {FNAME("multiplexedStream") SEQ, 0, 2, 2, SKIP | EXT, 0, NULL}, -}; - -static field_t _H222LogicalChannelParameters[] = { /* SEQUENCE */ - {FNAME("resourceID") INT, WORD, 0, 0, SKIP, 0, NULL}, - {FNAME("subChannelID") INT, WORD, 0, 0, SKIP, 0, NULL}, - {FNAME("pcr-pid") INT, WORD, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("programDescriptors") OCTSTR, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("streamDescriptors") OCTSTR, SEMI, 0, 0, SKIP | OPT, 0, NULL}, -}; - -static field_t _H223LogicalChannelParameters_adaptationLayerType_al3[] = { /* SEQUENCE */ - {FNAME("controlFieldOctets") INT, 2, 0, 0, SKIP, 0, NULL}, - {FNAME("sendBufferSize") INT, CONS, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _H223LogicalChannelParameters_adaptationLayerType[] = { /* CHOICE */ - {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0, - _H245_NonStandardParameter}, - {FNAME("al1Framed") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("al1NotFramed") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("al2WithoutSequenceNumbers") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("al2WithSequenceNumbers") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("al3") SEQ, 0, 2, 2, SKIP, 0, - _H223LogicalChannelParameters_adaptationLayerType_al3}, - {FNAME("al1M") SEQ, 0, 7, 8, SKIP | EXT, 0, NULL}, - {FNAME("al2M") SEQ, 0, 2, 2, SKIP | EXT, 0, NULL}, - {FNAME("al3M") SEQ, 0, 5, 6, SKIP | EXT, 0, NULL}, -}; - -static field_t _H223LogicalChannelParameters[] = { /* SEQUENCE */ - {FNAME("adaptationLayerType") CHOICE, 3, 6, 9, SKIP | EXT, 0, - _H223LogicalChannelParameters_adaptationLayerType}, - {FNAME("segmentableFlag") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _CRCLength[] = { /* CHOICE */ - {FNAME("crc8bit") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("crc16bit") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("crc32bit") NUL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _V76HDLCParameters[] = { /* SEQUENCE */ - {FNAME("crcLength") CHOICE, 2, 3, 3, SKIP | EXT, 0, _CRCLength}, - {FNAME("n401") INT, WORD, 1, 0, SKIP, 0, NULL}, - {FNAME("loopbackTestProcedure") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _V76LogicalChannelParameters_suspendResume[] = { /* CHOICE */ - {FNAME("noSuspendResume") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("suspendResumewAddress") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("suspendResumewoAddress") NUL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _V76LogicalChannelParameters_mode_eRM_recovery[] = { /* CHOICE */ - {FNAME("rej") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("sREJ") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("mSREJ") NUL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _V76LogicalChannelParameters_mode_eRM[] = { /* SEQUENCE */ - {FNAME("windowSize") INT, 7, 1, 0, SKIP, 0, NULL}, - {FNAME("recovery") CHOICE, 2, 3, 3, SKIP | EXT, 0, - _V76LogicalChannelParameters_mode_eRM_recovery}, -}; - -static field_t _V76LogicalChannelParameters_mode[] = { /* CHOICE */ - {FNAME("eRM") SEQ, 0, 2, 2, SKIP | EXT, 0, - _V76LogicalChannelParameters_mode_eRM}, - {FNAME("uNERM") NUL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _V75Parameters[] = { /* SEQUENCE */ - {FNAME("audioHeaderPresent") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _V76LogicalChannelParameters[] = { /* SEQUENCE */ - {FNAME("hdlcParameters") SEQ, 0, 3, 3, SKIP | EXT, 0, - _V76HDLCParameters}, - {FNAME("suspendResume") CHOICE, 2, 3, 3, SKIP | EXT, 0, - _V76LogicalChannelParameters_suspendResume}, - {FNAME("uIH") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("mode") CHOICE, 1, 2, 2, SKIP | EXT, 0, - _V76LogicalChannelParameters_mode}, - {FNAME("v75Parameters") SEQ, 0, 1, 1, SKIP | EXT, 0, _V75Parameters}, -}; - -static field_t _H2250LogicalChannelParameters_nonStandard[] = { /* SEQUENCE OF */ - {FNAME("item") SEQ, 0, 2, 2, SKIP, 0, _H245_NonStandardParameter}, -}; - -static field_t _UnicastAddress_iPAddress[] = { /* SEQUENCE */ - {FNAME("network") OCTSTR, FIXD, 4, 0, DECODE, - offsetof(UnicastAddress_iPAddress, network), NULL}, - {FNAME("tsapIdentifier") INT, WORD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _UnicastAddress_iPXAddress[] = { /* SEQUENCE */ - {FNAME("node") OCTSTR, FIXD, 6, 0, SKIP, 0, NULL}, - {FNAME("netnum") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL}, - {FNAME("tsapIdentifier") OCTSTR, FIXD, 2, 0, SKIP, 0, NULL}, -}; - -static field_t _UnicastAddress_iP6Address[] = { /* SEQUENCE */ - {FNAME("network") OCTSTR, FIXD, 16, 0, SKIP, 0, NULL}, - {FNAME("tsapIdentifier") INT, WORD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _UnicastAddress_iPSourceRouteAddress_routing[] = { /* CHOICE */ - {FNAME("strict") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("loose") NUL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _UnicastAddress_iPSourceRouteAddress_route[] = { /* SEQUENCE OF */ - {FNAME("item") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL}, -}; - -static field_t _UnicastAddress_iPSourceRouteAddress[] = { /* SEQUENCE */ - {FNAME("routing") CHOICE, 1, 2, 2, SKIP, 0, - _UnicastAddress_iPSourceRouteAddress_routing}, - {FNAME("network") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL}, - {FNAME("tsapIdentifier") INT, WORD, 0, 0, SKIP, 0, NULL}, - {FNAME("route") SEQOF, SEMI, 0, 0, SKIP, 0, - _UnicastAddress_iPSourceRouteAddress_route}, -}; - -static field_t _UnicastAddress[] = { /* CHOICE */ - {FNAME("iPAddress") SEQ, 0, 2, 2, DECODE | EXT, - offsetof(UnicastAddress, iPAddress), _UnicastAddress_iPAddress}, - {FNAME("iPXAddress") SEQ, 0, 3, 3, SKIP | EXT, 0, - _UnicastAddress_iPXAddress}, - {FNAME("iP6Address") SEQ, 0, 2, 2, SKIP | EXT, 0, - _UnicastAddress_iP6Address}, - {FNAME("netBios") OCTSTR, FIXD, 16, 0, SKIP, 0, NULL}, - {FNAME("iPSourceRouteAddress") SEQ, 0, 4, 4, SKIP | EXT, 0, - _UnicastAddress_iPSourceRouteAddress}, - {FNAME("nsap") OCTSTR, 5, 1, 0, SKIP, 0, NULL}, - {FNAME("nonStandardAddress") SEQ, 0, 2, 2, SKIP, 0, NULL}, -}; - -static field_t _MulticastAddress_iPAddress[] = { /* SEQUENCE */ - {FNAME("network") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL}, - {FNAME("tsapIdentifier") INT, WORD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _MulticastAddress_iP6Address[] = { /* SEQUENCE */ - {FNAME("network") OCTSTR, FIXD, 16, 0, SKIP, 0, NULL}, - {FNAME("tsapIdentifier") INT, WORD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _MulticastAddress[] = { /* CHOICE */ - {FNAME("iPAddress") SEQ, 0, 2, 2, SKIP | EXT, 0, - _MulticastAddress_iPAddress}, - {FNAME("iP6Address") SEQ, 0, 2, 2, SKIP | EXT, 0, - _MulticastAddress_iP6Address}, - {FNAME("nsap") OCTSTR, 5, 1, 0, SKIP, 0, NULL}, - {FNAME("nonStandardAddress") SEQ, 0, 2, 2, SKIP, 0, NULL}, -}; - -static field_t _H245_TransportAddress[] = { /* CHOICE */ - {FNAME("unicastAddress") CHOICE, 3, 5, 7, DECODE | EXT, - offsetof(H245_TransportAddress, unicastAddress), _UnicastAddress}, - {FNAME("multicastAddress") CHOICE, 1, 2, 4, SKIP | EXT, 0, - _MulticastAddress}, -}; - -static field_t _H2250LogicalChannelParameters[] = { /* SEQUENCE */ - {FNAME("nonStandard") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, - _H2250LogicalChannelParameters_nonStandard}, - {FNAME("sessionID") INT, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("associatedSessionID") INT, 8, 1, 0, SKIP | OPT, 0, NULL}, - {FNAME("mediaChannel") CHOICE, 1, 2, 2, DECODE | EXT | OPT, - offsetof(H2250LogicalChannelParameters, mediaChannel), - _H245_TransportAddress}, - {FNAME("mediaGuaranteedDelivery") BOOL, FIXD, 0, 0, SKIP | OPT, 0, - NULL}, - {FNAME("mediaControlChannel") CHOICE, 1, 2, 2, DECODE | EXT | OPT, - offsetof(H2250LogicalChannelParameters, mediaControlChannel), - _H245_TransportAddress}, - {FNAME("mediaControlGuaranteedDelivery") BOOL, FIXD, 0, 0, STOP | OPT, - 0, NULL}, - {FNAME("silenceSuppression") BOOL, FIXD, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("destination") SEQ, 0, 2, 2, STOP | EXT | OPT, 0, NULL}, - {FNAME("dynamicRTPPayloadType") INT, 5, 96, 0, STOP | OPT, 0, NULL}, - {FNAME("mediaPacketization") CHOICE, 0, 1, 2, STOP | EXT | OPT, 0, - NULL}, - {FNAME("transportCapability") SEQ, 3, 3, 3, STOP | EXT | OPT, 0, - NULL}, - {FNAME("redundancyEncoding") SEQ, 1, 2, 2, STOP | EXT | OPT, 0, NULL}, - {FNAME("source") SEQ, 0, 2, 2, SKIP | EXT | OPT, 0, NULL}, -}; - -static field_t _OpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters[] = { /* CHOICE */ - {FNAME("h222LogicalChannelParameters") SEQ, 3, 5, 5, SKIP | EXT, 0, - _H222LogicalChannelParameters}, - {FNAME("h223LogicalChannelParameters") SEQ, 0, 2, 2, SKIP | EXT, 0, - _H223LogicalChannelParameters}, - {FNAME("v76LogicalChannelParameters") SEQ, 0, 5, 5, SKIP | EXT, 0, - _V76LogicalChannelParameters}, - {FNAME("h2250LogicalChannelParameters") SEQ, 10, 11, 14, DECODE | EXT, - offsetof - (OpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters, - h2250LogicalChannelParameters), _H2250LogicalChannelParameters}, - {FNAME("none") NUL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _OpenLogicalChannel_forwardLogicalChannelParameters[] = { /* SEQUENCE */ - {FNAME("portNumber") INT, WORD, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("dataType") CHOICE, 3, 6, 9, DECODE | EXT, - offsetof(OpenLogicalChannel_forwardLogicalChannelParameters, - dataType), _DataType}, - {FNAME("multiplexParameters") CHOICE, 2, 3, 5, DECODE | EXT, - offsetof(OpenLogicalChannel_forwardLogicalChannelParameters, - multiplexParameters), - _OpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters}, - {FNAME("forwardLogicalChannelDependency") INT, WORD, 1, 0, SKIP | OPT, - 0, NULL}, - {FNAME("replacementFor") INT, WORD, 1, 0, SKIP | OPT, 0, NULL}, -}; - -static field_t _OpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters[] = { /* CHOICE */ - {FNAME("h223LogicalChannelParameters") SEQ, 0, 2, 2, SKIP | EXT, 0, - _H223LogicalChannelParameters}, - {FNAME("v76LogicalChannelParameters") SEQ, 0, 5, 5, SKIP | EXT, 0, - _V76LogicalChannelParameters}, - {FNAME("h2250LogicalChannelParameters") SEQ, 10, 11, 14, DECODE | EXT, - offsetof - (OpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters, - h2250LogicalChannelParameters), _H2250LogicalChannelParameters}, -}; - -static field_t _OpenLogicalChannel_reverseLogicalChannelParameters[] = { /* SEQUENCE */ - {FNAME("dataType") CHOICE, 3, 6, 9, SKIP | EXT, 0, _DataType}, - {FNAME("multiplexParameters") CHOICE, 1, 2, 3, DECODE | EXT | OPT, - offsetof(OpenLogicalChannel_reverseLogicalChannelParameters, - multiplexParameters), - _OpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters}, - {FNAME("reverseLogicalChannelDependency") INT, WORD, 1, 0, SKIP | OPT, - 0, NULL}, - {FNAME("replacementFor") INT, WORD, 1, 0, SKIP | OPT, 0, NULL}, -}; - -static field_t _NetworkAccessParameters_distribution[] = { /* CHOICE */ - {FNAME("unicast") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("multicast") NUL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _Q2931Address_address[] = { /* CHOICE */ - {FNAME("internationalNumber") NUMSTR, 4, 1, 0, SKIP, 0, NULL}, - {FNAME("nsapAddress") OCTSTR, 5, 1, 0, SKIP, 0, NULL}, -}; - -static field_t _Q2931Address[] = { /* SEQUENCE */ - {FNAME("address") CHOICE, 1, 2, 2, SKIP | EXT, 0, - _Q2931Address_address}, - {FNAME("subaddress") OCTSTR, 5, 1, 0, SKIP | OPT, 0, NULL}, -}; - -static field_t _NetworkAccessParameters_networkAddress[] = { /* CHOICE */ - {FNAME("q2931Address") SEQ, 1, 2, 2, SKIP | EXT, 0, _Q2931Address}, - {FNAME("e164Address") NUMDGT, 7, 1, 0, SKIP, 0, NULL}, - {FNAME("localAreaAddress") CHOICE, 1, 2, 2, DECODE | EXT, - offsetof(NetworkAccessParameters_networkAddress, localAreaAddress), - _H245_TransportAddress}, -}; - -static field_t _NetworkAccessParameters[] = { /* SEQUENCE */ - {FNAME("distribution") CHOICE, 1, 2, 2, SKIP | EXT | OPT, 0, - _NetworkAccessParameters_distribution}, - {FNAME("networkAddress") CHOICE, 2, 3, 3, DECODE | EXT, - offsetof(NetworkAccessParameters, networkAddress), - _NetworkAccessParameters_networkAddress}, - {FNAME("associateConference") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("externalReference") OCTSTR, 8, 1, 0, SKIP | OPT, 0, NULL}, - {FNAME("t120SetupProcedure") CHOICE, 2, 3, 3, SKIP | EXT | OPT, 0, - NULL}, -}; - -static field_t _OpenLogicalChannel[] = { /* SEQUENCE */ - {FNAME("forwardLogicalChannelNumber") INT, WORD, 1, 0, SKIP, 0, NULL}, - {FNAME("forwardLogicalChannelParameters") SEQ, 1, 3, 5, DECODE | EXT, - offsetof(OpenLogicalChannel, forwardLogicalChannelParameters), - _OpenLogicalChannel_forwardLogicalChannelParameters}, - {FNAME("reverseLogicalChannelParameters") SEQ, 1, 2, 4, - DECODE | EXT | OPT, offsetof(OpenLogicalChannel, - reverseLogicalChannelParameters), - _OpenLogicalChannel_reverseLogicalChannelParameters}, - {FNAME("separateStack") SEQ, 2, 4, 5, DECODE | EXT | OPT, - offsetof(OpenLogicalChannel, separateStack), - _NetworkAccessParameters}, - {FNAME("encryptionSync") SEQ, 2, 4, 4, STOP | EXT | OPT, 0, NULL}, -}; - -static field_t _Setup_UUIE_fastStart[] = { /* SEQUENCE OF */ - {FNAME("item") SEQ, 1, 3, 5, DECODE | OPEN | EXT, - sizeof(OpenLogicalChannel), _OpenLogicalChannel} - , -}; - -static field_t _Setup_UUIE[] = { /* SEQUENCE */ - {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("h245Address") CHOICE, 3, 7, 7, DECODE | EXT | OPT, - offsetof(Setup_UUIE, h245Address), _TransportAddress}, - {FNAME("sourceAddress") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, - _Setup_UUIE_sourceAddress}, - {FNAME("sourceInfo") SEQ, 6, 8, 10, SKIP | EXT, 0, _EndpointType}, - {FNAME("destinationAddress") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, - _Setup_UUIE_destinationAddress}, - {FNAME("destCallSignalAddress") CHOICE, 3, 7, 7, DECODE | EXT | OPT, - offsetof(Setup_UUIE, destCallSignalAddress), _TransportAddress}, - {FNAME("destExtraCallInfo") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, - _Setup_UUIE_destExtraCallInfo}, - {FNAME("destExtraCRV") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, - _Setup_UUIE_destExtraCRV}, - {FNAME("activeMC") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("conferenceID") OCTSTR, FIXD, 16, 0, SKIP, 0, NULL}, - {FNAME("conferenceGoal") CHOICE, 2, 3, 5, SKIP | EXT, 0, - _Setup_UUIE_conferenceGoal}, - {FNAME("callServices") SEQ, 0, 8, 8, SKIP | EXT | OPT, 0, - _QseriesOptions}, - {FNAME("callType") CHOICE, 2, 4, 4, SKIP | EXT, 0, _CallType}, - {FNAME("sourceCallSignalAddress") CHOICE, 3, 7, 7, DECODE | EXT | OPT, - offsetof(Setup_UUIE, sourceCallSignalAddress), _TransportAddress}, - {FNAME("remoteExtensionAddress") CHOICE, 1, 2, 7, SKIP | EXT | OPT, 0, - NULL}, - {FNAME("callIdentifier") SEQ, 0, 1, 1, SKIP | EXT, 0, NULL}, - {FNAME("h245SecurityCapability") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, - NULL}, - {FNAME("tokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("fastStart") SEQOF, SEMI, 0, 30, DECODE | OPT, - offsetof(Setup_UUIE, fastStart), _Setup_UUIE_fastStart}, - {FNAME("mediaWaitForConnect") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("canOverlapSend") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("endpointIdentifier") BMPSTR, 7, 1, 0, STOP | OPT, 0, NULL}, - {FNAME("multipleCalls") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("maintainConnection") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("connectionParameters") SEQ, 0, 3, 3, SKIP | EXT | OPT, 0, - NULL}, - {FNAME("language") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("presentationIndicator") CHOICE, 2, 3, 3, SKIP | EXT | OPT, 0, - NULL}, - {FNAME("screeningIndicator") ENUM, 2, 0, 0, SKIP | EXT | OPT, 0, - NULL}, - {FNAME("serviceControl") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("symmetricOperationRequired") NUL, FIXD, 0, 0, SKIP | OPT, 0, - NULL}, - {FNAME("capacity") SEQ, 2, 2, 2, SKIP | EXT | OPT, 0, NULL}, - {FNAME("circuitInfo") SEQ, 3, 3, 3, SKIP | EXT | OPT, 0, NULL}, - {FNAME("desiredProtocols") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("neededFeatures") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("desiredFeatures") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("supportedFeatures") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("parallelH245Control") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("additionalSourceAddresses") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, - NULL}, -}; - -static field_t _CallProceeding_UUIE_fastStart[] = { /* SEQUENCE OF */ - {FNAME("item") SEQ, 1, 3, 5, DECODE | OPEN | EXT, - sizeof(OpenLogicalChannel), _OpenLogicalChannel} - , -}; - -static field_t _CallProceeding_UUIE[] = { /* SEQUENCE */ - {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("destinationInfo") SEQ, 6, 8, 10, SKIP | EXT, 0, - _EndpointType}, - {FNAME("h245Address") CHOICE, 3, 7, 7, DECODE | EXT | OPT, - offsetof(CallProceeding_UUIE, h245Address), _TransportAddress}, - {FNAME("callIdentifier") SEQ, 0, 1, 1, SKIP | EXT, 0, NULL}, - {FNAME("h245SecurityMode") CHOICE, 2, 4, 4, SKIP | EXT | OPT, 0, - NULL}, - {FNAME("tokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("fastStart") SEQOF, SEMI, 0, 30, DECODE | OPT, - offsetof(CallProceeding_UUIE, fastStart), - _CallProceeding_UUIE_fastStart}, - {FNAME("multipleCalls") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("maintainConnection") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("fastConnectRefused") NUL, FIXD, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("featureSet") SEQ, 3, 4, 4, SKIP | EXT | OPT, 0, NULL}, -}; - -static field_t _Connect_UUIE_fastStart[] = { /* SEQUENCE OF */ - {FNAME("item") SEQ, 1, 3, 5, DECODE | OPEN | EXT, - sizeof(OpenLogicalChannel), _OpenLogicalChannel} - , -}; - -static field_t _Connect_UUIE[] = { /* SEQUENCE */ - {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("h245Address") CHOICE, 3, 7, 7, DECODE | EXT | OPT, - offsetof(Connect_UUIE, h245Address), _TransportAddress}, - {FNAME("destinationInfo") SEQ, 6, 8, 10, SKIP | EXT, 0, - _EndpointType}, - {FNAME("conferenceID") OCTSTR, FIXD, 16, 0, SKIP, 0, NULL}, - {FNAME("callIdentifier") SEQ, 0, 1, 1, SKIP | EXT, 0, NULL}, - {FNAME("h245SecurityMode") CHOICE, 2, 4, 4, SKIP | EXT | OPT, 0, - NULL}, - {FNAME("tokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("fastStart") SEQOF, SEMI, 0, 30, DECODE | OPT, - offsetof(Connect_UUIE, fastStart), _Connect_UUIE_fastStart}, - {FNAME("multipleCalls") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("maintainConnection") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("language") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("connectedAddress") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("presentationIndicator") CHOICE, 2, 3, 3, SKIP | EXT | OPT, 0, - NULL}, - {FNAME("screeningIndicator") ENUM, 2, 0, 0, SKIP | EXT | OPT, 0, - NULL}, - {FNAME("fastConnectRefused") NUL, FIXD, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("serviceControl") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("capacity") SEQ, 2, 2, 2, SKIP | EXT | OPT, 0, NULL}, - {FNAME("featureSet") SEQ, 3, 4, 4, SKIP | EXT | OPT, 0, NULL}, -}; - -static field_t _Alerting_UUIE_fastStart[] = { /* SEQUENCE OF */ - {FNAME("item") SEQ, 1, 3, 5, DECODE | OPEN | EXT, - sizeof(OpenLogicalChannel), _OpenLogicalChannel} - , -}; - -static field_t _Alerting_UUIE[] = { /* SEQUENCE */ - {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("destinationInfo") SEQ, 6, 8, 10, SKIP | EXT, 0, - _EndpointType}, - {FNAME("h245Address") CHOICE, 3, 7, 7, DECODE | EXT | OPT, - offsetof(Alerting_UUIE, h245Address), _TransportAddress}, - {FNAME("callIdentifier") SEQ, 0, 1, 1, SKIP | EXT, 0, NULL}, - {FNAME("h245SecurityMode") CHOICE, 2, 4, 4, SKIP | EXT | OPT, 0, - NULL}, - {FNAME("tokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("fastStart") SEQOF, SEMI, 0, 30, DECODE | OPT, - offsetof(Alerting_UUIE, fastStart), _Alerting_UUIE_fastStart}, - {FNAME("multipleCalls") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("maintainConnection") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("alertingAddress") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("presentationIndicator") CHOICE, 2, 3, 3, SKIP | EXT | OPT, 0, - NULL}, - {FNAME("screeningIndicator") ENUM, 2, 0, 0, SKIP | EXT | OPT, 0, - NULL}, - {FNAME("fastConnectRefused") NUL, FIXD, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("serviceControl") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("capacity") SEQ, 2, 2, 2, SKIP | EXT | OPT, 0, NULL}, - {FNAME("featureSet") SEQ, 3, 4, 4, SKIP | EXT | OPT, 0, NULL}, -}; - -static field_t _Information_UUIE_fastStart[] = { /* SEQUENCE OF */ - {FNAME("item") SEQ, 1, 3, 5, DECODE | OPEN | EXT, - sizeof(OpenLogicalChannel), _OpenLogicalChannel} - , -}; - -static field_t _Information_UUIE[] = { /* SEQUENCE */ - {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("callIdentifier") SEQ, 0, 1, 1, SKIP | EXT, 0, NULL}, - {FNAME("tokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("fastStart") SEQOF, SEMI, 0, 30, DECODE | OPT, - offsetof(Information_UUIE, fastStart), _Information_UUIE_fastStart}, - {FNAME("fastConnectRefused") NUL, FIXD, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("circuitInfo") SEQ, 3, 3, 3, SKIP | EXT | OPT, 0, NULL}, -}; - -static field_t _ReleaseCompleteReason[] = { /* CHOICE */ - {FNAME("noBandwidth") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("gatekeeperResources") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("unreachableDestination") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("destinationRejection") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("invalidRevision") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("noPermission") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("unreachableGatekeeper") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("gatewayResources") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("badFormatAddress") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("adaptiveBusy") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("inConf") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("undefinedReason") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("facilityCallDeflection") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("securityDenied") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("calledPartyNotRegistered") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("callerNotRegistered") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("newConnectionNeeded") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("nonStandardReason") SEQ, 0, 2, 2, SKIP, 0, NULL}, - {FNAME("replaceWithConferenceInvite") OCTSTR, FIXD, 16, 0, SKIP, 0, - NULL}, - {FNAME("genericDataReason") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("neededFeatureNotSupported") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("tunnelledSignallingRejected") NUL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _ReleaseComplete_UUIE[] = { /* SEQUENCE */ - {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("reason") CHOICE, 4, 12, 22, SKIP | EXT | OPT, 0, - _ReleaseCompleteReason}, - {FNAME("callIdentifier") SEQ, 0, 1, 1, SKIP | EXT, 0, NULL}, - {FNAME("tokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("busyAddress") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("presentationIndicator") CHOICE, 2, 3, 3, SKIP | EXT | OPT, 0, - NULL}, - {FNAME("screeningIndicator") ENUM, 2, 0, 0, SKIP | EXT | OPT, 0, - NULL}, - {FNAME("capacity") SEQ, 2, 2, 2, SKIP | EXT | OPT, 0, NULL}, - {FNAME("serviceControl") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("featureSet") SEQ, 3, 4, 4, SKIP | EXT | OPT, 0, NULL}, -}; - -static field_t _Facility_UUIE_alternativeAliasAddress[] = { /* SEQUENCE OF */ - {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, -}; - -static field_t _FacilityReason[] = { /* CHOICE */ - {FNAME("routeCallToGatekeeper") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("callForwarded") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("routeCallToMC") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("undefinedReason") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("conferenceListChoice") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("startH245") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("noH245") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("newTokens") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("featureSetUpdate") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("forwardedElements") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("transportedInformation") NUL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _Facility_UUIE_fastStart[] = { /* SEQUENCE OF */ - {FNAME("item") SEQ, 1, 3, 5, DECODE | OPEN | EXT, - sizeof(OpenLogicalChannel), _OpenLogicalChannel} - , -}; - -static field_t _Facility_UUIE[] = { /* SEQUENCE */ - {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("alternativeAddress") CHOICE, 3, 7, 7, DECODE | EXT | OPT, - offsetof(Facility_UUIE, alternativeAddress), _TransportAddress}, - {FNAME("alternativeAliasAddress") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, - _Facility_UUIE_alternativeAliasAddress}, - {FNAME("conferenceID") OCTSTR, FIXD, 16, 0, SKIP | OPT, 0, NULL}, - {FNAME("reason") CHOICE, 2, 4, 11, DECODE | EXT, - offsetof(Facility_UUIE, reason), _FacilityReason}, - {FNAME("callIdentifier") SEQ, 0, 1, 1, SKIP | EXT, 0, NULL}, - {FNAME("destExtraCallInfo") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("remoteExtensionAddress") CHOICE, 1, 2, 7, SKIP | EXT | OPT, 0, - NULL}, - {FNAME("tokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("conferences") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("h245Address") CHOICE, 3, 7, 7, DECODE | EXT | OPT, - offsetof(Facility_UUIE, h245Address), _TransportAddress}, - {FNAME("fastStart") SEQOF, SEMI, 0, 30, DECODE | OPT, - offsetof(Facility_UUIE, fastStart), _Facility_UUIE_fastStart}, - {FNAME("multipleCalls") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("maintainConnection") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("fastConnectRefused") NUL, FIXD, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("serviceControl") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("circuitInfo") SEQ, 3, 3, 3, SKIP | EXT | OPT, 0, NULL}, - {FNAME("featureSet") SEQ, 3, 4, 4, SKIP | EXT | OPT, 0, NULL}, - {FNAME("destinationInfo") SEQ, 6, 8, 10, SKIP | EXT | OPT, 0, NULL}, - {FNAME("h245SecurityMode") CHOICE, 2, 4, 4, SKIP | EXT | OPT, 0, - NULL}, -}; - -static field_t _CallIdentifier[] = { /* SEQUENCE */ - {FNAME("guid") OCTSTR, FIXD, 16, 0, SKIP, 0, NULL}, -}; - -static field_t _SecurityServiceMode[] = { /* CHOICE */ - {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0, _NonStandardParameter}, - {FNAME("none") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("default") NUL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _SecurityCapabilities[] = { /* SEQUENCE */ - {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP | OPT, 0, - _NonStandardParameter}, - {FNAME("encryption") CHOICE, 2, 3, 3, SKIP | EXT, 0, - _SecurityServiceMode}, - {FNAME("authenticaton") CHOICE, 2, 3, 3, SKIP | EXT, 0, - _SecurityServiceMode}, - {FNAME("integrity") CHOICE, 2, 3, 3, SKIP | EXT, 0, - _SecurityServiceMode}, -}; - -static field_t _H245Security[] = { /* CHOICE */ - {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0, _NonStandardParameter}, - {FNAME("noSecurity") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("tls") SEQ, 1, 4, 4, SKIP | EXT, 0, _SecurityCapabilities}, - {FNAME("ipsec") SEQ, 1, 4, 4, SKIP | EXT, 0, _SecurityCapabilities}, -}; - -static field_t _DHset[] = { /* SEQUENCE */ - {FNAME("halfkey") BITSTR, WORD, 0, 0, SKIP, 0, NULL}, - {FNAME("modSize") BITSTR, WORD, 0, 0, SKIP, 0, NULL}, - {FNAME("generator") BITSTR, WORD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _TypedCertificate[] = { /* SEQUENCE */ - {FNAME("type") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("certificate") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _H235_NonStandardParameter[] = { /* SEQUENCE */ - {FNAME("nonStandardIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("data") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _ClearToken[] = { /* SEQUENCE */ - {FNAME("tokenOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("timeStamp") INT, CONS, 1, 0, SKIP | OPT, 0, NULL}, - {FNAME("password") BMPSTR, 7, 1, 0, SKIP | OPT, 0, NULL}, - {FNAME("dhkey") SEQ, 0, 3, 3, SKIP | EXT | OPT, 0, _DHset}, - {FNAME("challenge") OCTSTR, 7, 8, 0, SKIP | OPT, 0, NULL}, - {FNAME("random") INT, UNCO, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("certificate") SEQ, 0, 2, 2, SKIP | EXT | OPT, 0, - _TypedCertificate}, - {FNAME("generalID") BMPSTR, 7, 1, 0, SKIP | OPT, 0, NULL}, - {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP | OPT, 0, - _H235_NonStandardParameter}, - {FNAME("eckasdhkey") CHOICE, 1, 2, 2, SKIP | EXT | OPT, 0, NULL}, - {FNAME("sendersID") BMPSTR, 7, 1, 0, SKIP | OPT, 0, NULL}, -}; - -static field_t _Progress_UUIE_tokens[] = { /* SEQUENCE OF */ - {FNAME("item") SEQ, 8, 9, 11, SKIP | EXT, 0, _ClearToken}, -}; - -static field_t _Params[] = { /* SEQUENCE */ - {FNAME("ranInt") INT, UNCO, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("iv8") OCTSTR, FIXD, 8, 0, SKIP | OPT, 0, NULL}, - {FNAME("iv16") OCTSTR, FIXD, 16, 0, SKIP | OPT, 0, NULL}, -}; - -static field_t _CryptoH323Token_cryptoEPPwdHash_token[] = { /* SEQUENCE */ - {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, - {FNAME("hash") BITSTR, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _CryptoH323Token_cryptoEPPwdHash[] = { /* SEQUENCE */ - {FNAME("alias") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, - {FNAME("timeStamp") INT, CONS, 1, 0, SKIP, 0, NULL}, - {FNAME("token") SEQ, 0, 3, 3, SKIP, 0, - _CryptoH323Token_cryptoEPPwdHash_token}, -}; - -static field_t _CryptoH323Token_cryptoGKPwdHash_token[] = { /* SEQUENCE */ - {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, - {FNAME("hash") BITSTR, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _CryptoH323Token_cryptoGKPwdHash[] = { /* SEQUENCE */ - {FNAME("gatekeeperId") BMPSTR, 7, 1, 0, SKIP, 0, NULL}, - {FNAME("timeStamp") INT, CONS, 1, 0, SKIP, 0, NULL}, - {FNAME("token") SEQ, 0, 3, 3, SKIP, 0, - _CryptoH323Token_cryptoGKPwdHash_token}, -}; - -static field_t _CryptoH323Token_cryptoEPPwdEncr[] = { /* SEQUENCE */ - {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, - {FNAME("encryptedData") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _CryptoH323Token_cryptoGKPwdEncr[] = { /* SEQUENCE */ - {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, - {FNAME("encryptedData") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _CryptoH323Token_cryptoEPCert[] = { /* SEQUENCE */ - {FNAME("toBeSigned") SEQ, 8, 9, 11, SKIP | OPEN | EXT, 0, NULL}, - {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, - {FNAME("signature") BITSTR, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _CryptoH323Token_cryptoGKCert[] = { /* SEQUENCE */ - {FNAME("toBeSigned") SEQ, 8, 9, 11, SKIP | OPEN | EXT, 0, NULL}, - {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, - {FNAME("signature") BITSTR, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _CryptoH323Token_cryptoFastStart[] = { /* SEQUENCE */ - {FNAME("toBeSigned") SEQ, 8, 9, 11, SKIP | OPEN | EXT, 0, NULL}, - {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, - {FNAME("signature") BITSTR, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _CryptoToken_cryptoEncryptedToken_token[] = { /* SEQUENCE */ - {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, - {FNAME("encryptedData") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _CryptoToken_cryptoEncryptedToken[] = { /* SEQUENCE */ - {FNAME("tokenOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("token") SEQ, 0, 3, 3, SKIP, 0, - _CryptoToken_cryptoEncryptedToken_token}, -}; - -static field_t _CryptoToken_cryptoSignedToken_token[] = { /* SEQUENCE */ - {FNAME("toBeSigned") SEQ, 8, 9, 11, SKIP | OPEN | EXT, 0, NULL}, - {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, - {FNAME("signature") BITSTR, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _CryptoToken_cryptoSignedToken[] = { /* SEQUENCE */ - {FNAME("tokenOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("token") SEQ, 0, 4, 4, SKIP, 0, - _CryptoToken_cryptoSignedToken_token}, -}; - -static field_t _CryptoToken_cryptoHashedToken_token[] = { /* SEQUENCE */ - {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, - {FNAME("hash") BITSTR, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _CryptoToken_cryptoHashedToken[] = { /* SEQUENCE */ - {FNAME("tokenOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("hashedVals") SEQ, 8, 9, 11, SKIP | EXT, 0, _ClearToken}, - {FNAME("token") SEQ, 0, 3, 3, SKIP, 0, - _CryptoToken_cryptoHashedToken_token}, -}; - -static field_t _CryptoToken_cryptoPwdEncr[] = { /* SEQUENCE */ - {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, - {FNAME("encryptedData") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _CryptoToken[] = { /* CHOICE */ - {FNAME("cryptoEncryptedToken") SEQ, 0, 2, 2, SKIP, 0, - _CryptoToken_cryptoEncryptedToken}, - {FNAME("cryptoSignedToken") SEQ, 0, 2, 2, SKIP, 0, - _CryptoToken_cryptoSignedToken}, - {FNAME("cryptoHashedToken") SEQ, 0, 3, 3, SKIP, 0, - _CryptoToken_cryptoHashedToken}, - {FNAME("cryptoPwdEncr") SEQ, 0, 3, 3, SKIP, 0, - _CryptoToken_cryptoPwdEncr}, -}; - -static field_t _CryptoH323Token[] = { /* CHOICE */ - {FNAME("cryptoEPPwdHash") SEQ, 0, 3, 3, SKIP, 0, - _CryptoH323Token_cryptoEPPwdHash}, - {FNAME("cryptoGKPwdHash") SEQ, 0, 3, 3, SKIP, 0, - _CryptoH323Token_cryptoGKPwdHash}, - {FNAME("cryptoEPPwdEncr") SEQ, 0, 3, 3, SKIP, 0, - _CryptoH323Token_cryptoEPPwdEncr}, - {FNAME("cryptoGKPwdEncr") SEQ, 0, 3, 3, SKIP, 0, - _CryptoH323Token_cryptoGKPwdEncr}, - {FNAME("cryptoEPCert") SEQ, 0, 4, 4, SKIP, 0, - _CryptoH323Token_cryptoEPCert}, - {FNAME("cryptoGKCert") SEQ, 0, 4, 4, SKIP, 0, - _CryptoH323Token_cryptoGKCert}, - {FNAME("cryptoFastStart") SEQ, 0, 4, 4, SKIP, 0, - _CryptoH323Token_cryptoFastStart}, - {FNAME("nestedcryptoToken") CHOICE, 2, 4, 4, SKIP | EXT, 0, - _CryptoToken}, -}; - -static field_t _Progress_UUIE_cryptoTokens[] = { /* SEQUENCE OF */ - {FNAME("item") CHOICE, 3, 8, 8, SKIP | EXT, 0, _CryptoH323Token}, -}; - -static field_t _Progress_UUIE_fastStart[] = { /* SEQUENCE OF */ - {FNAME("item") SEQ, 1, 3, 5, DECODE | OPEN | EXT, - sizeof(OpenLogicalChannel), _OpenLogicalChannel} - , -}; - -static field_t _Progress_UUIE[] = { /* SEQUENCE */ - {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("destinationInfo") SEQ, 6, 8, 10, SKIP | EXT, 0, - _EndpointType}, - {FNAME("h245Address") CHOICE, 3, 7, 7, DECODE | EXT | OPT, - offsetof(Progress_UUIE, h245Address), _TransportAddress}, - {FNAME("callIdentifier") SEQ, 0, 1, 1, SKIP | EXT, 0, - _CallIdentifier}, - {FNAME("h245SecurityMode") CHOICE, 2, 4, 4, SKIP | EXT | OPT, 0, - _H245Security}, - {FNAME("tokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, - _Progress_UUIE_tokens}, - {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, - _Progress_UUIE_cryptoTokens}, - {FNAME("fastStart") SEQOF, SEMI, 0, 30, DECODE | OPT, - offsetof(Progress_UUIE, fastStart), _Progress_UUIE_fastStart}, - {FNAME("multipleCalls") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("maintainConnection") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("fastConnectRefused") NUL, FIXD, 0, 0, SKIP | OPT, 0, NULL}, -}; - -static field_t _H323_UU_PDU_h323_message_body[] = { /* CHOICE */ - {FNAME("setup") SEQ, 7, 13, 39, DECODE | EXT, - offsetof(H323_UU_PDU_h323_message_body, setup), _Setup_UUIE}, - {FNAME("callProceeding") SEQ, 1, 3, 12, DECODE | EXT, - offsetof(H323_UU_PDU_h323_message_body, callProceeding), - _CallProceeding_UUIE}, - {FNAME("connect") SEQ, 1, 4, 19, DECODE | EXT, - offsetof(H323_UU_PDU_h323_message_body, connect), _Connect_UUIE}, - {FNAME("alerting") SEQ, 1, 3, 17, DECODE | EXT, - offsetof(H323_UU_PDU_h323_message_body, alerting), _Alerting_UUIE}, - {FNAME("information") SEQ, 0, 1, 7, DECODE | EXT, - offsetof(H323_UU_PDU_h323_message_body, information), - _Information_UUIE}, - {FNAME("releaseComplete") SEQ, 1, 2, 11, SKIP | EXT, 0, - _ReleaseComplete_UUIE}, - {FNAME("facility") SEQ, 3, 5, 21, DECODE | EXT, - offsetof(H323_UU_PDU_h323_message_body, facility), _Facility_UUIE}, - {FNAME("progress") SEQ, 5, 8, 11, DECODE | EXT, - offsetof(H323_UU_PDU_h323_message_body, progress), _Progress_UUIE}, - {FNAME("empty") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("status") SEQ, 2, 4, 4, SKIP | EXT, 0, NULL}, - {FNAME("statusInquiry") SEQ, 2, 4, 4, SKIP | EXT, 0, NULL}, - {FNAME("setupAcknowledge") SEQ, 2, 4, 4, SKIP | EXT, 0, NULL}, - {FNAME("notify") SEQ, 2, 4, 4, SKIP | EXT, 0, NULL}, -}; - -static field_t _RequestMessage[] = { /* CHOICE */ - {FNAME("nonStandard") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, - {FNAME("masterSlaveDetermination") SEQ, 0, 2, 2, STOP | EXT, 0, NULL}, - {FNAME("terminalCapabilitySet") SEQ, 3, 5, 5, STOP | EXT, 0, NULL}, - {FNAME("openLogicalChannel") SEQ, 1, 3, 5, DECODE | EXT, - offsetof(RequestMessage, openLogicalChannel), _OpenLogicalChannel}, - {FNAME("closeLogicalChannel") SEQ, 0, 2, 3, STOP | EXT, 0, NULL}, - {FNAME("requestChannelClose") SEQ, 0, 1, 3, STOP | EXT, 0, NULL}, - {FNAME("multiplexEntrySend") SEQ, 0, 2, 2, STOP | EXT, 0, NULL}, - {FNAME("requestMultiplexEntry") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, - {FNAME("requestMode") SEQ, 0, 2, 2, STOP | EXT, 0, NULL}, - {FNAME("roundTripDelayRequest") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, - {FNAME("maintenanceLoopRequest") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, - {FNAME("communicationModeRequest") SEQ, 0, 0, 0, STOP | EXT, 0, NULL}, - {FNAME("conferenceRequest") CHOICE, 3, 8, 16, STOP | EXT, 0, NULL}, - {FNAME("multilinkRequest") CHOICE, 3, 5, 5, STOP | EXT, 0, NULL}, - {FNAME("logicalChannelRateRequest") SEQ, 0, 3, 3, STOP | EXT, 0, - NULL}, -}; - -static field_t _OpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters[] = { /* CHOICE */ - {FNAME("h222LogicalChannelParameters") SEQ, 3, 5, 5, SKIP | EXT, 0, - _H222LogicalChannelParameters}, - {FNAME("h2250LogicalChannelParameters") SEQ, 10, 11, 14, DECODE | EXT, - offsetof - (OpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters, - h2250LogicalChannelParameters), _H2250LogicalChannelParameters}, -}; - -static field_t _OpenLogicalChannelAck_reverseLogicalChannelParameters[] = { /* SEQUENCE */ - {FNAME("reverseLogicalChannelNumber") INT, WORD, 1, 0, SKIP, 0, NULL}, - {FNAME("portNumber") INT, WORD, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("multiplexParameters") CHOICE, 0, 1, 2, DECODE | EXT | OPT, - offsetof(OpenLogicalChannelAck_reverseLogicalChannelParameters, - multiplexParameters), - _OpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters}, - {FNAME("replacementFor") INT, WORD, 1, 0, SKIP | OPT, 0, NULL}, -}; - -static field_t _H2250LogicalChannelAckParameters_nonStandard[] = { /* SEQUENCE OF */ - {FNAME("item") SEQ, 0, 2, 2, SKIP, 0, _H245_NonStandardParameter}, -}; - -static field_t _H2250LogicalChannelAckParameters[] = { /* SEQUENCE */ - {FNAME("nonStandard") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, - _H2250LogicalChannelAckParameters_nonStandard}, - {FNAME("sessionID") INT, 8, 1, 0, SKIP | OPT, 0, NULL}, - {FNAME("mediaChannel") CHOICE, 1, 2, 2, DECODE | EXT | OPT, - offsetof(H2250LogicalChannelAckParameters, mediaChannel), - _H245_TransportAddress}, - {FNAME("mediaControlChannel") CHOICE, 1, 2, 2, DECODE | EXT | OPT, - offsetof(H2250LogicalChannelAckParameters, mediaControlChannel), - _H245_TransportAddress}, - {FNAME("dynamicRTPPayloadType") INT, 5, 96, 0, SKIP | OPT, 0, NULL}, - {FNAME("flowControlToZero") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("portNumber") INT, WORD, 0, 0, SKIP | OPT, 0, NULL}, -}; - -static field_t _OpenLogicalChannelAck_forwardMultiplexAckParameters[] = { /* CHOICE */ - {FNAME("h2250LogicalChannelAckParameters") SEQ, 5, 5, 7, DECODE | EXT, - offsetof(OpenLogicalChannelAck_forwardMultiplexAckParameters, - h2250LogicalChannelAckParameters), - _H2250LogicalChannelAckParameters}, -}; - -static field_t _OpenLogicalChannelAck[] = { /* SEQUENCE */ - {FNAME("forwardLogicalChannelNumber") INT, WORD, 1, 0, SKIP, 0, NULL}, - {FNAME("reverseLogicalChannelParameters") SEQ, 2, 3, 4, - DECODE | EXT | OPT, offsetof(OpenLogicalChannelAck, - reverseLogicalChannelParameters), - _OpenLogicalChannelAck_reverseLogicalChannelParameters}, - {FNAME("separateStack") SEQ, 2, 4, 5, SKIP | EXT | OPT, 0, NULL}, - {FNAME("forwardMultiplexAckParameters") CHOICE, 0, 1, 1, - DECODE | EXT | OPT, offsetof(OpenLogicalChannelAck, - forwardMultiplexAckParameters), - _OpenLogicalChannelAck_forwardMultiplexAckParameters}, - {FNAME("encryptionSync") SEQ, 2, 4, 4, STOP | EXT | OPT, 0, NULL}, -}; - -static field_t _ResponseMessage[] = { /* CHOICE */ - {FNAME("nonStandard") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, - {FNAME("masterSlaveDeterminationAck") SEQ, 0, 1, 1, STOP | EXT, 0, - NULL}, - {FNAME("masterSlaveDeterminationReject") SEQ, 0, 1, 1, STOP | EXT, 0, - NULL}, - {FNAME("terminalCapabilitySetAck") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, - {FNAME("terminalCapabilitySetReject") SEQ, 0, 2, 2, STOP | EXT, 0, - NULL}, - {FNAME("openLogicalChannelAck") SEQ, 1, 2, 5, DECODE | EXT, - offsetof(ResponseMessage, openLogicalChannelAck), - _OpenLogicalChannelAck}, - {FNAME("openLogicalChannelReject") SEQ, 0, 2, 2, STOP | EXT, 0, NULL}, - {FNAME("closeLogicalChannelAck") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, - {FNAME("requestChannelCloseAck") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, - {FNAME("requestChannelCloseReject") SEQ, 0, 2, 2, STOP | EXT, 0, - NULL}, - {FNAME("multiplexEntrySendAck") SEQ, 0, 2, 2, STOP | EXT, 0, NULL}, - {FNAME("multiplexEntrySendReject") SEQ, 0, 2, 2, STOP | EXT, 0, NULL}, - {FNAME("requestMultiplexEntryAck") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, - {FNAME("requestMultiplexEntryReject") SEQ, 0, 2, 2, STOP | EXT, 0, - NULL}, - {FNAME("requestModeAck") SEQ, 0, 2, 2, STOP | EXT, 0, NULL}, - {FNAME("requestModeReject") SEQ, 0, 2, 2, STOP | EXT, 0, NULL}, - {FNAME("roundTripDelayResponse") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, - {FNAME("maintenanceLoopAck") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, - {FNAME("maintenanceLoopReject") SEQ, 0, 2, 2, STOP | EXT, 0, NULL}, - {FNAME("communicationModeResponse") CHOICE, 0, 1, 1, STOP | EXT, 0, - NULL}, - {FNAME("conferenceResponse") CHOICE, 3, 8, 16, STOP | EXT, 0, NULL}, - {FNAME("multilinkResponse") CHOICE, 3, 5, 5, STOP | EXT, 0, NULL}, - {FNAME("logicalChannelRateAcknowledge") SEQ, 0, 3, 3, STOP | EXT, 0, - NULL}, - {FNAME("logicalChannelRateReject") SEQ, 1, 4, 4, STOP | EXT, 0, NULL}, -}; - -static field_t _MultimediaSystemControlMessage[] = { /* CHOICE */ - {FNAME("request") CHOICE, 4, 11, 15, DECODE | EXT, - offsetof(MultimediaSystemControlMessage, request), _RequestMessage}, - {FNAME("response") CHOICE, 5, 19, 24, DECODE | EXT, - offsetof(MultimediaSystemControlMessage, response), - _ResponseMessage}, - {FNAME("command") CHOICE, 3, 7, 12, STOP | EXT, 0, NULL}, - {FNAME("indication") CHOICE, 4, 14, 23, STOP | EXT, 0, NULL}, -}; - -static field_t _H323_UU_PDU_h245Control[] = { /* SEQUENCE OF */ - {FNAME("item") CHOICE, 2, 4, 4, DECODE | OPEN | EXT, - sizeof(MultimediaSystemControlMessage), - _MultimediaSystemControlMessage} - , -}; - -static field_t _H323_UU_PDU[] = { /* SEQUENCE */ - {FNAME("h323-message-body") CHOICE, 3, 7, 13, DECODE | EXT, - offsetof(H323_UU_PDU, h323_message_body), - _H323_UU_PDU_h323_message_body}, - {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, - _NonStandardParameter}, - {FNAME("h4501SupplementaryService") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, - NULL}, - {FNAME("h245Tunneling") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("h245Control") SEQOF, SEMI, 0, 4, DECODE | OPT, - offsetof(H323_UU_PDU, h245Control), _H323_UU_PDU_h245Control}, - {FNAME("nonStandardControl") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("callLinkage") SEQ, 2, 2, 2, STOP | EXT | OPT, 0, NULL}, - {FNAME("tunnelledSignallingMessage") SEQ, 2, 4, 4, STOP | EXT | OPT, - 0, NULL}, - {FNAME("provisionalRespToH245Tunneling") NUL, FIXD, 0, 0, STOP | OPT, - 0, NULL}, - {FNAME("stimulusControl") SEQ, 3, 3, 3, STOP | EXT | OPT, 0, NULL}, - {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, -}; - -static field_t _H323_UserInformation[] = { /* SEQUENCE */ - {FNAME("h323-uu-pdu") SEQ, 1, 2, 11, DECODE | EXT, - offsetof(H323_UserInformation, h323_uu_pdu), _H323_UU_PDU}, - {FNAME("user-data") SEQ, 0, 2, 2, STOP | EXT | OPT, 0, NULL}, -}; - -static field_t _GatekeeperRequest[] = { /* SEQUENCE */ - {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, - {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, - _NonStandardParameter}, - {FNAME("rasAddress") CHOICE, 3, 7, 7, DECODE | EXT, - offsetof(GatekeeperRequest, rasAddress), _TransportAddress}, - {FNAME("endpointType") SEQ, 6, 8, 10, STOP | EXT, 0, NULL}, - {FNAME("gatekeeperIdentifier") BMPSTR, 7, 1, 0, STOP | OPT, 0, NULL}, - {FNAME("callServices") SEQ, 0, 8, 8, STOP | EXT | OPT, 0, NULL}, - {FNAME("endpointAlias") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("alternateEndpoints") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("authenticationCapability") SEQOF, SEMI, 0, 0, STOP | OPT, 0, - NULL}, - {FNAME("algorithmOIDs") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("integrity") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, - {FNAME("supportsAltGK") NUL, FIXD, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("featureSet") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, NULL}, - {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, -}; - -static field_t _GatekeeperConfirm[] = { /* SEQUENCE */ - {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, - {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, - _NonStandardParameter}, - {FNAME("gatekeeperIdentifier") BMPSTR, 7, 1, 0, SKIP | OPT, 0, NULL}, - {FNAME("rasAddress") CHOICE, 3, 7, 7, DECODE | EXT, - offsetof(GatekeeperConfirm, rasAddress), _TransportAddress}, - {FNAME("alternateGatekeeper") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("authenticationMode") CHOICE, 3, 7, 8, STOP | EXT | OPT, 0, - NULL}, - {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("algorithmOID") OID, BYTE, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("integrity") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, - {FNAME("featureSet") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, NULL}, - {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, -}; - -static field_t _RegistrationRequest_callSignalAddress[] = { /* SEQUENCE OF */ - {FNAME("item") CHOICE, 3, 7, 7, DECODE | EXT, - sizeof(TransportAddress), _TransportAddress} - , -}; - -static field_t _RegistrationRequest_rasAddress[] = { /* SEQUENCE OF */ - {FNAME("item") CHOICE, 3, 7, 7, DECODE | EXT, - sizeof(TransportAddress), _TransportAddress} - , -}; - -static field_t _RegistrationRequest_terminalAlias[] = { /* SEQUENCE OF */ - {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, -}; - -static field_t _RegistrationRequest[] = { /* SEQUENCE */ - {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, - {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, - _NonStandardParameter}, - {FNAME("discoveryComplete") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("callSignalAddress") SEQOF, SEMI, 0, 10, DECODE, - offsetof(RegistrationRequest, callSignalAddress), - _RegistrationRequest_callSignalAddress}, - {FNAME("rasAddress") SEQOF, SEMI, 0, 10, DECODE, - offsetof(RegistrationRequest, rasAddress), - _RegistrationRequest_rasAddress}, - {FNAME("terminalType") SEQ, 6, 8, 10, SKIP | EXT, 0, _EndpointType}, - {FNAME("terminalAlias") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, - _RegistrationRequest_terminalAlias}, - {FNAME("gatekeeperIdentifier") BMPSTR, 7, 1, 0, SKIP | OPT, 0, NULL}, - {FNAME("endpointVendor") SEQ, 2, 3, 3, SKIP | EXT, 0, - _VendorIdentifier}, - {FNAME("alternateEndpoints") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("timeToLive") INT, CONS, 1, 0, DECODE | OPT, - offsetof(RegistrationRequest, timeToLive), NULL}, - {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, - {FNAME("keepAlive") BOOL, FIXD, 0, 0, STOP, 0, NULL}, - {FNAME("endpointIdentifier") BMPSTR, 7, 1, 0, STOP | OPT, 0, NULL}, - {FNAME("willSupplyUUIEs") BOOL, FIXD, 0, 0, STOP, 0, NULL}, - {FNAME("maintainConnection") BOOL, FIXD, 0, 0, STOP, 0, NULL}, - {FNAME("alternateTransportAddresses") SEQ, 1, 1, 1, STOP | EXT | OPT, - 0, NULL}, - {FNAME("additiveRegistration") NUL, FIXD, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("terminalAliasPattern") SEQOF, SEMI, 0, 0, STOP | OPT, 0, - NULL}, - {FNAME("supportsAltGK") NUL, FIXD, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("usageReportingCapability") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, - NULL}, - {FNAME("multipleCalls") BOOL, FIXD, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("supportedH248Packages") SEQOF, SEMI, 0, 0, STOP | OPT, 0, - NULL}, - {FNAME("callCreditCapability") SEQ, 2, 2, 2, STOP | EXT | OPT, 0, - NULL}, - {FNAME("capacityReportingCapability") SEQ, 0, 1, 1, STOP | EXT | OPT, - 0, NULL}, - {FNAME("capacity") SEQ, 2, 2, 2, STOP | EXT | OPT, 0, NULL}, - {FNAME("featureSet") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, NULL}, - {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, -}; - -static field_t _RegistrationConfirm_callSignalAddress[] = { /* SEQUENCE OF */ - {FNAME("item") CHOICE, 3, 7, 7, DECODE | EXT, - sizeof(TransportAddress), _TransportAddress} - , -}; - -static field_t _RegistrationConfirm_terminalAlias[] = { /* SEQUENCE OF */ - {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, -}; - -static field_t _RegistrationConfirm[] = { /* SEQUENCE */ - {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, - {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, - _NonStandardParameter}, - {FNAME("callSignalAddress") SEQOF, SEMI, 0, 10, DECODE, - offsetof(RegistrationConfirm, callSignalAddress), - _RegistrationConfirm_callSignalAddress}, - {FNAME("terminalAlias") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, - _RegistrationConfirm_terminalAlias}, - {FNAME("gatekeeperIdentifier") BMPSTR, 7, 1, 0, SKIP | OPT, 0, NULL}, - {FNAME("endpointIdentifier") BMPSTR, 7, 1, 0, SKIP, 0, NULL}, - {FNAME("alternateGatekeeper") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("timeToLive") INT, CONS, 1, 0, DECODE | OPT, - offsetof(RegistrationConfirm, timeToLive), NULL}, - {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, - {FNAME("willRespondToIRR") BOOL, FIXD, 0, 0, STOP, 0, NULL}, - {FNAME("preGrantedARQ") SEQ, 0, 4, 8, STOP | EXT | OPT, 0, NULL}, - {FNAME("maintainConnection") BOOL, FIXD, 0, 0, STOP, 0, NULL}, - {FNAME("serviceControl") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("supportsAdditiveRegistration") NUL, FIXD, 0, 0, STOP | OPT, 0, - NULL}, - {FNAME("terminalAliasPattern") SEQOF, SEMI, 0, 0, STOP | OPT, 0, - NULL}, - {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("usageSpec") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("featureServerAlias") CHOICE, 1, 2, 7, STOP | EXT | OPT, 0, - NULL}, - {FNAME("capacityReportingSpec") SEQ, 0, 1, 1, STOP | EXT | OPT, 0, - NULL}, - {FNAME("featureSet") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, NULL}, - {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, -}; - -static field_t _UnregistrationRequest_callSignalAddress[] = { /* SEQUENCE OF */ - {FNAME("item") CHOICE, 3, 7, 7, DECODE | EXT, - sizeof(TransportAddress), _TransportAddress} - , -}; - -static field_t _UnregistrationRequest[] = { /* SEQUENCE */ - {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, - {FNAME("callSignalAddress") SEQOF, SEMI, 0, 10, DECODE, - offsetof(UnregistrationRequest, callSignalAddress), - _UnregistrationRequest_callSignalAddress}, - {FNAME("endpointAlias") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("nonStandardData") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, - {FNAME("endpointIdentifier") BMPSTR, 7, 1, 0, STOP | OPT, 0, NULL}, - {FNAME("alternateEndpoints") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("gatekeeperIdentifier") BMPSTR, 7, 1, 0, STOP | OPT, 0, NULL}, - {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, - {FNAME("reason") CHOICE, 2, 4, 5, STOP | EXT | OPT, 0, NULL}, - {FNAME("endpointAliasPattern") SEQOF, SEMI, 0, 0, STOP | OPT, 0, - NULL}, - {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("alternateGatekeeper") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, -}; - -static field_t _CallModel[] = { /* CHOICE */ - {FNAME("direct") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("gatekeeperRouted") NUL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _AdmissionRequest_destinationInfo[] = { /* SEQUENCE OF */ - {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, -}; - -static field_t _AdmissionRequest_destExtraCallInfo[] = { /* SEQUENCE OF */ - {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, -}; - -static field_t _AdmissionRequest_srcInfo[] = { /* SEQUENCE OF */ - {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, -}; - -static field_t _AdmissionRequest[] = { /* SEQUENCE */ - {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, - {FNAME("callType") CHOICE, 2, 4, 4, SKIP | EXT, 0, _CallType}, - {FNAME("callModel") CHOICE, 1, 2, 2, SKIP | EXT | OPT, 0, _CallModel}, - {FNAME("endpointIdentifier") BMPSTR, 7, 1, 0, SKIP, 0, NULL}, - {FNAME("destinationInfo") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, - _AdmissionRequest_destinationInfo}, - {FNAME("destCallSignalAddress") CHOICE, 3, 7, 7, DECODE | EXT | OPT, - offsetof(AdmissionRequest, destCallSignalAddress), - _TransportAddress}, - {FNAME("destExtraCallInfo") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, - _AdmissionRequest_destExtraCallInfo}, - {FNAME("srcInfo") SEQOF, SEMI, 0, 0, SKIP, 0, - _AdmissionRequest_srcInfo}, - {FNAME("srcCallSignalAddress") CHOICE, 3, 7, 7, DECODE | EXT | OPT, - offsetof(AdmissionRequest, srcCallSignalAddress), _TransportAddress}, - {FNAME("bandWidth") INT, CONS, 0, 0, STOP, 0, NULL}, - {FNAME("callReferenceValue") INT, WORD, 0, 0, STOP, 0, NULL}, - {FNAME("nonStandardData") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, - {FNAME("callServices") SEQ, 0, 8, 8, STOP | EXT | OPT, 0, NULL}, - {FNAME("conferenceID") OCTSTR, FIXD, 16, 0, STOP, 0, NULL}, - {FNAME("activeMC") BOOL, FIXD, 0, 0, STOP, 0, NULL}, - {FNAME("answerCall") BOOL, FIXD, 0, 0, STOP, 0, NULL}, - {FNAME("canMapAlias") BOOL, FIXD, 0, 0, STOP, 0, NULL}, - {FNAME("callIdentifier") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, - {FNAME("srcAlternatives") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("destAlternatives") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("gatekeeperIdentifier") BMPSTR, 7, 1, 0, STOP | OPT, 0, NULL}, - {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, - {FNAME("transportQOS") CHOICE, 2, 3, 3, STOP | EXT | OPT, 0, NULL}, - {FNAME("willSupplyUUIEs") BOOL, FIXD, 0, 0, STOP, 0, NULL}, - {FNAME("callLinkage") SEQ, 2, 2, 2, STOP | EXT | OPT, 0, NULL}, - {FNAME("gatewayDataRate") SEQ, 2, 3, 3, STOP | EXT | OPT, 0, NULL}, - {FNAME("capacity") SEQ, 2, 2, 2, STOP | EXT | OPT, 0, NULL}, - {FNAME("circuitInfo") SEQ, 3, 3, 3, STOP | EXT | OPT, 0, NULL}, - {FNAME("desiredProtocols") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("desiredTunnelledProtocol") SEQ, 1, 2, 2, STOP | EXT | OPT, 0, - NULL}, - {FNAME("featureSet") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, NULL}, - {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, -}; - -static field_t _AdmissionConfirm[] = { /* SEQUENCE */ - {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, - {FNAME("bandWidth") INT, CONS, 0, 0, SKIP, 0, NULL}, - {FNAME("callModel") CHOICE, 1, 2, 2, SKIP | EXT, 0, _CallModel}, - {FNAME("destCallSignalAddress") CHOICE, 3, 7, 7, DECODE | EXT, - offsetof(AdmissionConfirm, destCallSignalAddress), - _TransportAddress}, - {FNAME("irrFrequency") INT, WORD, 1, 0, STOP | OPT, 0, NULL}, - {FNAME("nonStandardData") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, - {FNAME("destinationInfo") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("destExtraCallInfo") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("destinationType") SEQ, 6, 8, 10, STOP | EXT | OPT, 0, NULL}, - {FNAME("remoteExtensionAddress") SEQOF, SEMI, 0, 0, STOP | OPT, 0, - NULL}, - {FNAME("alternateEndpoints") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, - {FNAME("transportQOS") CHOICE, 2, 3, 3, STOP | EXT | OPT, 0, NULL}, - {FNAME("willRespondToIRR") BOOL, FIXD, 0, 0, STOP, 0, NULL}, - {FNAME("uuiesRequested") SEQ, 0, 9, 13, STOP | EXT, 0, NULL}, - {FNAME("language") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("alternateTransportAddresses") SEQ, 1, 1, 1, STOP | EXT | OPT, - 0, NULL}, - {FNAME("useSpecifiedTransport") CHOICE, 1, 2, 2, STOP | EXT | OPT, 0, - NULL}, - {FNAME("circuitInfo") SEQ, 3, 3, 3, STOP | EXT | OPT, 0, NULL}, - {FNAME("usageSpec") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("supportedProtocols") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("serviceControl") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("multipleCalls") BOOL, FIXD, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("featureSet") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, NULL}, - {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, -}; - -static field_t _LocationRequest_destinationInfo[] = { /* SEQUENCE OF */ - {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, -}; - -static field_t _LocationRequest[] = { /* SEQUENCE */ - {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, - {FNAME("endpointIdentifier") BMPSTR, 7, 1, 0, SKIP | OPT, 0, NULL}, - {FNAME("destinationInfo") SEQOF, SEMI, 0, 0, SKIP, 0, - _LocationRequest_destinationInfo}, - {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, - _NonStandardParameter}, - {FNAME("replyAddress") CHOICE, 3, 7, 7, DECODE | EXT, - offsetof(LocationRequest, replyAddress), _TransportAddress}, - {FNAME("sourceInfo") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("canMapAlias") BOOL, FIXD, 0, 0, STOP, 0, NULL}, - {FNAME("gatekeeperIdentifier") BMPSTR, 7, 1, 0, STOP | OPT, 0, NULL}, - {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, - {FNAME("desiredProtocols") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("desiredTunnelledProtocol") SEQ, 1, 2, 2, STOP | EXT | OPT, 0, - NULL}, - {FNAME("featureSet") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, NULL}, - {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("hopCount") INT, 8, 1, 0, STOP | OPT, 0, NULL}, - {FNAME("circuitInfo") SEQ, 3, 3, 3, STOP | EXT | OPT, 0, NULL}, -}; - -static field_t _LocationConfirm[] = { /* SEQUENCE */ - {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, - {FNAME("callSignalAddress") CHOICE, 3, 7, 7, DECODE | EXT, - offsetof(LocationConfirm, callSignalAddress), _TransportAddress}, - {FNAME("rasAddress") CHOICE, 3, 7, 7, DECODE | EXT, - offsetof(LocationConfirm, rasAddress), _TransportAddress}, - {FNAME("nonStandardData") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, - {FNAME("destinationInfo") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("destExtraCallInfo") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("destinationType") SEQ, 6, 8, 10, STOP | EXT | OPT, 0, NULL}, - {FNAME("remoteExtensionAddress") SEQOF, SEMI, 0, 0, STOP | OPT, 0, - NULL}, - {FNAME("alternateEndpoints") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, - {FNAME("alternateTransportAddresses") SEQ, 1, 1, 1, STOP | EXT | OPT, - 0, NULL}, - {FNAME("supportedProtocols") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("multipleCalls") BOOL, FIXD, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("featureSet") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, NULL}, - {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("circuitInfo") SEQ, 3, 3, 3, STOP | EXT | OPT, 0, NULL}, - {FNAME("serviceControl") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, -}; - -static field_t _InfoRequestResponse_callSignalAddress[] = { /* SEQUENCE OF */ - {FNAME("item") CHOICE, 3, 7, 7, DECODE | EXT, - sizeof(TransportAddress), _TransportAddress} - , -}; - -static field_t _InfoRequestResponse[] = { /* SEQUENCE */ - {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, - _NonStandardParameter}, - {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, - {FNAME("endpointType") SEQ, 6, 8, 10, SKIP | EXT, 0, _EndpointType}, - {FNAME("endpointIdentifier") BMPSTR, 7, 1, 0, SKIP, 0, NULL}, - {FNAME("rasAddress") CHOICE, 3, 7, 7, DECODE | EXT, - offsetof(InfoRequestResponse, rasAddress), _TransportAddress}, - {FNAME("callSignalAddress") SEQOF, SEMI, 0, 10, DECODE, - offsetof(InfoRequestResponse, callSignalAddress), - _InfoRequestResponse_callSignalAddress}, - {FNAME("endpointAlias") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("perCallInfo") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, - {FNAME("needResponse") BOOL, FIXD, 0, 0, STOP, 0, NULL}, - {FNAME("capacity") SEQ, 2, 2, 2, STOP | EXT | OPT, 0, NULL}, - {FNAME("irrStatus") CHOICE, 2, 4, 4, STOP | EXT | OPT, 0, NULL}, - {FNAME("unsolicited") BOOL, FIXD, 0, 0, STOP, 0, NULL}, - {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, -}; - -static field_t _RasMessage[] = { /* CHOICE */ - {FNAME("gatekeeperRequest") SEQ, 4, 8, 18, DECODE | EXT, - offsetof(RasMessage, gatekeeperRequest), _GatekeeperRequest}, - {FNAME("gatekeeperConfirm") SEQ, 2, 5, 14, DECODE | EXT, - offsetof(RasMessage, gatekeeperConfirm), _GatekeeperConfirm}, - {FNAME("gatekeeperReject") SEQ, 2, 5, 11, STOP | EXT, 0, NULL}, - {FNAME("registrationRequest") SEQ, 3, 10, 31, DECODE | EXT, - offsetof(RasMessage, registrationRequest), _RegistrationRequest}, - {FNAME("registrationConfirm") SEQ, 3, 7, 24, DECODE | EXT, - offsetof(RasMessage, registrationConfirm), _RegistrationConfirm}, - {FNAME("registrationReject") SEQ, 2, 5, 11, STOP | EXT, 0, NULL}, - {FNAME("unregistrationRequest") SEQ, 3, 5, 15, DECODE | EXT, - offsetof(RasMessage, unregistrationRequest), _UnregistrationRequest}, - {FNAME("unregistrationConfirm") SEQ, 1, 2, 6, STOP | EXT, 0, NULL}, - {FNAME("unregistrationReject") SEQ, 1, 3, 8, STOP | EXT, 0, NULL}, - {FNAME("admissionRequest") SEQ, 7, 16, 34, DECODE | EXT, - offsetof(RasMessage, admissionRequest), _AdmissionRequest}, - {FNAME("admissionConfirm") SEQ, 2, 6, 27, DECODE | EXT, - offsetof(RasMessage, admissionConfirm), _AdmissionConfirm}, - {FNAME("admissionReject") SEQ, 1, 3, 11, STOP | EXT, 0, NULL}, - {FNAME("bandwidthRequest") SEQ, 2, 7, 18, STOP | EXT, 0, NULL}, - {FNAME("bandwidthConfirm") SEQ, 1, 3, 8, STOP | EXT, 0, NULL}, - {FNAME("bandwidthReject") SEQ, 1, 4, 9, STOP | EXT, 0, NULL}, - {FNAME("disengageRequest") SEQ, 1, 6, 19, STOP | EXT, 0, NULL}, - {FNAME("disengageConfirm") SEQ, 1, 2, 9, STOP | EXT, 0, NULL}, - {FNAME("disengageReject") SEQ, 1, 3, 8, STOP | EXT, 0, NULL}, - {FNAME("locationRequest") SEQ, 2, 5, 17, DECODE | EXT, - offsetof(RasMessage, locationRequest), _LocationRequest}, - {FNAME("locationConfirm") SEQ, 1, 4, 19, DECODE | EXT, - offsetof(RasMessage, locationConfirm), _LocationConfirm}, - {FNAME("locationReject") SEQ, 1, 3, 10, STOP | EXT, 0, NULL}, - {FNAME("infoRequest") SEQ, 2, 4, 15, STOP | EXT, 0, NULL}, - {FNAME("infoRequestResponse") SEQ, 3, 8, 16, DECODE | EXT, - offsetof(RasMessage, infoRequestResponse), _InfoRequestResponse}, - {FNAME("nonStandardMessage") SEQ, 0, 2, 7, STOP | EXT, 0, NULL}, - {FNAME("unknownMessageResponse") SEQ, 0, 1, 5, STOP | EXT, 0, NULL}, - {FNAME("requestInProgress") SEQ, 4, 6, 6, STOP | EXT, 0, NULL}, - {FNAME("resourcesAvailableIndicate") SEQ, 4, 9, 11, STOP | EXT, 0, - NULL}, - {FNAME("resourcesAvailableConfirm") SEQ, 4, 6, 7, STOP | EXT, 0, - NULL}, - {FNAME("infoRequestAck") SEQ, 4, 5, 5, STOP | EXT, 0, NULL}, - {FNAME("infoRequestNak") SEQ, 5, 7, 7, STOP | EXT, 0, NULL}, - {FNAME("serviceControlIndication") SEQ, 8, 10, 10, STOP | EXT, 0, - NULL}, - {FNAME("serviceControlResponse") SEQ, 7, 8, 8, STOP | EXT, 0, NULL}, -}; diff --git a/net/ipv4/netfilter/nf_nat_h323.c b/net/ipv4/netfilter/nf_nat_h323.c new file mode 100644 index 00000000000..fb9ab0114c2 --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_h323.c @@ -0,0 +1,596 @@ +/* + * H.323 extension for NAT alteration. + * + * Copyright (c) 2006 Jing Min Zhao + * + * This source code is licensed under General Public License version 2. + * + * Based on the 'brute force' H.323 NAT module by + * Jozsef Kadlecsik + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(format, args...) +#endif + +/****************************************************************************/ +static int set_addr(struct sk_buff **pskb, + unsigned char **data, int dataoff, + unsigned int addroff, __be32 ip, __be16 port) +{ + enum ip_conntrack_info ctinfo; + struct nf_conn *ct = ip_conntrack_get(*pskb, &ctinfo); + struct { + __be32 ip; + __be16 port; + } __attribute__ ((__packed__)) buf; + struct tcphdr _tcph, *th; + + buf.ip = ip; + buf.port = port; + addroff += dataoff; + + if ((*pskb)->nh.iph->protocol == IPPROTO_TCP) { + if (!nf_nat_mangle_tcp_packet(pskb, ct, ctinfo, + addroff, sizeof(buf), + (char *) &buf, sizeof(buf))) { + if (net_ratelimit()) + printk("nf_nat_h323: nf_nat_mangle_tcp_packet" + " error\n"); + return -1; + } + + /* Relocate data pointer */ + th = skb_header_pointer(*pskb, (*pskb)->nh.iph->ihl * 4, + sizeof(_tcph), &_tcph); + if (th == NULL) + return -1; + *data = (*pskb)->data + (*pskb)->nh.iph->ihl * 4 + + th->doff * 4 + dataoff; + } else { + if (!nf_nat_mangle_udp_packet(pskb, ct, ctinfo, + addroff, sizeof(buf), + (char *) &buf, sizeof(buf))) { + if (net_ratelimit()) + printk("nf_nat_h323: nf_nat_mangle_udp_packet" + " error\n"); + return -1; + } + /* nf_nat_mangle_udp_packet uses skb_make_writable() to copy + * or pull everything in a linear buffer, so we can safely + * use the skb pointers now */ + *data = (*pskb)->data + (*pskb)->nh.iph->ihl * 4 + + sizeof(struct udphdr); + } + + return 0; +} + +/****************************************************************************/ +static int set_h225_addr(struct sk_buff **pskb, + unsigned char **data, int dataoff, + TransportAddress *taddr, + union nf_conntrack_address *addr, __be16 port) +{ + return set_addr(pskb, data, dataoff, taddr->ipAddress.ip, + addr->ip, port); +} + +/****************************************************************************/ +static int set_h245_addr(struct sk_buff **pskb, + unsigned char **data, int dataoff, + H245_TransportAddress *taddr, + union nf_conntrack_address *addr, __be16 port) +{ + return set_addr(pskb, data, dataoff, + taddr->unicastAddress.iPAddress.network, + addr->ip, port); +} + +/****************************************************************************/ +static int set_sig_addr(struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, + TransportAddress *taddr, int count) +{ + struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info; + int dir = CTINFO2DIR(ctinfo); + int i; + __be16 port; + union nf_conntrack_address addr; + + for (i = 0; i < count; i++) { + if (get_h225_addr(ct, *data, &taddr[i], &addr, &port)) { + if (addr.ip == ct->tuplehash[dir].tuple.src.u3.ip && + port == info->sig_port[dir]) { + /* GW->GK */ + + /* Fix for Gnomemeeting */ + if (i > 0 && + get_h225_addr(ct, *data, &taddr[0], + &addr, &port) && + (ntohl(addr.ip) & 0xff000000) == 0x7f000000) + i = 0; + + DEBUGP + ("nf_nat_ras: set signal address " + "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", + NIPQUAD(ip), port, + NIPQUAD(ct->tuplehash[!dir].tuple.dst. + ip), info->sig_port[!dir]); + return set_h225_addr(pskb, data, 0, &taddr[i], + &ct->tuplehash[!dir]. + tuple.dst.u3, + info->sig_port[!dir]); + } else if (addr.ip == ct->tuplehash[dir].tuple.dst.u3.ip && + port == info->sig_port[dir]) { + /* GK->GW */ + DEBUGP + ("nf_nat_ras: set signal address " + "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", + NIPQUAD(ip), port, + NIPQUAD(ct->tuplehash[!dir].tuple.src. + ip), info->sig_port[!dir]); + return set_h225_addr(pskb, data, 0, &taddr[i], + &ct->tuplehash[!dir]. + tuple.src.u3, + info->sig_port[!dir]); + } + } + } + + return 0; +} + +/****************************************************************************/ +static int set_ras_addr(struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, + TransportAddress *taddr, int count) +{ + int dir = CTINFO2DIR(ctinfo); + int i; + __be16 port; + union nf_conntrack_address addr; + + for (i = 0; i < count; i++) { + if (get_h225_addr(ct, *data, &taddr[i], &addr, &port) && + addr.ip == ct->tuplehash[dir].tuple.src.u3.ip && + port == ct->tuplehash[dir].tuple.src.u.udp.port) { + DEBUGP("nf_nat_ras: set rasAddress " + "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", + NIPQUAD(ip), ntohs(port), + NIPQUAD(ct->tuplehash[!dir].tuple.dst.u3.ip), + ntohs(ct->tuplehash[!dir].tuple.dst.u.udp. + port)); + return set_h225_addr(pskb, data, 0, &taddr[i], + &ct->tuplehash[!dir].tuple.dst.u3, + ct->tuplehash[!dir].tuple. + dst.u.udp.port); + } + } + + return 0; +} + +/****************************************************************************/ +static int nat_rtp_rtcp(struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, int dataoff, + H245_TransportAddress *taddr, + __be16 port, __be16 rtp_port, + struct nf_conntrack_expect *rtp_exp, + struct nf_conntrack_expect *rtcp_exp) +{ + struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info; + int dir = CTINFO2DIR(ctinfo); + int i; + u_int16_t nated_port; + + /* Set expectations for NAT */ + rtp_exp->saved_proto.udp.port = rtp_exp->tuple.dst.u.udp.port; + rtp_exp->expectfn = nf_nat_follow_master; + rtp_exp->dir = !dir; + rtcp_exp->saved_proto.udp.port = rtcp_exp->tuple.dst.u.udp.port; + rtcp_exp->expectfn = nf_nat_follow_master; + rtcp_exp->dir = !dir; + + /* Lookup existing expects */ + for (i = 0; i < H323_RTP_CHANNEL_MAX; i++) { + if (info->rtp_port[i][dir] == rtp_port) { + /* Expected */ + + /* Use allocated ports first. This will refresh + * the expects */ + rtp_exp->tuple.dst.u.udp.port = info->rtp_port[i][dir]; + rtcp_exp->tuple.dst.u.udp.port = + htons(ntohs(info->rtp_port[i][dir]) + 1); + break; + } else if (info->rtp_port[i][dir] == 0) { + /* Not expected */ + break; + } + } + + /* Run out of expectations */ + if (i >= H323_RTP_CHANNEL_MAX) { + if (net_ratelimit()) + printk("nf_nat_h323: out of expectations\n"); + return 0; + } + + /* Try to get a pair of ports. */ + for (nated_port = ntohs(rtp_exp->tuple.dst.u.udp.port); + nated_port != 0; nated_port += 2) { + rtp_exp->tuple.dst.u.udp.port = htons(nated_port); + if (nf_conntrack_expect_related(rtp_exp) == 0) { + rtcp_exp->tuple.dst.u.udp.port = + htons(nated_port + 1); + if (nf_conntrack_expect_related(rtcp_exp) == 0) + break; + nf_conntrack_unexpect_related(rtp_exp); + } + } + + if (nated_port == 0) { /* No port available */ + if (net_ratelimit()) + printk("nf_nat_h323: out of RTP ports\n"); + return 0; + } + + /* Modify signal */ + if (set_h245_addr(pskb, data, dataoff, taddr, + &ct->tuplehash[!dir].tuple.dst.u3, + htons((port & htons(1)) ? nated_port + 1 : + nated_port)) == 0) { + /* Save ports */ + info->rtp_port[i][dir] = rtp_port; + info->rtp_port[i][!dir] = htons(nated_port); + } else { + nf_conntrack_unexpect_related(rtp_exp); + nf_conntrack_unexpect_related(rtcp_exp); + return -1; + } + + /* Success */ + DEBUGP("nf_nat_h323: expect RTP %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", + NIPQUAD(rtp_exp->tuple.src.ip), + ntohs(rtp_exp->tuple.src.u.udp.port), + NIPQUAD(rtp_exp->tuple.dst.ip), + ntohs(rtp_exp->tuple.dst.u.udp.port)); + DEBUGP("nf_nat_h323: expect RTCP %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", + NIPQUAD(rtcp_exp->tuple.src.ip), + ntohs(rtcp_exp->tuple.src.u.udp.port), + NIPQUAD(rtcp_exp->tuple.dst.ip), + ntohs(rtcp_exp->tuple.dst.u.udp.port)); + + return 0; +} + +/****************************************************************************/ +static int nat_t120(struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, int dataoff, + H245_TransportAddress *taddr, __be16 port, + struct nf_conntrack_expect *exp) +{ + int dir = CTINFO2DIR(ctinfo); + u_int16_t nated_port = ntohs(port); + + /* Set expectations for NAT */ + exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port; + exp->expectfn = nf_nat_follow_master; + exp->dir = !dir; + + /* Try to get same port: if not, try to change it. */ + for (; nated_port != 0; nated_port++) { + exp->tuple.dst.u.tcp.port = htons(nated_port); + if (nf_conntrack_expect_related(exp) == 0) + break; + } + + if (nated_port == 0) { /* No port available */ + if (net_ratelimit()) + printk("nf_nat_h323: out of TCP ports\n"); + return 0; + } + + /* Modify signal */ + if (set_h245_addr(pskb, data, dataoff, taddr, + &ct->tuplehash[!dir].tuple.dst.u3, + htons(nated_port)) < 0) { + nf_conntrack_unexpect_related(exp); + return -1; + } + + DEBUGP("nf_nat_h323: expect T.120 %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", + NIPQUAD(exp->tuple.src.ip), ntohs(exp->tuple.src.u.tcp.port), + NIPQUAD(exp->tuple.dst.ip), ntohs(exp->tuple.dst.u.tcp.port)); + + return 0; +} + +/****************************************************************************/ +static int nat_h245(struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, int dataoff, + TransportAddress *taddr, __be16 port, + struct nf_conntrack_expect *exp) +{ + struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info; + int dir = CTINFO2DIR(ctinfo); + u_int16_t nated_port = ntohs(port); + + /* Set expectations for NAT */ + exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port; + exp->expectfn = nf_nat_follow_master; + exp->dir = !dir; + + /* Check existing expects */ + if (info->sig_port[dir] == port) + nated_port = ntohs(info->sig_port[!dir]); + + /* Try to get same port: if not, try to change it. */ + for (; nated_port != 0; nated_port++) { + exp->tuple.dst.u.tcp.port = htons(nated_port); + if (nf_conntrack_expect_related(exp) == 0) + break; + } + + if (nated_port == 0) { /* No port available */ + if (net_ratelimit()) + printk("nf_nat_q931: out of TCP ports\n"); + return 0; + } + + /* Modify signal */ + if (set_h225_addr(pskb, data, dataoff, taddr, + &ct->tuplehash[!dir].tuple.dst.u3, + htons(nated_port)) == 0) { + /* Save ports */ + info->sig_port[dir] = port; + info->sig_port[!dir] = htons(nated_port); + } else { + nf_conntrack_unexpect_related(exp); + return -1; + } + + DEBUGP("nf_nat_q931: expect H.245 %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", + NIPQUAD(exp->tuple.src.ip), ntohs(exp->tuple.src.u.tcp.port), + NIPQUAD(exp->tuple.dst.ip), ntohs(exp->tuple.dst.u.tcp.port)); + + return 0; +} + +/**************************************************************************** + * This conntrack expect function replaces nf_conntrack_q931_expect() + * which was set by nf_conntrack_h323.c. + ****************************************************************************/ +static void ip_nat_q931_expect(struct nf_conn *new, + struct nf_conntrack_expect *this) +{ + struct ip_nat_range range; + + if (this->tuple.src.u3.ip != 0) { /* Only accept calls from GK */ + nf_nat_follow_master(new, this); + return; + } + + /* This must be a fresh one. */ + BUG_ON(new->status & IPS_NAT_DONE_MASK); + + /* Change src to where master sends to */ + range.flags = IP_NAT_RANGE_MAP_IPS; + range.min_ip = range.max_ip = new->tuplehash[!this->dir].tuple.src.u3.ip; + + /* hook doesn't matter, but it has to do source manip */ + nf_nat_setup_info(new, &range, NF_IP_POST_ROUTING); + + /* For DST manip, map port here to where it's expected. */ + range.flags = (IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED); + range.min = range.max = this->saved_proto; + range.min_ip = range.max_ip = + new->master->tuplehash[!this->dir].tuple.src.u3.ip; + + /* hook doesn't matter, but it has to do destination manip */ + nf_nat_setup_info(new, &range, NF_IP_PRE_ROUTING); +} + +/****************************************************************************/ +static int nat_q931(struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, TransportAddress *taddr, int idx, + __be16 port, struct nf_conntrack_expect *exp) +{ + struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info; + int dir = CTINFO2DIR(ctinfo); + u_int16_t nated_port = ntohs(port); + union nf_conntrack_address addr; + + /* Set expectations for NAT */ + exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port; + exp->expectfn = ip_nat_q931_expect; + exp->dir = !dir; + + /* Check existing expects */ + if (info->sig_port[dir] == port) + nated_port = ntohs(info->sig_port[!dir]); + + /* Try to get same port: if not, try to change it. */ + for (; nated_port != 0; nated_port++) { + exp->tuple.dst.u.tcp.port = htons(nated_port); + if (nf_conntrack_expect_related(exp) == 0) + break; + } + + if (nated_port == 0) { /* No port available */ + if (net_ratelimit()) + printk("nf_nat_ras: out of TCP ports\n"); + return 0; + } + + /* Modify signal */ + if (set_h225_addr(pskb, data, 0, &taddr[idx], + &ct->tuplehash[!dir].tuple.dst.u3, + htons(nated_port)) == 0) { + /* Save ports */ + info->sig_port[dir] = port; + info->sig_port[!dir] = htons(nated_port); + + /* Fix for Gnomemeeting */ + if (idx > 0 && + get_h225_addr(ct, *data, &taddr[0], &addr, &port) && + (ntohl(addr.ip) & 0xff000000) == 0x7f000000) { + set_h225_addr_hook(pskb, data, 0, &taddr[0], + &ct->tuplehash[!dir].tuple.dst.u3, + info->sig_port[!dir]); + } + } else { + nf_conntrack_unexpect_related(exp); + return -1; + } + + /* Success */ + DEBUGP("nf_nat_ras: expect Q.931 %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", + NIPQUAD(exp->tuple.src.ip), ntohs(exp->tuple.src.u.tcp.port), + NIPQUAD(exp->tuple.dst.ip), ntohs(exp->tuple.dst.u.tcp.port)); + + return 0; +} + +/****************************************************************************/ +static void ip_nat_callforwarding_expect(struct nf_conn *new, + struct nf_conntrack_expect *this) +{ + struct nf_nat_range range; + + /* This must be a fresh one. */ + BUG_ON(new->status & IPS_NAT_DONE_MASK); + + /* Change src to where master sends to */ + range.flags = IP_NAT_RANGE_MAP_IPS; + range.min_ip = range.max_ip = new->tuplehash[!this->dir].tuple.src.u3.ip; + + /* hook doesn't matter, but it has to do source manip */ + nf_nat_setup_info(new, &range, NF_IP_POST_ROUTING); + + /* For DST manip, map port here to where it's expected. */ + range.flags = (IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED); + range.min = range.max = this->saved_proto; + range.min_ip = range.max_ip = this->saved_ip; + + /* hook doesn't matter, but it has to do destination manip */ + nf_nat_setup_info(new, &range, NF_IP_PRE_ROUTING); +} + +/****************************************************************************/ +static int nat_callforwarding(struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, int dataoff, + TransportAddress *taddr, __be16 port, + struct nf_conntrack_expect *exp) +{ + int dir = CTINFO2DIR(ctinfo); + u_int16_t nated_port; + + /* Set expectations for NAT */ + exp->saved_ip = exp->tuple.dst.u3.ip; + exp->tuple.dst.u3.ip = ct->tuplehash[!dir].tuple.dst.u3.ip; + exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port; + exp->expectfn = ip_nat_callforwarding_expect; + exp->dir = !dir; + + /* Try to get same port: if not, try to change it. */ + for (nated_port = ntohs(port); nated_port != 0; nated_port++) { + exp->tuple.dst.u.tcp.port = htons(nated_port); + if (nf_conntrack_expect_related(exp) == 0) + break; + } + + if (nated_port == 0) { /* No port available */ + if (net_ratelimit()) + printk("nf_nat_q931: out of TCP ports\n"); + return 0; + } + + /* Modify signal */ + if (!set_h225_addr(pskb, data, dataoff, taddr, + &ct->tuplehash[!dir].tuple.dst.u3, + htons(nated_port)) == 0) { + nf_conntrack_unexpect_related(exp); + return -1; + } + + /* Success */ + DEBUGP("nf_nat_q931: expect Call Forwarding " + "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", + NIPQUAD(exp->tuple.src.ip), ntohs(exp->tuple.src.u.tcp.port), + NIPQUAD(exp->tuple.dst.ip), ntohs(exp->tuple.dst.u.tcp.port)); + + return 0; +} + +/****************************************************************************/ +static int __init init(void) +{ + BUG_ON(rcu_dereference(set_h245_addr_hook) != NULL); + BUG_ON(rcu_dereference(set_h225_addr_hook) != NULL); + BUG_ON(rcu_dereference(set_sig_addr_hook) != NULL); + BUG_ON(rcu_dereference(set_ras_addr_hook) != NULL); + BUG_ON(rcu_dereference(nat_rtp_rtcp_hook) != NULL); + BUG_ON(rcu_dereference(nat_t120_hook) != NULL); + BUG_ON(rcu_dereference(nat_h245_hook) != NULL); + BUG_ON(rcu_dereference(nat_callforwarding_hook) != NULL); + BUG_ON(rcu_dereference(nat_q931_hook) != NULL); + + rcu_assign_pointer(set_h245_addr_hook, set_h245_addr); + rcu_assign_pointer(set_h225_addr_hook, set_h225_addr); + rcu_assign_pointer(set_sig_addr_hook, set_sig_addr); + rcu_assign_pointer(set_ras_addr_hook, set_ras_addr); + rcu_assign_pointer(nat_rtp_rtcp_hook, nat_rtp_rtcp); + rcu_assign_pointer(nat_t120_hook, nat_t120); + rcu_assign_pointer(nat_h245_hook, nat_h245); + rcu_assign_pointer(nat_callforwarding_hook, nat_callforwarding); + rcu_assign_pointer(nat_q931_hook, nat_q931); + + DEBUGP("nf_nat_h323: init success\n"); + return 0; +} + +/****************************************************************************/ +static void __exit fini(void) +{ + rcu_assign_pointer(set_h245_addr_hook, NULL); + rcu_assign_pointer(set_h225_addr_hook, NULL); + rcu_assign_pointer(set_sig_addr_hook, NULL); + rcu_assign_pointer(set_ras_addr_hook, NULL); + rcu_assign_pointer(nat_rtp_rtcp_hook, NULL); + rcu_assign_pointer(nat_t120_hook, NULL); + rcu_assign_pointer(nat_h245_hook, NULL); + rcu_assign_pointer(nat_callforwarding_hook, NULL); + rcu_assign_pointer(nat_q931_hook, NULL); + synchronize_rcu(); +} + +/****************************************************************************/ +module_init(init); +module_exit(fini); + +MODULE_AUTHOR("Jing Min Zhao "); +MODULE_DESCRIPTION("H.323 NAT helper"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("ip_nat_h323"); -- cgit v1.2.3 From 869f37d8e48f3911eb70f38a994feaa8f8380008 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Sat, 2 Dec 2006 22:09:06 -0800 Subject: [NETFILTER]: nf_conntrack/nf_nat: add IRC helper port Add nf_conntrack port of the IRC conntrack/NAT helper. Since DCC doesn't support IPv6 yet, the helper is still IPv4 only. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/ipv4/netfilter/Kconfig | 5 ++ net/ipv4/netfilter/Makefile | 1 + net/ipv4/netfilter/nf_nat_irc.c | 101 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 107 insertions(+) create mode 100644 net/ipv4/netfilter/nf_nat_irc.c (limited to 'net/ipv4') diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index e14156d1122..4555f721dfc 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig @@ -500,6 +500,11 @@ config IP_NF_NAT_IRC default IP_NF_NAT if IP_NF_IRC=y default m if IP_NF_IRC=m +config NF_NAT_IRC + tristate + depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT + default NF_NAT && NF_CONNTRACK_IRC + config IP_NF_NAT_TFTP tristate depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index bdaba4700e3..56733c37032 100644 --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile @@ -53,6 +53,7 @@ obj-$(CONFIG_IP_NF_NAT_SIP) += ip_nat_sip.o obj-$(CONFIG_NF_NAT_AMANDA) += nf_nat_amanda.o obj-$(CONFIG_NF_NAT_FTP) += nf_nat_ftp.o obj-$(CONFIG_NF_NAT_H323) += nf_nat_h323.o +obj-$(CONFIG_NF_NAT_IRC) += nf_nat_irc.o # generic IP tables obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o diff --git a/net/ipv4/netfilter/nf_nat_irc.c b/net/ipv4/netfilter/nf_nat_irc.c new file mode 100644 index 00000000000..9b8c0daea74 --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_irc.c @@ -0,0 +1,101 @@ +/* IRC extension for TCP NAT alteration. + * + * (C) 2000-2001 by Harald Welte + * (C) 2004 Rusty Russell IBM Corporation + * based on a copy of RR's ip_nat_ftp.c + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(format, args...) +#endif + +MODULE_AUTHOR("Harald Welte "); +MODULE_DESCRIPTION("IRC (DCC) NAT helper"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("ip_nat_irc"); + +static unsigned int help(struct sk_buff **pskb, + enum ip_conntrack_info ctinfo, + unsigned int matchoff, + unsigned int matchlen, + struct nf_conntrack_expect *exp) +{ + char buffer[sizeof("4294967296 65635")]; + u_int32_t ip; + u_int16_t port; + unsigned int ret; + + DEBUGP("IRC_NAT: info (seq %u + %u) in %u\n", + expect->seq, exp_irc_info->len, ntohl(tcph->seq)); + + /* Reply comes from server. */ + exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port; + exp->dir = IP_CT_DIR_REPLY; + exp->expectfn = nf_nat_follow_master; + + /* Try to get same port: if not, try to change it. */ + for (port = ntohs(exp->saved_proto.tcp.port); port != 0; port++) { + exp->tuple.dst.u.tcp.port = htons(port); + if (nf_conntrack_expect_related(exp) == 0) + break; + } + + if (port == 0) + return NF_DROP; + + ip = ntohl(exp->master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip); + sprintf(buffer, "%u %u", ip, port); + DEBUGP("nf_nat_irc: inserting '%s' == %u.%u.%u.%u, port %u\n", + buffer, NIPQUAD(ip), port); + + ret = nf_nat_mangle_tcp_packet(pskb, exp->master, ctinfo, + matchoff, matchlen, buffer, + strlen(buffer)); + if (ret != NF_ACCEPT) + nf_conntrack_unexpect_related(exp); + return ret; +} + +static void __exit nf_nat_irc_fini(void) +{ + rcu_assign_pointer(nf_nat_irc_hook, NULL); + synchronize_rcu(); +} + +static int __init nf_nat_irc_init(void) +{ + BUG_ON(rcu_dereference(nf_nat_irc_hook)); + rcu_assign_pointer(nf_nat_irc_hook, help); + return 0; +} + +/* Prior to 2.6.11, we had a ports param. No longer, but don't break users. */ +static int warn_set(const char *val, struct kernel_param *kp) +{ + printk(KERN_INFO KBUILD_MODNAME + ": kernel >= 2.6.10 only uses 'ports' for conntrack modules\n"); + return 0; +} +module_param_call(ports, warn_set, NULL, NULL, 0); + +module_init(nf_nat_irc_init); +module_exit(nf_nat_irc_fini); -- cgit v1.2.3 From f09943fefe6b702e40893d35b4f10fd1064037fe Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Sat, 2 Dec 2006 22:09:41 -0800 Subject: [NETFILTER]: nf_conntrack/nf_nat: add PPTP helper port Add nf_conntrack port of the PPtP conntrack/NAT helper. Since there seems to be no IPv6-capable PPtP implementation the helper only support IPv4. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/ipv4/netfilter/Kconfig | 10 ++ net/ipv4/netfilter/Makefile | 4 + net/ipv4/netfilter/nf_nat_pptp.c | 315 ++++++++++++++++++++++++++++++++++ net/ipv4/netfilter/nf_nat_proto_gre.c | 179 +++++++++++++++++++ 4 files changed, 508 insertions(+) create mode 100644 net/ipv4/netfilter/nf_nat_pptp.c create mode 100644 net/ipv4/netfilter/nf_nat_proto_gre.c (limited to 'net/ipv4') diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index 4555f721dfc..c3327ac024d 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig @@ -484,6 +484,10 @@ config IP_NF_NAT_SNMP_BASIC # '&&' (6) # # (6) Returns the result of min(/expr/, /expr/). +config NF_NAT_PROTO_GRE + tristate + depends on NF_NAT && NF_CT_PROTO_GRE + config IP_NF_NAT_FTP tristate depends on IP_NF_IPTABLES && IP_NF_CONNTRACK && IP_NF_NAT @@ -528,6 +532,12 @@ config IP_NF_NAT_PPTP default IP_NF_NAT if IP_NF_PPTP=y default m if IP_NF_PPTP=m +config NF_NAT_PPTP + tristate + depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT + default NF_NAT && NF_CONNTRACK_PPTP + select NF_NAT_PROTO_GRE + config IP_NF_NAT_H323 tristate depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index 56733c37032..ef33ff2cdda 100644 --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile @@ -54,6 +54,10 @@ obj-$(CONFIG_NF_NAT_AMANDA) += nf_nat_amanda.o obj-$(CONFIG_NF_NAT_FTP) += nf_nat_ftp.o obj-$(CONFIG_NF_NAT_H323) += nf_nat_h323.o obj-$(CONFIG_NF_NAT_IRC) += nf_nat_irc.o +obj-$(CONFIG_NF_NAT_PPTP) += nf_nat_pptp.o + +# NAT protocols (nf_nat) +obj-$(CONFIG_NF_NAT_PROTO_GRE) += nf_nat_proto_gre.o # generic IP tables obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o diff --git a/net/ipv4/netfilter/nf_nat_pptp.c b/net/ipv4/netfilter/nf_nat_pptp.c new file mode 100644 index 00000000000..0ae45b79a4e --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_pptp.c @@ -0,0 +1,315 @@ +/* + * nf_nat_pptp.c + * + * NAT support for PPTP (Point to Point Tunneling Protocol). + * PPTP is a a protocol for creating virtual private networks. + * It is a specification defined by Microsoft and some vendors + * working with Microsoft. PPTP is built on top of a modified + * version of the Internet Generic Routing Encapsulation Protocol. + * GRE is defined in RFC 1701 and RFC 1702. Documentation of + * PPTP can be found in RFC 2637 + * + * (C) 2000-2005 by Harald Welte + * + * Development of this code funded by Astaro AG (http://www.astaro.com/) + * + * TODO: - NAT to a unique tuple, not to TCP source port + * (needs netfilter tuple reservation) + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define NF_NAT_PPTP_VERSION "3.0" + +#define REQ_CID(req, off) (*(__be16 *)((char *)(req) + (off))) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Harald Welte "); +MODULE_DESCRIPTION("Netfilter NAT helper module for PPTP"); +MODULE_ALIAS("ip_nat_pptp"); + +#if 0 +extern const char *pptp_msg_name[]; +#define DEBUGP(format, args...) printk(KERN_DEBUG "%s:%s: " format, __FILE__, \ + __FUNCTION__, ## args) +#else +#define DEBUGP(format, args...) +#endif + +static void pptp_nat_expected(struct nf_conn *ct, + struct nf_conntrack_expect *exp) +{ + struct nf_conn *master = ct->master; + struct nf_conntrack_expect *other_exp; + struct nf_conntrack_tuple t; + struct nf_ct_pptp_master *ct_pptp_info; + struct nf_nat_pptp *nat_pptp_info; + struct ip_nat_range range; + + ct_pptp_info = &nfct_help(master)->help.ct_pptp_info; + nat_pptp_info = &nfct_nat(master)->help.nat_pptp_info; + + /* And here goes the grand finale of corrosion... */ + if (exp->dir == IP_CT_DIR_ORIGINAL) { + DEBUGP("we are PNS->PAC\n"); + /* therefore, build tuple for PAC->PNS */ + t.src.l3num = AF_INET; + t.src.u3.ip = master->tuplehash[!exp->dir].tuple.src.u3.ip; + t.src.u.gre.key = ct_pptp_info->pac_call_id; + t.dst.u3.ip = master->tuplehash[!exp->dir].tuple.dst.u3.ip; + t.dst.u.gre.key = ct_pptp_info->pns_call_id; + t.dst.protonum = IPPROTO_GRE; + } else { + DEBUGP("we are PAC->PNS\n"); + /* build tuple for PNS->PAC */ + t.src.l3num = AF_INET; + t.src.u3.ip = master->tuplehash[exp->dir].tuple.src.u3.ip; + t.src.u.gre.key = nat_pptp_info->pns_call_id; + t.dst.u3.ip = master->tuplehash[exp->dir].tuple.dst.u3.ip; + t.dst.u.gre.key = nat_pptp_info->pac_call_id; + t.dst.protonum = IPPROTO_GRE; + } + + DEBUGP("trying to unexpect other dir: "); + NF_CT_DUMP_TUPLE(&t); + other_exp = nf_conntrack_expect_find_get(&t); + if (other_exp) { + nf_conntrack_unexpect_related(other_exp); + nf_conntrack_expect_put(other_exp); + DEBUGP("success\n"); + } else { + DEBUGP("not found!\n"); + } + + /* This must be a fresh one. */ + BUG_ON(ct->status & IPS_NAT_DONE_MASK); + + /* Change src to where master sends to */ + range.flags = IP_NAT_RANGE_MAP_IPS; + range.min_ip = range.max_ip + = ct->master->tuplehash[!exp->dir].tuple.dst.u3.ip; + if (exp->dir == IP_CT_DIR_ORIGINAL) { + range.flags |= IP_NAT_RANGE_PROTO_SPECIFIED; + range.min = range.max = exp->saved_proto; + } + /* hook doesn't matter, but it has to do source manip */ + nf_nat_setup_info(ct, &range, NF_IP_POST_ROUTING); + + /* For DST manip, map port here to where it's expected. */ + range.flags = IP_NAT_RANGE_MAP_IPS; + range.min_ip = range.max_ip + = ct->master->tuplehash[!exp->dir].tuple.src.u3.ip; + if (exp->dir == IP_CT_DIR_REPLY) { + range.flags |= IP_NAT_RANGE_PROTO_SPECIFIED; + range.min = range.max = exp->saved_proto; + } + /* hook doesn't matter, but it has to do destination manip */ + nf_nat_setup_info(ct, &range, NF_IP_PRE_ROUTING); +} + +/* outbound packets == from PNS to PAC */ +static int +pptp_outbound_pkt(struct sk_buff **pskb, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + struct PptpControlHeader *ctlh, + union pptp_ctrl_union *pptpReq) + +{ + struct nf_ct_pptp_master *ct_pptp_info; + struct nf_nat_pptp *nat_pptp_info; + u_int16_t msg; + __be16 new_callid; + unsigned int cid_off; + + ct_pptp_info = &nfct_help(ct)->help.ct_pptp_info; + nat_pptp_info = &nfct_nat(ct)->help.nat_pptp_info; + + new_callid = ct_pptp_info->pns_call_id; + + switch (msg = ntohs(ctlh->messageType)) { + case PPTP_OUT_CALL_REQUEST: + cid_off = offsetof(union pptp_ctrl_union, ocreq.callID); + /* FIXME: ideally we would want to reserve a call ID + * here. current netfilter NAT core is not able to do + * this :( For now we use TCP source port. This breaks + * multiple calls within one control session */ + + /* save original call ID in nat_info */ + nat_pptp_info->pns_call_id = ct_pptp_info->pns_call_id; + + /* don't use tcph->source since we are at a DSTmanip + * hook (e.g. PREROUTING) and pkt is not mangled yet */ + new_callid = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.tcp.port; + + /* save new call ID in ct info */ + ct_pptp_info->pns_call_id = new_callid; + break; + case PPTP_IN_CALL_REPLY: + cid_off = offsetof(union pptp_ctrl_union, icack.callID); + break; + case PPTP_CALL_CLEAR_REQUEST: + cid_off = offsetof(union pptp_ctrl_union, clrreq.callID); + break; + default: + DEBUGP("unknown outbound packet 0x%04x:%s\n", msg, + (msg <= PPTP_MSG_MAX)? + pptp_msg_name[msg]:pptp_msg_name[0]); + /* fall through */ + case PPTP_SET_LINK_INFO: + /* only need to NAT in case PAC is behind NAT box */ + case PPTP_START_SESSION_REQUEST: + case PPTP_START_SESSION_REPLY: + case PPTP_STOP_SESSION_REQUEST: + case PPTP_STOP_SESSION_REPLY: + case PPTP_ECHO_REQUEST: + case PPTP_ECHO_REPLY: + /* no need to alter packet */ + return NF_ACCEPT; + } + + /* only OUT_CALL_REQUEST, IN_CALL_REPLY, CALL_CLEAR_REQUEST pass + * down to here */ + DEBUGP("altering call id from 0x%04x to 0x%04x\n", + ntohs(REQ_CID(pptpReq, cid_off)), ntohs(new_callid)); + + /* mangle packet */ + if (nf_nat_mangle_tcp_packet(pskb, ct, ctinfo, + cid_off + sizeof(struct pptp_pkt_hdr) + + sizeof(struct PptpControlHeader), + sizeof(new_callid), (char *)&new_callid, + sizeof(new_callid)) == 0) + return NF_DROP; + return NF_ACCEPT; +} + +static void +pptp_exp_gre(struct nf_conntrack_expect *expect_orig, + struct nf_conntrack_expect *expect_reply) +{ + struct nf_conn *ct = expect_orig->master; + struct nf_ct_pptp_master *ct_pptp_info; + struct nf_nat_pptp *nat_pptp_info; + + ct_pptp_info = &nfct_help(ct)->help.ct_pptp_info; + nat_pptp_info = &nfct_nat(ct)->help.nat_pptp_info; + + /* save original PAC call ID in nat_info */ + nat_pptp_info->pac_call_id = ct_pptp_info->pac_call_id; + + /* alter expectation for PNS->PAC direction */ + expect_orig->saved_proto.gre.key = ct_pptp_info->pns_call_id; + expect_orig->tuple.src.u.gre.key = nat_pptp_info->pns_call_id; + expect_orig->tuple.dst.u.gre.key = ct_pptp_info->pac_call_id; + expect_orig->dir = IP_CT_DIR_ORIGINAL; + + /* alter expectation for PAC->PNS direction */ + expect_reply->saved_proto.gre.key = nat_pptp_info->pns_call_id; + expect_reply->tuple.src.u.gre.key = nat_pptp_info->pac_call_id; + expect_reply->tuple.dst.u.gre.key = ct_pptp_info->pns_call_id; + expect_reply->dir = IP_CT_DIR_REPLY; +} + +/* inbound packets == from PAC to PNS */ +static int +pptp_inbound_pkt(struct sk_buff **pskb, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + struct PptpControlHeader *ctlh, + union pptp_ctrl_union *pptpReq) +{ + struct nf_nat_pptp *nat_pptp_info; + u_int16_t msg; + __be16 new_pcid; + unsigned int pcid_off; + + nat_pptp_info = &nfct_nat(ct)->help.nat_pptp_info; + new_pcid = nat_pptp_info->pns_call_id; + + switch (msg = ntohs(ctlh->messageType)) { + case PPTP_OUT_CALL_REPLY: + pcid_off = offsetof(union pptp_ctrl_union, ocack.peersCallID); + break; + case PPTP_IN_CALL_CONNECT: + pcid_off = offsetof(union pptp_ctrl_union, iccon.peersCallID); + break; + case PPTP_IN_CALL_REQUEST: + /* only need to nat in case PAC is behind NAT box */ + return NF_ACCEPT; + case PPTP_WAN_ERROR_NOTIFY: + pcid_off = offsetof(union pptp_ctrl_union, wanerr.peersCallID); + break; + case PPTP_CALL_DISCONNECT_NOTIFY: + pcid_off = offsetof(union pptp_ctrl_union, disc.callID); + break; + case PPTP_SET_LINK_INFO: + pcid_off = offsetof(union pptp_ctrl_union, setlink.peersCallID); + break; + default: + DEBUGP("unknown inbound packet %s\n", (msg <= PPTP_MSG_MAX)? + pptp_msg_name[msg]:pptp_msg_name[0]); + /* fall through */ + case PPTP_START_SESSION_REQUEST: + case PPTP_START_SESSION_REPLY: + case PPTP_STOP_SESSION_REQUEST: + case PPTP_STOP_SESSION_REPLY: + case PPTP_ECHO_REQUEST: + case PPTP_ECHO_REPLY: + /* no need to alter packet */ + return NF_ACCEPT; + } + + /* only OUT_CALL_REPLY, IN_CALL_CONNECT, IN_CALL_REQUEST, + * WAN_ERROR_NOTIFY, CALL_DISCONNECT_NOTIFY pass down here */ + + /* mangle packet */ + DEBUGP("altering peer call id from 0x%04x to 0x%04x\n", + ntohs(REQ_CID(pptpReq, pcid_off)), ntohs(new_pcid)); + + if (nf_nat_mangle_tcp_packet(pskb, ct, ctinfo, + pcid_off + sizeof(struct pptp_pkt_hdr) + + sizeof(struct PptpControlHeader), + sizeof(new_pcid), (char *)&new_pcid, + sizeof(new_pcid)) == 0) + return NF_DROP; + return NF_ACCEPT; +} + +static int __init nf_nat_helper_pptp_init(void) +{ + nf_nat_need_gre(); + + BUG_ON(rcu_dereference(nf_nat_pptp_hook_outbound)); + rcu_assign_pointer(nf_nat_pptp_hook_outbound, pptp_outbound_pkt); + + BUG_ON(rcu_dereference(nf_nat_pptp_hook_inbound)); + rcu_assign_pointer(nf_nat_pptp_hook_inbound, pptp_inbound_pkt); + + BUG_ON(rcu_dereference(nf_nat_pptp_hook_exp_gre)); + rcu_assign_pointer(nf_nat_pptp_hook_exp_gre, pptp_exp_gre); + + BUG_ON(rcu_dereference(nf_nat_pptp_hook_expectfn)); + rcu_assign_pointer(nf_nat_pptp_hook_expectfn, pptp_nat_expected); + return 0; +} + +static void __exit nf_nat_helper_pptp_fini(void) +{ + rcu_assign_pointer(nf_nat_pptp_hook_expectfn, NULL); + rcu_assign_pointer(nf_nat_pptp_hook_exp_gre, NULL); + rcu_assign_pointer(nf_nat_pptp_hook_inbound, NULL); + rcu_assign_pointer(nf_nat_pptp_hook_outbound, NULL); + synchronize_rcu(); +} + +module_init(nf_nat_helper_pptp_init); +module_exit(nf_nat_helper_pptp_fini); diff --git a/net/ipv4/netfilter/nf_nat_proto_gre.c b/net/ipv4/netfilter/nf_nat_proto_gre.c new file mode 100644 index 00000000000..d3de579e09d --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_proto_gre.c @@ -0,0 +1,179 @@ +/* + * nf_nat_proto_gre.c + * + * NAT protocol helper module for GRE. + * + * GRE is a generic encapsulation protocol, which is generally not very + * suited for NAT, as it has no protocol-specific part as port numbers. + * + * It has an optional key field, which may help us distinguishing two + * connections between the same two hosts. + * + * GRE is defined in RFC 1701 and RFC 1702, as well as RFC 2784 + * + * PPTP is built on top of a modified version of GRE, and has a mandatory + * field called "CallID", which serves us for the same purpose as the key + * field in plain GRE. + * + * Documentation about PPTP can be found in RFC 2637 + * + * (C) 2000-2005 by Harald Welte + * + * Development of this code funded by Astaro AG (http://www.astaro.com/) + * + */ + +#include +#include +#include + +#include +#include +#include +#include + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Harald Welte "); +MODULE_DESCRIPTION("Netfilter NAT protocol helper module for GRE"); + +#if 0 +#define DEBUGP(format, args...) printk(KERN_DEBUG "%s:%s: " format, __FILE__, \ + __FUNCTION__, ## args) +#else +#define DEBUGP(x, args...) +#endif + +/* is key in given range between min and max */ +static int +gre_in_range(const struct nf_conntrack_tuple *tuple, + enum nf_nat_manip_type maniptype, + const union nf_conntrack_man_proto *min, + const union nf_conntrack_man_proto *max) +{ + __be16 key; + + if (maniptype == IP_NAT_MANIP_SRC) + key = tuple->src.u.gre.key; + else + key = tuple->dst.u.gre.key; + + return ntohs(key) >= ntohs(min->gre.key) && + ntohs(key) <= ntohs(max->gre.key); +} + +/* generate unique tuple ... */ +static int +gre_unique_tuple(struct nf_conntrack_tuple *tuple, + const struct nf_nat_range *range, + enum nf_nat_manip_type maniptype, + const struct nf_conn *conntrack) +{ + static u_int16_t key; + __be16 *keyptr; + unsigned int min, i, range_size; + + if (maniptype == IP_NAT_MANIP_SRC) + keyptr = &tuple->src.u.gre.key; + else + keyptr = &tuple->dst.u.gre.key; + + if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) { + DEBUGP("%p: NATing GRE PPTP\n", conntrack); + min = 1; + range_size = 0xffff; + } else { + min = ntohs(range->min.gre.key); + range_size = ntohs(range->max.gre.key) - min + 1; + } + + DEBUGP("min = %u, range_size = %u\n", min, range_size); + + for (i = 0; i < range_size; i++, key++) { + *keyptr = htons(min + key % range_size); + if (!nf_nat_used_tuple(tuple, conntrack)) + return 1; + } + + DEBUGP("%p: no NAT mapping\n", conntrack); + return 0; +} + +/* manipulate a GRE packet according to maniptype */ +static int +gre_manip_pkt(struct sk_buff **pskb, unsigned int iphdroff, + const struct nf_conntrack_tuple *tuple, + enum nf_nat_manip_type maniptype) +{ + struct gre_hdr *greh; + struct gre_hdr_pptp *pgreh; + struct iphdr *iph = (struct iphdr *)((*pskb)->data + iphdroff); + unsigned int hdroff = iphdroff + iph->ihl * 4; + + /* pgreh includes two optional 32bit fields which are not required + * to be there. That's where the magic '8' comes from */ + if (!skb_make_writable(pskb, hdroff + sizeof(*pgreh) - 8)) + return 0; + + greh = (void *)(*pskb)->data + hdroff; + pgreh = (struct gre_hdr_pptp *)greh; + + /* we only have destination manip of a packet, since 'source key' + * is not present in the packet itself */ + if (maniptype != IP_NAT_MANIP_DST) + return 1; + switch (greh->version) { + case 0: + if (!greh->key) { + DEBUGP("can't nat GRE w/o key\n"); + break; + } + if (greh->csum) { + /* FIXME: Never tested this code... */ + nf_proto_csum_replace4(gre_csum(greh), *pskb, + *(gre_key(greh)), + tuple->dst.u.gre.key, 0); + } + *(gre_key(greh)) = tuple->dst.u.gre.key; + break; + case GRE_VERSION_PPTP: + DEBUGP("call_id -> 0x%04x\n", ntohs(tuple->dst.u.gre.key)); + pgreh->call_id = tuple->dst.u.gre.key; + break; + default: + DEBUGP("can't nat unknown GRE version\n"); + return 0; + } + return 1; +} + +static struct nf_nat_protocol gre __read_mostly = { + .name = "GRE", + .protonum = IPPROTO_GRE, + .manip_pkt = gre_manip_pkt, + .in_range = gre_in_range, + .unique_tuple = gre_unique_tuple, +#if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \ + defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE) + .range_to_nfattr = nf_nat_port_range_to_nfattr, + .nfattr_to_range = nf_nat_port_nfattr_to_range, +#endif +}; + +int __init nf_nat_proto_gre_init(void) +{ + return nf_nat_protocol_register(&gre); +} + +void __exit nf_nat_proto_gre_fini(void) +{ + nf_nat_protocol_unregister(&gre); +} + +module_init(nf_nat_proto_gre_init); +module_exit(nf_nat_proto_gre_fini); + +void nf_nat_need_gre(void) +{ + return; +} +EXPORT_SYMBOL_GPL(nf_nat_need_gre); -- cgit v1.2.3 From 9fafcd7b203229c3f3893a475741afc27e276306 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Sat, 2 Dec 2006 22:09:57 -0800 Subject: [NETFILTER]: nf_conntrack/nf_nat: add SIP helper port Add IPv4 and IPv6 capable nf_conntrack port of the SIP conntrack/NAT helper. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/ipv4/netfilter/Kconfig | 5 + net/ipv4/netfilter/Makefile | 1 + net/ipv4/netfilter/nf_nat_sip.c | 283 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 289 insertions(+) create mode 100644 net/ipv4/netfilter/nf_nat_sip.c (limited to 'net/ipv4') diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index c3327ac024d..83e83f553cc 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig @@ -555,6 +555,11 @@ config IP_NF_NAT_SIP default IP_NF_NAT if IP_NF_SIP=y default m if IP_NF_SIP=m +config NF_NAT_SIP + tristate + depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT + default NF_NAT && NF_CONNTRACK_SIP + # mangle + specific targets config IP_NF_MANGLE tristate "Packet mangling" diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index ef33ff2cdda..167b65e89ac 100644 --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile @@ -55,6 +55,7 @@ obj-$(CONFIG_NF_NAT_FTP) += nf_nat_ftp.o obj-$(CONFIG_NF_NAT_H323) += nf_nat_h323.o obj-$(CONFIG_NF_NAT_IRC) += nf_nat_irc.o obj-$(CONFIG_NF_NAT_PPTP) += nf_nat_pptp.o +obj-$(CONFIG_NF_NAT_SIP) += nf_nat_sip.o # NAT protocols (nf_nat) obj-$(CONFIG_NF_NAT_PROTO_GRE) += nf_nat_proto_gre.o diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c new file mode 100644 index 00000000000..3d524b95731 --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_sip.c @@ -0,0 +1,283 @@ +/* SIP extension for UDP NAT alteration. + * + * (C) 2005 by Christian Hentschel + * based on RR's ip_nat_ftp.c and other modules. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Christian Hentschel "); +MODULE_DESCRIPTION("SIP NAT helper"); +MODULE_ALIAS("ip_nat_sip"); + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(format, args...) +#endif + +struct addr_map { + struct { + char src[sizeof("nnn.nnn.nnn.nnn:nnnnn")]; + char dst[sizeof("nnn.nnn.nnn.nnn:nnnnn")]; + unsigned int srclen, srciplen; + unsigned int dstlen, dstiplen; + } addr[IP_CT_DIR_MAX]; +}; + +static void addr_map_init(struct nf_conn *ct, struct addr_map *map) +{ + struct nf_conntrack_tuple *t; + enum ip_conntrack_dir dir; + unsigned int n; + + for (dir = 0; dir < IP_CT_DIR_MAX; dir++) { + t = &ct->tuplehash[dir].tuple; + + n = sprintf(map->addr[dir].src, "%u.%u.%u.%u", + NIPQUAD(t->src.u3.ip)); + map->addr[dir].srciplen = n; + n += sprintf(map->addr[dir].src + n, ":%u", + ntohs(t->src.u.udp.port)); + map->addr[dir].srclen = n; + + n = sprintf(map->addr[dir].dst, "%u.%u.%u.%u", + NIPQUAD(t->dst.u3.ip)); + map->addr[dir].dstiplen = n; + n += sprintf(map->addr[dir].dst + n, ":%u", + ntohs(t->dst.u.udp.port)); + map->addr[dir].dstlen = n; + } +} + +static int map_sip_addr(struct sk_buff **pskb, enum ip_conntrack_info ctinfo, + struct nf_conn *ct, const char **dptr, size_t dlen, + enum sip_header_pos pos, struct addr_map *map) +{ + enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); + unsigned int matchlen, matchoff, addrlen; + char *addr; + + if (ct_sip_get_info(ct, *dptr, dlen, &matchoff, &matchlen, pos) <= 0) + return 1; + + if ((matchlen == map->addr[dir].srciplen || + matchlen == map->addr[dir].srclen) && + memcmp(*dptr + matchoff, map->addr[dir].src, matchlen) == 0) { + addr = map->addr[!dir].dst; + addrlen = map->addr[!dir].dstlen; + } else if ((matchlen == map->addr[dir].dstiplen || + matchlen == map->addr[dir].dstlen) && + memcmp(*dptr + matchoff, map->addr[dir].dst, matchlen) == 0) { + addr = map->addr[!dir].src; + addrlen = map->addr[!dir].srclen; + } else + return 1; + + if (!nf_nat_mangle_udp_packet(pskb, ct, ctinfo, + matchoff, matchlen, addr, addrlen)) + return 0; + *dptr = (*pskb)->data + (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr); + return 1; + +} + +static unsigned int ip_nat_sip(struct sk_buff **pskb, + enum ip_conntrack_info ctinfo, + struct nf_conn *ct, + const char **dptr) +{ + enum sip_header_pos pos; + struct addr_map map; + int dataoff, datalen; + + dataoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr); + datalen = (*pskb)->len - dataoff; + if (datalen < sizeof("SIP/2.0") - 1) + return NF_DROP; + + addr_map_init(ct, &map); + + /* Basic rules: requests and responses. */ + if (strncmp(*dptr, "SIP/2.0", sizeof("SIP/2.0") - 1) != 0) { + /* 10.2: Constructing the REGISTER Request: + * + * The "userinfo" and "@" components of the SIP URI MUST NOT + * be present. + */ + if (datalen >= sizeof("REGISTER") - 1 && + strncmp(*dptr, "REGISTER", sizeof("REGISTER") - 1) == 0) + pos = POS_REG_REQ_URI; + else + pos = POS_REQ_URI; + + if (!map_sip_addr(pskb, ctinfo, ct, dptr, datalen, pos, &map)) + return NF_DROP; + } + + if (!map_sip_addr(pskb, ctinfo, ct, dptr, datalen, POS_FROM, &map) || + !map_sip_addr(pskb, ctinfo, ct, dptr, datalen, POS_TO, &map) || + !map_sip_addr(pskb, ctinfo, ct, dptr, datalen, POS_VIA, &map) || + !map_sip_addr(pskb, ctinfo, ct, dptr, datalen, POS_CONTACT, &map)) + return NF_DROP; + return NF_ACCEPT; +} + +static unsigned int mangle_sip_packet(struct sk_buff **pskb, + enum ip_conntrack_info ctinfo, + struct nf_conn *ct, + const char **dptr, size_t dlen, + char *buffer, int bufflen, + enum sip_header_pos pos) +{ + unsigned int matchlen, matchoff; + + if (ct_sip_get_info(ct, *dptr, dlen, &matchoff, &matchlen, pos) <= 0) + return 0; + + if (!nf_nat_mangle_udp_packet(pskb, ct, ctinfo, + matchoff, matchlen, buffer, bufflen)) + return 0; + + /* We need to reload this. Thanks Patrick. */ + *dptr = (*pskb)->data + (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr); + return 1; +} + +static int mangle_content_len(struct sk_buff **pskb, + enum ip_conntrack_info ctinfo, + struct nf_conn *ct, + const char *dptr) +{ + unsigned int dataoff, matchoff, matchlen; + char buffer[sizeof("65536")]; + int bufflen; + + dataoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr); + + /* Get actual SDP lenght */ + if (ct_sip_get_info(ct, dptr, (*pskb)->len - dataoff, &matchoff, + &matchlen, POS_SDP_HEADER) > 0) { + + /* since ct_sip_get_info() give us a pointer passing 'v=' + we need to add 2 bytes in this count. */ + int c_len = (*pskb)->len - dataoff - matchoff + 2; + + /* Now, update SDP length */ + if (ct_sip_get_info(ct, dptr, (*pskb)->len - dataoff, &matchoff, + &matchlen, POS_CONTENT) > 0) { + + bufflen = sprintf(buffer, "%u", c_len); + return nf_nat_mangle_udp_packet(pskb, ct, ctinfo, + matchoff, matchlen, + buffer, bufflen); + } + } + return 0; +} + +static unsigned int mangle_sdp(struct sk_buff **pskb, + enum ip_conntrack_info ctinfo, + struct nf_conn *ct, + __be32 newip, u_int16_t port, + const char *dptr) +{ + char buffer[sizeof("nnn.nnn.nnn.nnn")]; + unsigned int dataoff, bufflen; + + dataoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr); + + /* Mangle owner and contact info. */ + bufflen = sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(newip)); + if (!mangle_sip_packet(pskb, ctinfo, ct, &dptr, (*pskb)->len - dataoff, + buffer, bufflen, POS_OWNER_IP4)) + return 0; + + if (!mangle_sip_packet(pskb, ctinfo, ct, &dptr, (*pskb)->len - dataoff, + buffer, bufflen, POS_CONNECTION_IP4)) + return 0; + + /* Mangle media port. */ + bufflen = sprintf(buffer, "%u", port); + if (!mangle_sip_packet(pskb, ctinfo, ct, &dptr, (*pskb)->len - dataoff, + buffer, bufflen, POS_MEDIA)) + return 0; + + return mangle_content_len(pskb, ctinfo, ct, dptr); +} + +/* So, this packet has hit the connection tracking matching code. + Mangle it, and change the expectation to match the new version. */ +static unsigned int ip_nat_sdp(struct sk_buff **pskb, + enum ip_conntrack_info ctinfo, + struct nf_conntrack_expect *exp, + const char *dptr) +{ + struct nf_conn *ct = exp->master; + enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); + __be32 newip; + u_int16_t port; + + DEBUGP("ip_nat_sdp():\n"); + + /* Connection will come from reply */ + newip = ct->tuplehash[!dir].tuple.dst.u3.ip; + + exp->tuple.dst.u3.ip = newip; + exp->saved_proto.udp.port = exp->tuple.dst.u.udp.port; + exp->dir = !dir; + + /* When you see the packet, we need to NAT it the same as the + this one. */ + exp->expectfn = nf_nat_follow_master; + + /* Try to get same port: if not, try to change it. */ + for (port = ntohs(exp->saved_proto.udp.port); port != 0; port++) { + exp->tuple.dst.u.udp.port = htons(port); + if (nf_conntrack_expect_related(exp) == 0) + break; + } + + if (port == 0) + return NF_DROP; + + if (!mangle_sdp(pskb, ctinfo, ct, newip, port, dptr)) { + nf_conntrack_unexpect_related(exp); + return NF_DROP; + } + return NF_ACCEPT; +} + +static void __exit nf_nat_sip_fini(void) +{ + rcu_assign_pointer(nf_nat_sip_hook, NULL); + rcu_assign_pointer(nf_nat_sdp_hook, NULL); + synchronize_rcu(); +} + +static int __init nf_nat_sip_init(void) +{ + BUG_ON(rcu_dereference(nf_nat_sip_hook)); + BUG_ON(rcu_dereference(nf_nat_sdp_hook)); + rcu_assign_pointer(nf_nat_sip_hook, ip_nat_sip); + rcu_assign_pointer(nf_nat_sdp_hook, ip_nat_sdp); + return 0; +} + +module_init(nf_nat_sip_init); +module_exit(nf_nat_sip_fini); -- cgit v1.2.3 From a536df35b3a58caa9015bf7887a374b20f658368 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Sat, 2 Dec 2006 22:10:18 -0800 Subject: [NETFILTER]: nf_conntrack/nf_nat: add TFTP helper port Add IPv4 and IPv6 capable nf_conntrack port of the TFTP conntrack/NAT helper. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/ipv4/netfilter/Kconfig | 5 ++++ net/ipv4/netfilter/Makefile | 1 + net/ipv4/netfilter/nf_nat_tftp.c | 52 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+) create mode 100644 net/ipv4/netfilter/nf_nat_tftp.c (limited to 'net/ipv4') diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index 83e83f553cc..1c0018b6bea 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig @@ -515,6 +515,11 @@ config IP_NF_NAT_TFTP default IP_NF_NAT if IP_NF_TFTP=y default m if IP_NF_TFTP=m +config NF_NAT_TFTP + tristate + depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT + default NF_NAT && NF_CONNTRACK_TFTP + config IP_NF_NAT_AMANDA tristate depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index 167b65e89ac..3ca0af0ed5f 100644 --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile @@ -56,6 +56,7 @@ obj-$(CONFIG_NF_NAT_H323) += nf_nat_h323.o obj-$(CONFIG_NF_NAT_IRC) += nf_nat_irc.o obj-$(CONFIG_NF_NAT_PPTP) += nf_nat_pptp.o obj-$(CONFIG_NF_NAT_SIP) += nf_nat_sip.o +obj-$(CONFIG_NF_NAT_TFTP) += nf_nat_tftp.o # NAT protocols (nf_nat) obj-$(CONFIG_NF_NAT_PROTO_GRE) += nf_nat_proto_gre.o diff --git a/net/ipv4/netfilter/nf_nat_tftp.c b/net/ipv4/netfilter/nf_nat_tftp.c new file mode 100644 index 00000000000..2566b79de22 --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_tftp.c @@ -0,0 +1,52 @@ +/* (C) 2001-2002 Magnus Boden + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Magnus Boden "); +MODULE_DESCRIPTION("TFTP NAT helper"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("ip_nat_tftp"); + +static unsigned int help(struct sk_buff **pskb, + enum ip_conntrack_info ctinfo, + struct nf_conntrack_expect *exp) +{ + struct nf_conn *ct = exp->master; + + exp->saved_proto.udp.port + = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.udp.port; + exp->dir = IP_CT_DIR_REPLY; + exp->expectfn = nf_nat_follow_master; + if (nf_conntrack_expect_related(exp) != 0) + return NF_DROP; + return NF_ACCEPT; +} + +static void __exit nf_nat_tftp_fini(void) +{ + rcu_assign_pointer(nf_nat_tftp_hook, NULL); + synchronize_rcu(); +} + +static int __init nf_nat_tftp_init(void) +{ + BUG_ON(rcu_dereference(nf_nat_tftp_hook)); + rcu_assign_pointer(nf_nat_tftp_hook, help); + return 0; +} + +module_init(nf_nat_tftp_init); +module_exit(nf_nat_tftp_fini); -- cgit v1.2.3 From 807467c22a12381985878be23c778657fc0364d0 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Sat, 2 Dec 2006 22:10:34 -0800 Subject: [NETFILTER]: nf_nat: add SNMP NAT helper port Add nf_conntrack port of the SNMP NAT helper. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/ipv4/netfilter/Kconfig | 15 + net/ipv4/netfilter/Makefile | 1 + net/ipv4/netfilter/nf_nat_snmp_basic.c | 1332 ++++++++++++++++++++++++++++++++ 3 files changed, 1348 insertions(+) create mode 100644 net/ipv4/netfilter/nf_nat_snmp_basic.c (limited to 'net/ipv4') diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index 1c0018b6bea..16390add2eb 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig @@ -477,6 +477,21 @@ config IP_NF_NAT_SNMP_BASIC To compile it as a module, choose M here. If unsure, say N. +config NF_NAT_SNMP_BASIC + tristate "Basic SNMP-ALG support (EXPERIMENTAL)" + depends on EXPERIMENTAL && NF_NAT + ---help--- + + This module implements an Application Layer Gateway (ALG) for + SNMP payloads. In conjunction with NAT, it allows a network + management system to access multiple private networks with + conflicting addresses. It works by modifying IP addresses + inside SNMP payloads to match IP-layer NAT mapping. + + This is the "basic" form of SNMP-ALG, as described in RFC 2962 + + To compile it as a module, choose M here. If unsure, say N. + # If they want FTP, set to $CONFIG_IP_NF_NAT (m or y), # or $CONFIG_IP_NF_FTP (m or y), whichever is weaker. # From kconfig-language.txt: diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index 3ca0af0ed5f..15e741aeb29 100644 --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile @@ -56,6 +56,7 @@ obj-$(CONFIG_NF_NAT_H323) += nf_nat_h323.o obj-$(CONFIG_NF_NAT_IRC) += nf_nat_irc.o obj-$(CONFIG_NF_NAT_PPTP) += nf_nat_pptp.o obj-$(CONFIG_NF_NAT_SIP) += nf_nat_sip.o +obj-$(CONFIG_NF_NAT_SNMP_BASIC) += nf_nat_snmp_basic.o obj-$(CONFIG_NF_NAT_TFTP) += nf_nat_tftp.o # NAT protocols (nf_nat) diff --git a/net/ipv4/netfilter/nf_nat_snmp_basic.c b/net/ipv4/netfilter/nf_nat_snmp_basic.c new file mode 100644 index 00000000000..f12528fe1bf --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_snmp_basic.c @@ -0,0 +1,1332 @@ +/* + * nf_nat_snmp_basic.c + * + * Basic SNMP Application Layer Gateway + * + * This IP NAT module is intended for use with SNMP network + * discovery and monitoring applications where target networks use + * conflicting private address realms. + * + * Static NAT is used to remap the networks from the view of the network + * management system at the IP layer, and this module remaps some application + * layer addresses to match. + * + * The simplest form of ALG is performed, where only tagged IP addresses + * are modified. The module does not need to be MIB aware and only scans + * messages at the ASN.1/BER level. + * + * Currently, only SNMPv1 and SNMPv2 are supported. + * + * More information on ALG and associated issues can be found in + * RFC 2962 + * + * The ASB.1/BER parsing code is derived from the gxsnmp package by Gregory + * McLean & Jochen Friedrich, stripped down for use in the kernel. + * + * Copyright (c) 2000 RP Internet (www.rpi.net.au). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: James Morris + * + * Updates: + * 2000-08-06: Convert to new helper API (Harald Welte). + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("James Morris "); +MODULE_DESCRIPTION("Basic SNMP Application Layer Gateway"); +MODULE_ALIAS("ip_nat_snmp_basic"); + +#define SNMP_PORT 161 +#define SNMP_TRAP_PORT 162 +#define NOCT1(n) (*(u8 *)n) + +static int debug; +static DEFINE_SPINLOCK(snmp_lock); + +/* + * Application layer address mapping mimics the NAT mapping, but + * only for the first octet in this case (a more flexible system + * can be implemented if needed). + */ +struct oct1_map +{ + u_int8_t from; + u_int8_t to; +}; + + +/***************************************************************************** + * + * Basic ASN.1 decoding routines (gxsnmp author Dirk Wisse) + * + *****************************************************************************/ + +/* Class */ +#define ASN1_UNI 0 /* Universal */ +#define ASN1_APL 1 /* Application */ +#define ASN1_CTX 2 /* Context */ +#define ASN1_PRV 3 /* Private */ + +/* Tag */ +#define ASN1_EOC 0 /* End Of Contents */ +#define ASN1_BOL 1 /* Boolean */ +#define ASN1_INT 2 /* Integer */ +#define ASN1_BTS 3 /* Bit String */ +#define ASN1_OTS 4 /* Octet String */ +#define ASN1_NUL 5 /* Null */ +#define ASN1_OJI 6 /* Object Identifier */ +#define ASN1_OJD 7 /* Object Description */ +#define ASN1_EXT 8 /* External */ +#define ASN1_SEQ 16 /* Sequence */ +#define ASN1_SET 17 /* Set */ +#define ASN1_NUMSTR 18 /* Numerical String */ +#define ASN1_PRNSTR 19 /* Printable String */ +#define ASN1_TEXSTR 20 /* Teletext String */ +#define ASN1_VIDSTR 21 /* Video String */ +#define ASN1_IA5STR 22 /* IA5 String */ +#define ASN1_UNITIM 23 /* Universal Time */ +#define ASN1_GENTIM 24 /* General Time */ +#define ASN1_GRASTR 25 /* Graphical String */ +#define ASN1_VISSTR 26 /* Visible String */ +#define ASN1_GENSTR 27 /* General String */ + +/* Primitive / Constructed methods*/ +#define ASN1_PRI 0 /* Primitive */ +#define ASN1_CON 1 /* Constructed */ + +/* + * Error codes. + */ +#define ASN1_ERR_NOERROR 0 +#define ASN1_ERR_DEC_EMPTY 2 +#define ASN1_ERR_DEC_EOC_MISMATCH 3 +#define ASN1_ERR_DEC_LENGTH_MISMATCH 4 +#define ASN1_ERR_DEC_BADVALUE 5 + +/* + * ASN.1 context. + */ +struct asn1_ctx +{ + int error; /* Error condition */ + unsigned char *pointer; /* Octet just to be decoded */ + unsigned char *begin; /* First octet */ + unsigned char *end; /* Octet after last octet */ +}; + +/* + * Octet string (not null terminated) + */ +struct asn1_octstr +{ + unsigned char *data; + unsigned int len; +}; + +static void asn1_open(struct asn1_ctx *ctx, + unsigned char *buf, + unsigned int len) +{ + ctx->begin = buf; + ctx->end = buf + len; + ctx->pointer = buf; + ctx->error = ASN1_ERR_NOERROR; +} + +static unsigned char asn1_octet_decode(struct asn1_ctx *ctx, unsigned char *ch) +{ + if (ctx->pointer >= ctx->end) { + ctx->error = ASN1_ERR_DEC_EMPTY; + return 0; + } + *ch = *(ctx->pointer)++; + return 1; +} + +static unsigned char asn1_tag_decode(struct asn1_ctx *ctx, unsigned int *tag) +{ + unsigned char ch; + + *tag = 0; + + do + { + if (!asn1_octet_decode(ctx, &ch)) + return 0; + *tag <<= 7; + *tag |= ch & 0x7F; + } while ((ch & 0x80) == 0x80); + return 1; +} + +static unsigned char asn1_id_decode(struct asn1_ctx *ctx, + unsigned int *cls, + unsigned int *con, + unsigned int *tag) +{ + unsigned char ch; + + if (!asn1_octet_decode(ctx, &ch)) + return 0; + + *cls = (ch & 0xC0) >> 6; + *con = (ch & 0x20) >> 5; + *tag = (ch & 0x1F); + + if (*tag == 0x1F) { + if (!asn1_tag_decode(ctx, tag)) + return 0; + } + return 1; +} + +static unsigned char asn1_length_decode(struct asn1_ctx *ctx, + unsigned int *def, + unsigned int *len) +{ + unsigned char ch, cnt; + + if (!asn1_octet_decode(ctx, &ch)) + return 0; + + if (ch == 0x80) + *def = 0; + else { + *def = 1; + + if (ch < 0x80) + *len = ch; + else { + cnt = (unsigned char) (ch & 0x7F); + *len = 0; + + while (cnt > 0) { + if (!asn1_octet_decode(ctx, &ch)) + return 0; + *len <<= 8; + *len |= ch; + cnt--; + } + } + } + return 1; +} + +static unsigned char asn1_header_decode(struct asn1_ctx *ctx, + unsigned char **eoc, + unsigned int *cls, + unsigned int *con, + unsigned int *tag) +{ + unsigned int def, len; + + if (!asn1_id_decode(ctx, cls, con, tag)) + return 0; + + def = len = 0; + if (!asn1_length_decode(ctx, &def, &len)) + return 0; + + if (def) + *eoc = ctx->pointer + len; + else + *eoc = NULL; + return 1; +} + +static unsigned char asn1_eoc_decode(struct asn1_ctx *ctx, unsigned char *eoc) +{ + unsigned char ch; + + if (eoc == 0) { + if (!asn1_octet_decode(ctx, &ch)) + return 0; + + if (ch != 0x00) { + ctx->error = ASN1_ERR_DEC_EOC_MISMATCH; + return 0; + } + + if (!asn1_octet_decode(ctx, &ch)) + return 0; + + if (ch != 0x00) { + ctx->error = ASN1_ERR_DEC_EOC_MISMATCH; + return 0; + } + return 1; + } else { + if (ctx->pointer != eoc) { + ctx->error = ASN1_ERR_DEC_LENGTH_MISMATCH; + return 0; + } + return 1; + } +} + +static unsigned char asn1_null_decode(struct asn1_ctx *ctx, unsigned char *eoc) +{ + ctx->pointer = eoc; + return 1; +} + +static unsigned char asn1_long_decode(struct asn1_ctx *ctx, + unsigned char *eoc, + long *integer) +{ + unsigned char ch; + unsigned int len; + + if (!asn1_octet_decode(ctx, &ch)) + return 0; + + *integer = (signed char) ch; + len = 1; + + while (ctx->pointer < eoc) { + if (++len > sizeof (long)) { + ctx->error = ASN1_ERR_DEC_BADVALUE; + return 0; + } + + if (!asn1_octet_decode(ctx, &ch)) + return 0; + + *integer <<= 8; + *integer |= ch; + } + return 1; +} + +static unsigned char asn1_uint_decode(struct asn1_ctx *ctx, + unsigned char *eoc, + unsigned int *integer) +{ + unsigned char ch; + unsigned int len; + + if (!asn1_octet_decode(ctx, &ch)) + return 0; + + *integer = ch; + if (ch == 0) len = 0; + else len = 1; + + while (ctx->pointer < eoc) { + if (++len > sizeof (unsigned int)) { + ctx->error = ASN1_ERR_DEC_BADVALUE; + return 0; + } + + if (!asn1_octet_decode(ctx, &ch)) + return 0; + + *integer <<= 8; + *integer |= ch; + } + return 1; +} + +static unsigned char asn1_ulong_decode(struct asn1_ctx *ctx, + unsigned char *eoc, + unsigned long *integer) +{ + unsigned char ch; + unsigned int len; + + if (!asn1_octet_decode(ctx, &ch)) + return 0; + + *integer = ch; + if (ch == 0) len = 0; + else len = 1; + + while (ctx->pointer < eoc) { + if (++len > sizeof (unsigned long)) { + ctx->error = ASN1_ERR_DEC_BADVALUE; + return 0; + } + + if (!asn1_octet_decode(ctx, &ch)) + return 0; + + *integer <<= 8; + *integer |= ch; + } + return 1; +} + +static unsigned char asn1_octets_decode(struct asn1_ctx *ctx, + unsigned char *eoc, + unsigned char **octets, + unsigned int *len) +{ + unsigned char *ptr; + + *len = 0; + + *octets = kmalloc(eoc - ctx->pointer, GFP_ATOMIC); + if (*octets == NULL) { + if (net_ratelimit()) + printk("OOM in bsalg (%d)\n", __LINE__); + return 0; + } + + ptr = *octets; + while (ctx->pointer < eoc) { + if (!asn1_octet_decode(ctx, (unsigned char *)ptr++)) { + kfree(*octets); + *octets = NULL; + return 0; + } + (*len)++; + } + return 1; +} + +static unsigned char asn1_subid_decode(struct asn1_ctx *ctx, + unsigned long *subid) +{ + unsigned char ch; + + *subid = 0; + + do { + if (!asn1_octet_decode(ctx, &ch)) + return 0; + + *subid <<= 7; + *subid |= ch & 0x7F; + } while ((ch & 0x80) == 0x80); + return 1; +} + +static unsigned char asn1_oid_decode(struct asn1_ctx *ctx, + unsigned char *eoc, + unsigned long **oid, + unsigned int *len) +{ + unsigned long subid; + unsigned int size; + unsigned long *optr; + + size = eoc - ctx->pointer + 1; + *oid = kmalloc(size * sizeof(unsigned long), GFP_ATOMIC); + if (*oid == NULL) { + if (net_ratelimit()) + printk("OOM in bsalg (%d)\n", __LINE__); + return 0; + } + + optr = *oid; + + if (!asn1_subid_decode(ctx, &subid)) { + kfree(*oid); + *oid = NULL; + return 0; + } + + if (subid < 40) { + optr [0] = 0; + optr [1] = subid; + } else if (subid < 80) { + optr [0] = 1; + optr [1] = subid - 40; + } else { + optr [0] = 2; + optr [1] = subid - 80; + } + + *len = 2; + optr += 2; + + while (ctx->pointer < eoc) { + if (++(*len) > size) { + ctx->error = ASN1_ERR_DEC_BADVALUE; + kfree(*oid); + *oid = NULL; + return 0; + } + + if (!asn1_subid_decode(ctx, optr++)) { + kfree(*oid); + *oid = NULL; + return 0; + } + } + return 1; +} + +/***************************************************************************** + * + * SNMP decoding routines (gxsnmp author Dirk Wisse) + * + *****************************************************************************/ + +/* SNMP Versions */ +#define SNMP_V1 0 +#define SNMP_V2C 1 +#define SNMP_V2 2 +#define SNMP_V3 3 + +/* Default Sizes */ +#define SNMP_SIZE_COMM 256 +#define SNMP_SIZE_OBJECTID 128 +#define SNMP_SIZE_BUFCHR 256 +#define SNMP_SIZE_BUFINT 128 +#define SNMP_SIZE_SMALLOBJECTID 16 + +/* Requests */ +#define SNMP_PDU_GET 0 +#define SNMP_PDU_NEXT 1 +#define SNMP_PDU_RESPONSE 2 +#define SNMP_PDU_SET 3 +#define SNMP_PDU_TRAP1 4 +#define SNMP_PDU_BULK 5 +#define SNMP_PDU_INFORM 6 +#define SNMP_PDU_TRAP2 7 + +/* Errors */ +#define SNMP_NOERROR 0 +#define SNMP_TOOBIG 1 +#define SNMP_NOSUCHNAME 2 +#define SNMP_BADVALUE 3 +#define SNMP_READONLY 4 +#define SNMP_GENERROR 5 +#define SNMP_NOACCESS 6 +#define SNMP_WRONGTYPE 7 +#define SNMP_WRONGLENGTH 8 +#define SNMP_WRONGENCODING 9 +#define SNMP_WRONGVALUE 10 +#define SNMP_NOCREATION 11 +#define SNMP_INCONSISTENTVALUE 12 +#define SNMP_RESOURCEUNAVAILABLE 13 +#define SNMP_COMMITFAILED 14 +#define SNMP_UNDOFAILED 15 +#define SNMP_AUTHORIZATIONERROR 16 +#define SNMP_NOTWRITABLE 17 +#define SNMP_INCONSISTENTNAME 18 + +/* General SNMP V1 Traps */ +#define SNMP_TRAP_COLDSTART 0 +#define SNMP_TRAP_WARMSTART 1 +#define SNMP_TRAP_LINKDOWN 2 +#define SNMP_TRAP_LINKUP 3 +#define SNMP_TRAP_AUTFAILURE 4 +#define SNMP_TRAP_EQPNEIGHBORLOSS 5 +#define SNMP_TRAP_ENTSPECIFIC 6 + +/* SNMPv1 Types */ +#define SNMP_NULL 0 +#define SNMP_INTEGER 1 /* l */ +#define SNMP_OCTETSTR 2 /* c */ +#define SNMP_DISPLAYSTR 2 /* c */ +#define SNMP_OBJECTID 3 /* ul */ +#define SNMP_IPADDR 4 /* uc */ +#define SNMP_COUNTER 5 /* ul */ +#define SNMP_GAUGE 6 /* ul */ +#define SNMP_TIMETICKS 7 /* ul */ +#define SNMP_OPAQUE 8 /* c */ + +/* Additional SNMPv2 Types */ +#define SNMP_UINTEGER 5 /* ul */ +#define SNMP_BITSTR 9 /* uc */ +#define SNMP_NSAP 10 /* uc */ +#define SNMP_COUNTER64 11 /* ul */ +#define SNMP_NOSUCHOBJECT 12 +#define SNMP_NOSUCHINSTANCE 13 +#define SNMP_ENDOFMIBVIEW 14 + +union snmp_syntax +{ + unsigned char uc[0]; /* 8 bit unsigned */ + char c[0]; /* 8 bit signed */ + unsigned long ul[0]; /* 32 bit unsigned */ + long l[0]; /* 32 bit signed */ +}; + +struct snmp_object +{ + unsigned long *id; + unsigned int id_len; + unsigned short type; + unsigned int syntax_len; + union snmp_syntax syntax; +}; + +struct snmp_request +{ + unsigned long id; + unsigned int error_status; + unsigned int error_index; +}; + +struct snmp_v1_trap +{ + unsigned long *id; + unsigned int id_len; + unsigned long ip_address; /* pointer */ + unsigned int general; + unsigned int specific; + unsigned long time; +}; + +/* SNMP types */ +#define SNMP_IPA 0 +#define SNMP_CNT 1 +#define SNMP_GGE 2 +#define SNMP_TIT 3 +#define SNMP_OPQ 4 +#define SNMP_C64 6 + +/* SNMP errors */ +#define SERR_NSO 0 +#define SERR_NSI 1 +#define SERR_EOM 2 + +static inline void mangle_address(unsigned char *begin, + unsigned char *addr, + const struct oct1_map *map, + __sum16 *check); +struct snmp_cnv +{ + unsigned int class; + unsigned int tag; + int syntax; +}; + +static struct snmp_cnv snmp_conv [] = +{ + {ASN1_UNI, ASN1_NUL, SNMP_NULL}, + {ASN1_UNI, ASN1_INT, SNMP_INTEGER}, + {ASN1_UNI, ASN1_OTS, SNMP_OCTETSTR}, + {ASN1_UNI, ASN1_OTS, SNMP_DISPLAYSTR}, + {ASN1_UNI, ASN1_OJI, SNMP_OBJECTID}, + {ASN1_APL, SNMP_IPA, SNMP_IPADDR}, + {ASN1_APL, SNMP_CNT, SNMP_COUNTER}, /* Counter32 */ + {ASN1_APL, SNMP_GGE, SNMP_GAUGE}, /* Gauge32 == Unsigned32 */ + {ASN1_APL, SNMP_TIT, SNMP_TIMETICKS}, + {ASN1_APL, SNMP_OPQ, SNMP_OPAQUE}, + + /* SNMPv2 data types and errors */ + {ASN1_UNI, ASN1_BTS, SNMP_BITSTR}, + {ASN1_APL, SNMP_C64, SNMP_COUNTER64}, + {ASN1_CTX, SERR_NSO, SNMP_NOSUCHOBJECT}, + {ASN1_CTX, SERR_NSI, SNMP_NOSUCHINSTANCE}, + {ASN1_CTX, SERR_EOM, SNMP_ENDOFMIBVIEW}, + {0, 0, -1} +}; + +static unsigned char snmp_tag_cls2syntax(unsigned int tag, + unsigned int cls, + unsigned short *syntax) +{ + struct snmp_cnv *cnv; + + cnv = snmp_conv; + + while (cnv->syntax != -1) { + if (cnv->tag == tag && cnv->class == cls) { + *syntax = cnv->syntax; + return 1; + } + cnv++; + } + return 0; +} + +static unsigned char snmp_object_decode(struct asn1_ctx *ctx, + struct snmp_object **obj) +{ + unsigned int cls, con, tag, len, idlen; + unsigned short type; + unsigned char *eoc, *end, *p; + unsigned long *lp, *id; + unsigned long ul; + long l; + + *obj = NULL; + id = NULL; + + if (!asn1_header_decode(ctx, &eoc, &cls, &con, &tag)) + return 0; + + if (cls != ASN1_UNI || con != ASN1_CON || tag != ASN1_SEQ) + return 0; + + if (!asn1_header_decode(ctx, &end, &cls, &con, &tag)) + return 0; + + if (cls != ASN1_UNI || con != ASN1_PRI || tag != ASN1_OJI) + return 0; + + if (!asn1_oid_decode(ctx, end, &id, &idlen)) + return 0; + + if (!asn1_header_decode(ctx, &end, &cls, &con, &tag)) { + kfree(id); + return 0; + } + + if (con != ASN1_PRI) { + kfree(id); + return 0; + } + + type = 0; + if (!snmp_tag_cls2syntax(tag, cls, &type)) { + kfree(id); + return 0; + } + + l = 0; + switch (type) { + case SNMP_INTEGER: + len = sizeof(long); + if (!asn1_long_decode(ctx, end, &l)) { + kfree(id); + return 0; + } + *obj = kmalloc(sizeof(struct snmp_object) + len, + GFP_ATOMIC); + if (*obj == NULL) { + kfree(id); + if (net_ratelimit()) + printk("OOM in bsalg (%d)\n", __LINE__); + return 0; + } + (*obj)->syntax.l[0] = l; + break; + case SNMP_OCTETSTR: + case SNMP_OPAQUE: + if (!asn1_octets_decode(ctx, end, &p, &len)) { + kfree(id); + return 0; + } + *obj = kmalloc(sizeof(struct snmp_object) + len, + GFP_ATOMIC); + if (*obj == NULL) { + kfree(id); + if (net_ratelimit()) + printk("OOM in bsalg (%d)\n", __LINE__); + return 0; + } + memcpy((*obj)->syntax.c, p, len); + kfree(p); + break; + case SNMP_NULL: + case SNMP_NOSUCHOBJECT: + case SNMP_NOSUCHINSTANCE: + case SNMP_ENDOFMIBVIEW: + len = 0; + *obj = kmalloc(sizeof(struct snmp_object), GFP_ATOMIC); + if (*obj == NULL) { + kfree(id); + if (net_ratelimit()) + printk("OOM in bsalg (%d)\n", __LINE__); + return 0; + } + if (!asn1_null_decode(ctx, end)) { + kfree(id); + kfree(*obj); + *obj = NULL; + return 0; + } + break; + case SNMP_OBJECTID: + if (!asn1_oid_decode(ctx, end, (unsigned long **)&lp, &len)) { + kfree(id); + return 0; + } + len *= sizeof(unsigned long); + *obj = kmalloc(sizeof(struct snmp_object) + len, GFP_ATOMIC); + if (*obj == NULL) { + kfree(lp); + kfree(id); + if (net_ratelimit()) + printk("OOM in bsalg (%d)\n", __LINE__); + return 0; + } + memcpy((*obj)->syntax.ul, lp, len); + kfree(lp); + break; + case SNMP_IPADDR: + if (!asn1_octets_decode(ctx, end, &p, &len)) { + kfree(id); + return 0; + } + if (len != 4) { + kfree(p); + kfree(id); + return 0; + } + *obj = kmalloc(sizeof(struct snmp_object) + len, GFP_ATOMIC); + if (*obj == NULL) { + kfree(p); + kfree(id); + if (net_ratelimit()) + printk("OOM in bsalg (%d)\n", __LINE__); + return 0; + } + memcpy((*obj)->syntax.uc, p, len); + kfree(p); + break; + case SNMP_COUNTER: + case SNMP_GAUGE: + case SNMP_TIMETICKS: + len = sizeof(unsigned long); + if (!asn1_ulong_decode(ctx, end, &ul)) { + kfree(id); + return 0; + } + *obj = kmalloc(sizeof(struct snmp_object) + len, GFP_ATOMIC); + if (*obj == NULL) { + kfree(id); + if (net_ratelimit()) + printk("OOM in bsalg (%d)\n", __LINE__); + return 0; + } + (*obj)->syntax.ul[0] = ul; + break; + default: + kfree(id); + return 0; + } + + (*obj)->syntax_len = len; + (*obj)->type = type; + (*obj)->id = id; + (*obj)->id_len = idlen; + + if (!asn1_eoc_decode(ctx, eoc)) { + kfree(id); + kfree(*obj); + *obj = NULL; + return 0; + } + return 1; +} + +static unsigned char snmp_request_decode(struct asn1_ctx *ctx, + struct snmp_request *request) +{ + unsigned int cls, con, tag; + unsigned char *end; + + if (!asn1_header_decode(ctx, &end, &cls, &con, &tag)) + return 0; + + if (cls != ASN1_UNI || con != ASN1_PRI || tag != ASN1_INT) + return 0; + + if (!asn1_ulong_decode(ctx, end, &request->id)) + return 0; + + if (!asn1_header_decode(ctx, &end, &cls, &con, &tag)) + return 0; + + if (cls != ASN1_UNI || con != ASN1_PRI || tag != ASN1_INT) + return 0; + + if (!asn1_uint_decode(ctx, end, &request->error_status)) + return 0; + + if (!asn1_header_decode(ctx, &end, &cls, &con, &tag)) + return 0; + + if (cls != ASN1_UNI || con != ASN1_PRI || tag != ASN1_INT) + return 0; + + if (!asn1_uint_decode(ctx, end, &request->error_index)) + return 0; + + return 1; +} + +/* + * Fast checksum update for possibly oddly-aligned UDP byte, from the + * code example in the draft. + */ +static void fast_csum(__sum16 *csum, + const unsigned char *optr, + const unsigned char *nptr, + int offset) +{ + unsigned char s[4]; + + if (offset & 1) { + s[0] = s[2] = 0; + s[1] = ~*optr; + s[3] = *nptr; + } else { + s[1] = s[3] = 0; + s[0] = ~*optr; + s[2] = *nptr; + } + + *csum = csum_fold(csum_partial(s, 4, ~csum_unfold(*csum))); +} + +/* + * Mangle IP address. + * - begin points to the start of the snmp messgae + * - addr points to the start of the address + */ +static inline void mangle_address(unsigned char *begin, + unsigned char *addr, + const struct oct1_map *map, + __sum16 *check) +{ + if (map->from == NOCT1(addr)) { + u_int32_t old; + + if (debug) + memcpy(&old, (unsigned char *)addr, sizeof(old)); + + *addr = map->to; + + /* Update UDP checksum if being used */ + if (*check) { + fast_csum(check, + &map->from, &map->to, addr - begin); + + } + + if (debug) + printk(KERN_DEBUG "bsalg: mapped %u.%u.%u.%u to " + "%u.%u.%u.%u\n", NIPQUAD(old), NIPQUAD(*addr)); + } +} + +static unsigned char snmp_trap_decode(struct asn1_ctx *ctx, + struct snmp_v1_trap *trap, + const struct oct1_map *map, + __sum16 *check) +{ + unsigned int cls, con, tag, len; + unsigned char *end; + + if (!asn1_header_decode(ctx, &end, &cls, &con, &tag)) + return 0; + + if (cls != ASN1_UNI || con != ASN1_PRI || tag != ASN1_OJI) + return 0; + + if (!asn1_oid_decode(ctx, end, &trap->id, &trap->id_len)) + return 0; + + if (!asn1_header_decode(ctx, &end, &cls, &con, &tag)) + goto err_id_free; + + if (!((cls == ASN1_APL && con == ASN1_PRI && tag == SNMP_IPA) || + (cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_OTS))) + goto err_id_free; + + if (!asn1_octets_decode(ctx, end, (unsigned char **)&trap->ip_address, &len)) + goto err_id_free; + + /* IPv4 only */ + if (len != 4) + goto err_addr_free; + + mangle_address(ctx->begin, ctx->pointer - 4, map, check); + + if (!asn1_header_decode(ctx, &end, &cls, &con, &tag)) + goto err_addr_free; + + if (cls != ASN1_UNI || con != ASN1_PRI || tag != ASN1_INT) + goto err_addr_free; + + if (!asn1_uint_decode(ctx, end, &trap->general)) + goto err_addr_free; + + if (!asn1_header_decode(ctx, &end, &cls, &con, &tag)) + goto err_addr_free; + + if (cls != ASN1_UNI || con != ASN1_PRI || tag != ASN1_INT) + goto err_addr_free; + + if (!asn1_uint_decode(ctx, end, &trap->specific)) + goto err_addr_free; + + if (!asn1_header_decode(ctx, &end, &cls, &con, &tag)) + goto err_addr_free; + + if (!((cls == ASN1_APL && con == ASN1_PRI && tag == SNMP_TIT) || + (cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_INT))) + goto err_addr_free; + + if (!asn1_ulong_decode(ctx, end, &trap->time)) + goto err_addr_free; + + return 1; + +err_addr_free: + kfree((unsigned long *)trap->ip_address); + +err_id_free: + kfree(trap->id); + + return 0; +} + +/***************************************************************************** + * + * Misc. routines + * + *****************************************************************************/ + +static void hex_dump(unsigned char *buf, size_t len) +{ + size_t i; + + for (i = 0; i < len; i++) { + if (i && !(i % 16)) + printk("\n"); + printk("%02x ", *(buf + i)); + } + printk("\n"); +} + +/* + * Parse and mangle SNMP message according to mapping. + * (And this is the fucking 'basic' method). + */ +static int snmp_parse_mangle(unsigned char *msg, + u_int16_t len, + const struct oct1_map *map, + __sum16 *check) +{ + unsigned char *eoc, *end; + unsigned int cls, con, tag, vers, pdutype; + struct asn1_ctx ctx; + struct asn1_octstr comm; + struct snmp_object **obj; + + if (debug > 1) + hex_dump(msg, len); + + asn1_open(&ctx, msg, len); + + /* + * Start of SNMP message. + */ + if (!asn1_header_decode(&ctx, &eoc, &cls, &con, &tag)) + return 0; + if (cls != ASN1_UNI || con != ASN1_CON || tag != ASN1_SEQ) + return 0; + + /* + * Version 1 or 2 handled. + */ + if (!asn1_header_decode(&ctx, &end, &cls, &con, &tag)) + return 0; + if (cls != ASN1_UNI || con != ASN1_PRI || tag != ASN1_INT) + return 0; + if (!asn1_uint_decode (&ctx, end, &vers)) + return 0; + if (debug > 1) + printk(KERN_DEBUG "bsalg: snmp version: %u\n", vers + 1); + if (vers > 1) + return 1; + + /* + * Community. + */ + if (!asn1_header_decode (&ctx, &end, &cls, &con, &tag)) + return 0; + if (cls != ASN1_UNI || con != ASN1_PRI || tag != ASN1_OTS) + return 0; + if (!asn1_octets_decode(&ctx, end, &comm.data, &comm.len)) + return 0; + if (debug > 1) { + unsigned int i; + + printk(KERN_DEBUG "bsalg: community: "); + for (i = 0; i < comm.len; i++) + printk("%c", comm.data[i]); + printk("\n"); + } + kfree(comm.data); + + /* + * PDU type + */ + if (!asn1_header_decode(&ctx, &eoc, &cls, &con, &pdutype)) + return 0; + if (cls != ASN1_CTX || con != ASN1_CON) + return 0; + if (debug > 1) { + unsigned char *pdus[] = { + [SNMP_PDU_GET] = "get", + [SNMP_PDU_NEXT] = "get-next", + [SNMP_PDU_RESPONSE] = "response", + [SNMP_PDU_SET] = "set", + [SNMP_PDU_TRAP1] = "trapv1", + [SNMP_PDU_BULK] = "bulk", + [SNMP_PDU_INFORM] = "inform", + [SNMP_PDU_TRAP2] = "trapv2" + }; + + if (pdutype > SNMP_PDU_TRAP2) + printk(KERN_DEBUG "bsalg: bad pdu type %u\n", pdutype); + else + printk(KERN_DEBUG "bsalg: pdu: %s\n", pdus[pdutype]); + } + if (pdutype != SNMP_PDU_RESPONSE && + pdutype != SNMP_PDU_TRAP1 && pdutype != SNMP_PDU_TRAP2) + return 1; + + /* + * Request header or v1 trap + */ + if (pdutype == SNMP_PDU_TRAP1) { + struct snmp_v1_trap trap; + unsigned char ret = snmp_trap_decode(&ctx, &trap, map, check); + + if (ret) { + kfree(trap.id); + kfree((unsigned long *)trap.ip_address); + } else + return ret; + + } else { + struct snmp_request req; + + if (!snmp_request_decode(&ctx, &req)) + return 0; + + if (debug > 1) + printk(KERN_DEBUG "bsalg: request: id=0x%lx error_status=%u " + "error_index=%u\n", req.id, req.error_status, + req.error_index); + } + + /* + * Loop through objects, look for IP addresses to mangle. + */ + if (!asn1_header_decode(&ctx, &eoc, &cls, &con, &tag)) + return 0; + + if (cls != ASN1_UNI || con != ASN1_CON || tag != ASN1_SEQ) + return 0; + + obj = kmalloc(sizeof(struct snmp_object), GFP_ATOMIC); + if (obj == NULL) { + if (net_ratelimit()) + printk(KERN_WARNING "OOM in bsalg(%d)\n", __LINE__); + return 0; + } + + while (!asn1_eoc_decode(&ctx, eoc)) { + unsigned int i; + + if (!snmp_object_decode(&ctx, obj)) { + if (*obj) { + kfree((*obj)->id); + kfree(*obj); + } + kfree(obj); + return 0; + } + + if (debug > 1) { + printk(KERN_DEBUG "bsalg: object: "); + for (i = 0; i < (*obj)->id_len; i++) { + if (i > 0) + printk("."); + printk("%lu", (*obj)->id[i]); + } + printk(": type=%u\n", (*obj)->type); + + } + + if ((*obj)->type == SNMP_IPADDR) + mangle_address(ctx.begin, ctx.pointer - 4 , map, check); + + kfree((*obj)->id); + kfree(*obj); + } + kfree(obj); + + if (!asn1_eoc_decode(&ctx, eoc)) + return 0; + + return 1; +} + +/***************************************************************************** + * + * NAT routines. + * + *****************************************************************************/ + +/* + * SNMP translation routine. + */ +static int snmp_translate(struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + struct sk_buff **pskb) +{ + struct iphdr *iph = (*pskb)->nh.iph; + struct udphdr *udph = (struct udphdr *)((__be32 *)iph + iph->ihl); + u_int16_t udplen = ntohs(udph->len); + u_int16_t paylen = udplen - sizeof(struct udphdr); + int dir = CTINFO2DIR(ctinfo); + struct oct1_map map; + + /* + * Determine mappping for application layer addresses based + * on NAT manipulations for the packet. + */ + if (dir == IP_CT_DIR_ORIGINAL) { + /* SNAT traps */ + map.from = NOCT1(&ct->tuplehash[dir].tuple.src.u3.ip); + map.to = NOCT1(&ct->tuplehash[!dir].tuple.dst.u3.ip); + } else { + /* DNAT replies */ + map.from = NOCT1(&ct->tuplehash[dir].tuple.src.u3.ip); + map.to = NOCT1(&ct->tuplehash[!dir].tuple.dst.u3.ip); + } + + if (map.from == map.to) + return NF_ACCEPT; + + if (!snmp_parse_mangle((unsigned char *)udph + sizeof(struct udphdr), + paylen, &map, &udph->check)) { + if (net_ratelimit()) + printk(KERN_WARNING "bsalg: parser failed\n"); + return NF_DROP; + } + return NF_ACCEPT; +} + +/* We don't actually set up expectations, just adjust internal IP + * addresses if this is being NATted */ +static int help(struct sk_buff **pskb, unsigned int protoff, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo) +{ + int dir = CTINFO2DIR(ctinfo); + unsigned int ret; + struct iphdr *iph = (*pskb)->nh.iph; + struct udphdr *udph = (struct udphdr *)((u_int32_t *)iph + iph->ihl); + + /* SNMP replies and originating SNMP traps get mangled */ + if (udph->source == htons(SNMP_PORT) && dir != IP_CT_DIR_REPLY) + return NF_ACCEPT; + if (udph->dest == htons(SNMP_TRAP_PORT) && dir != IP_CT_DIR_ORIGINAL) + return NF_ACCEPT; + + /* No NAT? */ + if (!(ct->status & IPS_NAT_MASK)) + return NF_ACCEPT; + + /* + * Make sure the packet length is ok. So far, we were only guaranteed + * to have a valid length IP header plus 8 bytes, which means we have + * enough room for a UDP header. Just verify the UDP length field so we + * can mess around with the payload. + */ + if (ntohs(udph->len) != (*pskb)->len - (iph->ihl << 2)) { + if (net_ratelimit()) + printk(KERN_WARNING "SNMP: dropping malformed packet " + "src=%u.%u.%u.%u dst=%u.%u.%u.%u\n", + NIPQUAD(iph->saddr), NIPQUAD(iph->daddr)); + return NF_DROP; + } + + if (!skb_make_writable(pskb, (*pskb)->len)) + return NF_DROP; + + spin_lock_bh(&snmp_lock); + ret = snmp_translate(ct, ctinfo, pskb); + spin_unlock_bh(&snmp_lock); + return ret; +} + +static struct nf_conntrack_helper snmp_helper __read_mostly = { + .max_expected = 0, + .timeout = 180, + .me = THIS_MODULE, + .help = help, + .name = "snmp", + .tuple.src.l3num = AF_INET, + .tuple.src.u.udp.port = __constant_htons(SNMP_PORT), + .tuple.dst.protonum = IPPROTO_UDP, + .mask.src.l3num = 0xFFFF, + .mask.src.u.udp.port = __constant_htons(0xFFFF), + .mask.dst.protonum = 0xFF, +}; + +static struct nf_conntrack_helper snmp_trap_helper __read_mostly = { + .max_expected = 0, + .timeout = 180, + .me = THIS_MODULE, + .help = help, + .name = "snmp_trap", + .tuple.src.l3num = AF_INET, + .tuple.src.u.udp.port = __constant_htons(SNMP_TRAP_PORT), + .tuple.dst.protonum = IPPROTO_UDP, + .mask.src.l3num = 0xFFFF, + .mask.src.u.udp.port = __constant_htons(0xFFFF), + .mask.dst.protonum = 0xFF, +}; + +/***************************************************************************** + * + * Module stuff. + * + *****************************************************************************/ + +static int __init nf_nat_snmp_basic_init(void) +{ + int ret = 0; + + ret = nf_conntrack_helper_register(&snmp_helper); + if (ret < 0) + return ret; + ret = nf_conntrack_helper_register(&snmp_trap_helper); + if (ret < 0) { + nf_conntrack_helper_unregister(&snmp_helper); + return ret; + } + return ret; +} + +static void __exit nf_nat_snmp_basic_fini(void) +{ + nf_conntrack_helper_unregister(&snmp_helper); + nf_conntrack_helper_unregister(&snmp_trap_helper); +} + +module_init(nf_nat_snmp_basic_init); +module_exit(nf_nat_snmp_basic_fini); + +module_param(debug, int, 0600); -- cgit v1.2.3 From a3c479772c9f4239749950e7c8ea0e9c914a9d7e Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Sat, 2 Dec 2006 22:11:01 -0800 Subject: [NETFILTER]: Mark old IPv4-only connection tracking scheduled for removal Also remove the references to "new connection tracking" from Kconfig. After some short stabilization period of the new connection tracking helpers/NAT code the old one will be removed. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/ipv4/netfilter/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/ipv4') diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index 16390add2eb..363df9976c9 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig @@ -6,7 +6,7 @@ menu "IP: Netfilter Configuration" depends on INET && NETFILTER config NF_CONNTRACK_IPV4 - tristate "IPv4 support for new connection tracking (required for NAT) (EXPERIMENTAL)" + tristate "IPv4 connection tracking support (required for NAT) (EXPERIMENTAL)" depends on EXPERIMENTAL && NF_CONNTRACK ---help--- Connection tracking keeps a record of what packets have passed -- cgit v1.2.3 From 13b1833910205289172cdc655cb9bc61188f77e9 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Sat, 2 Dec 2006 22:11:25 -0800 Subject: [NETFILTER]: nf_conntrack: EXPORT_SYMBOL cleanup - move EXPORT_SYMBOL next to exported symbol - use EXPORT_SYMBOL_GPL since this is what the original code used Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c | 7 ++----- net/ipv4/netfilter/nf_conntrack_proto_icmp.c | 3 +-- 2 files changed, 3 insertions(+), 7 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c index 5655109dcaf..471b638cede 100644 --- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c +++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c @@ -112,6 +112,8 @@ ipv4_prepare(struct sk_buff **pskb, unsigned int hooknum, unsigned int *dataoff, } int nf_nat_module_is_loaded = 0; +EXPORT_SYMBOL_GPL(nf_nat_module_is_loaded); + static u_int32_t ipv4_get_features(const struct nf_conntrack_tuple *tuple) { if (nf_nat_module_is_loaded) @@ -530,8 +532,3 @@ static void __exit nf_conntrack_l3proto_ipv4_fini(void) module_init(nf_conntrack_l3proto_ipv4_init); module_exit(nf_conntrack_l3proto_ipv4_fini); - -EXPORT_SYMBOL(nf_ct_ipv4_gather_frags); -#ifdef CONFIG_NF_NAT_NEEDED -EXPORT_SYMBOL(nf_nat_module_is_loaded); -#endif diff --git a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c index d25002fb817..db9e7c45d3b 100644 --- a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c +++ b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c @@ -380,5 +380,4 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_icmp = #endif #endif }; - -EXPORT_SYMBOL(nf_conntrack_l4proto_icmp); +EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_icmp); -- cgit v1.2.3