aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4')
-rw-r--r--net/ipv4/af_inet.c120
-rw-r--r--net/ipv4/ah4.c1
-rw-r--r--net/ipv4/arp.c20
-rw-r--r--net/ipv4/devinet.c8
-rw-r--r--net/ipv4/esp4.c1
-rw-r--r--net/ipv4/fib_rules.c140
-rw-r--r--net/ipv4/fib_trie.c24
-rw-r--r--net/ipv4/icmp.c2
-rw-r--r--net/ipv4/igmp.c26
-rw-r--r--net/ipv4/inet_connection_sock.c49
-rw-r--r--net/ipv4/inet_hashtables.c2
-rw-r--r--net/ipv4/ip_output.c6
-rw-r--r--net/ipv4/ip_sockglue.c170
-rw-r--r--net/ipv4/ipcomp.c17
-rw-r--r--net/ipv4/ipconfig.c10
-rw-r--r--net/ipv4/ipmr.c4
-rw-r--r--net/ipv4/ipvs/ip_vs_app.c19
-rw-r--r--net/ipv4/netfilter/Kconfig36
-rw-r--r--net/ipv4/netfilter/Makefile6
-rw-r--r--net/ipv4/netfilter/arp_tables.c27
-rw-r--r--net/ipv4/netfilter/arpt_mangle.c23
-rw-r--r--net/ipv4/netfilter/ip_conntrack_core.c4
-rw-r--r--net/ipv4/netfilter/ip_conntrack_helper_h323.c1731
-rw-r--r--net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.c870
-rw-r--r--net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.h98
-rw-r--r--net/ipv4/netfilter/ip_conntrack_helper_h323_types.c1926
-rw-r--r--net/ipv4/netfilter/ip_conntrack_helper_h323_types.h938
-rw-r--r--net/ipv4/netfilter/ip_conntrack_netlink.c79
-rw-r--r--net/ipv4/netfilter/ip_nat_helper_h323.c605
-rw-r--r--net/ipv4/netfilter/ip_nat_helper_pptp.c8
-rw-r--r--net/ipv4/netfilter/ip_nat_rule.c45
-rw-r--r--net/ipv4/netfilter/ip_nat_snmp_basic.c5
-rw-r--r--net/ipv4/netfilter/ip_nat_standalone.c2
-rw-r--r--net/ipv4/netfilter/ip_queue.c11
-rw-r--r--net/ipv4/netfilter/ip_tables.c84
-rw-r--r--net/ipv4/netfilter/ipt_CLUSTERIP.c27
-rw-r--r--net/ipv4/netfilter/ipt_DSCP.c17
-rw-r--r--net/ipv4/netfilter/ipt_ECN.c18
-rw-r--r--net/ipv4/netfilter/ipt_LOG.c11
-rw-r--r--net/ipv4/netfilter/ipt_MASQUERADE.c18
-rw-r--r--net/ipv4/netfilter/ipt_NETMAP.c19
-rw-r--r--net/ipv4/netfilter/ipt_REDIRECT.c17
-rw-r--r--net/ipv4/netfilter/ipt_REJECT.c28
-rw-r--r--net/ipv4/netfilter/ipt_SAME.c19
-rw-r--r--net/ipv4/netfilter/ipt_TCPMSS.c16
-rw-r--r--net/ipv4/netfilter/ipt_TOS.c17
-rw-r--r--net/ipv4/netfilter/ipt_TTL.c25
-rw-r--r--net/ipv4/netfilter/ipt_ULOG.c12
-rw-r--r--net/ipv4/netfilter/ipt_addrtype.c20
-rw-r--r--net/ipv4/netfilter/ipt_ah.c25
-rw-r--r--net/ipv4/netfilter/ipt_dscp.c19
-rw-r--r--net/ipv4/netfilter/ipt_ecn.c14
-rw-r--r--net/ipv4/netfilter/ipt_esp.c25
-rw-r--r--net/ipv4/netfilter/ipt_hashlimit.c21
-rw-r--r--net/ipv4/netfilter/ipt_iprange.c28
-rw-r--r--net/ipv4/netfilter/ipt_multiport.c31
-rw-r--r--net/ipv4/netfilter/ipt_owner.c21
-rw-r--r--net/ipv4/netfilter/ipt_policy.c176
-rw-r--r--net/ipv4/netfilter/ipt_recent.c22
-rw-r--r--net/ipv4/netfilter/ipt_tos.c18
-rw-r--r--net/ipv4/netfilter/ipt_ttl.c19
-rw-r--r--net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c23
-rw-r--r--net/ipv4/raw.c80
-rw-r--r--net/ipv4/route.c45
-rw-r--r--net/ipv4/sysctl_net_ipv4.c25
-rw-r--r--net/ipv4/tcp.c91
-rw-r--r--net/ipv4/tcp_htcp.c66
-rw-r--r--net/ipv4/tcp_input.c49
-rw-r--r--net/ipv4/tcp_ipv4.c44
-rw-r--r--net/ipv4/tcp_output.c259
-rw-r--r--net/ipv4/tcp_timer.c36
-rw-r--r--net/ipv4/udp.c83
-rw-r--r--net/ipv4/xfrm4_tunnel.c11
73 files changed, 7563 insertions, 1049 deletions
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 97c276f95b35..dc206f1f914f 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -788,45 +788,53 @@ int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
}
const struct proto_ops inet_stream_ops = {
- .family = PF_INET,
- .owner = THIS_MODULE,
- .release = inet_release,
- .bind = inet_bind,
- .connect = inet_stream_connect,
- .socketpair = sock_no_socketpair,
- .accept = inet_accept,
- .getname = inet_getname,
- .poll = tcp_poll,
- .ioctl = inet_ioctl,
- .listen = inet_listen,
- .shutdown = inet_shutdown,
- .setsockopt = sock_common_setsockopt,
- .getsockopt = sock_common_getsockopt,
- .sendmsg = inet_sendmsg,
- .recvmsg = sock_common_recvmsg,
- .mmap = sock_no_mmap,
- .sendpage = tcp_sendpage
+ .family = PF_INET,
+ .owner = THIS_MODULE,
+ .release = inet_release,
+ .bind = inet_bind,
+ .connect = inet_stream_connect,
+ .socketpair = sock_no_socketpair,
+ .accept = inet_accept,
+ .getname = inet_getname,
+ .poll = tcp_poll,
+ .ioctl = inet_ioctl,
+ .listen = inet_listen,
+ .shutdown = inet_shutdown,
+ .setsockopt = sock_common_setsockopt,
+ .getsockopt = sock_common_getsockopt,
+ .sendmsg = inet_sendmsg,
+ .recvmsg = sock_common_recvmsg,
+ .mmap = sock_no_mmap,
+ .sendpage = tcp_sendpage,
+#ifdef CONFIG_COMPAT
+ .compat_setsockopt = compat_sock_common_setsockopt,
+ .compat_getsockopt = compat_sock_common_getsockopt,
+#endif
};
const struct proto_ops inet_dgram_ops = {
- .family = PF_INET,
- .owner = THIS_MODULE,
- .release = inet_release,
- .bind = inet_bind,
- .connect = inet_dgram_connect,
- .socketpair = sock_no_socketpair,
- .accept = sock_no_accept,
- .getname = inet_getname,
- .poll = udp_poll,
- .ioctl = inet_ioctl,
- .listen = sock_no_listen,
- .shutdown = inet_shutdown,
- .setsockopt = sock_common_setsockopt,
- .getsockopt = sock_common_getsockopt,
- .sendmsg = inet_sendmsg,
- .recvmsg = sock_common_recvmsg,
- .mmap = sock_no_mmap,
- .sendpage = inet_sendpage,
+ .family = PF_INET,
+ .owner = THIS_MODULE,
+ .release = inet_release,
+ .bind = inet_bind,
+ .connect = inet_dgram_connect,
+ .socketpair = sock_no_socketpair,
+ .accept = sock_no_accept,
+ .getname = inet_getname,
+ .poll = udp_poll,
+ .ioctl = inet_ioctl,
+ .listen = sock_no_listen,
+ .shutdown = inet_shutdown,
+ .setsockopt = sock_common_setsockopt,
+ .getsockopt = sock_common_getsockopt,
+ .sendmsg = inet_sendmsg,
+ .recvmsg = sock_common_recvmsg,
+ .mmap = sock_no_mmap,
+ .sendpage = inet_sendpage,
+#ifdef CONFIG_COMPAT
+ .compat_setsockopt = compat_sock_common_setsockopt,
+ .compat_getsockopt = compat_sock_common_getsockopt,
+#endif
};
/*
@@ -834,24 +842,28 @@ const struct proto_ops inet_dgram_ops = {
* udp_poll
*/
static const struct proto_ops inet_sockraw_ops = {
- .family = PF_INET,
- .owner = THIS_MODULE,
- .release = inet_release,
- .bind = inet_bind,
- .connect = inet_dgram_connect,
- .socketpair = sock_no_socketpair,
- .accept = sock_no_accept,
- .getname = inet_getname,
- .poll = datagram_poll,
- .ioctl = inet_ioctl,
- .listen = sock_no_listen,
- .shutdown = inet_shutdown,
- .setsockopt = sock_common_setsockopt,
- .getsockopt = sock_common_getsockopt,
- .sendmsg = inet_sendmsg,
- .recvmsg = sock_common_recvmsg,
- .mmap = sock_no_mmap,
- .sendpage = inet_sendpage,
+ .family = PF_INET,
+ .owner = THIS_MODULE,
+ .release = inet_release,
+ .bind = inet_bind,
+ .connect = inet_dgram_connect,
+ .socketpair = sock_no_socketpair,
+ .accept = sock_no_accept,
+ .getname = inet_getname,
+ .poll = datagram_poll,
+ .ioctl = inet_ioctl,
+ .listen = sock_no_listen,
+ .shutdown = inet_shutdown,
+ .setsockopt = sock_common_setsockopt,
+ .getsockopt = sock_common_getsockopt,
+ .sendmsg = inet_sendmsg,
+ .recvmsg = sock_common_recvmsg,
+ .mmap = sock_no_mmap,
+ .sendpage = inet_sendpage,
+#ifdef CONFIG_COMPAT
+ .compat_setsockopt = compat_sock_common_setsockopt,
+ .compat_getsockopt = compat_sock_common_getsockopt,
+#endif
};
static struct net_proto_family inet_family_ops = {
diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c
index aed537fa2c88..e16d8b42b953 100644
--- a/net/ipv4/ah4.c
+++ b/net/ipv4/ah4.c
@@ -97,6 +97,7 @@ static int ah_output(struct xfrm_state *x, struct sk_buff *skb)
ah->reserved = 0;
ah->spi = x->id.spi;
ah->seq_no = htonl(++x->replay.oseq);
+ xfrm_aevent_doreplay(x);
ahp->icv(ahp, skb, ah->auth_data);
top_iph->tos = iph->tos;
diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c
index accdefedfed7..041dadde31af 100644
--- a/net/ipv4/arp.c
+++ b/net/ipv4/arp.c
@@ -879,16 +879,16 @@ static int arp_process(struct sk_buff *skb)
n = __neigh_lookup(&arp_tbl, &sip, dev, 0);
-#ifdef CONFIG_IP_ACCEPT_UNSOLICITED_ARP
- /* Unsolicited ARP is not accepted by default.
- It is possible, that this option should be enabled for some
- devices (strip is candidate)
- */
- if (n == NULL &&
- arp->ar_op == htons(ARPOP_REPLY) &&
- inet_addr_type(sip) == RTN_UNICAST)
- n = __neigh_lookup(&arp_tbl, &sip, dev, -1);
-#endif
+ if (ipv4_devconf.arp_accept) {
+ /* Unsolicited ARP is not accepted by default.
+ It is possible, that this option should be enabled for some
+ devices (strip is candidate)
+ */
+ if (n == NULL &&
+ arp->ar_op == htons(ARPOP_REPLY) &&
+ inet_addr_type(sip) == RTN_UNICAST)
+ n = __neigh_lookup(&arp_tbl, &sip, dev, -1);
+ }
if (n) {
int state = NUD_REACHABLE;
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index 3ffa60dadc0c..44fdf1413e2c 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -1394,6 +1394,14 @@ static struct devinet_sysctl_table {
.proc_handler = &proc_dointvec,
},
{
+ .ctl_name = NET_IPV4_CONF_ARP_ACCEPT,
+ .procname = "arp_accept",
+ .data = &ipv4_devconf.arp_accept,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
+ {
.ctl_name = NET_IPV4_CONF_NOXFRM,
.procname = "disable_xfrm",
.data = &ipv4_devconf.no_xfrm,
diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c
index 09590f356086..bf88c620a954 100644
--- a/net/ipv4/esp4.c
+++ b/net/ipv4/esp4.c
@@ -90,6 +90,7 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb)
esph->spi = x->id.spi;
esph->seq_no = htonl(++x->replay.oseq);
+ xfrm_aevent_doreplay(x);
if (esp->conf.ivlen)
crypto_cipher_set_iv(tfm, esp->conf.ivec, crypto_tfm_alg_ivsize(tfm));
diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c
index 0dd4d06e456d..ec566f3e66c7 100644
--- a/net/ipv4/fib_rules.c
+++ b/net/ipv4/fib_rules.c
@@ -40,6 +40,8 @@
#include <linux/skbuff.h>
#include <linux/netlink.h>
#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/rcupdate.h>
#include <net/ip.h>
#include <net/protocol.h>
@@ -52,7 +54,7 @@
struct fib_rule
{
- struct fib_rule *r_next;
+ struct hlist_node hlist;
atomic_t r_clntref;
u32 r_preference;
unsigned char r_table;
@@ -75,6 +77,7 @@ struct fib_rule
#endif
char r_ifname[IFNAMSIZ];
int r_dead;
+ struct rcu_head rcu;
};
static struct fib_rule default_rule = {
@@ -85,7 +88,6 @@ static struct fib_rule default_rule = {
};
static struct fib_rule main_rule = {
- .r_next = &default_rule,
.r_clntref = ATOMIC_INIT(2),
.r_preference = 0x7FFE,
.r_table = RT_TABLE_MAIN,
@@ -93,23 +95,26 @@ static struct fib_rule main_rule = {
};
static struct fib_rule local_rule = {
- .r_next = &main_rule,
.r_clntref = ATOMIC_INIT(2),
.r_table = RT_TABLE_LOCAL,
.r_action = RTN_UNICAST,
};
-static struct fib_rule *fib_rules = &local_rule;
-static DEFINE_RWLOCK(fib_rules_lock);
+static struct hlist_head fib_rules;
+
+/* writer func called from netlink -- rtnl_sem hold*/
+
+static void rtmsg_rule(int, struct fib_rule *);
int inet_rtm_delrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
{
struct rtattr **rta = arg;
struct rtmsg *rtm = NLMSG_DATA(nlh);
- struct fib_rule *r, **rp;
+ struct fib_rule *r;
+ struct hlist_node *node;
int err = -ESRCH;
- for (rp=&fib_rules; (r=*rp) != NULL; rp=&r->r_next) {
+ hlist_for_each_entry(r, node, &fib_rules, hlist) {
if ((!rta[RTA_SRC-1] || memcmp(RTA_DATA(rta[RTA_SRC-1]), &r->r_src, 4) == 0) &&
rtm->rtm_src_len == r->r_src_len &&
rtm->rtm_dst_len == r->r_dst_len &&
@@ -126,10 +131,9 @@ int inet_rtm_delrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
if (r == &local_rule)
break;
- write_lock_bh(&fib_rules_lock);
- *rp = r->r_next;
+ hlist_del_rcu(&r->hlist);
r->r_dead = 1;
- write_unlock_bh(&fib_rules_lock);
+ rtmsg_rule(RTM_DELRULE, r);
fib_rule_put(r);
err = 0;
break;
@@ -150,21 +154,30 @@ static struct fib_table *fib_empty_table(void)
return NULL;
}
+static inline void fib_rule_put_rcu(struct rcu_head *head)
+{
+ struct fib_rule *r = container_of(head, struct fib_rule, rcu);
+ kfree(r);
+}
+
void fib_rule_put(struct fib_rule *r)
{
if (atomic_dec_and_test(&r->r_clntref)) {
if (r->r_dead)
- kfree(r);
+ call_rcu(&r->rcu, fib_rule_put_rcu);
else
printk("Freeing alive rule %p\n", r);
}
}
+/* writer func called from netlink -- rtnl_sem hold*/
+
int inet_rtm_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
{
struct rtattr **rta = arg;
struct rtmsg *rtm = NLMSG_DATA(nlh);
- struct fib_rule *r, *new_r, **rp;
+ struct fib_rule *r, *new_r, *last = NULL;
+ struct hlist_node *node = NULL;
unsigned char table_id;
if (rtm->rtm_src_len > 32 || rtm->rtm_dst_len > 32 ||
@@ -188,6 +201,7 @@ int inet_rtm_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
if (!new_r)
return -ENOMEM;
memset(new_r, 0, sizeof(*new_r));
+
if (rta[RTA_SRC-1])
memcpy(&new_r->r_src, RTA_DATA(rta[RTA_SRC-1]), 4);
if (rta[RTA_DST-1])
@@ -220,28 +234,29 @@ int inet_rtm_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
if (rta[RTA_FLOW-1])
memcpy(&new_r->r_tclassid, RTA_DATA(rta[RTA_FLOW-1]), 4);
#endif
+ r = container_of(fib_rules.first, struct fib_rule, hlist);
- rp = &fib_rules;
if (!new_r->r_preference) {
- r = fib_rules;
- if (r && (r = r->r_next) != NULL) {
- rp = &fib_rules->r_next;
+ if (r && r->hlist.next != NULL) {
+ r = container_of(r->hlist.next, struct fib_rule, hlist);
if (r->r_preference)
new_r->r_preference = r->r_preference - 1;
}
}
- while ( (r = *rp) != NULL ) {
+ hlist_for_each_entry(r, node, &fib_rules, hlist) {
if (r->r_preference > new_r->r_preference)
break;
- rp = &r->r_next;
+ last = r;
}
-
- new_r->r_next = r;
atomic_inc(&new_r->r_clntref);
- write_lock_bh(&fib_rules_lock);
- *rp = new_r;
- write_unlock_bh(&fib_rules_lock);
+
+ if (last)
+ hlist_add_after_rcu(&last->hlist, &new_r->hlist);
+ else
+ hlist_add_before_rcu(&new_r->hlist, &r->hlist);
+
+ rtmsg_rule(RTM_NEWRULE, new_r);
return 0;
}
@@ -254,30 +269,30 @@ u32 fib_rules_tclass(struct fib_result *res)
}
#endif
+/* callers should hold rtnl semaphore */
static void fib_rules_detach(struct net_device *dev)
{
+ struct hlist_node *node;
struct fib_rule *r;
- for (r=fib_rules; r; r=r->r_next) {
- if (r->r_ifindex == dev->ifindex) {
- write_lock_bh(&fib_rules_lock);
+ hlist_for_each_entry(r, node, &fib_rules, hlist) {
+ if (r->r_ifindex == dev->ifindex)
r->r_ifindex = -1;
- write_unlock_bh(&fib_rules_lock);
- }
+
}
}
+/* callers should hold rtnl semaphore */
+
static void fib_rules_attach(struct net_device *dev)
{
+ struct hlist_node *node;
struct fib_rule *r;
- for (r=fib_rules; r; r=r->r_next) {
- if (r->r_ifindex == -1 && strcmp(dev->name, r->r_ifname) == 0) {
- write_lock_bh(&fib_rules_lock);
+ hlist_for_each_entry(r, node, &fib_rules, hlist) {
+ if (r->r_ifindex == -1 && strcmp(dev->name, r->r_ifname) == 0)
r->r_ifindex = dev->ifindex;
- write_unlock_bh(&fib_rules_lock);
- }
}
}
@@ -286,14 +301,17 @@ int fib_lookup(const struct flowi *flp, struct fib_result *res)
int err;
struct fib_rule *r, *policy;
struct fib_table *tb;
+ struct hlist_node *node;
u32 daddr = flp->fl4_dst;
u32 saddr = flp->fl4_src;
FRprintk("Lookup: %u.%u.%u.%u <- %u.%u.%u.%u ",
NIPQUAD(flp->fl4_dst), NIPQUAD(flp->fl4_src));
- read_lock(&fib_rules_lock);
- for (r = fib_rules; r; r=r->r_next) {
+
+ rcu_read_lock();
+
+ hlist_for_each_entry_rcu(r, node, &fib_rules, hlist) {
if (((saddr^r->r_src) & r->r_srcmask) ||
((daddr^r->r_dst) & r->r_dstmask) ||
(r->r_tos && r->r_tos != flp->fl4_tos) ||
@@ -309,14 +327,14 @@ FRprintk("tb %d r %d ", r->r_table, r->r_action);
policy = r;
break;
case RTN_UNREACHABLE:
- read_unlock(&fib_rules_lock);
+ rcu_read_unlock();
return -ENETUNREACH;
default:
case RTN_BLACKHOLE:
- read_unlock(&fib_rules_lock);
+ rcu_read_unlock();
return -EINVAL;
case RTN_PROHIBIT:
- read_unlock(&fib_rules_lock);
+ rcu_read_unlock();
return -EACCES;
}
@@ -327,16 +345,16 @@ FRprintk("tb %d r %d ", r->r_table, r->r_action);
res->r = policy;
if (policy)
atomic_inc(&policy->r_clntref);
- read_unlock(&fib_rules_lock);
+ rcu_read_unlock();
return 0;
}
if (err < 0 && err != -EAGAIN) {
- read_unlock(&fib_rules_lock);
+ rcu_read_unlock();
return err;
}
}
FRprintk("FAILURE\n");
- read_unlock(&fib_rules_lock);
+ rcu_read_unlock();
return -ENETUNREACH;
}
@@ -368,14 +386,14 @@ static struct notifier_block fib_rules_notifier = {
static __inline__ int inet_fill_rule(struct sk_buff *skb,
struct fib_rule *r,
- struct netlink_callback *cb,
+ u32 pid, u32 seq, int event,
unsigned int flags)
{
struct rtmsg *rtm;
struct nlmsghdr *nlh;
unsigned char *b = skb->tail;
- nlh = NLMSG_NEW_ANSWER(skb, cb, RTM_NEWRULE, sizeof(*rtm), flags);
+ nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*rtm), flags);
rtm = NLMSG_DATA(nlh);
rtm->rtm_family = AF_INET;
rtm->rtm_dst_len = r->r_dst_len;
@@ -414,20 +432,42 @@ rtattr_failure:
return -1;
}
+/* callers should hold rtnl semaphore */
+
+static void rtmsg_rule(int event, struct fib_rule *r)
+{
+ int size = NLMSG_SPACE(sizeof(struct rtmsg) + 128);
+ struct sk_buff *skb = alloc_skb(size, GFP_KERNEL);
+
+ if (!skb)
+ netlink_set_err(rtnl, 0, RTNLGRP_IPV4_RULE, ENOBUFS);
+ else if (inet_fill_rule(skb, r, 0, 0, event, 0) < 0) {
+ kfree_skb(skb);
+ netlink_set_err(rtnl, 0, RTNLGRP_IPV4_RULE, EINVAL);
+ } else {
+ netlink_broadcast(rtnl, skb, 0, RTNLGRP_IPV4_RULE, GFP_KERNEL);
+ }
+}
+
int inet_dump_rules(struct sk_buff *skb, struct netlink_callback *cb)
{
- int idx;
+ int idx = 0;
int s_idx = cb->args[0];
struct fib_rule *r;
+ struct hlist_node *node;
+
+ rcu_read_lock();
+ hlist_for_each_entry(r, node, &fib_rules, hlist) {
- read_lock(&fib_rules_lock);
- for (r=fib_rules, idx=0; r; r = r->r_next, idx++) {
if (idx < s_idx)
continue;
- if (inet_fill_rule(skb, r, cb, NLM_F_MULTI) < 0)
+ if (inet_fill_rule(skb, r, NETLINK_CB(cb->skb).pid,
+ cb->nlh->nlmsg_seq,
+ RTM_NEWRULE, NLM_F_MULTI) < 0)
break;
+ idx++;
}
- read_unlock(&fib_rules_lock);
+ rcu_read_unlock();
cb->args[0] = idx;
return skb->len;
@@ -435,5 +475,9 @@ int inet_dump_rules(struct sk_buff *skb, struct netlink_callback *cb)
void __init fib_rules_init(void)
{
+ INIT_HLIST_HEAD(&fib_rules);
+ hlist_add_head(&local_rule.hlist, &fib_rules);
+ hlist_add_after(&local_rule.hlist, &main_rule.hlist);
+ hlist_add_after(&main_rule.hlist, &default_rule.hlist);
register_netdevice_notifier(&fib_rules_notifier);
}
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
index e320b32373e5..ccd3efc6a173 100644
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@ -50,7 +50,7 @@
* Patrick McHardy <kaber@trash.net>
*/
-#define VERSION "0.404"
+#define VERSION "0.406"
#include <linux/config.h>
#include <asm/uaccess.h>
@@ -84,7 +84,7 @@
#include "fib_lookup.h"
#undef CONFIG_IP_FIB_TRIE_STATS
-#define MAX_CHILDS 16384
+#define MAX_STAT_DEPTH 32
#define KEYLENGTH (8*sizeof(t_key))
#define MASK_PFX(k, l) (((l)==0)?0:(k >> (KEYLENGTH-l)) << (KEYLENGTH-l))
@@ -154,7 +154,7 @@ struct trie_stat {
unsigned int tnodes;
unsigned int leaves;
unsigned int nullpointers;
- unsigned int nodesizes[MAX_CHILDS];
+ unsigned int nodesizes[MAX_STAT_DEPTH];
};
struct trie {
@@ -2040,7 +2040,15 @@ rescan:
static struct node *fib_trie_get_first(struct fib_trie_iter *iter,
struct trie *t)
{
- struct node *n = rcu_dereference(t->trie);
+ struct node *n ;
+
+ if(!t)
+ return NULL;
+
+ n = rcu_dereference(t->trie);
+
+ if(!iter)
+ return NULL;
if (n && IS_TNODE(n)) {
iter->tnode = (struct tnode *) n;
@@ -2072,7 +2080,9 @@ static void trie_collect_stats(struct trie *t, struct trie_stat *s)
int i;
s->tnodes++;
- s->nodesizes[tn->bits]++;
+ if(tn->bits < MAX_STAT_DEPTH)
+ s->nodesizes[tn->bits]++;
+
for (i = 0; i < (1<<tn->bits); i++)
if (!tn->child[i])
s->nullpointers++;
@@ -2102,8 +2112,8 @@ static void trie_show_stats(struct seq_file *seq, struct trie_stat *stat)
seq_printf(seq, "\tInternal nodes: %d\n\t", stat->tnodes);
bytes += sizeof(struct tnode) * stat->tnodes;
- max = MAX_CHILDS-1;
- while (max >= 0 && stat->nodesizes[max] == 0)
+ max = MAX_STAT_DEPTH;
+ while (max > 0 && stat->nodesizes[max-1] == 0)
max--;
pointers = 0;
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index e7bbff4340bb..9831fd2c73a0 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -753,7 +753,7 @@ static void icmp_redirect(struct sk_buff *skb)
case ICMP_REDIR_HOST:
case ICMP_REDIR_HOSTTOS:
ip_rt_redirect(skb->nh.iph->saddr, ip, skb->h.icmph->un.gateway,
- iph->saddr, iph->tos, skb->dev);
+ iph->saddr, skb->dev);
break;
}
out:
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index 64ce52bf0485..d512239a1473 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -1382,7 +1382,7 @@ static struct in_device * ip_mc_find_dev(struct ip_mreqn *imr)
dev = ip_dev_find(imr->imr_address.s_addr);
if (!dev)
return NULL;
- __dev_put(dev);
+ dev_put(dev);
}
if (!dev && !ip_route_output_key(&rt, &fl)) {
@@ -1730,7 +1730,7 @@ int ip_mc_join_group(struct sock *sk , struct ip_mreqn *imr)
if (!MULTICAST(addr))
return -EINVAL;
- rtnl_shlock();
+ rtnl_lock();
in_dev = ip_mc_find_dev(imr);
@@ -1763,7 +1763,7 @@ int ip_mc_join_group(struct sock *sk , struct ip_mreqn *imr)
ip_mc_inc_group(in_dev, addr);
err = 0;
done:
- rtnl_shunlock();
+ rtnl_unlock();
return err;
}
@@ -1837,7 +1837,7 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct
if (!MULTICAST(addr))
return -EINVAL;
- rtnl_shlock();
+ rtnl_lock();
imr.imr_multiaddr.s_addr = mreqs->imr_multiaddr;
imr.imr_address.s_addr = mreqs->imr_interface;
@@ -1947,7 +1947,7 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct
ip_mc_add_src(in_dev, &mreqs->imr_multiaddr, omode, 1,
&mreqs->imr_sourceaddr, 1);
done:
- rtnl_shunlock();
+ rtnl_unlock();
if (leavegroup)
return ip_mc_leave_group(sk, &imr);
return err;
@@ -1970,7 +1970,7 @@ int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf, int ifindex)
msf->imsf_fmode != MCAST_EXCLUDE)
return -EINVAL;
- rtnl_shlock();
+ rtnl_lock();
imr.imr_multiaddr.s_addr = msf->imsf_multiaddr;
imr.imr_address.s_addr = msf->imsf_interface;
@@ -2030,7 +2030,7 @@ int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf, int ifindex)
pmc->sfmode = msf->imsf_fmode;
err = 0;
done:
- rtnl_shunlock();
+ rtnl_unlock();
if (leavegroup)
err = ip_mc_leave_group(sk, &imr);
return err;
@@ -2050,7 +2050,7 @@ int ip_mc_msfget(struct sock *sk, struct ip_msfilter *msf,
if (!MULTICAST(addr))
return -EINVAL;
- rtnl_shlock();
+ rtnl_lock();
imr.imr_multiaddr.s_addr = msf->imsf_multiaddr;
imr.imr_address.s_addr = msf->imsf_interface;
@@ -2072,7 +2072,7 @@ int ip_mc_msfget(struct sock *sk, struct ip_msfilter *msf,
goto done;
msf->imsf_fmode = pmc->sfmode;
psl = pmc->sflist;
- rtnl_shunlock();
+ rtnl_unlock();
if (!psl) {
len = 0;
count = 0;
@@ -2091,7 +2091,7 @@ int ip_mc_msfget(struct sock *sk, struct ip_msfilter *msf,
return -EFAULT;
return 0;
done:
- rtnl_shunlock();
+ rtnl_unlock();
return err;
}
@@ -2112,7 +2112,7 @@ int ip_mc_gsfget(struct sock *sk, struct group_filter *gsf,
if (!MULTICAST(addr))
return -EINVAL;
- rtnl_shlock();
+ rtnl_lock();
err = -EADDRNOTAVAIL;
@@ -2125,7 +2125,7 @@ int ip_mc_gsfget(struct sock *sk, struct group_filter *gsf,
goto done;
gsf->gf_fmode = pmc->sfmode;
psl = pmc->sflist;
- rtnl_shunlock();
+ rtnl_unlock();
count = psl ? psl->sl_count : 0;
copycount = count < gsf->gf_numsrc ? count : gsf->gf_numsrc;
gsf->gf_numsrc = count;
@@ -2146,7 +2146,7 @@ int ip_mc_gsfget(struct sock *sk, struct group_filter *gsf,
}
return 0;
done:
- rtnl_shunlock();
+ rtnl_unlock();
return err;
}
diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c
index ae20281d8deb..9a01bb81f8bf 100644
--- a/net/ipv4/inet_connection_sock.c
+++ b/net/ipv4/inet_connection_sock.c
@@ -648,3 +648,52 @@ void inet_csk_addr2sockaddr(struct sock *sk, struct sockaddr *uaddr)
}
EXPORT_SYMBOL_GPL(inet_csk_addr2sockaddr);
+
+int inet_csk_ctl_sock_create(struct socket **sock, unsigned short family,
+ unsigned short type, unsigned char protocol)
+{
+ int rc = sock_create_kern(family, type, protocol, sock);
+
+ if (rc == 0) {
+ (*sock)->sk->sk_allocation = GFP_ATOMIC;
+ inet_sk((*sock)->sk)->uc_ttl = -1;
+ /*
+ * Unhash it so that IP input processing does not even see it,
+ * we do not wish this socket to see incoming packets.
+ */
+ (*sock)->sk->sk_prot->unhash((*sock)->sk);
+ }
+ return rc;
+}
+
+EXPORT_SYMBOL_GPL(inet_csk_ctl_sock_create);
+
+#ifdef CONFIG_COMPAT
+int inet_csk_compat_getsockopt(struct sock *sk, int level, int optname,
+ char __user *optval, int __user *optlen)
+{
+ const struct inet_connection_sock *icsk = inet_csk(sk);
+
+ if (icsk->icsk_af_ops->compat_getsockopt != NULL)
+ return icsk->icsk_af_ops->compat_getsockopt(sk, level, optname,
+ optval, optlen);
+ return icsk->icsk_af_ops->getsockopt(sk, level, optname,
+ optval, optlen);
+}
+
+EXPORT_SYMBOL_GPL(inet_csk_compat_getsockopt);
+
+int inet_csk_compat_setsockopt(struct sock *sk, int level, int optname,
+ char __user *optval, int optlen)
+{
+ const struct inet_connection_sock *icsk = inet_csk(sk);
+
+ if (icsk->icsk_af_ops->compat_setsockopt != NULL)
+ return icsk->icsk_af_ops->compat_setsockopt(sk, level, optname,
+ optval, optlen);
+ return icsk->icsk_af_ops->setsockopt(sk, level, optname,
+ optval, optlen);
+}
+
+EXPORT_SYMBOL_GPL(inet_csk_compat_setsockopt);
+#endif
diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c
index 33228115cda4..ef7366fc132f 100644
--- a/net/ipv4/inet_hashtables.c
+++ b/net/ipv4/inet_hashtables.c
@@ -315,7 +315,7 @@ ok:
spin_unlock(&head->lock);
if (tw) {
- inet_twsk_deschedule(tw, death_row);;
+ inet_twsk_deschedule(tw, death_row);
inet_twsk_put(tw);
}
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index 8ee4d016740d..f75ff1d96551 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -1249,11 +1249,7 @@ int ip_push_pending_frames(struct sock *sk)
iph->tos = inet->tos;
iph->tot_len = htons(skb->len);
iph->frag_off = df;
- if (!df) {
- __ip_select_ident(iph, &rt->u.dst, 0);
- } else {
- iph->id = htons(inet->id++);
- }
+ ip_select_ident(iph, &rt->u.dst, sk);
iph->ttl = ttl;
iph->protocol = sk->sk_protocol;
iph->saddr = rt->rt_src;
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
index 2bf8d782f678..12e0bf19f24a 100644
--- a/net/ipv4/ip_sockglue.c
+++ b/net/ipv4/ip_sockglue.c
@@ -50,6 +50,7 @@
#define IP_CMSG_TOS 4
#define IP_CMSG_RECVOPTS 8
#define IP_CMSG_RETOPTS 16
+#define IP_CMSG_PASSSEC 32
/*
* SOL_IP control messages.
@@ -109,6 +110,19 @@ static void ip_cmsg_recv_retopts(struct msghdr *msg, struct sk_buff *skb)
put_cmsg(msg, SOL_IP, IP_RETOPTS, opt->optlen, opt->__data);
}
+static void ip_cmsg_recv_security(struct msghdr *msg, struct sk_buff *skb)
+{
+ char *secdata;
+ u32 seclen;
+ int err;
+
+ err = security_socket_getpeersec_dgram(skb, &secdata, &seclen);
+ if (err)
+ return;
+
+ put_cmsg(msg, SOL_IP, SCM_SECURITY, seclen, secdata);
+}
+
void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb)
{
@@ -138,6 +152,11 @@ void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb)
if (flags & 1)
ip_cmsg_recv_retopts(msg, skb);
+ if ((flags>>=1) == 0)
+ return;
+
+ if (flags & 1)
+ ip_cmsg_recv_security(msg, skb);
}
int ip_cmsg_send(struct msghdr *msg, struct ipcm_cookie *ipc)
@@ -380,20 +399,19 @@ out:
* an IP socket.
*/
-int ip_setsockopt(struct sock *sk, int level, int optname, char __user *optval, int optlen)
+static int do_ip_setsockopt(struct sock *sk, int level,
+ int optname, char __user *optval, int optlen)
{
struct inet_sock *inet = inet_sk(sk);
int val=0,err;
- if (level != SOL_IP)
- return -ENOPROTOOPT;
-
if (((1<<optname) & ((1<<IP_PKTINFO) | (1<<IP_RECVTTL) |
(1<<IP_RECVOPTS) | (1<<IP_RECVTOS) |
(1<<IP_RETOPTS) | (1<<IP_TOS) |
(1<<IP_TTL) | (1<<IP_HDRINCL) |
(1<<IP_MTU_DISCOVER) | (1<<IP_RECVERR) |
- (1<<IP_ROUTER_ALERT) | (1<<IP_FREEBIND))) ||
+ (1<<IP_ROUTER_ALERT) | (1<<IP_FREEBIND) |
+ (1<<IP_PASSSEC))) ||
optname == IP_MULTICAST_TTL ||
optname == IP_MULTICAST_LOOP) {
if (optlen >= sizeof(int)) {
@@ -478,6 +496,12 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char __user *optval,
else
inet->cmsg_flags &= ~IP_CMSG_RETOPTS;
break;
+ case IP_PASSSEC:
+ if (val)
+ inet->cmsg_flags |= IP_CMSG_PASSSEC;
+ else
+ inet->cmsg_flags &= ~IP_CMSG_PASSSEC;
+ break;
case IP_TOS: /* This sets both TOS and Precedence */
if (sk->sk_type == SOCK_STREAM) {
val &= ~3;
@@ -849,12 +873,7 @@ mc_msf_out:
break;
default:
-#ifdef CONFIG_NETFILTER
- err = nf_setsockopt(sk, PF_INET, optname, optval,
- optlen);
-#else
err = -ENOPROTOOPT;
-#endif
break;
}
release_sock(sk);
@@ -865,12 +884,68 @@ e_inval:
return -EINVAL;
}
+int ip_setsockopt(struct sock *sk, int level,
+ int optname, char __user *optval, int optlen)
+{
+ int err;
+
+ if (level != SOL_IP)
+ return -ENOPROTOOPT;
+
+ err = do_ip_setsockopt(sk, level, optname, optval, optlen);
+#ifdef CONFIG_NETFILTER
+ /* we need to exclude all possible ENOPROTOOPTs except default case */
+ if (err == -ENOPROTOOPT && optname != IP_HDRINCL &&
+ optname != IP_IPSEC_POLICY && optname != IP_XFRM_POLICY
+#ifdef CONFIG_IP_MROUTE
+ && (optname < MRT_BASE || optname > (MRT_BASE + 10))
+#endif
+ ) {
+ lock_sock(sk);
+ err = nf_setsockopt(sk, PF_INET, optname, optval, optlen);
+ release_sock(sk);
+ }
+#endif
+ return err;
+}
+
+#ifdef CONFIG_COMPAT
+int compat_ip_setsockopt(struct sock *sk, int level, int optname,
+ char __user *optval, int optlen)
+{
+ int err;
+
+ if (level != SOL_IP)
+ return -ENOPROTOOPT;
+
+ err = do_ip_setsockopt(sk, level, optname, optval, optlen);
+#ifdef CONFIG_NETFILTER
+ /* we need to exclude all possible ENOPROTOOPTs except default case */
+ if (err == -ENOPROTOOPT && optname != IP_HDRINCL &&
+ optname != IP_IPSEC_POLICY && optname != IP_XFRM_POLICY
+#ifdef CONFIG_IP_MROUTE
+ && (optname < MRT_BASE || optname > (MRT_BASE + 10))
+#endif
+ ) {
+ lock_sock(sk);
+ err = compat_nf_setsockopt(sk, PF_INET, optname,
+ optval, optlen);
+ release_sock(sk);
+ }
+#endif
+ return err;
+}
+
+EXPORT_SYMBOL(compat_ip_setsockopt);
+#endif
+
/*
* Get the options. Note for future reference. The GET of IP options gets the
* _received_ ones. The set sets the _sent_ ones.
*/
-int ip_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen)
+static int do_ip_getsockopt(struct sock *sk, int level, int optname,
+ char __user *optval, int __user *optlen)
{
struct inet_sock *inet = inet_sk(sk);
int val;
@@ -932,6 +1007,9 @@ int ip_getsockopt(struct sock *sk, int level, int optname, char __user *optval,
case IP_RETOPTS:
val = (inet->cmsg_flags & IP_CMSG_RETOPTS) != 0;
break;
+ case IP_PASSSEC:
+ val = (inet->cmsg_flags & IP_CMSG_PASSSEC) != 0;
+ break;
case IP_TOS:
val = inet->tos;
break;
@@ -1051,17 +1129,8 @@ int ip_getsockopt(struct sock *sk, int level, int optname, char __user *optval,
val = inet->freebind;
break;
default:
-#ifdef CONFIG_NETFILTER
- val = nf_getsockopt(sk, PF_INET, optname, optval,
- &len);
- release_sock(sk);
- if (val >= 0)
- val = put_user(len, optlen);
- return val;
-#else
release_sock(sk);
return -ENOPROTOOPT;
-#endif
}
release_sock(sk);
@@ -1082,6 +1151,67 @@ int ip_getsockopt(struct sock *sk, int level, int optname, char __user *optval,
return 0;
}
+int ip_getsockopt(struct sock *sk, int level,
+ int optname, char __user *optval, int __user *optlen)
+{
+ int err;
+
+ err = do_ip_getsockopt(sk, level, optname, optval, optlen);
+#ifdef CONFIG_NETFILTER
+ /* we need to exclude all possible ENOPROTOOPTs except default case */
+ if (err == -ENOPROTOOPT && optname != IP_PKTOPTIONS
+#ifdef CONFIG_IP_MROUTE
+ && (optname < MRT_BASE || optname > MRT_BASE+10)
+#endif
+ ) {
+ int len;
+
+ if(get_user(len,optlen))
+ return -EFAULT;
+
+ lock_sock(sk);
+ err = nf_getsockopt(sk, PF_INET, optname, optval,
+ &len);
+ release_sock(sk);
+ if (err >= 0)
+ err = put_user(len, optlen);
+ return err;
+ }
+#endif
+ return err;
+}
+
+#ifdef CONFIG_COMPAT
+int compat_ip_getsockopt(struct sock *sk, int level, int optname,
+ char __user *optval, int __user *optlen)
+{
+ int err = do_ip_getsockopt(sk, level, optname, optval, optlen);
+#ifdef CONFIG_NETFILTER
+ /* we need to exclude all possible ENOPROTOOPTs except default case */
+ if (err == -ENOPROTOOPT && optname != IP_PKTOPTIONS
+#ifdef CONFIG_IP_MROUTE
+ && (optname < MRT_BASE || optname > MRT_BASE+10)
+#endif
+ ) {
+ int len;
+
+ if (get_user(len, optlen))
+ return -EFAULT;
+
+ lock_sock(sk);
+ err = compat_nf_getsockopt(sk, PF_INET, optname, optval, &len);
+ release_sock(sk);
+ if (err >= 0)
+ err = put_user(len, optlen);
+ return err;
+ }
+#endif
+ return err;
+}
+
+EXPORT_SYMBOL(compat_ip_getsockopt);
+#endif
+
EXPORT_SYMBOL(ip_cmsg_recv);
EXPORT_SYMBOL(ip_getsockopt);
diff --git a/net/ipv4/ipcomp.c b/net/ipv4/ipcomp.c
index d64e2ec8da7b..c95020f7c81e 100644
--- a/net/ipv4/ipcomp.c
+++ b/net/ipv4/ipcomp.c
@@ -24,6 +24,7 @@
#include <linux/list.h>
#include <linux/vmalloc.h>
#include <linux/rtnetlink.h>
+#include <linux/mutex.h>
#include <net/ip.h>
#include <net/xfrm.h>
#include <net/icmp.h>
@@ -36,7 +37,7 @@ struct ipcomp_tfms {
int users;
};
-static DECLARE_MUTEX(ipcomp_resource_sem);
+static DEFINE_MUTEX(ipcomp_resource_mutex);
static void **ipcomp_scratches;
static int ipcomp_scratch_users;
static LIST_HEAD(ipcomp_tfms_list);
@@ -253,7 +254,7 @@ error:
}
/*
- * Must be protected by xfrm_cfg_sem. State and tunnel user references are
+ * Must be protected by xfrm_cfg_mutex. State and tunnel user references are
* always incremented on success.
*/
static int ipcomp_tunnel_attach(struct xfrm_state *x)
@@ -411,9 +412,9 @@ static void ipcomp_destroy(struct xfrm_state *x)
if (!ipcd)
return;
xfrm_state_delete_tunnel(x);
- down(&ipcomp_resource_sem);
+ mutex_lock(&ipcomp_resource_mutex);
ipcomp_free_data(ipcd);
- up(&ipcomp_resource_sem);
+ mutex_unlock(&ipcomp_resource_mutex);
kfree(ipcd);
}
@@ -440,14 +441,14 @@ static int ipcomp_init_state(struct xfrm_state *x)
if (x->props.mode)
x->props.header_len += sizeof(struct iphdr);
- down(&ipcomp_resource_sem);
+ mutex_lock(&ipcomp_resource_mutex);
if (!ipcomp_alloc_scratches())
goto error;
ipcd->tfms = ipcomp_alloc_tfms(x->calg->alg_name);
if (!ipcd->tfms)
goto error;
- up(&ipcomp_resource_sem);
+ mutex_unlock(&ipcomp_resource_mutex);
if (x->props.mode) {
err = ipcomp_tunnel_attach(x);
@@ -464,10 +465,10 @@ out:
return err;
error_tunnel:
- down(&ipcomp_resource_sem);
+ mutex_lock(&ipcomp_resource_mutex);
error:
ipcomp_free_data(ipcd);
- up(&ipcomp_resource_sem);
+ mutex_unlock(&ipcomp_resource_mutex);
kfree(ipcd);
goto out;
}
diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c
index bb3613ec448c..cb8a92f18ef6 100644
--- a/net/ipv4/ipconfig.c
+++ b/net/ipv4/ipconfig.c
@@ -186,7 +186,7 @@ static int __init ic_open_devs(void)
unsigned short oflags;
last = &ic_first_dev;
- rtnl_shlock();
+ rtnl_lock();
/* bring loopback device up first */
if (dev_change_flags(&loopback_dev, loopback_dev.flags | IFF_UP) < 0)
@@ -215,7 +215,7 @@ static int __init ic_open_devs(void)
continue;
}
if (!(d = kmalloc(sizeof(struct ic_device), GFP_KERNEL))) {
- rtnl_shunlock();
+ rtnl_unlock();
return -1;
}
d->dev = dev;
@@ -232,7 +232,7 @@ static int __init ic_open_devs(void)
dev->name, able, d->xid));
}
}
- rtnl_shunlock();
+ rtnl_unlock();
*last = NULL;
@@ -251,7 +251,7 @@ static void __init ic_close_devs(void)
struct ic_device *d, *next;
struct net_device *dev;
- rtnl_shlock();
+ rtnl_lock();
next = ic_first_dev;
while ((d = next)) {
next = d->next;
@@ -262,7 +262,7 @@ static void __init ic_close_devs(void)
}
kfree(d);
}
- rtnl_shunlock();
+ rtnl_unlock();
}
/*
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index 5c94c222e3f3..717ab7d6d7b6 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -415,10 +415,10 @@ static int vif_add(struct vifctl *vifc, int mrtsock)
return -ENOBUFS;
break;
case 0:
- dev=ip_dev_find(vifc->vifc_lcl_addr.s_addr);
+ dev = ip_dev_find(vifc->vifc_lcl_addr.s_addr);
if (!dev)
return -EADDRNOTAVAIL;
- __dev_put(dev);
+ dev_put(dev);
break;
default:
return -EINVAL;
diff --git a/net/ipv4/ipvs/ip_vs_app.c b/net/ipv4/ipvs/ip_vs_app.c
index 9b176a942ac5..e7752334d296 100644
--- a/net/ipv4/ipvs/ip_vs_app.c
+++ b/net/ipv4/ipvs/ip_vs_app.c
@@ -31,6 +31,7 @@
#include <linux/stat.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
+#include <linux/mutex.h>
#include <net/ip_vs.h>
@@ -40,7 +41,7 @@ EXPORT_SYMBOL(register_ip_vs_app_inc);
/* ipvs application list head */
static LIST_HEAD(ip_vs_app_list);
-static DECLARE_MUTEX(__ip_vs_app_mutex);
+static DEFINE_MUTEX(__ip_vs_app_mutex);
/*
@@ -173,11 +174,11 @@ register_ip_vs_app_inc(struct ip_vs_app *app, __u16 proto, __u16 port)
{
int result;
- down(&__ip_vs_app_mutex);
+ mutex_lock(&__ip_vs_app_mutex);
result = ip_vs_app_inc_new(app, proto, port);
- up(&__ip_vs_app_mutex);
+ mutex_unlock(&__ip_vs_app_mutex);
return result;
}
@@ -191,11 +192,11 @@ int register_ip_vs_app(struct ip_vs_app *app)
/* increase the module use count */
ip_vs_use_count_inc();
- down(&__ip_vs_app_mutex);
+ mutex_lock(&__ip_vs_app_mutex);
list_add(&app->a_list, &ip_vs_app_list);
- up(&__ip_vs_app_mutex);
+ mutex_unlock(&__ip_vs_app_mutex);
return 0;
}
@@ -209,7 +210,7 @@ void unregister_ip_vs_app(struct ip_vs_app *app)
{
struct ip_vs_app *inc, *nxt;
- down(&__ip_vs_app_mutex);
+ mutex_lock(&__ip_vs_app_mutex);
list_for_each_entry_safe(inc, nxt, &app->incs_list, a_list) {
ip_vs_app_inc_release(inc);
@@ -217,7 +218,7 @@ void unregister_ip_vs_app(struct ip_vs_app *app)
list_del(&app->a_list);
- up(&__ip_vs_app_mutex);
+ mutex_unlock(&__ip_vs_app_mutex);
/* decrease the module use count */
ip_vs_use_count_dec();
@@ -498,7 +499,7 @@ static struct ip_vs_app *ip_vs_app_idx(loff_t pos)
static void *ip_vs_app_seq_start(struct seq_file *seq, loff_t *pos)
{
- down(&__ip_vs_app_mutex);
+ mutex_lock(&__ip_vs_app_mutex);
return *pos ? ip_vs_app_idx(*pos - 1) : SEQ_START_TOKEN;
}
@@ -530,7 +531,7 @@ static void *ip_vs_app_seq_next(struct seq_file *seq, void *v, loff_t *pos)
static void ip_vs_app_seq_stop(struct seq_file *seq, void *v)
{
- up(&__ip_vs_app_mutex);
+ mutex_unlock(&__ip_vs_app_mutex);
}
static int ip_vs_app_seq_show(struct seq_file *seq, void *v)
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig
index db783036e4d8..882b842c25d4 100644
--- a/net/ipv4/netfilter/Kconfig
+++ b/net/ipv4/netfilter/Kconfig
@@ -168,6 +168,26 @@ config IP_NF_PPTP
If you want to compile it as a module, say M here and read
Documentation/modules.txt. If unsure, say `N'.
+config IP_NF_H323
+ tristate 'H.323 protocol support'
+ depends on IP_NF_CONNTRACK
+ help
+ H.323 is a VoIP signalling protocol from ITU-T. As one of the most
+ important VoIP protocols, it is widely used by voice hardware and
+ software including voice gateways, IP phones, Netmeeting, OpenPhone,
+ Gnomemeeting, etc.
+
+ With this module you can support H.323 on a connection tracking/NAT
+ firewall.
+
+ This module supports RAS, Fast-start, H.245 tunnelling, RTP/RTCP
+ and T.120 based data and applications including audio, video, FAX,
+ chat, whiteboard, file transfer, etc. For more information, please
+ see http://nath323.sourceforge.net/.
+
+ If you want to compile it as a module, say 'M' here and read
+ Documentation/modules.txt. If unsure, say 'N'.
+
config IP_NF_QUEUE
tristate "IP Userspace queueing via NETLINK (OBSOLETE)"
help
@@ -303,16 +323,6 @@ config IP_NF_MATCH_HASHLIMIT
destination IP' or `500pps from any given source IP' with a single
IPtables rule.
-config IP_NF_MATCH_POLICY
- tristate "IPsec policy match support"
- depends on IP_NF_IPTABLES && XFRM
- help
- Policy matching allows you to match packets based on the
- IPsec policy that was used during decapsulation/will
- be used during encapsulation.
-
- To compile it as a module, choose M here. If unsure, say N.
-
# `filter', generic and specific targets
config IP_NF_FILTER
tristate "Packet filtering"
@@ -494,6 +504,12 @@ config IP_NF_NAT_PPTP
default IP_NF_NAT if IP_NF_PPTP=y
default m if IP_NF_PPTP=m
+config IP_NF_NAT_H323
+ tristate
+ depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n
+ default IP_NF_NAT if IP_NF_H323=y
+ default m if IP_NF_H323=m
+
# mangle + specific targets
config IP_NF_MANGLE
tristate "Packet mangling"
diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile
index e5c5b3202f02..f2cd9a6c5b91 100644
--- a/net/ipv4/netfilter/Makefile
+++ b/net/ipv4/netfilter/Makefile
@@ -10,6 +10,9 @@ iptable_nat-objs := ip_nat_rule.o ip_nat_standalone.o
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_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
@@ -22,6 +25,7 @@ obj-$(CONFIG_IP_NF_CONNTRACK_NETLINK) += ip_conntrack_netlink.o
obj-$(CONFIG_IP_NF_CT_PROTO_SCTP) += ip_conntrack_proto_sctp.o
# connection tracking helpers
+obj-$(CONFIG_IP_NF_H323) += ip_conntrack_h323.o
obj-$(CONFIG_IP_NF_PPTP) += ip_conntrack_pptp.o
obj-$(CONFIG_IP_NF_AMANDA) += ip_conntrack_amanda.o
obj-$(CONFIG_IP_NF_TFTP) += ip_conntrack_tftp.o
@@ -30,6 +34,7 @@ obj-$(CONFIG_IP_NF_IRC) += ip_conntrack_irc.o
obj-$(CONFIG_IP_NF_NETBIOS_NS) += ip_conntrack_netbios_ns.o
# NAT helpers
+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
obj-$(CONFIG_IP_NF_NAT_TFTP) += ip_nat_tftp.o
@@ -57,7 +62,6 @@ obj-$(CONFIG_IP_NF_MATCH_DSCP) += ipt_dscp.o
obj-$(CONFIG_IP_NF_MATCH_AH_ESP) += ipt_ah.o ipt_esp.o
obj-$(CONFIG_IP_NF_MATCH_TTL) += ipt_ttl.o
obj-$(CONFIG_IP_NF_MATCH_ADDRTYPE) += ipt_addrtype.o
-obj-$(CONFIG_IP_NF_MATCH_POLICY) += ipt_policy.o
# targets
obj-$(CONFIG_IP_NF_TARGET_REJECT) += ipt_REJECT.o
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c
index 7d7ab94a7a2e..ff0c594a4198 100644
--- a/net/ipv4/netfilter/arp_tables.c
+++ b/net/ipv4/netfilter/arp_tables.c
@@ -22,7 +22,7 @@
#include <linux/init.h>
#include <asm/uaccess.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
#include <linux/netfilter/x_tables.h>
#include <linux/netfilter_arp/arp_tables.h>
@@ -208,6 +208,7 @@ static unsigned int arpt_error(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,
void *userinfo)
{
@@ -300,6 +301,7 @@ unsigned int arpt_do_table(struct sk_buff **pskb,
verdict = t->u.kernel.target->target(pskb,
in, out,
hook,
+ t->u.kernel.target,
t->data,
userdata);
@@ -480,26 +482,31 @@ static inline int check_entry(struct arpt_entry *e, const char *name, unsigned i
}
t->u.kernel.target = target;
+ ret = xt_check_target(target, NF_ARP, t->u.target_size - sizeof(*t),
+ name, e->comefrom, 0, 0);
+ if (ret)
+ goto err;
+
if (t->u.kernel.target == &arpt_standard_target) {
if (!standard_check(t, size)) {
ret = -EINVAL;
goto out;
}
} else if (t->u.kernel.target->checkentry
- && !t->u.kernel.target->checkentry(name, e, t->data,
+ && !t->u.kernel.target->checkentry(name, e, target, t->data,
t->u.target_size
- sizeof(*t),
e->comefrom)) {
- module_put(t->u.kernel.target->me);
duprintf("arp_tables: check failed for `%s'.\n",
t->u.kernel.target->name);
ret = -EINVAL;
- goto out;
+ goto err;
}
(*i)++;
return 0;
-
+err:
+ module_put(t->u.kernel.target->me);
out:
return ret;
}
@@ -555,7 +562,7 @@ static inline int cleanup_entry(struct arpt_entry *e, unsigned int *i)
t = arpt_get_target(e);
if (t->u.kernel.target->destroy)
- t->u.kernel.target->destroy(t->data,
+ t->u.kernel.target->destroy(t->u.kernel.target, t->data,
t->u.target_size - sizeof(*t));
module_put(t->u.kernel.target->me);
return 0;
@@ -1138,11 +1145,15 @@ void arpt_unregister_table(struct arpt_table *table)
/* The built-in targets: standard (NULL) and error. */
static struct arpt_target arpt_standard_target = {
.name = ARPT_STANDARD_TARGET,
+ .targetsize = sizeof(int),
+ .family = NF_ARP,
};
static struct arpt_target arpt_error_target = {
.name = ARPT_ERROR_TARGET,
.target = arpt_error,
+ .targetsize = ARPT_FUNCTION_MAXNAMELEN,
+ .family = NF_ARP,
};
static struct nf_sockopt_ops arpt_sockopts = {
@@ -1162,8 +1173,8 @@ static int __init init(void)
xt_proto_init(NF_ARP);
/* Noone else will be downing sem now, so we won't sleep */
- xt_register_target(NF_ARP, &arpt_standard_target);
- xt_register_target(NF_ARP, &arpt_error_target);
+ xt_register_target(&arpt_standard_target);
+ xt_register_target(&arpt_error_target);
/* Register setsockopt */
ret = nf_register_sockopt(&arpt_sockopts);
diff --git a/net/ipv4/netfilter/arpt_mangle.c b/net/ipv4/netfilter/arpt_mangle.c
index c97650a16a5b..0f2a95350e26 100644
--- a/net/ipv4/netfilter/arpt_mangle.c
+++ b/net/ipv4/netfilter/arpt_mangle.c
@@ -8,9 +8,10 @@ MODULE_AUTHOR("Bart De Schuymer <bdschuym@pandora.be>");
MODULE_DESCRIPTION("arptables arp payload mangle target");
static unsigned int
-target(struct sk_buff **pskb, const struct net_device *in,
- const struct net_device *out, unsigned int hooknum, const void *targinfo,
- void *userinfo)
+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, void *userinfo)
{
const struct arpt_mangle *mangle = targinfo;
struct arphdr *arp;
@@ -65,8 +66,8 @@ target(struct sk_buff **pskb, const struct net_device *in,
}
static int
-checkentry(const char *tablename, const void *e, void *targinfo,
- unsigned int targinfosize, unsigned int hook_mask)
+checkentry(const char *tablename, const void *e, const struct xt_target *target,
+ void *targinfo, unsigned int targinfosize, unsigned int hook_mask)
{
const struct arpt_mangle *mangle = targinfo;
@@ -80,12 +81,12 @@ checkentry(const char *tablename, const void *e, void *targinfo,
return 1;
}
-static struct arpt_target arpt_mangle_reg
-= {
- .name = "mangle",
- .target = target,
- .checkentry = checkentry,
- .me = THIS_MODULE,
+static struct arpt_target arpt_mangle_reg = {
+ .name = "mangle",
+ .target = target,
+ .targetsize = sizeof(struct arpt_mangle),
+ .checkentry = checkentry,
+ .me = THIS_MODULE,
};
static int __init init(void)
diff --git a/net/ipv4/netfilter/ip_conntrack_core.c b/net/ipv4/netfilter/ip_conntrack_core.c
index 84c66dbfedaf..9e34034729a6 100644
--- a/net/ipv4/netfilter/ip_conntrack_core.c
+++ b/net/ipv4/netfilter/ip_conntrack_core.c
@@ -77,8 +77,8 @@ unsigned int ip_ct_log_invalid;
static LIST_HEAD(unconfirmed);
static int ip_conntrack_vmalloc;
-static unsigned int ip_conntrack_next_id = 1;
-static unsigned int ip_conntrack_expect_next_id = 1;
+static unsigned int ip_conntrack_next_id;
+static unsigned int ip_conntrack_expect_next_id;
#ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
struct notifier_block *ip_conntrack_chain;
struct notifier_block *ip_conntrack_expect_chain;
diff --git a/net/ipv4/netfilter/ip_conntrack_helper_h323.c b/net/ipv4/netfilter/ip_conntrack_helper_h323.c
new file mode 100644
index 000000000000..daeb1395faa4
--- /dev/null
+++ b/net/ipv4/netfilter/ip_conntrack_helper_h323.c
@@ -0,0 +1,1731 @@
+/*
+ * H.323 connection tracking helper
+ *
+ * Copyright (c) 2006 Jing Min Zhao <zhaojingmin@users.sourceforge.net>
+ *
+ * This source code is licensed under General Public License version 2.
+ *
+ * Based on the 'brute force' H.323 connection tracking module by
+ * Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+ *
+ * For more information, please see http://nath323.sourceforge.net/
+ *
+ * Changes:
+ * 2006-02-01 - initial version 0.1
+ *
+ * 2006-02-20 - version 0.2
+ * 1. Changed source format to follow kernel conventions
+ * 2. Deleted some unnecessary structures
+ * 3. Minor fixes
+ *
+ * 2006-03-10 - version 0.3
+ * 1. Added support for multiple TPKTs in one packet (suggested by
+ * Patrick McHardy)
+ * 2. Avoid excessive stack usage (based on Patrick McHardy's patch)
+ * 3. Added support for non-linear skb (based on Patrick McHardy's patch)
+ * 4. Fixed missing H.245 module owner (Patrick McHardy)
+ * 5. Avoid long RAS expectation chains (Patrick McHardy)
+ * 6. Fixed incorrect __exit attribute (Patrick McHardy)
+ * 7. Eliminated unnecessary return code
+ * 8. Fixed incorrect use of NAT data from conntrack code (suggested by
+ * Patrick McHardy)
+ * 9. Fixed TTL calculation error in RCF
+ * 10. Added TTL support in RRQ
+ * 11. Better support for separate TPKT header and data
+ *
+ * 2006-03-15 - version 0.4
+ * 1. Added support for T.120 channels
+ * 2. Added parameter gkrouted_only (suggested by Patrick McHardy)
+ * 3. Splitted ASN.1 code and data (suggested by Patrick McHardy)
+ * 4. Sort ASN.1 data to avoid forwarding declarations (suggested by
+ * Patrick McHardy)
+ * 5. Reset next TPKT data length in get_tpkt_data()
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/netfilter.h>
+#include <linux/ip.h>
+#include <net/tcp.h>
+#include <linux/netfilter_ipv4/ip_conntrack.h>
+#include <linux/netfilter_ipv4/ip_conntrack_core.h>
+#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
+#include <linux/netfilter_ipv4/ip_conntrack_tuple.h>
+#include <linux/netfilter_ipv4/ip_conntrack_h323.h>
+#include <linux/moduleparam.h>
+
+#include "ip_conntrack_helper_h323_asn1.h"
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+/* Parameters */
+static int gkrouted_only = 1;
+module_param(gkrouted_only, int, 0600);
+MODULE_PARM_DESC(gkrouted_only, "only accept calls from gatekeeper");
+
+/* Hooks for NAT */
+int (*set_h245_addr_hook) (struct sk_buff ** pskb,
+ unsigned char **data, int dataoff,
+ H245_TransportAddress * addr,
+ u_int32_t ip, u_int16_t port);
+int (*set_h225_addr_hook) (struct sk_buff ** pskb,
+ unsigned char **data, int dataoff,
+ TransportAddress * addr,
+ u_int32_t ip, u_int16_t port);
+int (*set_sig_addr_hook) (struct sk_buff ** pskb,
+ struct ip_conntrack * ct,
+ enum ip_conntrack_info ctinfo,
+ unsigned char **data,
+ TransportAddress * addr, int count);
+int (*set_ras_addr_hook) (struct sk_buff ** pskb,
+ struct ip_conntrack * ct,
+ enum ip_conntrack_info ctinfo,
+ unsigned char **data,
+ TransportAddress * addr, int count);
+int (*nat_rtp_rtcp_hook) (struct sk_buff ** pskb,
+ struct ip_conntrack * ct,
+ enum ip_conntrack_info ctinfo,
+ unsigned char **data, int dataoff,
+ H245_TransportAddress * addr,
+ u_int16_t port, u_int16_t rtp_port,
+ struct ip_conntrack_expect * rtp_exp,
+ struct ip_conntrack_expect * rtcp_exp);
+int (*nat_t120_hook) (struct sk_buff ** pskb,
+ struct ip_conntrack * ct,
+ enum ip_conntrack_info ctinfo,
+ unsigned char **data, int dataoff,
+ H245_TransportAddress * addr, u_int16_t port,
+ struct ip_conntrack_expect * exp);
+int (*nat_h245_hook) (struct sk_buff ** pskb,
+ struct ip_conntrack * ct,
+ enum ip_conntrack_info ctinfo,
+ unsigned char **data, int dataoff,
+ TransportAddress * addr, u_int16_t port,
+ struct ip_conntrack_expect * exp);
+int (*nat_q931_hook) (struct sk_buff ** pskb,
+ struct ip_conntrack * ct,
+ enum ip_conntrack_info ctinfo,
+ unsigned char **data, TransportAddress * addr, int idx,
+ u_int16_t port, struct ip_conntrack_expect * exp);
+
+
+static DEFINE_SPINLOCK(ip_h323_lock);
+static char *h323_buffer;
+
+/****************************************************************************/
+static int get_tpkt_data(struct sk_buff **pskb, struct ip_conntrack *ct,
+ enum ip_conntrack_info ctinfo,
+ unsigned char **data, int *datalen, int *dataoff)
+{
+ struct ip_ct_h323_master *info = &ct->help.ct_h323_info;
+ int dir = CTINFO2DIR(ctinfo);
+ struct tcphdr _tcph, *th;
+ int tcpdatalen;
+ int tcpdataoff;
+ unsigned char *tpkt;
+ int tpktlen;
+ int tpktoff;
+
+ /* Get TCP header */
+ th = skb_header_pointer(*pskb, (*pskb)->nh.iph->ihl * 4,
+ sizeof(_tcph), &_tcph);
+ if (th == NULL)
+ return 0;
+
+ /* Get TCP data offset */
+ tcpdataoff = (*pskb)->nh.iph->ihl * 4 + th->doff * 4;
+
+ /* Get TCP data length */
+ tcpdatalen = (*pskb)->len - tcpdataoff;
+ if (tcpdatalen <= 0) /* No TCP data */
+ goto clear_out;
+
+ if (*data == NULL) { /* first TPKT */
+ /* Get first TPKT pointer */
+ tpkt = skb_header_pointer(*pskb, tcpdataoff, tcpdatalen,
+ h323_buffer);
+ BUG_ON(tpkt == NULL);
+
+ /* Validate TPKT identifier */
+ if (tcpdatalen < 4 || tpkt[0] != 0x03 || tpkt[1] != 0) {
+ /* Netmeeting sends TPKT header and data separately */
+ if (info->tpkt_len[dir] > 0) {
+ DEBUGP("ip_ct_h323: previous packet "
+ "indicated separate TPKT data of %hu "
+ "bytes\n", info->tpkt_len[dir]);
+ if (info->tpkt_len[dir] <= tcpdatalen) {
+ /* Yes, there was a TPKT header
+ * received */
+ *data = tpkt;
+ *datalen = info->tpkt_len[dir];
+ *dataoff = 0;
+ goto out;
+ }
+
+ /* Fragmented TPKT */
+ if (net_ratelimit())
+ printk("ip_ct_h323: "
+ "fragmented TPKT\n");
+ goto clear_out;
+ }
+
+ /* It is not even a TPKT */
+ return 0;
+ }
+ tpktoff = 0;
+ } else { /* Next TPKT */
+ tpktoff = *dataoff + *datalen;
+ tcpdatalen -= tpktoff;
+ if (tcpdatalen <= 4) /* No more TPKT */
+ goto clear_out;
+ tpkt = *data + *datalen;
+
+ /* Validate TPKT identifier */
+ if (tpkt[0] != 0x03 || tpkt[1] != 0)
+ goto clear_out;
+ }
+
+ /* Validate TPKT length */
+ tpktlen = tpkt[2] * 256 + tpkt[3];
+ if (tpktlen > tcpdatalen) {
+ if (tcpdatalen == 4) { /* Separate TPKT header */
+ /* Netmeeting sends TPKT header and data separately */
+ DEBUGP("ip_ct_h323: separate TPKT header indicates "
+ "there will be TPKT data of %hu bytes\n",
+ tpktlen - 4);
+ info->tpkt_len[dir] = tpktlen - 4;
+ return 0;
+ }
+
+ if (net_ratelimit())
+ printk("ip_ct_h323: incomplete TPKT (fragmented?)\n");
+ goto clear_out;
+ }
+
+ /* This is the encapsulated data */
+ *data = tpkt + 4;
+ *datalen = tpktlen - 4;
+ *dataoff = tpktoff + 4;
+
+ out:
+ /* Clear TPKT length */
+ info->tpkt_len[dir] = 0;
+ return 1;
+
+ clear_out:
+ info->tpkt_len[dir] = 0;
+ return 0;
+}
+
+/****************************************************************************/
+int get_h245_addr(unsigned char *data, H245_TransportAddress * addr,
+ u_int32_t * ip, u_int16_t * port)
+{
+ unsigned char *p;
+
+ if (addr->choice != eH245_TransportAddress_unicastAddress ||
+ addr->unicastAddress.choice != eUnicastAddress_iPAddress)
+ return 0;
+
+ p = data + addr->unicastAddress.iPAddress.network;
+ *ip = htonl((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3]));
+ *port = (p[4] << 8) | (p[5]);
+
+ return 1;
+}
+
+/****************************************************************************/
+static int expect_rtp_rtcp(struct sk_buff **pskb, struct ip_conntrack *ct,
+ enum ip_conntrack_info ctinfo,
+ unsigned char **data, int dataoff,
+ H245_TransportAddress * addr)
+{
+ int dir = CTINFO2DIR(ctinfo);
+ int ret = 0;
+ u_int32_t ip;
+ u_int16_t port;
+ u_int16_t rtp_port;
+ struct ip_conntrack_expect *rtp_exp;
+ struct ip_conntrack_expect *rtcp_exp;
+
+ /* Read RTP or RTCP address */
+ if (!get_h245_addr(*data, addr, &ip, &port) ||
+ ip != ct->tuplehash[dir].tuple.src.ip || port == 0)
+ return 0;
+
+ /* RTP port is even */
+ rtp_port = port & (~1);
+
+ /* Create expect for RTP */
+ if ((rtp_exp = ip_conntrack_expect_alloc(ct)) == NULL)
+ return -1;
+ rtp_exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip;
+ rtp_exp->tuple.src.u.udp.port = 0;
+ rtp_exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip;
+ rtp_exp->tuple.dst.u.udp.port = htons(rtp_port);
+ rtp_exp->tuple.dst.protonum = IPPROTO_UDP;
+ rtp_exp->mask.src.ip = 0xFFFFFFFF;
+ rtp_exp->mask.src.u.udp.port = 0;
+ rtp_exp->mask.dst.ip = 0xFFFFFFFF;
+ rtp_exp->mask.dst.u.udp.port = 0xFFFF;
+ rtp_exp->mask.dst.protonum = 0xFF;
+ rtp_exp->flags = 0;
+
+ /* Create expect for RTCP */
+ if ((rtcp_exp = ip_conntrack_expect_alloc(ct)) == NULL) {
+ ip_conntrack_expect_put(rtp_exp);
+ return -1;
+ }
+ rtcp_exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip;
+ rtcp_exp->tuple.src.u.udp.port = 0;
+ rtcp_exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip;
+ rtcp_exp->tuple.dst.u.udp.port = htons(rtp_port + 1);
+ rtcp_exp->tuple.dst.protonum = IPPROTO_UDP;
+ rtcp_exp->mask.src.ip = 0xFFFFFFFF;
+ rtcp_exp->mask.src.u.udp.port = 0;
+ rtcp_exp->mask.dst.ip = 0xFFFFFFFF;
+ rtcp_exp->mask.dst.u.udp.port = 0xFFFF;
+ rtcp_exp->mask.dst.protonum = 0xFF;
+ rtcp_exp->flags = 0;
+
+ if (ct->tuplehash[dir].tuple.src.ip !=
+ ct->tuplehash[!dir].tuple.dst.ip && nat_rtp_rtcp_hook) {
+ /* NAT needed */
+ ret = nat_rtp_rtcp_hook(pskb, ct, ctinfo, data, dataoff,
+ addr, port, rtp_port, rtp_exp,
+ rtcp_exp);
+ } else { /* Conntrack only */
+ rtp_exp->expectfn = NULL;
+ rtcp_exp->expectfn = NULL;
+
+ if (ip_conntrack_expect_related(rtp_exp) == 0) {
+ if (ip_conntrack_expect_related(rtcp_exp) == 0) {
+ DEBUGP("ip_ct_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("ip_ct_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));
+ } else {
+ ip_conntrack_unexpect_related(rtp_exp);
+ ret = -1;
+ }
+ } else
+ ret = -1;
+ }
+
+ ip_conntrack_expect_put(rtp_exp);
+ ip_conntrack_expect_put(rtcp_exp);
+
+ return ret;
+}
+
+/****************************************************************************/
+static int expect_t120(struct sk_buff **pskb,
+ struct ip_conntrack *ct,
+ enum ip_conntrack_info ctinfo,
+ unsigned char **data, int dataoff,
+ H245_TransportAddress * addr)
+{
+ int dir = CTINFO2DIR(ctinfo);
+ int ret = 0;
+ u_int32_t ip;
+ u_int16_t port;
+ struct ip_conntrack_expect *exp = NULL;
+
+ /* Read T.120 address */
+ if (!get_h245_addr(*data, addr, &ip, &port) ||
+ ip != ct->tuplehash[dir].tuple.src.ip || port == 0)
+ return 0;
+
+ /* Create expect for T.120 connections */
+ if ((exp = ip_conntrack_expect_alloc(ct)) == NULL)
+ return -1;
+ exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip;
+ exp->tuple.src.u.tcp.port = 0;
+ exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip;
+ exp->tuple.dst.u.tcp.port = htons(port);
+ exp->tuple.dst.protonum = IPPROTO_TCP;
+ exp->mask.src.ip = 0xFFFFFFFF;
+ exp->mask.src.u.tcp.port = 0;
+ exp->mask.dst.ip = 0xFFFFFFFF;
+ exp->mask.dst.u.tcp.port = 0xFFFF;
+ exp->mask.dst.protonum = 0xFF;
+ 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) {
+ /* NAT needed */
+ ret = nat_t120_hook(pskb, ct, ctinfo, data, dataoff, addr,
+ port, exp);
+ } else { /* Conntrack only */
+ exp->expectfn = NULL;
+ if (ip_conntrack_expect_related(exp) == 0) {
+ DEBUGP("ip_ct_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));
+ } else
+ ret = -1;
+ }
+
+ ip_conntrack_expect_put(exp);
+
+ return ret;
+}
+
+/****************************************************************************/
+static int process_h245_channel(struct sk_buff **pskb,
+ struct ip_conntrack *ct,
+ enum ip_conntrack_info ctinfo,
+ unsigned char **data, int dataoff,
+ H2250LogicalChannelParameters * channel)
+{
+ int ret;
+
+ if (channel->options & eH2250LogicalChannelParameters_mediaChannel) {
+ /* RTP */
+ ret = expect_rtp_rtcp(pskb, ct, ctinfo, data, dataoff,
+ &channel->mediaChannel);
+ if (ret < 0)
+ return -1;
+ }
+
+ if (channel->
+ options & eH2250LogicalChannelParameters_mediaControlChannel) {
+ /* RTCP */
+ ret = expect_rtp_rtcp(pskb, ct, ctinfo, data, dataoff,
+ &channel->mediaControlChannel);
+ if (ret < 0)
+ return -1;
+ }
+
+ return 0;
+}
+
+/****************************************************************************/
+static int process_olc(struct sk_buff **pskb, struct ip_conntrack *ct,
+ enum ip_conntrack_info ctinfo,
+ unsigned char **data, int dataoff,
+ OpenLogicalChannel * olc)
+{
+ int ret;
+
+ DEBUGP("ip_ct_h323: OpenLogicalChannel\n");
+
+ if (olc->forwardLogicalChannelParameters.multiplexParameters.choice ==
+ eOpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters_h2250LogicalChannelParameters)
+ {
+ ret = process_h245_channel(pskb, ct, ctinfo, data, dataoff,
+ &olc->
+ forwardLogicalChannelParameters.
+ multiplexParameters.
+ h2250LogicalChannelParameters);
+ if (ret < 0)
+ return -1;
+ }
+
+ if ((olc->options &
+ eOpenLogicalChannel_reverseLogicalChannelParameters) &&
+ (olc->reverseLogicalChannelParameters.options &
+ eOpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters)
+ && (olc->reverseLogicalChannelParameters.multiplexParameters.
+ choice ==
+ eOpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters_h2250LogicalChannelParameters))
+ {
+ ret =
+ process_h245_channel(pskb, ct, ctinfo, data, dataoff,
+ &olc->
+ reverseLogicalChannelParameters.
+ multiplexParameters.
+ h2250LogicalChannelParameters);
+ if (ret < 0)
+ return -1;
+ }
+
+ if ((olc->options & eOpenLogicalChannel_separateStack) &&
+ olc->forwardLogicalChannelParameters.dataType.choice ==
+ eDataType_data &&
+ olc->forwardLogicalChannelParameters.dataType.data.application.
+ choice == eDataApplicationCapability_application_t120 &&
+ olc->forwardLogicalChannelParameters.dataType.data.application.
+ t120.choice == eDataProtocolCapability_separateLANStack &&
+ olc->separateStack.networkAddress.choice ==
+ eNetworkAccessParameters_networkAddress_localAreaAddress) {
+ ret = expect_t120(pskb, ct, ctinfo, data, dataoff,
+ &olc->separateStack.networkAddress.
+ localAreaAddress);
+ if (ret < 0)
+ return -1;
+ }
+
+ return 0;
+}
+
+/****************************************************************************/
+static int process_olca(struct sk_buff **pskb, struct ip_conntrack *ct,
+ enum ip_conntrack_info ctinfo,
+ unsigned char **data, int dataoff,
+ OpenLogicalChannelAck * olca)
+{
+ H2250LogicalChannelAckParameters *ack;
+ int ret;
+
+ DEBUGP("ip_ct_h323: OpenLogicalChannelAck\n");
+
+ if ((olca->options &
+ eOpenLogicalChannelAck_reverseLogicalChannelParameters) &&
+ (olca->reverseLogicalChannelParameters.options &
+ eOpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters)
+ && (olca->reverseLogicalChannelParameters.multiplexParameters.
+ choice ==
+ eOpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters_h2250LogicalChannelParameters))
+ {
+ ret = process_h245_channel(pskb, ct, ctinfo, data, dataoff,
+ &olca->
+ reverseLogicalChannelParameters.
+ multiplexParameters.
+ h2250LogicalChannelParameters);
+ if (ret < 0)
+ return -1;
+ }
+
+ if ((olca->options &
+ eOpenLogicalChannelAck_forwardMultiplexAckParameters) &&
+ (olca->forwardMultiplexAckParameters.choice ==
+ eOpenLogicalChannelAck_forwardMultiplexAckParameters_h2250LogicalChannelAckParameters))
+ {
+ ack = &olca->forwardMultiplexAckParameters.
+ h2250LogicalChannelAckParameters;
+ if (ack->options &
+ eH2250LogicalChannelAckParameters_mediaChannel) {
+ /* RTP */
+ ret = expect_rtp_rtcp(pskb, ct, ctinfo, data, dataoff,
+ &ack->mediaChannel);
+ if (ret < 0)
+ return -1;
+ }
+
+ if (ack->options &
+ eH2250LogicalChannelAckParameters_mediaControlChannel) {
+ /* RTCP */
+ ret = expect_rtp_rtcp(pskb, ct, ctinfo, data, dataoff,
+ &ack->mediaControlChannel);
+ if (ret < 0)
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/****************************************************************************/
+static int process_h245(struct sk_buff **pskb, struct ip_conntrack *ct,
+ enum ip_conntrack_info ctinfo,
+ unsigned char **data, int dataoff,
+ MultimediaSystemControlMessage * mscm)
+{
+ switch (mscm->choice) {
+ case eMultimediaSystemControlMessage_request:
+ if (mscm->request.choice ==
+ eRequestMessage_openLogicalChannel) {
+ return process_olc(pskb, ct, ctinfo, data, dataoff,
+ &mscm->request.openLogicalChannel);
+ }
+ DEBUGP("ip_ct_h323: H.245 Request %d\n",
+ mscm->request.choice);
+ break;
+ case eMultimediaSystemControlMessage_response:
+ if (mscm->response.choice ==
+ eResponseMessage_openLogicalChannelAck) {
+ return process_olca(pskb, ct, ctinfo, data, dataoff,
+ &mscm->response.
+ openLogicalChannelAck);
+ }
+ DEBUGP("ip_ct_h323: H.245 Response %d\n",
+ mscm->response.choice);
+ break;
+ default:
+ DEBUGP("ip_ct_h323: H.245 signal %d\n", mscm->choice);
+ break;
+ }
+
+ return 0;
+}
+
+/****************************************************************************/
+static int h245_help(struct sk_buff **pskb, struct ip_conntrack *ct,
+ enum ip_conntrack_info ctinfo)
+{
+ static MultimediaSystemControlMessage mscm;
+ unsigned char *data = NULL;
+ int datalen;
+ int dataoff;
+ int ret;
+
+ /* Until there's been traffic both ways, don't look in packets. */
+ if (ctinfo != IP_CT_ESTABLISHED
+ && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) {
+ return NF_ACCEPT;
+ }
+ DEBUGP("ip_ct_h245: skblen = %u\n", (*pskb)->len);
+
+ spin_lock_bh(&ip_h323_lock);
+
+ /* Process each TPKT */
+ while (get_tpkt_data(pskb, ct, ctinfo, &data, &datalen, &dataoff)) {
+ DEBUGP("ip_ct_h245: TPKT %u.%u.%u.%u->%u.%u.%u.%u, len=%d\n",
+ NIPQUAD((*pskb)->nh.iph->saddr),
+ NIPQUAD((*pskb)->nh.iph->daddr), datalen);
+
+ /* Decode H.245 signal */
+ ret = DecodeMultimediaSystemControlMessage(data, datalen,
+ &mscm);
+ if (ret < 0) {
+ if (net_ratelimit())
+ printk("ip_ct_h245: decoding error: %s\n",
+ ret == H323_ERROR_BOUND ?
+ "out of bound" : "out of range");
+ /* We don't drop when decoding error */
+ break;
+ }
+
+ /* Process H.245 signal */
+ if (process_h245(pskb, ct, ctinfo, &data, dataoff, &mscm) < 0)
+ goto drop;
+ }
+
+ spin_unlock_bh(&ip_h323_lock);
+ return NF_ACCEPT;
+
+ drop:
+ spin_unlock_bh(&ip_h323_lock);
+ if (net_ratelimit())
+ printk("ip_ct_h245: packet dropped\n");
+ return NF_DROP;
+}
+
+/****************************************************************************/
+static struct ip_conntrack_helper ip_conntrack_helper_h245 = {
+ .name = "H.245",
+ .me = THIS_MODULE,
+ .max_expected = H323_RTP_CHANNEL_MAX * 4 + 2 /* T.120 */ ,
+ .timeout = 240,
+ .tuple = {.dst = {.protonum = IPPROTO_TCP}},
+ .mask = {.src = {.u = {0xFFFF}},
+ .dst = {.protonum = 0xFF}},
+ .help = h245_help
+};
+
+/****************************************************************************/
+void ip_conntrack_h245_expect(struct ip_conntrack *new,
+ struct ip_conntrack_expect *this)
+{
+ write_lock_bh(&ip_conntrack_lock);
+ new->helper = &ip_conntrack_helper_h245;
+ write_unlock_bh(&ip_conntrack_lock);
+}
+
+/****************************************************************************/
+int get_h225_addr(unsigned char *data, TransportAddress * addr,
+ u_int32_t * ip, u_int16_t * port)
+{
+ unsigned char *p;
+
+ if (addr->choice != eTransportAddress_ipAddress)
+ return 0;
+
+ p = data + addr->ipAddress.ip;
+ *ip = htonl((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3]));
+ *port = (p[4] << 8) | (p[5]);
+
+ return 1;
+}
+
+/****************************************************************************/
+static int expect_h245(struct sk_buff **pskb, struct ip_conntrack *ct,
+ enum ip_conntrack_info ctinfo,
+ unsigned char **data, int dataoff,
+ TransportAddress * addr)
+{
+ int dir = CTINFO2DIR(ctinfo);
+ int ret = 0;
+ u_int32_t ip;
+ u_int16_t port;
+ struct ip_conntrack_expect *exp = NULL;
+
+ /* Read h245Address */
+ if (!get_h225_addr(*data, addr, &ip, &port) ||
+ ip != ct->tuplehash[dir].tuple.src.ip || port == 0)
+ return 0;
+
+ /* Create expect for h245 connection */
+ if ((exp = ip_conntrack_expect_alloc(ct)) == NULL)
+ return -1;
+ exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip;
+ exp->tuple.src.u.tcp.port = 0;
+ exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip;
+ exp->tuple.dst.u.tcp.port = htons(port);
+ exp->tuple.dst.protonum = IPPROTO_TCP;
+ exp->mask.src.ip = 0xFFFFFFFF;
+ exp->mask.src.u.tcp.port = 0;
+ exp->mask.dst.ip = 0xFFFFFFFF;
+ exp->mask.dst.u.tcp.port = 0xFFFF;
+ exp->mask.dst.protonum = 0xFF;
+ exp->flags = 0;
+
+ if (ct->tuplehash[dir].tuple.src.ip !=
+ ct->tuplehash[!dir].tuple.dst.ip && nat_h245_hook) {
+ /* NAT needed */
+ ret = nat_h245_hook(pskb, ct, ctinfo, data, dataoff, addr,
+ port, exp);
+ } else { /* Conntrack only */
+ exp->expectfn = ip_conntrack_h245_expect;
+
+ if (ip_conntrack_expect_related(exp) == 0) {
+ DEBUGP("ip_ct_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));
+ } else
+ ret = -1;
+ }
+
+ ip_conntrack_expect_put(exp);
+
+ return ret;
+}
+
+/****************************************************************************/
+static int process_setup(struct sk_buff **pskb, struct ip_conntrack *ct,
+ enum ip_conntrack_info ctinfo,
+ unsigned char **data, int dataoff,
+ Setup_UUIE * setup)
+{
+ int dir = CTINFO2DIR(ctinfo);
+ int ret;
+ int i;
+ u_int32_t ip;
+ u_int16_t port;
+
+ DEBUGP("ip_ct_q931: Setup\n");
+
+ if (setup->options & eSetup_UUIE_h245Address) {
+ ret = expect_h245(pskb, ct, ctinfo, data, dataoff,
+ &setup->h245Address);
+ if (ret < 0)
+ return -1;
+ }
+
+ if ((setup->options & eSetup_UUIE_destCallSignalAddress) &&
+ (set_h225_addr_hook) &&
+ get_h225_addr(*data, &setup->destCallSignalAddress, &ip, &port) &&
+ ip != ct->tuplehash[!dir].tuple.src.ip) {
+ DEBUGP("ip_ct_q931: set destCallSignalAddress "
+ "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
+ 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));
+ if (ret < 0)
+ return -1;
+ }
+
+ if ((setup->options & eSetup_UUIE_sourceCallSignalAddress) &&
+ (set_h225_addr_hook) &&
+ get_h225_addr(*data, &setup->sourceCallSignalAddress, &ip, &port)
+ && ip != ct->tuplehash[!dir].tuple.dst.ip) {
+ DEBUGP("ip_ct_q931: set sourceCallSignalAddress "
+ "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
+ 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));
+ if (ret < 0)
+ return -1;
+ }
+
+ if (setup->options & eSetup_UUIE_fastStart) {
+ for (i = 0; i < setup->fastStart.count; i++) {
+ ret = process_olc(pskb, ct, ctinfo, data, dataoff,
+ &setup->fastStart.item[i]);
+ if (ret < 0)
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/****************************************************************************/
+static int process_callproceeding(struct sk_buff **pskb,
+ struct ip_conntrack *ct,
+ enum ip_conntrack_info ctinfo,
+ unsigned char **data, int dataoff,
+ CallProceeding_UUIE * callproc)
+{
+ int ret;
+ int i;
+
+ DEBUGP("ip_ct_q931: CallProceeding\n");
+
+ if (callproc->options & eCallProceeding_UUIE_h245Address) {
+ ret = expect_h245(pskb, ct, ctinfo, data, dataoff,
+ &callproc->h245Address);
+ if (ret < 0)
+ return -1;
+ }
+
+ if (callproc->options & eCallProceeding_UUIE_fastStart) {
+ for (i = 0; i < callproc->fastStart.count; i++) {
+ ret = process_olc(pskb, ct, ctinfo, data, dataoff,
+ &callproc->fastStart.item[i]);
+ if (ret < 0)
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/****************************************************************************/
+static int process_connect(struct sk_buff **pskb, struct ip_conntrack *ct,
+ enum ip_conntrack_info ctinfo,
+ unsigned char **data, int dataoff,
+ Connect_UUIE * connect)
+{
+ int ret;
+ int i;
+
+ DEBUGP("ip_ct_q931: Connect\n");
+
+ if (connect->options & eConnect_UUIE_h245Address) {
+ ret = expect_h245(pskb, ct, ctinfo, data, dataoff,
+ &connect->h245Address);
+ if (ret < 0)
+ return -1;
+ }
+
+ if (connect->options & eConnect_UUIE_fastStart) {
+ for (i = 0; i < connect->fastStart.count; i++) {
+ ret = process_olc(pskb, ct, ctinfo, data, dataoff,
+ &connect->fastStart.item[i]);
+ if (ret < 0)
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/****************************************************************************/
+static int process_alerting(struct sk_buff **pskb, struct ip_conntrack *ct,
+ enum ip_conntrack_info ctinfo,
+ unsigned char **data, int dataoff,
+ Alerting_UUIE * alert)
+{
+ int ret;
+ int i;
+
+ DEBUGP("ip_ct_q931: Alerting\n");
+
+ if (alert->options & eAlerting_UUIE_h245Address) {
+ ret = expect_h245(pskb, ct, ctinfo, data, dataoff,
+ &alert->h245Address);
+ if (ret < 0)
+ return -1;
+ }
+
+ if (alert->options & eAlerting_UUIE_fastStart) {
+ for (i = 0; i < alert->fastStart.count; i++) {
+ ret = process_olc(pskb, ct, ctinfo, data, dataoff,
+ &alert->fastStart.item[i]);
+ if (ret < 0)
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/****************************************************************************/
+static int process_information(struct sk_buff **pskb,
+ struct ip_conntrack *ct,
+ enum ip_conntrack_info ctinfo,
+ unsigned char **data, int dataoff,
+ Information_UUIE * info)
+{
+ int ret;
+ int i;
+
+ DEBUGP("ip_ct_q931: Information\n");
+
+ if (info->options & eInformation_UUIE_fastStart) {
+ for (i = 0; i < info->fastStart.count; i++) {
+ ret = process_olc(pskb, ct, ctinfo, data, dataoff,
+ &info->fastStart.item[i]);
+ if (ret < 0)
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/****************************************************************************/
+static int process_facility(struct sk_buff **pskb, struct ip_conntrack *ct,
+ enum ip_conntrack_info ctinfo,
+ unsigned char **data, int dataoff,
+ Facility_UUIE * facility)
+{
+ int ret;
+ int i;
+
+ DEBUGP("ip_ct_q931: Facility\n");
+
+ if (facility->options & eFacility_UUIE_h245Address) {
+ ret = expect_h245(pskb, ct, ctinfo, data, dataoff,
+ &facility->h245Address);
+ if (ret < 0)
+ return -1;
+ }
+
+ if (facility->options & eFacility_UUIE_fastStart) {
+ for (i = 0; i < facility->fastStart.count; i++) {
+ ret = process_olc(pskb, ct, ctinfo, data, dataoff,
+ &facility->fastStart.item[i]);
+ if (ret < 0)
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/****************************************************************************/
+static int process_progress(struct sk_buff **pskb, struct ip_conntrack *ct,
+ enum ip_conntrack_info ctinfo,
+ unsigned char **data, int dataoff,
+ Progress_UUIE * progress)
+{
+ int ret;
+ int i;
+
+ DEBUGP("ip_ct_q931: Progress\n");
+
+ if (progress->options & eProgress_UUIE_h245Address) {
+ ret = expect_h245(pskb, ct, ctinfo, data, dataoff,
+ &progress->h245Address);
+ if (ret < 0)
+ return -1;
+ }
+
+ if (progress->options & eProgress_UUIE_fastStart) {
+ for (i = 0; i < progress->fastStart.count; i++) {
+ ret = process_olc(pskb, ct, ctinfo, data, dataoff,
+ &progress->fastStart.item[i]);
+ if (ret < 0)
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/****************************************************************************/
+static int process_q931(struct sk_buff **pskb, struct ip_conntrack *ct,
+ enum ip_conntrack_info ctinfo,
+ unsigned char **data, int dataoff, Q931 * q931)
+{
+ H323_UU_PDU *pdu = &q931->UUIE.h323_uu_pdu;
+ int i;
+ int ret = 0;
+
+ switch (pdu->h323_message_body.choice) {
+ case eH323_UU_PDU_h323_message_body_setup:
+ ret = process_setup(pskb, ct, ctinfo, data, dataoff,
+ &pdu->h323_message_body.setup);
+ break;
+ case eH323_UU_PDU_h323_message_body_callProceeding:
+ ret = process_callproceeding(pskb, ct, ctinfo, data, dataoff,
+ &pdu->h323_message_body.
+ callProceeding);
+ break;
+ case eH323_UU_PDU_h323_message_body_connect:
+ ret = process_connect(pskb, ct, ctinfo, data, dataoff,
+ &pdu->h323_message_body.connect);
+ break;
+ case eH323_UU_PDU_h323_message_body_alerting:
+ ret = process_alerting(pskb, ct, ctinfo, data, dataoff,
+ &pdu->h323_message_body.alerting);
+ break;
+ case eH323_UU_PDU_h323_message_body_information:
+ ret = process_information(pskb, ct, ctinfo, data, dataoff,
+ &pdu->h323_message_body.
+ information);
+ break;
+ case eH323_UU_PDU_h323_message_body_facility:
+ ret = process_facility(pskb, ct, ctinfo, data, dataoff,
+ &pdu->h323_message_body.facility);
+ break;
+ case eH323_UU_PDU_h323_message_body_progress:
+ ret = process_progress(pskb, ct, ctinfo, data, dataoff,
+ &pdu->h323_message_body.progress);
+ break;
+ default:
+ DEBUGP("ip_ct_q931: Q.931 signal %d\n",
+ pdu->h323_message_body.choice);
+ break;
+ }
+
+ if (ret < 0)
+ return -1;
+
+ if (pdu->options & eH323_UU_PDU_h245Control) {
+ for (i = 0; i < pdu->h245Control.count; i++) {
+ ret = process_h245(pskb, ct, ctinfo, data, dataoff,
+ &pdu->h245Control.item[i]);
+ if (ret < 0)
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/****************************************************************************/
+static int q931_help(struct sk_buff **pskb, struct ip_conntrack *ct,
+ enum ip_conntrack_info ctinfo)
+{
+ static Q931 q931;
+ unsigned char *data = NULL;
+ int datalen;
+ int dataoff;
+ int ret;
+
+ /* Until there's been traffic both ways, don't look in packets. */
+ if (ctinfo != IP_CT_ESTABLISHED
+ && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) {
+ return NF_ACCEPT;
+ }
+ DEBUGP("ip_ct_q931: skblen = %u\n", (*pskb)->len);
+
+ spin_lock_bh(&ip_h323_lock);
+
+ /* Process each TPKT */
+ while (get_tpkt_data(pskb, ct, ctinfo, &data, &datalen, &dataoff)) {
+ DEBUGP("ip_ct_q931: TPKT %u.%u.%u.%u->%u.%u.%u.%u, len=%d\n",
+ NIPQUAD((*pskb)->nh.iph->saddr),
+ NIPQUAD((*pskb)->nh.iph->daddr), datalen);
+
+ /* Decode Q.931 signal */
+ ret = DecodeQ931(data, datalen, &q931);
+ if (ret < 0) {
+ if (net_ratelimit())
+ printk("ip_ct_q931: decoding error: %s\n",
+ ret == H323_ERROR_BOUND ?
+ "out of bound" : "out of range");
+ /* We don't drop when decoding error */
+ break;
+ }
+
+ /* Process Q.931 signal */
+ if (process_q931(pskb, ct, ctinfo, &data, dataoff, &q931) < 0)
+ goto drop;
+ }
+
+ spin_unlock_bh(&ip_h323_lock);
+ return NF_ACCEPT;
+
+ drop:
+ spin_unlock_bh(&ip_h323_lock);
+ if (net_ratelimit())
+ printk("ip_ct_q931: packet dropped\n");
+ return NF_DROP;
+}
+
+/****************************************************************************/
+static struct ip_conntrack_helper ip_conntrack_helper_q931 = {
+ .name = "Q.931",
+ .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)}},
+ .dst = {.protonum = IPPROTO_TCP}},
+ .mask = {.src = {.u = {0xFFFF}},
+ .dst = {.protonum = 0xFF}},
+ .help = q931_help
+};
+
+/****************************************************************************/
+void ip_conntrack_q931_expect(struct ip_conntrack *new,
+ struct ip_conntrack_expect *this)
+{
+ write_lock_bh(&ip_conntrack_lock);
+ new->helper = &ip_conntrack_helper_q931;
+ write_unlock_bh(&ip_conntrack_lock);
+}
+
+/****************************************************************************/
+static unsigned char *get_udp_data(struct sk_buff **pskb, int *datalen)
+{
+ struct udphdr _uh, *uh;
+ int dataoff;
+
+ uh = skb_header_pointer(*pskb, (*pskb)->nh.iph->ihl * 4, sizeof(_uh),
+ &_uh);
+ if (uh == NULL)
+ return NULL;
+ dataoff = (*pskb)->nh.iph->ihl * 4 + sizeof(_uh);
+ if (dataoff >= (*pskb)->len)
+ return NULL;
+ *datalen = (*pskb)->len - dataoff;
+ return skb_header_pointer(*pskb, dataoff, *datalen, h323_buffer);
+}
+
+/****************************************************************************/
+static struct ip_conntrack_expect *find_expect(struct ip_conntrack *ct,
+ u_int32_t ip, u_int16_t port)
+{
+ struct ip_conntrack_expect *exp;
+ struct ip_conntrack_tuple tuple;
+
+ tuple.src.ip = 0;
+ tuple.src.u.tcp.port = 0;
+ tuple.dst.ip = ip;
+ tuple.dst.u.tcp.port = htons(port);
+ tuple.dst.protonum = IPPROTO_TCP;
+
+ exp = __ip_conntrack_expect_find(&tuple);
+ if (exp->master == ct)
+ return exp;
+ return NULL;
+}
+
+/****************************************************************************/
+static int set_expect_timeout(struct ip_conntrack_expect *exp,
+ unsigned timeout)
+{
+ if (!exp || !del_timer(&exp->timeout))
+ return 0;
+
+ exp->timeout.expires = jiffies + timeout * HZ;
+ add_timer(&exp->timeout);
+
+ return 1;
+}
+
+/****************************************************************************/
+static int expect_q931(struct sk_buff **pskb, struct ip_conntrack *ct,
+ enum ip_conntrack_info ctinfo,
+ unsigned char **data,
+ TransportAddress * addr, int count)
+{
+ struct ip_ct_h323_master *info = &ct->help.ct_h323_info;
+ int dir = CTINFO2DIR(ctinfo);
+ int ret = 0;
+ int i;
+ u_int32_t ip;
+ u_int16_t port;
+ struct ip_conntrack_expect *exp;
+
+ /* Look for the first related address */
+ for (i = 0; i < count; i++) {
+ if (get_h225_addr(*data, &addr[i], &ip, &port) &&
+ ip == ct->tuplehash[dir].tuple.src.ip && port != 0)
+ break;
+ }
+
+ if (i >= count) /* Not found */
+ return 0;
+
+ /* Create expect for Q.931 */
+ if ((exp = ip_conntrack_expect_alloc(ct)) == NULL)
+ return -1;
+ exp->tuple.src.ip = gkrouted_only ? /* only accept calls from GK? */
+ ct->tuplehash[!dir].tuple.src.ip : 0;
+ exp->tuple.src.u.tcp.port = 0;
+ exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip;
+ exp->tuple.dst.u.tcp.port = htons(port);
+ exp->tuple.dst.protonum = IPPROTO_TCP;
+ exp->mask.src.ip = gkrouted_only ? 0xFFFFFFFF : 0;
+ exp->mask.src.u.tcp.port = 0;
+ exp->mask.dst.ip = 0xFFFFFFFF;
+ exp->mask.dst.u.tcp.port = 0xFFFF;
+ 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);
+ } else { /* Conntrack only */
+ exp->expectfn = ip_conntrack_q931_expect;
+
+ if (ip_conntrack_expect_related(exp) == 0) {
+ DEBUGP("ip_ct_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));
+
+ /* Save port for looking up expect in processing RCF */
+ info->sig_port[dir] = port;
+ } else
+ ret = -1;
+ }
+
+ ip_conntrack_expect_put(exp);
+
+ return ret;
+}
+
+/****************************************************************************/
+static int process_grq(struct sk_buff **pskb, struct ip_conntrack *ct,
+ enum ip_conntrack_info ctinfo,
+ unsigned char **data, GatekeeperRequest * grq)
+{
+ DEBUGP("ip_ct_ras: GRQ\n");
+
+ if (set_ras_addr_hook) /* NATed */
+ return set_ras_addr_hook(pskb, ct, ctinfo, data,
+ &grq->rasAddress, 1);
+ return 0;
+}
+
+/* Declare before using */
+static void ip_conntrack_ras_expect(struct ip_conntrack *new,
+ struct ip_conntrack_expect *this);
+
+/****************************************************************************/
+static int process_gcf(struct sk_buff **pskb, struct ip_conntrack *ct,
+ enum ip_conntrack_info ctinfo,
+ unsigned char **data, GatekeeperConfirm * gcf)
+{
+ int dir = CTINFO2DIR(ctinfo);
+ int ret = 0;
+ u_int32_t ip;
+ u_int16_t port;
+ struct ip_conntrack_expect *exp;
+
+ DEBUGP("ip_ct_ras: GCF\n");
+
+ if (!get_h225_addr(*data, &gcf->rasAddress, &ip, &port))
+ return 0;
+
+ /* Registration port is the same as discovery port */
+ if (ip == ct->tuplehash[dir].tuple.src.ip &&
+ port == ntohs(ct->tuplehash[dir].tuple.src.u.udp.port))
+ return 0;
+
+ /* Avoid RAS expectation loops. A GCF is never expected. */
+ if (test_bit(IPS_EXPECTED_BIT, &ct->status))
+ return 0;
+
+ /* Need new expect */
+ if ((exp = ip_conntrack_expect_alloc(ct)) == NULL)
+ return -1;
+ exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip;
+ exp->tuple.src.u.tcp.port = 0;
+ exp->tuple.dst.ip = ip;
+ exp->tuple.dst.u.tcp.port = htons(port);
+ exp->tuple.dst.protonum = IPPROTO_UDP;
+ exp->mask.src.ip = 0xFFFFFFFF;
+ exp->mask.src.u.tcp.port = 0;
+ exp->mask.dst.ip = 0xFFFFFFFF;
+ exp->mask.dst.u.tcp.port = 0xFFFF;
+ exp->mask.dst.protonum = 0xFF;
+ exp->flags = 0;
+ exp->expectfn = ip_conntrack_ras_expect;
+ if (ip_conntrack_expect_related(exp) == 0) {
+ DEBUGP("ip_ct_ras: expect RAS "
+ "%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));
+ } else
+ ret = -1;
+
+ ip_conntrack_expect_put(exp);
+
+ return ret;
+}
+
+/****************************************************************************/
+static int process_rrq(struct sk_buff **pskb, struct ip_conntrack *ct,
+ enum ip_conntrack_info ctinfo,
+ unsigned char **data, RegistrationRequest * rrq)
+{
+ struct ip_ct_h323_master *info = &ct->help.ct_h323_info;
+ int ret;
+
+ DEBUGP("ip_ct_ras: RRQ\n");
+
+ ret = expect_q931(pskb, ct, ctinfo, data,
+ rrq->callSignalAddress.item,
+ rrq->callSignalAddress.count);
+ 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);
+ if (ret < 0)
+ return -1;
+ }
+
+ if (rrq->options & eRegistrationRequest_timeToLive) {
+ DEBUGP("ip_ct_ras: RRQ TTL = %u seconds\n", rrq->timeToLive);
+ info->timeout = rrq->timeToLive;
+ } else
+ info->timeout = 0;
+
+ return 0;
+}
+
+/****************************************************************************/
+static int process_rcf(struct sk_buff **pskb, struct ip_conntrack *ct,
+ enum ip_conntrack_info ctinfo,
+ unsigned char **data, RegistrationConfirm * rcf)
+{
+ struct ip_ct_h323_master *info = &ct->help.ct_h323_info;
+ int dir = CTINFO2DIR(ctinfo);
+ int ret;
+ struct ip_conntrack_expect *exp;
+
+ 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);
+ if (ret < 0)
+ return -1;
+ }
+
+ if (rcf->options & eRegistrationConfirm_timeToLive) {
+ DEBUGP("ip_ct_ras: RCF TTL = %u seconds\n", rcf->timeToLive);
+ info->timeout = rcf->timeToLive;
+ }
+
+ if (info->timeout > 0) {
+ DEBUGP
+ ("ip_ct_ras: set RAS connection timeout to %u seconds\n",
+ info->timeout);
+ ip_ct_refresh_acct(ct, ctinfo, NULL, info->timeout * HZ);
+
+ /* Set expect timeout */
+ read_lock_bh(&ip_conntrack_lock);
+ exp = find_expect(ct, ct->tuplehash[dir].tuple.dst.ip,
+ info->sig_port[!dir]);
+ if (exp) {
+ DEBUGP("ip_ct_ras: set Q.931 expect "
+ "(%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu) "
+ "timeout to %u seconds\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),
+ info->timeout);
+ set_expect_timeout(exp, info->timeout);
+ }
+ read_unlock_bh(&ip_conntrack_lock);
+ }
+
+ return 0;
+}
+
+/****************************************************************************/
+static int process_urq(struct sk_buff **pskb, struct ip_conntrack *ct,
+ enum ip_conntrack_info ctinfo,
+ unsigned char **data, UnregistrationRequest * urq)
+{
+ struct ip_ct_h323_master *info = &ct->help.ct_h323_info;
+ int dir = CTINFO2DIR(ctinfo);
+ int ret;
+
+ 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);
+ if (ret < 0)
+ return -1;
+ }
+
+ /* Clear old expect */
+ ip_ct_remove_expectations(ct);
+ info->sig_port[dir] = 0;
+ info->sig_port[!dir] = 0;
+
+ /* Give it 30 seconds for UCF or URJ */
+ ip_ct_refresh_acct(ct, ctinfo, NULL, 30 * HZ);
+
+ return 0;
+}
+
+/****************************************************************************/
+static int process_arq(struct sk_buff **pskb, struct ip_conntrack *ct,
+ enum ip_conntrack_info ctinfo,
+ unsigned char **data, AdmissionRequest * arq)
+{
+ struct ip_ct_h323_master *info = &ct->help.ct_h323_info;
+ int dir = CTINFO2DIR(ctinfo);
+ u_int32_t ip;
+ u_int16_t port;
+
+ DEBUGP("ip_ct_ras: ARQ\n");
+
+ 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) {
+ /* Answering ARQ */
+ return set_h225_addr_hook(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) {
+ /* Calling ARQ */
+ return set_h225_addr_hook(pskb, data, 0,
+ &arq->srcCallSignalAddress,
+ ct->tuplehash[!dir].tuple.dst.ip,
+ port);
+ }
+
+ return 0;
+}
+
+/****************************************************************************/
+static int process_acf(struct sk_buff **pskb, struct ip_conntrack *ct,
+ enum ip_conntrack_info ctinfo,
+ unsigned char **data, AdmissionConfirm * acf)
+{
+ int dir = CTINFO2DIR(ctinfo);
+ int ret = 0;
+ u_int32_t ip;
+ u_int16_t port;
+ struct ip_conntrack_expect *exp;
+
+ DEBUGP("ip_ct_ras: ACF\n");
+
+ if (!get_h225_addr(*data, &acf->destCallSignalAddress, &ip, &port))
+ 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);
+ return 0;
+ }
+
+ /* Need new expect */
+ if ((exp = ip_conntrack_expect_alloc(ct)) == NULL)
+ return -1;
+ exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip;
+ exp->tuple.src.u.tcp.port = 0;
+ exp->tuple.dst.ip = ip;
+ exp->tuple.dst.u.tcp.port = htons(port);
+ exp->tuple.dst.protonum = IPPROTO_TCP;
+ exp->mask.src.ip = 0xFFFFFFFF;
+ exp->mask.src.u.tcp.port = 0;
+ exp->mask.dst.ip = 0xFFFFFFFF;
+ exp->mask.dst.u.tcp.port = 0xFFFF;
+ exp->mask.dst.protonum = 0xFF;
+ exp->flags = IP_CT_EXPECT_PERMANENT;
+ exp->expectfn = ip_conntrack_q931_expect;
+
+ if (ip_conntrack_expect_related(exp) == 0) {
+ DEBUGP("ip_ct_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));
+ } else
+ ret = -1;
+
+ ip_conntrack_expect_put(exp);
+
+ return ret;
+}
+
+/****************************************************************************/
+static int process_lrq(struct sk_buff **pskb, struct ip_conntrack *ct,
+ enum ip_conntrack_info ctinfo,
+ unsigned char **data, LocationRequest * lrq)
+{
+ DEBUGP("ip_ct_ras: LRQ\n");
+
+ if (set_ras_addr_hook)
+ return set_ras_addr_hook(pskb, ct, ctinfo, data,
+ &lrq->replyAddress, 1);
+ return 0;
+}
+
+/****************************************************************************/
+static int process_lcf(struct sk_buff **pskb, struct ip_conntrack *ct,
+ enum ip_conntrack_info ctinfo,
+ unsigned char **data, LocationConfirm * lcf)
+{
+ int dir = CTINFO2DIR(ctinfo);
+ int ret = 0;
+ u_int32_t ip;
+ u_int16_t port;
+ struct ip_conntrack_expect *exp = NULL;
+
+ DEBUGP("ip_ct_ras: LCF\n");
+
+ if (!get_h225_addr(*data, &lcf->callSignalAddress, &ip, &port))
+ return 0;
+
+ /* Need new expect for call signal */
+ if ((exp = ip_conntrack_expect_alloc(ct)) == NULL)
+ return -1;
+ exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip;
+ exp->tuple.src.u.tcp.port = 0;
+ exp->tuple.dst.ip = ip;
+ exp->tuple.dst.u.tcp.port = htons(port);
+ exp->tuple.dst.protonum = IPPROTO_TCP;
+ exp->mask.src.ip = 0xFFFFFFFF;
+ exp->mask.src.u.tcp.port = 0;
+ exp->mask.dst.ip = 0xFFFFFFFF;
+ exp->mask.dst.u.tcp.port = 0xFFFF;
+ exp->mask.dst.protonum = 0xFF;
+ exp->flags = IP_CT_EXPECT_PERMANENT;
+ exp->expectfn = ip_conntrack_q931_expect;
+
+ if (ip_conntrack_expect_related(exp) == 0) {
+ DEBUGP("ip_ct_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));
+ } else
+ ret = -1;
+
+ ip_conntrack_expect_put(exp);
+
+ /* Ignore rasAddress */
+
+ return ret;
+}
+
+/****************************************************************************/
+static int process_irr(struct sk_buff **pskb, struct ip_conntrack *ct,
+ enum ip_conntrack_info ctinfo,
+ unsigned char **data, InfoRequestResponse * irr)
+{
+ int ret;
+
+ DEBUGP("ip_ct_ras: IRR\n");
+
+ if (set_ras_addr_hook) {
+ ret = set_ras_addr_hook(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);
+ if (ret < 0)
+ return -1;
+ }
+
+ return 0;
+}
+
+/****************************************************************************/
+static int process_ras(struct sk_buff **pskb, struct ip_conntrack *ct,
+ enum ip_conntrack_info ctinfo,
+ unsigned char **data, RasMessage * ras)
+{
+ switch (ras->choice) {
+ case eRasMessage_gatekeeperRequest:
+ return process_grq(pskb, ct, ctinfo, data,
+ &ras->gatekeeperRequest);
+ case eRasMessage_gatekeeperConfirm:
+ return process_gcf(pskb, ct, ctinfo, data,
+ &ras->gatekeeperConfirm);
+ case eRasMessage_registrationRequest:
+ return process_rrq(pskb, ct, ctinfo, data,
+ &ras->registrationRequest);
+ case eRasMessage_registrationConfirm:
+ return process_rcf(pskb, ct, ctinfo, data,
+ &ras->registrationConfirm);
+ case eRasMessage_unregistrationRequest:
+ return process_urq(pskb, ct, ctinfo, data,
+ &ras->unregistrationRequest);
+ case eRasMessage_admissionRequest:
+ return process_arq(pskb, ct, ctinfo, data,
+ &ras->admissionRequest);
+ case eRasMessage_admissionConfirm:
+ return process_acf(pskb, ct, ctinfo, data,
+ &ras->admissionConfirm);
+ case eRasMessage_locationRequest:
+ return process_lrq(pskb, ct, ctinfo, data,
+ &ras->locationRequest);
+ case eRasMessage_locationConfirm:
+ return process_lcf(pskb, ct, ctinfo, data,
+ &ras->locationConfirm);
+ case eRasMessage_infoRequestResponse:
+ return process_irr(pskb, ct, ctinfo, data,
+ &ras->infoRequestResponse);
+ default:
+ DEBUGP("ip_ct_ras: RAS message %d\n", ras->choice);
+ break;
+ }
+
+ return 0;
+}
+
+/****************************************************************************/
+static int ras_help(struct sk_buff **pskb, struct ip_conntrack *ct,
+ enum ip_conntrack_info ctinfo)
+{
+ static RasMessage ras;
+ unsigned char *data;
+ int datalen = 0;
+ int ret;
+
+ DEBUGP("ip_ct_ras: skblen = %u\n", (*pskb)->len);
+
+ spin_lock_bh(&ip_h323_lock);
+
+ /* Get UDP data */
+ data = get_udp_data(pskb, &datalen);
+ if (data == NULL)
+ goto accept;
+ DEBUGP("ip_ct_ras: RAS message %u.%u.%u.%u->%u.%u.%u.%u, len=%d\n",
+ NIPQUAD((*pskb)->nh.iph->saddr),
+ NIPQUAD((*pskb)->nh.iph->daddr), datalen);
+
+ /* Decode RAS message */
+ ret = DecodeRasMessage(data, datalen, &ras);
+ if (ret < 0) {
+ if (net_ratelimit())
+ printk("ip_ct_ras: decoding error: %s\n",
+ ret == H323_ERROR_BOUND ?
+ "out of bound" : "out of range");
+ goto accept;
+ }
+
+ /* Process RAS message */
+ if (process_ras(pskb, ct, ctinfo, &data, &ras) < 0)
+ goto drop;
+
+ accept:
+ spin_unlock_bh(&ip_h323_lock);
+ return NF_ACCEPT;
+
+ drop:
+ spin_unlock_bh(&ip_h323_lock);
+ if (net_ratelimit())
+ printk("ip_ct_ras: packet dropped\n");
+ return NF_DROP;
+}
+
+/****************************************************************************/
+static struct ip_conntrack_helper ip_conntrack_helper_ras = {
+ .name = "RAS",
+ .me = THIS_MODULE,
+ .max_expected = 32,
+ .timeout = 240,
+ .tuple = {.src = {.u = {__constant_htons(RAS_PORT)}},
+ .dst = {.protonum = IPPROTO_UDP}},
+ .mask = {.src = {.u = {0xFFFE}},
+ .dst = {.protonum = 0xFF}},
+ .help = ras_help,
+};
+
+/****************************************************************************/
+static void ip_conntrack_ras_expect(struct ip_conntrack *new,
+ struct ip_conntrack_expect *this)
+{
+ write_lock_bh(&ip_conntrack_lock);
+ new->helper = &ip_conntrack_helper_ras;
+ write_unlock_bh(&ip_conntrack_lock);
+}
+
+/****************************************************************************/
+/* Not __exit - called from init() */
+static void fini(void)
+{
+ ip_conntrack_helper_unregister(&ip_conntrack_helper_ras);
+ ip_conntrack_helper_unregister(&ip_conntrack_helper_q931);
+ kfree(h323_buffer);
+ DEBUGP("ip_ct_h323: fini\n");
+}
+
+/****************************************************************************/
+static int __init init(void)
+{
+ int ret;
+
+ h323_buffer = kmalloc(65536, GFP_KERNEL);
+ if (!h323_buffer)
+ return -ENOMEM;
+ if ((ret = ip_conntrack_helper_register(&ip_conntrack_helper_q931)) ||
+ (ret = ip_conntrack_helper_register(&ip_conntrack_helper_ras))) {
+ fini();
+ return ret;
+ }
+
+ DEBUGP("ip_ct_h323: init success\n");
+ return 0;
+}
+
+/****************************************************************************/
+module_init(init);
+module_exit(fini);
+
+EXPORT_SYMBOL(get_h245_addr);
+EXPORT_SYMBOL(get_h225_addr);
+EXPORT_SYMBOL(ip_conntrack_h245_expect);
+EXPORT_SYMBOL(ip_conntrack_q931_expect);
+EXPORT_SYMBOL(set_h245_addr_hook);
+EXPORT_SYMBOL(set_h225_addr_hook);
+EXPORT_SYMBOL(set_sig_addr_hook);
+EXPORT_SYMBOL(set_ras_addr_hook);
+EXPORT_SYMBOL(nat_rtp_rtcp_hook);
+EXPORT_SYMBOL(nat_t120_hook);
+EXPORT_SYMBOL(nat_h245_hook);
+EXPORT_SYMBOL(nat_q931_hook);
+
+MODULE_AUTHOR("Jing Min Zhao <zhaojingmin@users.sourceforge.net>");
+MODULE_DESCRIPTION("H.323 connection tracking helper");
+MODULE_LICENSE("GPL");
diff --git a/net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.c b/net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.c
new file mode 100644
index 000000000000..afa525129b51
--- /dev/null
+++ b/net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.c
@@ -0,0 +1,870 @@
+/****************************************************************************
+ * ip_conntrack_helper_h323_asn1.c - BER and PER decoding library for H.323
+ * conntrack/NAT module.
+ *
+ * Copyright (c) 2006 by Jing Min Zhao <zhaojingmin@hotmail.com>
+ *
+ * This source code is licensed under General Public License version 2.
+ *
+ * See ip_conntrack_helper_h323_asn1.h for details.
+ *
+ ****************************************************************************/
+
+#ifdef __KERNEL__
+#include <linux/kernel.h>
+#else
+#include <stdio.h>
+#endif
+#include "ip_conntrack_helper_h323_asn1.h"
+
+/* 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_STOP)
+ return err;
+
+ bs->cur = beg + len;
+ bs->bit = 0;
+ } else if ((err = (Decoders[son->type]) (bs, son, base,
+ level + 1)))
+ 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 (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_STOP)
+ 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_STOP)
+ return err;
+
+ bs->cur = beg + len;
+ bs->bit = 0;
+ } else
+ if ((err = (Decoders[son->type]) (bs, son,
+ i < effective_count ?
+ base : NULL,
+ level + 1)))
+ 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);
+ }
+
+ /* 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;
+ }
+
+ /* Write Type */
+ if (base)
+ *(unsigned *) base = type;
+
+ /* 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_STOP)
+ return err;
+
+ bs->cur = beg + len;
+ bs->bit = 0;
+ } else if ((err = (Decoders[son->type]) (bs, son, base, level + 1)))
+ 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_asn1.h b/net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.h
new file mode 100644
index 000000000000..0bd828081c0c
--- /dev/null
+++ b/net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.h
@@ -0,0 +1,98 @@
+/****************************************************************************
+ * ip_conntrack_helper_h323_asn1.h - BER and PER decoding library for H.323
+ * conntrack/NAT module.
+ *
+ * Copyright (c) 2006 by Jing Min Zhao <zhaojingmin@hotmail.com>
+ *
+ * This source code is licensed under General Public License version 2.
+ *
+ *
+ * This library is based on H.225 version 4, H.235 version 2 and H.245
+ * version 7. It is extremely optimized to decode only the absolutely
+ * necessary objects in a signal for Linux kernel NAT module use, so don't
+ * expect it to be a full ASN.1 library.
+ *
+ * Features:
+ *
+ * 1. Small. The total size of code plus data is less than 20 KB (IA32).
+ * 2. Fast. Decoding Netmeeting's Setup signal 1 million times on a PIII 866
+ * takes only 3.9 seconds.
+ * 3. No memory allocation. It uses a static object. No need to initialize or
+ * cleanup.
+ * 4. Thread safe.
+ * 5. Support embedded architectures that has no misaligned memory access
+ * support.
+ *
+ * Limitations:
+ *
+ * 1. At most 30 faststart entries. Actually this is limited by ethernet's MTU.
+ * If a Setup signal contains more than 30 faststart, the packet size will
+ * very likely exceed the MTU size, then the TPKT will be fragmented. I
+ * don't know how to handle this in a Netfilter module. Anybody can help?
+ * Although I think 30 is enough for most of the cases.
+ * 2. IPv4 addresses only.
+ *
+ ****************************************************************************/
+
+#ifndef _IP_CONNTRACK_HELPER_H323_ASN1_H_
+#define _IP_CONNTRACK_HELPER_H323_ASN1_H_
+
+/*****************************************************************************
+ * H.323 Types
+ ****************************************************************************/
+#include "ip_conntrack_helper_h323_types.h"
+
+typedef struct {
+ enum {
+ Q931_NationalEscape = 0x00,
+ Q931_Alerting = 0x01,
+ Q931_CallProceeding = 0x02,
+ Q931_Connect = 0x07,
+ Q931_ConnectAck = 0x0F,
+ Q931_Progress = 0x03,
+ Q931_Setup = 0x05,
+ Q931_SetupAck = 0x0D,
+ Q931_Resume = 0x26,
+ Q931_ResumeAck = 0x2E,
+ Q931_ResumeReject = 0x22,
+ Q931_Suspend = 0x25,
+ Q931_SuspendAck = 0x2D,
+ Q931_SuspendReject = 0x21,
+ Q931_UserInformation = 0x20,
+ Q931_Disconnect = 0x45,
+ Q931_Release = 0x4D,
+ Q931_ReleaseComplete = 0x5A,
+ Q931_Restart = 0x46,
+ Q931_RestartAck = 0x4E,
+ Q931_Segment = 0x60,
+ Q931_CongestionCtrl = 0x79,
+ Q931_Information = 0x7B,
+ Q931_Notify = 0x6E,
+ Q931_Status = 0x7D,
+ Q931_StatusEnquiry = 0x75,
+ Q931_Facility = 0x62
+ } MessageType;
+ H323_UserInformation UUIE;
+} Q931;
+
+/*****************************************************************************
+ * Decode Functions Return Codes
+ ****************************************************************************/
+
+#define H323_ERROR_NONE 0 /* Decoded successfully */
+#define H323_ERROR_STOP 1 /* Decoding stopped, not really an error */
+#define H323_ERROR_BOUND -1
+#define H323_ERROR_RANGE -2
+
+
+/*****************************************************************************
+ * Decode Functions
+ ****************************************************************************/
+
+int DecodeRasMessage(unsigned char *buf, size_t sz, RasMessage * ras);
+int DecodeQ931(unsigned char *buf, size_t sz, Q931 * q931);
+int DecodeMultimediaSystemControlMessage(unsigned char *buf, size_t sz,
+ MultimediaSystemControlMessage *
+ mscm);
+
+#endif
diff --git a/net/ipv4/netfilter/ip_conntrack_helper_h323_types.c b/net/ipv4/netfilter/ip_conntrack_helper_h323_types.c
new file mode 100644
index 000000000000..022c47b9f6c9
--- /dev/null
+++ b/net/ipv4/netfilter/ip_conntrack_helper_h323_types.c
@@ -0,0 +1,1926 @@
+/* Generated by Jing Min Zhao's ASN.1 parser, Mar 15 2006
+ *
+ * Copyright (c) 2006 Jing Min Zhao <zhaojingmin@users.sourceforge.net>
+ *
+ * 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, SKIP | EXT | OPT, 0,
+ _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/ip_conntrack_helper_h323_types.h b/net/ipv4/netfilter/ip_conntrack_helper_h323_types.h
new file mode 100644
index 000000000000..cc98f7aa5abe
--- /dev/null
+++ b/net/ipv4/netfilter/ip_conntrack_helper_h323_types.h
@@ -0,0 +1,938 @@
+/* Generated by Jing Min Zhao's ASN.1 parser, Mar 15 2006
+ *
+ * Copyright (c) 2006 Jing Min Zhao <zhaojingmin@users.sourceforge.net>
+ *
+ * This source code is licensed under General Public License version 2.
+ */
+
+typedef struct TransportAddress_ipAddress { /* SEQUENCE */
+ int options; /* No use */
+ unsigned ip;
+} TransportAddress_ipAddress;
+
+typedef struct TransportAddress { /* CHOICE */
+ enum {
+ eTransportAddress_ipAddress,
+ eTransportAddress_ipSourceRoute,
+ eTransportAddress_ipxAddress,
+ eTransportAddress_ip6Address,
+ eTransportAddress_netBios,
+ eTransportAddress_nsap,
+ eTransportAddress_nonStandardAddress,
+ } choice;
+ union {
+ TransportAddress_ipAddress ipAddress;
+ };
+} TransportAddress;
+
+typedef struct DataProtocolCapability { /* CHOICE */
+ enum {
+ eDataProtocolCapability_nonStandard,
+ eDataProtocolCapability_v14buffered,
+ eDataProtocolCapability_v42lapm,
+ eDataProtocolCapability_hdlcFrameTunnelling,
+ eDataProtocolCapability_h310SeparateVCStack,
+ eDataProtocolCapability_h310SingleVCStack,
+ eDataProtocolCapability_transparent,
+ eDataProtocolCapability_segmentationAndReassembly,
+ eDataProtocolCapability_hdlcFrameTunnelingwSAR,
+ eDataProtocolCapability_v120,
+ eDataProtocolCapability_separateLANStack,
+ eDataProtocolCapability_v76wCompression,
+ eDataProtocolCapability_tcp,
+ eDataProtocolCapability_udp,
+ } choice;
+} DataProtocolCapability;
+
+typedef struct DataApplicationCapability_application { /* CHOICE */
+ enum {
+ eDataApplicationCapability_application_nonStandard,
+ eDataApplicationCapability_application_t120,
+ eDataApplicationCapability_application_dsm_cc,
+ eDataApplicationCapability_application_userData,
+ eDataApplicationCapability_application_t84,
+ eDataApplicationCapability_application_t434,
+ eDataApplicationCapability_application_h224,
+ eDataApplicationCapability_application_nlpid,
+ eDataApplicationCapability_application_dsvdControl,
+ eDataApplicationCapability_application_h222DataPartitioning,
+ eDataApplicationCapability_application_t30fax,
+ eDataApplicationCapability_application_t140,
+ eDataApplicationCapability_application_t38fax,
+ eDataApplicationCapability_application_genericDataCapability,
+ } choice;
+ union {
+ DataProtocolCapability t120;
+ };
+} DataApplicationCapability_application;
+
+typedef struct DataApplicationCapability { /* SEQUENCE */
+ int options; /* No use */
+ DataApplicationCapability_application application;
+} DataApplicationCapability;
+
+typedef struct DataType { /* CHOICE */
+ enum {
+ eDataType_nonStandard,
+ eDataType_nullData,
+ eDataType_videoData,
+ eDataType_audioData,
+ eDataType_data,
+ eDataType_encryptionData,
+ eDataType_h235Control,
+ eDataType_h235Media,
+ eDataType_multiplexedStream,
+ } choice;
+ union {
+ DataApplicationCapability data;
+ };
+} DataType;
+
+typedef struct UnicastAddress_iPAddress { /* SEQUENCE */
+ int options; /* No use */
+ unsigned network;
+} UnicastAddress_iPAddress;
+
+typedef struct UnicastAddress { /* CHOICE */
+ enum {
+ eUnicastAddress_iPAddress,
+ eUnicastAddress_iPXAddress,
+ eUnicastAddress_iP6Address,
+ eUnicastAddress_netBios,
+ eUnicastAddress_iPSourceRouteAddress,
+ eUnicastAddress_nsap,
+ eUnicastAddress_nonStandardAddress,
+ } choice;
+ union {
+ UnicastAddress_iPAddress iPAddress;
+ };
+} UnicastAddress;
+
+typedef struct H245_TransportAddress { /* CHOICE */
+ enum {
+ eH245_TransportAddress_unicastAddress,
+ eH245_TransportAddress_multicastAddress,
+ } choice;
+ union {
+ UnicastAddress unicastAddress;
+ };
+} H245_TransportAddress;
+
+typedef struct H2250LogicalChannelParameters { /* SEQUENCE */
+ enum {
+ eH2250LogicalChannelParameters_nonStandard = (1 << 31),
+ eH2250LogicalChannelParameters_associatedSessionID =
+ (1 << 30),
+ eH2250LogicalChannelParameters_mediaChannel = (1 << 29),
+ eH2250LogicalChannelParameters_mediaGuaranteedDelivery =
+ (1 << 28),
+ eH2250LogicalChannelParameters_mediaControlChannel =
+ (1 << 27),
+ eH2250LogicalChannelParameters_mediaControlGuaranteedDelivery
+ = (1 << 26),
+ eH2250LogicalChannelParameters_silenceSuppression = (1 << 25),
+ eH2250LogicalChannelParameters_destination = (1 << 24),
+ eH2250LogicalChannelParameters_dynamicRTPPayloadType =
+ (1 << 23),
+ eH2250LogicalChannelParameters_mediaPacketization = (1 << 22),
+ eH2250LogicalChannelParameters_transportCapability =
+ (1 << 21),
+ eH2250LogicalChannelParameters_redundancyEncoding = (1 << 20),
+ eH2250LogicalChannelParameters_source = (1 << 19),
+ } options;
+ H245_TransportAddress mediaChannel;
+ H245_TransportAddress mediaControlChannel;
+} H2250LogicalChannelParameters;
+
+typedef struct OpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters { /* CHOICE */
+ enum {
+ eOpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters_h222LogicalChannelParameters,
+ eOpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters_h223LogicalChannelParameters,
+ eOpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters_v76LogicalChannelParameters,
+ eOpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters_h2250LogicalChannelParameters,
+ eOpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters_none,
+ } choice;
+ union {
+ H2250LogicalChannelParameters h2250LogicalChannelParameters;
+ };
+} OpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters;
+
+typedef struct OpenLogicalChannel_forwardLogicalChannelParameters { /* SEQUENCE */
+ enum {
+ eOpenLogicalChannel_forwardLogicalChannelParameters_portNumber
+ = (1 << 31),
+ eOpenLogicalChannel_forwardLogicalChannelParameters_forwardLogicalChannelDependency
+ = (1 << 30),
+ eOpenLogicalChannel_forwardLogicalChannelParameters_replacementFor
+ = (1 << 29),
+ } options;
+ DataType dataType;
+ OpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters
+ multiplexParameters;
+} OpenLogicalChannel_forwardLogicalChannelParameters;
+
+typedef struct OpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters { /* CHOICE */
+ enum {
+ eOpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters_h223LogicalChannelParameters,
+ eOpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters_v76LogicalChannelParameters,
+ eOpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters_h2250LogicalChannelParameters,
+ } choice;
+ union {
+ H2250LogicalChannelParameters h2250LogicalChannelParameters;
+ };
+} OpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters;
+
+typedef struct OpenLogicalChannel_reverseLogicalChannelParameters { /* SEQUENCE */
+ enum {
+ eOpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters
+ = (1 << 31),
+ eOpenLogicalChannel_reverseLogicalChannelParameters_reverseLogicalChannelDependency
+ = (1 << 30),
+ eOpenLogicalChannel_reverseLogicalChannelParameters_replacementFor
+ = (1 << 29),
+ } options;
+ OpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters
+ multiplexParameters;
+} OpenLogicalChannel_reverseLogicalChannelParameters;
+
+typedef struct NetworkAccessParameters_networkAddress { /* CHOICE */
+ enum {
+ eNetworkAccessParameters_networkAddress_q2931Address,
+ eNetworkAccessParameters_networkAddress_e164Address,
+ eNetworkAccessParameters_networkAddress_localAreaAddress,
+ } choice;
+ union {
+ H245_TransportAddress localAreaAddress;
+ };
+} NetworkAccessParameters_networkAddress;
+
+typedef struct NetworkAccessParameters { /* SEQUENCE */
+ enum {
+ eNetworkAccessParameters_distribution = (1 << 31),
+ eNetworkAccessParameters_externalReference = (1 << 30),
+ eNetworkAccessParameters_t120SetupProcedure = (1 << 29),
+ } options;
+ NetworkAccessParameters_networkAddress networkAddress;
+} NetworkAccessParameters;
+
+typedef struct OpenLogicalChannel { /* SEQUENCE */
+ enum {
+ eOpenLogicalChannel_reverseLogicalChannelParameters =
+ (1 << 31),
+ eOpenLogicalChannel_separateStack = (1 << 30),
+ eOpenLogicalChannel_encryptionSync = (1 << 29),
+ } options;
+ OpenLogicalChannel_forwardLogicalChannelParameters
+ forwardLogicalChannelParameters;
+ OpenLogicalChannel_reverseLogicalChannelParameters
+ reverseLogicalChannelParameters;
+ NetworkAccessParameters separateStack;
+} OpenLogicalChannel;
+
+typedef struct Setup_UUIE_fastStart { /* SEQUENCE OF */
+ int count;
+ OpenLogicalChannel item[30];
+} Setup_UUIE_fastStart;
+
+typedef struct Setup_UUIE { /* SEQUENCE */
+ enum {
+ eSetup_UUIE_h245Address = (1 << 31),
+ eSetup_UUIE_sourceAddress = (1 << 30),
+ eSetup_UUIE_destinationAddress = (1 << 29),
+ eSetup_UUIE_destCallSignalAddress = (1 << 28),
+ eSetup_UUIE_destExtraCallInfo = (1 << 27),
+ eSetup_UUIE_destExtraCRV = (1 << 26),
+ eSetup_UUIE_callServices = (1 << 25),
+ eSetup_UUIE_sourceCallSignalAddress = (1 << 24),
+ eSetup_UUIE_remoteExtensionAddress = (1 << 23),
+ eSetup_UUIE_callIdentifier = (1 << 22),
+ eSetup_UUIE_h245SecurityCapability = (1 << 21),
+ eSetup_UUIE_tokens = (1 << 20),
+ eSetup_UUIE_cryptoTokens = (1 << 19),
+ eSetup_UUIE_fastStart = (1 << 18),
+ eSetup_UUIE_mediaWaitForConnect = (1 << 17),
+ eSetup_UUIE_canOverlapSend = (1 << 16),
+ eSetup_UUIE_endpointIdentifier = (1 << 15),
+ eSetup_UUIE_multipleCalls = (1 << 14),
+ eSetup_UUIE_maintainConnection = (1 << 13),
+ eSetup_UUIE_connectionParameters = (1 << 12),
+ eSetup_UUIE_language = (1 << 11),
+ eSetup_UUIE_presentationIndicator = (1 << 10),
+ eSetup_UUIE_screeningIndicator = (1 << 9),
+ eSetup_UUIE_serviceControl = (1 << 8),
+ eSetup_UUIE_symmetricOperationRequired = (1 << 7),
+ eSetup_UUIE_capacity = (1 << 6),
+ eSetup_UUIE_circuitInfo = (1 << 5),
+ eSetup_UUIE_desiredProtocols = (1 << 4),
+ eSetup_UUIE_neededFeatures = (1 << 3),
+ eSetup_UUIE_desiredFeatures = (1 << 2),
+ eSetup_UUIE_supportedFeatures = (1 << 1),
+ eSetup_UUIE_parallelH245Control = (1 << 0),
+ } options;
+ TransportAddress h245Address;
+ TransportAddress destCallSignalAddress;
+ TransportAddress sourceCallSignalAddress;
+ Setup_UUIE_fastStart fastStart;
+} Setup_UUIE;
+
+typedef struct CallProceeding_UUIE_fastStart { /* SEQUENCE OF */
+ int count;
+ OpenLogicalChannel item[30];
+} CallProceeding_UUIE_fastStart;
+
+typedef struct CallProceeding_UUIE { /* SEQUENCE */
+ enum {
+ eCallProceeding_UUIE_h245Address = (1 << 31),
+ eCallProceeding_UUIE_callIdentifier = (1 << 30),
+ eCallProceeding_UUIE_h245SecurityMode = (1 << 29),
+ eCallProceeding_UUIE_tokens = (1 << 28),
+ eCallProceeding_UUIE_cryptoTokens = (1 << 27),
+ eCallProceeding_UUIE_fastStart = (1 << 26),
+ eCallProceeding_UUIE_multipleCalls = (1 << 25),
+ eCallProceeding_UUIE_maintainConnection = (1 << 24),
+ eCallProceeding_UUIE_fastConnectRefused = (1 << 23),
+ eCallProceeding_UUIE_featureSet = (1 << 22),
+ } options;
+ TransportAddress h245Address;
+ CallProceeding_UUIE_fastStart fastStart;
+} CallProceeding_UUIE;
+
+typedef struct Connect_UUIE_fastStart { /* SEQUENCE OF */
+ int count;
+ OpenLogicalChannel item[30];
+} Connect_UUIE_fastStart;
+
+typedef struct Connect_UUIE { /* SEQUENCE */
+ enum {
+ eConnect_UUIE_h245Address = (1 << 31),
+ eConnect_UUIE_callIdentifier = (1 << 30),
+ eConnect_UUIE_h245SecurityMode = (1 << 29),
+ eConnect_UUIE_tokens = (1 << 28),
+ eConnect_UUIE_cryptoTokens = (1 << 27),
+ eConnect_UUIE_fastStart = (1 << 26),
+ eConnect_UUIE_multipleCalls = (1 << 25),
+ eConnect_UUIE_maintainConnection = (1 << 24),
+ eConnect_UUIE_language = (1 << 23),
+ eConnect_UUIE_connectedAddress = (1 << 22),
+ eConnect_UUIE_presentationIndicator = (1 << 21),
+ eConnect_UUIE_screeningIndicator = (1 << 20),
+ eConnect_UUIE_fastConnectRefused = (1 << 19),
+ eConnect_UUIE_serviceControl = (1 << 18),
+ eConnect_UUIE_capacity = (1 << 17),
+ eConnect_UUIE_featureSet = (1 << 16),
+ } options;
+ TransportAddress h245Address;
+ Connect_UUIE_fastStart fastStart;
+} Connect_UUIE;
+
+typedef struct Alerting_UUIE_fastStart { /* SEQUENCE OF */
+ int count;
+ OpenLogicalChannel item[30];
+} Alerting_UUIE_fastStart;
+
+typedef struct Alerting_UUIE { /* SEQUENCE */
+ enum {
+ eAlerting_UUIE_h245Address = (1 << 31),
+ eAlerting_UUIE_callIdentifier = (1 << 30),
+ eAlerting_UUIE_h245SecurityMode = (1 << 29),
+ eAlerting_UUIE_tokens = (1 << 28),
+ eAlerting_UUIE_cryptoTokens = (1 << 27),
+ eAlerting_UUIE_fastStart = (1 << 26),
+ eAlerting_UUIE_multipleCalls = (1 << 25),
+ eAlerting_UUIE_maintainConnection = (1 << 24),
+ eAlerting_UUIE_alertingAddress = (1 << 23),
+ eAlerting_UUIE_presentationIndicator = (1 << 22),
+ eAlerting_UUIE_screeningIndicator = (1 << 21),
+ eAlerting_UUIE_fastConnectRefused = (1 << 20),
+ eAlerting_UUIE_serviceControl = (1 << 19),
+ eAlerting_UUIE_capacity = (1 << 18),
+ eAlerting_UUIE_featureSet = (1 << 17),
+ } options;
+ TransportAddress h245Address;
+ Alerting_UUIE_fastStart fastStart;
+} Alerting_UUIE;
+
+typedef struct Information_UUIE_fastStart { /* SEQUENCE OF */
+ int count;
+ OpenLogicalChannel item[30];
+} Information_UUIE_fastStart;
+
+typedef struct Information_UUIE { /* SEQUENCE */
+ enum {
+ eInformation_UUIE_callIdentifier = (1 << 31),
+ eInformation_UUIE_tokens = (1 << 30),
+ eInformation_UUIE_cryptoTokens = (1 << 29),
+ eInformation_UUIE_fastStart = (1 << 28),
+ eInformation_UUIE_fastConnectRefused = (1 << 27),
+ eInformation_UUIE_circuitInfo = (1 << 26),
+ } options;
+ Information_UUIE_fastStart fastStart;
+} Information_UUIE;
+
+typedef struct FacilityReason { /* CHOICE */
+ enum {
+ eFacilityReason_routeCallToGatekeeper,
+ eFacilityReason_callForwarded,
+ eFacilityReason_routeCallToMC,
+ eFacilityReason_undefinedReason,
+ eFacilityReason_conferenceListChoice,
+ eFacilityReason_startH245,
+ eFacilityReason_noH245,
+ eFacilityReason_newTokens,
+ eFacilityReason_featureSetUpdate,
+ eFacilityReason_forwardedElements,
+ eFacilityReason_transportedInformation,
+ } choice;
+} FacilityReason;
+
+typedef struct Facility_UUIE_fastStart { /* SEQUENCE OF */
+ int count;
+ OpenLogicalChannel item[30];
+} Facility_UUIE_fastStart;
+
+typedef struct Facility_UUIE { /* SEQUENCE */
+ enum {
+ eFacility_UUIE_alternativeAddress = (1 << 31),
+ eFacility_UUIE_alternativeAliasAddress = (1 << 30),
+ eFacility_UUIE_conferenceID = (1 << 29),
+ eFacility_UUIE_callIdentifier = (1 << 28),
+ eFacility_UUIE_destExtraCallInfo = (1 << 27),
+ eFacility_UUIE_remoteExtensionAddress = (1 << 26),
+ eFacility_UUIE_tokens = (1 << 25),
+ eFacility_UUIE_cryptoTokens = (1 << 24),
+ eFacility_UUIE_conferences = (1 << 23),
+ eFacility_UUIE_h245Address = (1 << 22),
+ eFacility_UUIE_fastStart = (1 << 21),
+ eFacility_UUIE_multipleCalls = (1 << 20),
+ eFacility_UUIE_maintainConnection = (1 << 19),
+ eFacility_UUIE_fastConnectRefused = (1 << 18),
+ eFacility_UUIE_serviceControl = (1 << 17),
+ eFacility_UUIE_circuitInfo = (1 << 16),
+ eFacility_UUIE_featureSet = (1 << 15),
+ eFacility_UUIE_destinationInfo = (1 << 14),
+ eFacility_UUIE_h245SecurityMode = (1 << 13),
+ } options;
+ FacilityReason reason;
+ TransportAddress h245Address;
+ Facility_UUIE_fastStart fastStart;
+} Facility_UUIE;
+
+typedef struct Progress_UUIE_fastStart { /* SEQUENCE OF */
+ int count;
+ OpenLogicalChannel item[30];
+} Progress_UUIE_fastStart;
+
+typedef struct Progress_UUIE { /* SEQUENCE */
+ enum {
+ eProgress_UUIE_h245Address = (1 << 31),
+ eProgress_UUIE_h245SecurityMode = (1 << 30),
+ eProgress_UUIE_tokens = (1 << 29),
+ eProgress_UUIE_cryptoTokens = (1 << 28),
+ eProgress_UUIE_fastStart = (1 << 27),
+ eProgress_UUIE_multipleCalls = (1 << 26),
+ eProgress_UUIE_maintainConnection = (1 << 25),
+ eProgress_UUIE_fastConnectRefused = (1 << 24),
+ } options;
+ TransportAddress h245Address;
+ Progress_UUIE_fastStart fastStart;
+} Progress_UUIE;
+
+typedef struct H323_UU_PDU_h323_message_body { /* CHOICE */
+ enum {
+ eH323_UU_PDU_h323_message_body_setup,
+ eH323_UU_PDU_h323_message_body_callProceeding,
+ eH323_UU_PDU_h323_message_body_connect,
+ eH323_UU_PDU_h323_message_body_alerting,
+ eH323_UU_PDU_h323_message_body_information,
+ eH323_UU_PDU_h323_message_body_releaseComplete,
+ eH323_UU_PDU_h323_message_body_facility,
+ eH323_UU_PDU_h323_message_body_progress,
+ eH323_UU_PDU_h323_message_body_empty,
+ eH323_UU_PDU_h323_message_body_status,
+ eH323_UU_PDU_h323_message_body_statusInquiry,
+ eH323_UU_PDU_h323_message_body_setupAcknowledge,
+ eH323_UU_PDU_h323_message_body_notify,
+ } choice;
+ union {
+ Setup_UUIE setup;
+ CallProceeding_UUIE callProceeding;
+ Connect_UUIE connect;
+ Alerting_UUIE alerting;
+ Information_UUIE information;
+ Facility_UUIE facility;
+ Progress_UUIE progress;
+ };
+} H323_UU_PDU_h323_message_body;
+
+typedef struct RequestMessage { /* CHOICE */
+ enum {
+ eRequestMessage_nonStandard,
+ eRequestMessage_masterSlaveDetermination,
+ eRequestMessage_terminalCapabilitySet,
+ eRequestMessage_openLogicalChannel,
+ eRequestMessage_closeLogicalChannel,
+ eRequestMessage_requestChannelClose,
+ eRequestMessage_multiplexEntrySend,
+ eRequestMessage_requestMultiplexEntry,
+ eRequestMessage_requestMode,
+ eRequestMessage_roundTripDelayRequest,
+ eRequestMessage_maintenanceLoopRequest,
+ eRequestMessage_communicationModeRequest,
+ eRequestMessage_conferenceRequest,
+ eRequestMessage_multilinkRequest,
+ eRequestMessage_logicalChannelRateRequest,
+ } choice;
+ union {
+ OpenLogicalChannel openLogicalChannel;
+ };
+} RequestMessage;
+
+typedef struct OpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters { /* CHOICE */
+ enum {
+ eOpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters_h222LogicalChannelParameters,
+ eOpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters_h2250LogicalChannelParameters,
+ } choice;
+ union {
+ H2250LogicalChannelParameters h2250LogicalChannelParameters;
+ };
+} OpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters;
+
+typedef struct OpenLogicalChannelAck_reverseLogicalChannelParameters { /* SEQUENCE */
+ enum {
+ eOpenLogicalChannelAck_reverseLogicalChannelParameters_portNumber
+ = (1 << 31),
+ eOpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters
+ = (1 << 30),
+ eOpenLogicalChannelAck_reverseLogicalChannelParameters_replacementFor
+ = (1 << 29),
+ } options;
+ OpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters
+ multiplexParameters;
+} OpenLogicalChannelAck_reverseLogicalChannelParameters;
+
+typedef struct H2250LogicalChannelAckParameters { /* SEQUENCE */
+ enum {
+ eH2250LogicalChannelAckParameters_nonStandard = (1 << 31),
+ eH2250LogicalChannelAckParameters_sessionID = (1 << 30),
+ eH2250LogicalChannelAckParameters_mediaChannel = (1 << 29),
+ eH2250LogicalChannelAckParameters_mediaControlChannel =
+ (1 << 28),
+ eH2250LogicalChannelAckParameters_dynamicRTPPayloadType =
+ (1 << 27),
+ eH2250LogicalChannelAckParameters_flowControlToZero =
+ (1 << 26),
+ eH2250LogicalChannelAckParameters_portNumber = (1 << 25),
+ } options;
+ H245_TransportAddress mediaChannel;
+ H245_TransportAddress mediaControlChannel;
+} H2250LogicalChannelAckParameters;
+
+typedef struct OpenLogicalChannelAck_forwardMultiplexAckParameters { /* CHOICE */
+ enum {
+ eOpenLogicalChannelAck_forwardMultiplexAckParameters_h2250LogicalChannelAckParameters,
+ } choice;
+ union {
+ H2250LogicalChannelAckParameters
+ h2250LogicalChannelAckParameters;
+ };
+} OpenLogicalChannelAck_forwardMultiplexAckParameters;
+
+typedef struct OpenLogicalChannelAck { /* SEQUENCE */
+ enum {
+ eOpenLogicalChannelAck_reverseLogicalChannelParameters =
+ (1 << 31),
+ eOpenLogicalChannelAck_separateStack = (1 << 30),
+ eOpenLogicalChannelAck_forwardMultiplexAckParameters =
+ (1 << 29),
+ eOpenLogicalChannelAck_encryptionSync = (1 << 28),
+ } options;
+ OpenLogicalChannelAck_reverseLogicalChannelParameters
+ reverseLogicalChannelParameters;
+ OpenLogicalChannelAck_forwardMultiplexAckParameters
+ forwardMultiplexAckParameters;
+} OpenLogicalChannelAck;
+
+typedef struct ResponseMessage { /* CHOICE */
+ enum {
+ eResponseMessage_nonStandard,
+ eResponseMessage_masterSlaveDeterminationAck,
+ eResponseMessage_masterSlaveDeterminationReject,
+ eResponseMessage_terminalCapabilitySetAck,
+ eResponseMessage_terminalCapabilitySetReject,
+ eResponseMessage_openLogicalChannelAck,
+ eResponseMessage_openLogicalChannelReject,
+ eResponseMessage_closeLogicalChannelAck,
+ eResponseMessage_requestChannelCloseAck,
+ eResponseMessage_requestChannelCloseReject,
+ eResponseMessage_multiplexEntrySendAck,
+ eResponseMessage_multiplexEntrySendReject,
+ eResponseMessage_requestMultiplexEntryAck,
+ eResponseMessage_requestMultiplexEntryReject,
+ eResponseMessage_requestModeAck,
+ eResponseMessage_requestModeReject,
+ eResponseMessage_roundTripDelayResponse,
+ eResponseMessage_maintenanceLoopAck,
+ eResponseMessage_maintenanceLoopReject,
+ eResponseMessage_communicationModeResponse,
+ eResponseMessage_conferenceResponse,
+ eResponseMessage_multilinkResponse,
+ eResponseMessage_logicalChannelRateAcknowledge,
+ eResponseMessage_logicalChannelRateReject,
+ } choice;
+ union {
+ OpenLogicalChannelAck openLogicalChannelAck;
+ };
+} ResponseMessage;
+
+typedef struct MultimediaSystemControlMessage { /* CHOICE */
+ enum {
+ eMultimediaSystemControlMessage_request,
+ eMultimediaSystemControlMessage_response,
+ eMultimediaSystemControlMessage_command,
+ eMultimediaSystemControlMessage_indication,
+ } choice;
+ union {
+ RequestMessage request;
+ ResponseMessage response;
+ };
+} MultimediaSystemControlMessage;
+
+typedef struct H323_UU_PDU_h245Control { /* SEQUENCE OF */
+ int count;
+ MultimediaSystemControlMessage item[4];
+} H323_UU_PDU_h245Control;
+
+typedef struct H323_UU_PDU { /* SEQUENCE */
+ enum {
+ eH323_UU_PDU_nonStandardData = (1 << 31),
+ eH323_UU_PDU_h4501SupplementaryService = (1 << 30),
+ eH323_UU_PDU_h245Tunneling = (1 << 29),
+ eH323_UU_PDU_h245Control = (1 << 28),
+ eH323_UU_PDU_nonStandardControl = (1 << 27),
+ eH323_UU_PDU_callLinkage = (1 << 26),
+ eH323_UU_PDU_tunnelledSignallingMessage = (1 << 25),
+ eH323_UU_PDU_provisionalRespToH245Tunneling = (1 << 24),
+ eH323_UU_PDU_stimulusControl = (1 << 23),
+ eH323_UU_PDU_genericData = (1 << 22),
+ } options;
+ H323_UU_PDU_h323_message_body h323_message_body;
+ H323_UU_PDU_h245Control h245Control;
+} H323_UU_PDU;
+
+typedef struct H323_UserInformation { /* SEQUENCE */
+ enum {
+ eH323_UserInformation_user_data = (1 << 31),
+ } options;
+ H323_UU_PDU h323_uu_pdu;
+} H323_UserInformation;
+
+typedef struct GatekeeperRequest { /* SEQUENCE */
+ enum {
+ eGatekeeperRequest_nonStandardData = (1 << 31),
+ eGatekeeperRequest_gatekeeperIdentifier = (1 << 30),
+ eGatekeeperRequest_callServices = (1 << 29),
+ eGatekeeperRequest_endpointAlias = (1 << 28),
+ eGatekeeperRequest_alternateEndpoints = (1 << 27),
+ eGatekeeperRequest_tokens = (1 << 26),
+ eGatekeeperRequest_cryptoTokens = (1 << 25),
+ eGatekeeperRequest_authenticationCapability = (1 << 24),
+ eGatekeeperRequest_algorithmOIDs = (1 << 23),
+ eGatekeeperRequest_integrity = (1 << 22),
+ eGatekeeperRequest_integrityCheckValue = (1 << 21),
+ eGatekeeperRequest_supportsAltGK = (1 << 20),
+ eGatekeeperRequest_featureSet = (1 << 19),
+ eGatekeeperRequest_genericData = (1 << 18),
+ } options;
+ TransportAddress rasAddress;
+} GatekeeperRequest;
+
+typedef struct GatekeeperConfirm { /* SEQUENCE */
+ enum {
+ eGatekeeperConfirm_nonStandardData = (1 << 31),
+ eGatekeeperConfirm_gatekeeperIdentifier = (1 << 30),
+ eGatekeeperConfirm_alternateGatekeeper = (1 << 29),
+ eGatekeeperConfirm_authenticationMode = (1 << 28),
+ eGatekeeperConfirm_tokens = (1 << 27),
+ eGatekeeperConfirm_cryptoTokens = (1 << 26),
+ eGatekeeperConfirm_algorithmOID = (1 << 25),
+ eGatekeeperConfirm_integrity = (1 << 24),
+ eGatekeeperConfirm_integrityCheckValue = (1 << 23),
+ eGatekeeperConfirm_featureSet = (1 << 22),
+ eGatekeeperConfirm_genericData = (1 << 21),
+ } options;
+ TransportAddress rasAddress;
+} GatekeeperConfirm;
+
+typedef struct RegistrationRequest_callSignalAddress { /* SEQUENCE OF */
+ int count;
+ TransportAddress item[10];
+} RegistrationRequest_callSignalAddress;
+
+typedef struct RegistrationRequest_rasAddress { /* SEQUENCE OF */
+ int count;
+ TransportAddress item[10];
+} RegistrationRequest_rasAddress;
+
+typedef struct RegistrationRequest { /* SEQUENCE */
+ enum {
+ eRegistrationRequest_nonStandardData = (1 << 31),
+ eRegistrationRequest_terminalAlias = (1 << 30),
+ eRegistrationRequest_gatekeeperIdentifier = (1 << 29),
+ eRegistrationRequest_alternateEndpoints = (1 << 28),
+ eRegistrationRequest_timeToLive = (1 << 27),
+ eRegistrationRequest_tokens = (1 << 26),
+ eRegistrationRequest_cryptoTokens = (1 << 25),
+ eRegistrationRequest_integrityCheckValue = (1 << 24),
+ eRegistrationRequest_keepAlive = (1 << 23),
+ eRegistrationRequest_endpointIdentifier = (1 << 22),
+ eRegistrationRequest_willSupplyUUIEs = (1 << 21),
+ eRegistrationRequest_maintainConnection = (1 << 20),
+ eRegistrationRequest_alternateTransportAddresses = (1 << 19),
+ eRegistrationRequest_additiveRegistration = (1 << 18),
+ eRegistrationRequest_terminalAliasPattern = (1 << 17),
+ eRegistrationRequest_supportsAltGK = (1 << 16),
+ eRegistrationRequest_usageReportingCapability = (1 << 15),
+ eRegistrationRequest_multipleCalls = (1 << 14),
+ eRegistrationRequest_supportedH248Packages = (1 << 13),
+ eRegistrationRequest_callCreditCapability = (1 << 12),
+ eRegistrationRequest_capacityReportingCapability = (1 << 11),
+ eRegistrationRequest_capacity = (1 << 10),
+ eRegistrationRequest_featureSet = (1 << 9),
+ eRegistrationRequest_genericData = (1 << 8),
+ } options;
+ RegistrationRequest_callSignalAddress callSignalAddress;
+ RegistrationRequest_rasAddress rasAddress;
+ unsigned timeToLive;
+} RegistrationRequest;
+
+typedef struct RegistrationConfirm_callSignalAddress { /* SEQUENCE OF */
+ int count;
+ TransportAddress item[10];
+} RegistrationConfirm_callSignalAddress;
+
+typedef struct RegistrationConfirm { /* SEQUENCE */
+ enum {
+ eRegistrationConfirm_nonStandardData = (1 << 31),
+ eRegistrationConfirm_terminalAlias = (1 << 30),
+ eRegistrationConfirm_gatekeeperIdentifier = (1 << 29),
+ eRegistrationConfirm_alternateGatekeeper = (1 << 28),
+ eRegistrationConfirm_timeToLive = (1 << 27),
+ eRegistrationConfirm_tokens = (1 << 26),
+ eRegistrationConfirm_cryptoTokens = (1 << 25),
+ eRegistrationConfirm_integrityCheckValue = (1 << 24),
+ eRegistrationConfirm_willRespondToIRR = (1 << 23),
+ eRegistrationConfirm_preGrantedARQ = (1 << 22),
+ eRegistrationConfirm_maintainConnection = (1 << 21),
+ eRegistrationConfirm_serviceControl = (1 << 20),
+ eRegistrationConfirm_supportsAdditiveRegistration = (1 << 19),
+ eRegistrationConfirm_terminalAliasPattern = (1 << 18),
+ eRegistrationConfirm_supportedPrefixes = (1 << 17),
+ eRegistrationConfirm_usageSpec = (1 << 16),
+ eRegistrationConfirm_featureServerAlias = (1 << 15),
+ eRegistrationConfirm_capacityReportingSpec = (1 << 14),
+ eRegistrationConfirm_featureSet = (1 << 13),
+ eRegistrationConfirm_genericData = (1 << 12),
+ } options;
+ RegistrationConfirm_callSignalAddress callSignalAddress;
+ unsigned timeToLive;
+} RegistrationConfirm;
+
+typedef struct UnregistrationRequest_callSignalAddress { /* SEQUENCE OF */
+ int count;
+ TransportAddress item[10];
+} UnregistrationRequest_callSignalAddress;
+
+typedef struct UnregistrationRequest { /* SEQUENCE */
+ enum {
+ eUnregistrationRequest_endpointAlias = (1 << 31),
+ eUnregistrationRequest_nonStandardData = (1 << 30),
+ eUnregistrationRequest_endpointIdentifier = (1 << 29),
+ eUnregistrationRequest_alternateEndpoints = (1 << 28),
+ eUnregistrationRequest_gatekeeperIdentifier = (1 << 27),
+ eUnregistrationRequest_tokens = (1 << 26),
+ eUnregistrationRequest_cryptoTokens = (1 << 25),
+ eUnregistrationRequest_integrityCheckValue = (1 << 24),
+ eUnregistrationRequest_reason = (1 << 23),
+ eUnregistrationRequest_endpointAliasPattern = (1 << 22),
+ eUnregistrationRequest_supportedPrefixes = (1 << 21),
+ eUnregistrationRequest_alternateGatekeeper = (1 << 20),
+ eUnregistrationRequest_genericData = (1 << 19),
+ } options;
+ UnregistrationRequest_callSignalAddress callSignalAddress;
+} UnregistrationRequest;
+
+typedef struct AdmissionRequest { /* SEQUENCE */
+ enum {
+ eAdmissionRequest_callModel = (1 << 31),
+ eAdmissionRequest_destinationInfo = (1 << 30),
+ eAdmissionRequest_destCallSignalAddress = (1 << 29),
+ eAdmissionRequest_destExtraCallInfo = (1 << 28),
+ eAdmissionRequest_srcCallSignalAddress = (1 << 27),
+ eAdmissionRequest_nonStandardData = (1 << 26),
+ eAdmissionRequest_callServices = (1 << 25),
+ eAdmissionRequest_canMapAlias = (1 << 24),
+ eAdmissionRequest_callIdentifier = (1 << 23),
+ eAdmissionRequest_srcAlternatives = (1 << 22),
+ eAdmissionRequest_destAlternatives = (1 << 21),
+ eAdmissionRequest_gatekeeperIdentifier = (1 << 20),
+ eAdmissionRequest_tokens = (1 << 19),
+ eAdmissionRequest_cryptoTokens = (1 << 18),
+ eAdmissionRequest_integrityCheckValue = (1 << 17),
+ eAdmissionRequest_transportQOS = (1 << 16),
+ eAdmissionRequest_willSupplyUUIEs = (1 << 15),
+ eAdmissionRequest_callLinkage = (1 << 14),
+ eAdmissionRequest_gatewayDataRate = (1 << 13),
+ eAdmissionRequest_capacity = (1 << 12),
+ eAdmissionRequest_circuitInfo = (1 << 11),
+ eAdmissionRequest_desiredProtocols = (1 << 10),
+ eAdmissionRequest_desiredTunnelledProtocol = (1 << 9),
+ eAdmissionRequest_featureSet = (1 << 8),
+ eAdmissionRequest_genericData = (1 << 7),
+ } options;
+ TransportAddress destCallSignalAddress;
+ TransportAddress srcCallSignalAddress;
+} AdmissionRequest;
+
+typedef struct AdmissionConfirm { /* SEQUENCE */
+ enum {
+ eAdmissionConfirm_irrFrequency = (1 << 31),
+ eAdmissionConfirm_nonStandardData = (1 << 30),
+ eAdmissionConfirm_destinationInfo = (1 << 29),
+ eAdmissionConfirm_destExtraCallInfo = (1 << 28),
+ eAdmissionConfirm_destinationType = (1 << 27),
+ eAdmissionConfirm_remoteExtensionAddress = (1 << 26),
+ eAdmissionConfirm_alternateEndpoints = (1 << 25),
+ eAdmissionConfirm_tokens = (1 << 24),
+ eAdmissionConfirm_cryptoTokens = (1 << 23),
+ eAdmissionConfirm_integrityCheckValue = (1 << 22),
+ eAdmissionConfirm_transportQOS = (1 << 21),
+ eAdmissionConfirm_willRespondToIRR = (1 << 20),
+ eAdmissionConfirm_uuiesRequested = (1 << 19),
+ eAdmissionConfirm_language = (1 << 18),
+ eAdmissionConfirm_alternateTransportAddresses = (1 << 17),
+ eAdmissionConfirm_useSpecifiedTransport = (1 << 16),
+ eAdmissionConfirm_circuitInfo = (1 << 15),
+ eAdmissionConfirm_usageSpec = (1 << 14),
+ eAdmissionConfirm_supportedProtocols = (1 << 13),
+ eAdmissionConfirm_serviceControl = (1 << 12),
+ eAdmissionConfirm_multipleCalls = (1 << 11),
+ eAdmissionConfirm_featureSet = (1 << 10),
+ eAdmissionConfirm_genericData = (1 << 9),
+ } options;
+ TransportAddress destCallSignalAddress;
+} AdmissionConfirm;
+
+typedef struct LocationRequest { /* SEQUENCE */
+ enum {
+ eLocationRequest_endpointIdentifier = (1 << 31),
+ eLocationRequest_nonStandardData = (1 << 30),
+ eLocationRequest_sourceInfo = (1 << 29),
+ eLocationRequest_canMapAlias = (1 << 28),
+ eLocationRequest_gatekeeperIdentifier = (1 << 27),
+ eLocationRequest_tokens = (1 << 26),
+ eLocationRequest_cryptoTokens = (1 << 25),
+ eLocationRequest_integrityCheckValue = (1 << 24),
+ eLocationRequest_desiredProtocols = (1 << 23),
+ eLocationRequest_desiredTunnelledProtocol = (1 << 22),
+ eLocationRequest_featureSet = (1 << 21),
+ eLocationRequest_genericData = (1 << 20),
+ eLocationRequest_hopCount = (1 << 19),
+ eLocationRequest_circuitInfo = (1 << 18),
+ } options;
+ TransportAddress replyAddress;
+} LocationRequest;
+
+typedef struct LocationConfirm { /* SEQUENCE */
+ enum {
+ eLocationConfirm_nonStandardData = (1 << 31),
+ eLocationConfirm_destinationInfo = (1 << 30),
+ eLocationConfirm_destExtraCallInfo = (1 << 29),
+ eLocationConfirm_destinationType = (1 << 28),
+ eLocationConfirm_remoteExtensionAddress = (1 << 27),
+ eLocationConfirm_alternateEndpoints = (1 << 26),
+ eLocationConfirm_tokens = (1 << 25),
+ eLocationConfirm_cryptoTokens = (1 << 24),
+ eLocationConfirm_integrityCheckValue = (1 << 23),
+ eLocationConfirm_alternateTransportAddresses = (1 << 22),
+ eLocationConfirm_supportedProtocols = (1 << 21),
+ eLocationConfirm_multipleCalls = (1 << 20),
+ eLocationConfirm_featureSet = (1 << 19),
+ eLocationConfirm_genericData = (1 << 18),
+ eLocationConfirm_circuitInfo = (1 << 17),
+ eLocationConfirm_serviceControl = (1 << 16),
+ } options;
+ TransportAddress callSignalAddress;
+ TransportAddress rasAddress;
+} LocationConfirm;
+
+typedef struct InfoRequestResponse_callSignalAddress { /* SEQUENCE OF */
+ int count;
+ TransportAddress item[10];
+} InfoRequestResponse_callSignalAddress;
+
+typedef struct InfoRequestResponse { /* SEQUENCE */
+ enum {
+ eInfoRequestResponse_nonStandardData = (1 << 31),
+ eInfoRequestResponse_endpointAlias = (1 << 30),
+ eInfoRequestResponse_perCallInfo = (1 << 29),
+ eInfoRequestResponse_tokens = (1 << 28),
+ eInfoRequestResponse_cryptoTokens = (1 << 27),
+ eInfoRequestResponse_integrityCheckValue = (1 << 26),
+ eInfoRequestResponse_needResponse = (1 << 25),
+ eInfoRequestResponse_capacity = (1 << 24),
+ eInfoRequestResponse_irrStatus = (1 << 23),
+ eInfoRequestResponse_unsolicited = (1 << 22),
+ eInfoRequestResponse_genericData = (1 << 21),
+ } options;
+ TransportAddress rasAddress;
+ InfoRequestResponse_callSignalAddress callSignalAddress;
+} InfoRequestResponse;
+
+typedef struct RasMessage { /* CHOICE */
+ enum {
+ eRasMessage_gatekeeperRequest,
+ eRasMessage_gatekeeperConfirm,
+ eRasMessage_gatekeeperReject,
+ eRasMessage_registrationRequest,
+ eRasMessage_registrationConfirm,
+ eRasMessage_registrationReject,
+ eRasMessage_unregistrationRequest,
+ eRasMessage_unregistrationConfirm,
+ eRasMessage_unregistrationReject,
+ eRasMessage_admissionRequest,
+ eRasMessage_admissionConfirm,
+ eRasMessage_admissionReject,
+ eRasMessage_bandwidthRequest,
+ eRasMessage_bandwidthConfirm,
+ eRasMessage_bandwidthReject,
+ eRasMessage_disengageRequest,
+ eRasMessage_disengageConfirm,
+ eRasMessage_disengageReject,
+ eRasMessage_locationRequest,
+ eRasMessage_locationConfirm,
+ eRasMessage_locationReject,
+ eRasMessage_infoRequest,
+ eRasMessage_infoRequestResponse,
+ eRasMessage_nonStandardMessage,
+ eRasMessage_unknownMessageResponse,
+ eRasMessage_requestInProgress,
+ eRasMessage_resourcesAvailableIndicate,
+ eRasMessage_resourcesAvailableConfirm,
+ eRasMessage_infoRequestAck,
+ eRasMessage_infoRequestNak,
+ eRasMessage_serviceControlIndication,
+ eRasMessage_serviceControlResponse,
+ } choice;
+ union {
+ GatekeeperRequest gatekeeperRequest;
+ GatekeeperConfirm gatekeeperConfirm;
+ RegistrationRequest registrationRequest;
+ RegistrationConfirm registrationConfirm;
+ UnregistrationRequest unregistrationRequest;
+ AdmissionRequest admissionRequest;
+ AdmissionConfirm admissionConfirm;
+ LocationRequest locationRequest;
+ LocationConfirm locationConfirm;
+ InfoRequestResponse infoRequestResponse;
+ };
+} RasMessage;
diff --git a/net/ipv4/netfilter/ip_conntrack_netlink.c b/net/ipv4/netfilter/ip_conntrack_netlink.c
index e0b5926c76f9..9b6e19bae90f 100644
--- a/net/ipv4/netfilter/ip_conntrack_netlink.c
+++ b/net/ipv4/netfilter/ip_conntrack_netlink.c
@@ -4,7 +4,7 @@
* (C) 2001 by Jay Schulist <jschlst@samba.org>
* (C) 2002-2005 by Harald Welte <laforge@gnumonks.org>
* (C) 2003 by Patrick Mchardy <kaber@trash.net>
- * (C) 2005 by Pablo Neira Ayuso <pablo@eurodev.net>
+ * (C) 2005-2006 by Pablo Neira Ayuso <pablo@eurodev.net>
*
* I've reworked this stuff to use attributes instead of conntrack
* structures. 5.44 am. I need more tea. --pablo 05/07/11.
@@ -53,20 +53,18 @@ static char __initdata version[] = "0.90";
static inline int
ctnetlink_dump_tuples_proto(struct sk_buff *skb,
- const struct ip_conntrack_tuple *tuple)
+ const struct ip_conntrack_tuple *tuple,
+ struct ip_conntrack_protocol *proto)
{
- struct ip_conntrack_protocol *proto;
int ret = 0;
+ struct nfattr *nest_parms = NFA_NEST(skb, CTA_TUPLE_PROTO);
NFA_PUT(skb, CTA_PROTO_NUM, sizeof(u_int8_t), &tuple->dst.protonum);
- /* If no protocol helper is found, this function will return the
- * generic protocol helper, so proto won't *ever* be NULL */
- proto = ip_conntrack_proto_find_get(tuple->dst.protonum);
if (likely(proto->tuple_to_nfattr))
ret = proto->tuple_to_nfattr(skb, tuple);
- ip_conntrack_proto_put(proto);
+ NFA_NEST_END(skb, nest_parms);
return ret;
@@ -75,28 +73,41 @@ nfattr_failure:
}
static inline int
-ctnetlink_dump_tuples(struct sk_buff *skb,
- const struct ip_conntrack_tuple *tuple)
+ctnetlink_dump_tuples_ip(struct sk_buff *skb,
+ const struct ip_conntrack_tuple *tuple)
{
- struct nfattr *nest_parms;
- int ret;
+ struct nfattr *nest_parms = NFA_NEST(skb, CTA_TUPLE_IP);
- nest_parms = NFA_NEST(skb, CTA_TUPLE_IP);
NFA_PUT(skb, CTA_IP_V4_SRC, sizeof(u_int32_t), &tuple->src.ip);
NFA_PUT(skb, CTA_IP_V4_DST, sizeof(u_int32_t), &tuple->dst.ip);
- NFA_NEST_END(skb, nest_parms);
- nest_parms = NFA_NEST(skb, CTA_TUPLE_PROTO);
- ret = ctnetlink_dump_tuples_proto(skb, tuple);
NFA_NEST_END(skb, nest_parms);
- return ret;
+ return 0;
nfattr_failure:
return -1;
}
static inline int
+ctnetlink_dump_tuples(struct sk_buff *skb,
+ const struct ip_conntrack_tuple *tuple)
+{
+ int ret;
+ struct ip_conntrack_protocol *proto;
+
+ ret = ctnetlink_dump_tuples_ip(skb, tuple);
+ if (unlikely(ret < 0))
+ return ret;
+
+ proto = ip_conntrack_proto_find_get(tuple->dst.protonum);
+ ret = ctnetlink_dump_tuples_proto(skb, tuple, proto);
+ ip_conntrack_proto_put(proto);
+
+ return ret;
+}
+
+static inline int
ctnetlink_dump_status(struct sk_buff *skb, const struct ip_conntrack *ct)
{
u_int32_t status = htonl((u_int32_t) ct->status);
@@ -327,9 +338,10 @@ static int ctnetlink_conntrack_event(struct notifier_block *this,
group = NFNLGRP_CONNTRACK_UPDATE;
} else
return NOTIFY_DONE;
-
- /* FIXME: Check if there are any listeners before, don't hurt performance */
-
+
+ if (!nfnetlink_has_listeners(group))
+ return NOTIFY_DONE;
+
skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC);
if (!skb)
return NOTIFY_DONE;
@@ -1134,6 +1146,33 @@ nfattr_failure:
}
static inline int
+ctnetlink_exp_dump_mask(struct sk_buff *skb,
+ const struct ip_conntrack_tuple *tuple,
+ const struct ip_conntrack_tuple *mask)
+{
+ int ret;
+ struct ip_conntrack_protocol *proto;
+ struct nfattr *nest_parms = NFA_NEST(skb, CTA_EXPECT_MASK);
+
+ ret = ctnetlink_dump_tuples_ip(skb, mask);
+ if (unlikely(ret < 0))
+ goto nfattr_failure;
+
+ proto = ip_conntrack_proto_find_get(tuple->dst.protonum);
+ ret = ctnetlink_dump_tuples_proto(skb, mask, proto);
+ ip_conntrack_proto_put(proto);
+ if (unlikely(ret < 0))
+ goto nfattr_failure;
+
+ NFA_NEST_END(skb, nest_parms);
+
+ return 0;
+
+nfattr_failure:
+ return -1;
+}
+
+static inline int
ctnetlink_exp_dump_expect(struct sk_buff *skb,
const struct ip_conntrack_expect *exp)
{
@@ -1143,7 +1182,7 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb,
if (ctnetlink_exp_dump_tuple(skb, &exp->tuple, CTA_EXPECT_TUPLE) < 0)
goto nfattr_failure;
- if (ctnetlink_exp_dump_tuple(skb, &exp->mask, CTA_EXPECT_MASK) < 0)
+ if (ctnetlink_exp_dump_mask(skb, &exp->tuple, &exp->mask) < 0)
goto nfattr_failure;
if (ctnetlink_exp_dump_tuple(skb,
&master->tuplehash[IP_CT_DIR_ORIGINAL].tuple,
diff --git a/net/ipv4/netfilter/ip_nat_helper_h323.c b/net/ipv4/netfilter/ip_nat_helper_h323.c
new file mode 100644
index 000000000000..a0bc883928c0
--- /dev/null
+++ b/net/ipv4/netfilter/ip_nat_helper_h323.c
@@ -0,0 +1,605 @@
+/*
+ * H.323 extension for NAT alteration.
+ *
+ * Copyright (c) 2006 Jing Min Zhao <zhaojingmin@users.sourceforge.net>
+ *
+ * This source code is licensed under General Public License version 2.
+ *
+ * Based on the 'brute force' H.323 NAT module by
+ * Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+ *
+ * Changes:
+ * 2006-02-01 - initial version 0.1
+ *
+ * 2006-02-20 - version 0.2
+ * 1. Changed source format to follow kernel conventions
+ * 2. Deleted some unnecessary structures
+ * 3. Minor fixes
+ *
+ * 2006-03-10 - version 0.3
+ * 1. Added support for multiple TPKTs in one packet (suggested by
+ * Patrick McHardy)
+ * 2. Added support for non-linear skb (based on Patrick McHardy's patch)
+ * 3. Eliminated unnecessary return code
+ *
+ * 2006-03-15 - version 0.4
+ * 1. Added support for T.120 channels
+ * 2. Added parameter gkrouted_only (suggested by Patrick McHardy)
+ */
+
+#include <linux/module.h>
+#include <linux/netfilter_ipv4.h>
+#include <linux/netfilter.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/moduleparam.h>
+#include <net/tcp.h>
+#include <linux/netfilter_ipv4/ip_nat.h>
+#include <linux/netfilter_ipv4/ip_nat_helper.h>
+#include <linux/netfilter_ipv4/ip_nat_rule.h>
+#include <linux/netfilter_ipv4/ip_conntrack_tuple.h>
+#include <linux/netfilter_ipv4/ip_conntrack_h323.h>
+#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
+
+#include "ip_conntrack_helper_h323_asn1.h"
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+extern int get_h245_addr(unsigned char *data, H245_TransportAddress * addr,
+ u_int32_t * ip, u_int16_t * port);
+extern int get_h225_addr(unsigned char *data, TransportAddress * addr,
+ u_int32_t * ip, u_int16_t * port);
+extern void ip_conntrack_h245_expect(struct ip_conntrack *new,
+ struct ip_conntrack_expect *this);
+extern void ip_conntrack_q931_expect(struct ip_conntrack *new,
+ struct ip_conntrack_expect *this);
+extern int (*set_h245_addr_hook) (struct sk_buff ** pskb,
+ unsigned char **data, int dataoff,
+ H245_TransportAddress * addr,
+ u_int32_t ip, u_int16_t port);
+extern int (*set_h225_addr_hook) (struct sk_buff ** pskb,
+ unsigned char **data, int dataoff,
+ TransportAddress * addr,
+ u_int32_t ip, u_int16_t port);
+extern int (*set_sig_addr_hook) (struct sk_buff ** pskb,
+ struct ip_conntrack * ct,
+ enum ip_conntrack_info ctinfo,
+ unsigned char **data,
+ TransportAddress * addr, int count);
+extern int (*set_ras_addr_hook) (struct sk_buff ** pskb,
+ struct ip_conntrack * ct,
+ enum ip_conntrack_info ctinfo,
+ unsigned char **data,
+ TransportAddress * addr, int count);
+extern int (*nat_rtp_rtcp_hook) (struct sk_buff ** pskb,
+ struct ip_conntrack * ct,
+ enum ip_conntrack_info ctinfo,
+ unsigned char **data, int dataoff,
+ H245_TransportAddress * addr,
+ u_int16_t port, u_int16_t rtp_port,
+ struct ip_conntrack_expect * rtp_exp,
+ struct ip_conntrack_expect * rtcp_exp);
+extern int (*nat_t120_hook) (struct sk_buff ** pskb, struct ip_conntrack * ct,
+ enum ip_conntrack_info ctinfo,
+ unsigned char **data, int dataoff,
+ H245_TransportAddress * addr, u_int16_t port,
+ struct ip_conntrack_expect * exp);
+extern int (*nat_h245_hook) (struct sk_buff ** pskb, struct ip_conntrack * ct,
+ enum ip_conntrack_info ctinfo,
+ unsigned char **data, int dataoff,
+ TransportAddress * addr, u_int16_t port,
+ struct ip_conntrack_expect * exp);
+extern int (*nat_q931_hook) (struct sk_buff ** pskb, struct ip_conntrack * ct,
+ enum ip_conntrack_info ctinfo,
+ unsigned char **data, TransportAddress * addr,
+ int idx, u_int16_t port,
+ struct ip_conntrack_expect * exp);
+
+
+/****************************************************************************/
+static int set_addr(struct sk_buff **pskb,
+ unsigned char **data, int dataoff,
+ unsigned int addroff, u_int32_t ip, u_int16_t port)
+{
+ enum ip_conntrack_info ctinfo;
+ struct ip_conntrack *ct = ip_conntrack_get(*pskb, &ctinfo);
+ struct {
+ u_int32_t ip;
+ u_int16_t port;
+ } __attribute__ ((__packed__)) buf;
+ struct tcphdr _tcph, *th;
+
+ buf.ip = ip;
+ buf.port = htons(port);
+ addroff += dataoff;
+
+ if ((*pskb)->nh.iph->protocol == IPPROTO_TCP) {
+ if (!ip_nat_mangle_tcp_packet(pskb, ct, ctinfo,
+ addroff, sizeof(buf),
+ (char *) &buf, sizeof(buf))) {
+ if (net_ratelimit())
+ printk("ip_nat_h323: ip_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 (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo,
+ addroff, sizeof(buf),
+ (char *) &buf, sizeof(buf))) {
+ if (net_ratelimit())
+ printk("ip_nat_h323: ip_nat_mangle_udp_packet"
+ " error\n");
+ return -1;
+ }
+ /* ip_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 * addr,
+ u_int32_t ip, u_int16_t port)
+{
+ return set_addr(pskb, data, dataoff, addr->ipAddress.ip, ip, port);
+}
+
+/****************************************************************************/
+static int set_h245_addr(struct sk_buff **pskb,
+ unsigned char **data, int dataoff,
+ H245_TransportAddress * addr,
+ u_int32_t ip, u_int16_t port)
+{
+ return set_addr(pskb, data, dataoff,
+ addr->unicastAddress.iPAddress.network, ip, port);
+}
+
+/****************************************************************************/
+static int set_sig_addr(struct sk_buff **pskb, struct ip_conntrack *ct,
+ enum ip_conntrack_info ctinfo,
+ unsigned char **data,
+ TransportAddress * addr, int count)
+{
+ struct ip_ct_h323_master *info = &ct->help.ct_h323_info;
+ int dir = CTINFO2DIR(ctinfo);
+ int i;
+ u_int32_t ip;
+ u_int16_t port;
+
+ for (i = 0; i < count; i++) {
+ if (get_h225_addr(*data, &addr[i], &ip, &port)) {
+ if (ip == ct->tuplehash[dir].tuple.src.ip &&
+ port == info->sig_port[dir]) {
+ /* GW->GK */
+
+ /* Fix for Gnomemeeting */
+ if (i > 0 &&
+ get_h225_addr(*data, &addr[0],
+ &ip, &port) &&
+ (ntohl(ip) & 0xff000000) == 0x7f000000)
+ i = 0;
+
+ DEBUGP
+ ("ip_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, &addr[i],
+ ct->tuplehash[!dir].
+ tuple.dst.ip,
+ info->sig_port[!dir]);
+ } else if (ip == ct->tuplehash[dir].tuple.dst.ip &&
+ port == info->sig_port[dir]) {
+ /* GK->GW */
+ DEBUGP
+ ("ip_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, &addr[i],
+ ct->tuplehash[!dir].
+ tuple.src.ip,
+ info->sig_port[!dir]);
+ }
+ }
+ }
+
+ return 0;
+}
+
+/****************************************************************************/
+static int set_ras_addr(struct sk_buff **pskb, struct ip_conntrack *ct,
+ enum ip_conntrack_info ctinfo,
+ unsigned char **data,
+ TransportAddress * addr, int count)
+{
+ int dir = CTINFO2DIR(ctinfo);
+ int i;
+ u_int32_t ip;
+ u_int16_t port;
+
+ for (i = 0; i < count; i++) {
+ if (get_h225_addr(*data, &addr[i], &ip, &port) &&
+ ip == ct->tuplehash[dir].tuple.src.ip &&
+ port == ntohs(ct->tuplehash[dir].tuple.src.u.udp.port)) {
+ DEBUGP("ip_nat_ras: set rasAddress "
+ "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
+ NIPQUAD(ip), port,
+ NIPQUAD(ct->tuplehash[!dir].tuple.dst.ip),
+ ntohs(ct->tuplehash[!dir].tuple.dst.u.udp.
+ port));
+ return set_h225_addr(pskb, data, 0, &addr[i],
+ ct->tuplehash[!dir].tuple.dst.ip,
+ ntohs(ct->tuplehash[!dir].tuple.
+ dst.u.udp.port));
+ }
+ }
+
+ return 0;
+}
+
+/****************************************************************************/
+static int nat_rtp_rtcp(struct sk_buff **pskb, struct ip_conntrack *ct,
+ enum ip_conntrack_info ctinfo,
+ unsigned char **data, int dataoff,
+ H245_TransportAddress * addr,
+ u_int16_t port, u_int16_t rtp_port,
+ struct ip_conntrack_expect *rtp_exp,
+ struct ip_conntrack_expect *rtcp_exp)
+{
+ struct ip_ct_h323_master *info = &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 = ip_nat_follow_master;
+ rtp_exp->dir = !dir;
+ rtcp_exp->saved_proto.udp.port = rtcp_exp->tuple.dst.u.udp.port;
+ rtcp_exp->expectfn = ip_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 =
+ htons(info->rtp_port[i][dir]);
+ rtcp_exp->tuple.dst.u.udp.port =
+ htons(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("ip_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 (ip_conntrack_expect_related(rtp_exp) == 0) {
+ rtcp_exp->tuple.dst.u.udp.port =
+ htons(nated_port + 1);
+ if (ip_conntrack_expect_related(rtcp_exp) == 0)
+ break;
+ ip_conntrack_unexpect_related(rtp_exp);
+ }
+ }
+
+ if (nated_port == 0) { /* No port available */
+ if (net_ratelimit())
+ printk("ip_nat_h323: out of RTP ports\n");
+ return 0;
+ }
+
+ /* Modify signal */
+ if (set_h245_addr(pskb, data, dataoff, addr,
+ ct->tuplehash[!dir].tuple.dst.ip,
+ (port & 1) ? nated_port + 1 : nated_port) == 0) {
+ /* Save ports */
+ info->rtp_port[i][dir] = rtp_port;
+ info->rtp_port[i][!dir] = nated_port;
+ } else {
+ ip_conntrack_unexpect_related(rtp_exp);
+ ip_conntrack_unexpect_related(rtcp_exp);
+ return -1;
+ }
+
+ /* Success */
+ DEBUGP("ip_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("ip_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 ip_conntrack *ct,
+ enum ip_conntrack_info ctinfo,
+ unsigned char **data, int dataoff,
+ H245_TransportAddress * addr, u_int16_t port,
+ struct ip_conntrack_expect *exp)
+{
+ int dir = CTINFO2DIR(ctinfo);
+ u_int16_t nated_port = port;
+
+ /* Set expectations for NAT */
+ exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
+ exp->expectfn = ip_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 (ip_conntrack_expect_related(exp) == 0)
+ break;
+ }
+
+ if (nated_port == 0) { /* No port available */
+ if (net_ratelimit())
+ printk("ip_nat_h323: out of TCP ports\n");
+ return 0;
+ }
+
+ /* Modify signal */
+ if (set_h245_addr(pskb, data, dataoff, addr,
+ ct->tuplehash[!dir].tuple.dst.ip, nated_port) < 0) {
+ ip_conntrack_unexpect_related(exp);
+ return -1;
+ }
+
+ DEBUGP("ip_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;
+}
+
+/****************************************************************************
+ * This conntrack expect function replaces ip_conntrack_h245_expect()
+ * which was set by ip_conntrack_helper_h323.c. It calls both
+ * ip_nat_follow_master() and ip_conntrack_h245_expect()
+ ****************************************************************************/
+static void ip_nat_h245_expect(struct ip_conntrack *new,
+ struct ip_conntrack_expect *this)
+{
+ ip_nat_follow_master(new, this);
+ ip_conntrack_h245_expect(new, this);
+}
+
+/****************************************************************************/
+static int nat_h245(struct sk_buff **pskb, struct ip_conntrack *ct,
+ enum ip_conntrack_info ctinfo,
+ unsigned char **data, int dataoff,
+ TransportAddress * addr, u_int16_t port,
+ struct ip_conntrack_expect *exp)
+{
+ struct ip_ct_h323_master *info = &ct->help.ct_h323_info;
+ int dir = CTINFO2DIR(ctinfo);
+ u_int16_t nated_port = port;
+
+ /* Set expectations for NAT */
+ exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
+ exp->expectfn = ip_nat_h245_expect;
+ exp->dir = !dir;
+
+ /* Check existing expects */
+ if (info->sig_port[dir] == port)
+ nated_port = 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 (ip_conntrack_expect_related(exp) == 0)
+ break;
+ }
+
+ if (nated_port == 0) { /* No port available */
+ if (net_ratelimit())
+ printk("ip_nat_q931: out of TCP ports\n");
+ return 0;
+ }
+
+ /* Modify signal */
+ if (set_h225_addr(pskb, data, dataoff, addr,
+ ct->tuplehash[!dir].tuple.dst.ip,
+ nated_port) == 0) {
+ /* Save ports */
+ info->sig_port[dir] = port;
+ info->sig_port[!dir] = nated_port;
+ } else {
+ ip_conntrack_unexpect_related(exp);
+ return -1;
+ }
+
+ DEBUGP("ip_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 ip_conntrack_q931_expect()
+ * which was set by ip_conntrack_helper_h323.c.
+ ****************************************************************************/
+static void ip_nat_q931_expect(struct ip_conntrack *new,
+ struct ip_conntrack_expect *this)
+{
+ struct ip_nat_range range;
+
+ if (this->tuple.src.ip != 0) { /* Only accept calls from GK */
+ ip_nat_follow_master(new, this);
+ goto out;
+ }
+
+ /* 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.ip;
+
+ /* hook doesn't matter, but it has to do source manip */
+ ip_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.ip;
+
+ /* hook doesn't matter, but it has to do destination manip */
+ ip_nat_setup_info(new, &range, NF_IP_PRE_ROUTING);
+
+ out:
+ ip_conntrack_q931_expect(new, this);
+}
+
+/****************************************************************************/
+static int nat_q931(struct sk_buff **pskb, struct ip_conntrack *ct,
+ enum ip_conntrack_info ctinfo,
+ unsigned char **data, TransportAddress * addr, int idx,
+ u_int16_t port, struct ip_conntrack_expect *exp)
+{
+ struct ip_ct_h323_master *info = &ct->help.ct_h323_info;
+ int dir = CTINFO2DIR(ctinfo);
+ u_int16_t nated_port = port;
+ u_int32_t ip;
+
+ /* 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 = 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 (ip_conntrack_expect_related(exp) == 0)
+ break;
+ }
+
+ if (nated_port == 0) { /* No port available */
+ if (net_ratelimit())
+ printk("ip_nat_ras: out of TCP ports\n");
+ return 0;
+ }
+
+ /* Modify signal */
+ if (set_h225_addr(pskb, data, 0, &addr[idx],
+ ct->tuplehash[!dir].tuple.dst.ip,
+ nated_port) == 0) {
+ /* Save ports */
+ info->sig_port[dir] = port;
+ info->sig_port[!dir] = nated_port;
+
+ /* Fix for Gnomemeeting */
+ if (idx > 0 &&
+ get_h225_addr(*data, &addr[0], &ip, &port) &&
+ (ntohl(ip) & 0xff000000) == 0x7f000000) {
+ set_h225_addr_hook(pskb, data, 0, &addr[0],
+ ct->tuplehash[!dir].tuple.dst.ip,
+ info->sig_port[!dir]);
+ }
+ } else {
+ ip_conntrack_unexpect_related(exp);
+ return -1;
+ }
+
+ /* Success */
+ DEBUGP("ip_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 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_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_q931_hook = nat_q931;
+
+ DEBUGP("ip_nat_h323: init success\n");
+ return 0;
+}
+
+/****************************************************************************/
+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_q931_hook = NULL;
+ synchronize_net();
+}
+
+/****************************************************************************/
+module_init(init);
+module_exit(fini);
+
+MODULE_AUTHOR("Jing Min Zhao <zhaojingmin@users.sourceforge.net>");
+MODULE_DESCRIPTION("H.323 NAT helper");
+MODULE_LICENSE("GPL");
diff --git a/net/ipv4/netfilter/ip_nat_helper_pptp.c b/net/ipv4/netfilter/ip_nat_helper_pptp.c
index ac004895781a..b9c016c063b8 100644
--- a/net/ipv4/netfilter/ip_nat_helper_pptp.c
+++ b/net/ipv4/netfilter/ip_nat_helper_pptp.c
@@ -52,6 +52,8 @@
#define IP_NAT_PPTP_VERSION "3.0"
+#define REQ_CID(req, off) (*(u_int16_t *)((char *)(req) + (off)))
+
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
MODULE_DESCRIPTION("Netfilter NAT helper module for PPTP");
@@ -198,7 +200,7 @@ pptp_outbound_pkt(struct sk_buff **pskb,
/* 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(*(u_int16_t *)pptpReq + cid_off), ntohs(new_callid));
+ ntohs(REQ_CID(pptpReq, cid_off)), ntohs(new_callid));
/* mangle packet */
if (ip_nat_mangle_tcp_packet(pskb, ct, ctinfo,
@@ -342,7 +344,7 @@ pptp_inbound_pkt(struct sk_buff **pskb,
/* mangle packet */
DEBUGP("altering peer call id from 0x%04x to 0x%04x\n",
- ntohs(*(u_int16_t *)pptpReq + pcid_off), ntohs(new_pcid));
+ ntohs(REQ_CID(pptpReq, pcid_off)), ntohs(new_pcid));
if (ip_nat_mangle_tcp_packet(pskb, ct, ctinfo,
pcid_off + sizeof(struct pptp_pkt_hdr) +
@@ -353,7 +355,7 @@ pptp_inbound_pkt(struct sk_buff **pskb,
if (new_cid) {
DEBUGP("altering call id from 0x%04x to 0x%04x\n",
- ntohs(*(u_int16_t *)pptpReq + cid_off), ntohs(new_cid));
+ ntohs(REQ_CID(pptpReq, cid_off)), ntohs(new_cid));
if (ip_nat_mangle_tcp_packet(pskb, ct, ctinfo,
cid_off + sizeof(struct pptp_pkt_hdr) +
sizeof(struct PptpControlHeader),
diff --git a/net/ipv4/netfilter/ip_nat_rule.c b/net/ipv4/netfilter/ip_nat_rule.c
index 1de86282d232..efba8c4e42e0 100644
--- a/net/ipv4/netfilter/ip_nat_rule.c
+++ b/net/ipv4/netfilter/ip_nat_rule.c
@@ -103,6 +103,7 @@ static unsigned int ipt_snat_target(struct sk_buff **pskb,
const struct net_device *in,
const struct net_device *out,
unsigned int hooknum,
+ const struct ipt_target *target,
const void *targinfo,
void *userinfo)
{
@@ -145,6 +146,7 @@ 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 ipt_target *target,
const void *targinfo,
void *userinfo)
{
@@ -170,6 +172,7 @@ static unsigned int ipt_dnat_target(struct sk_buff **pskb,
static int ipt_snat_checkentry(const char *tablename,
const void *entry,
+ const struct ipt_target *target,
void *targinfo,
unsigned int targinfosize,
unsigned int hook_mask)
@@ -181,28 +184,12 @@ static int ipt_snat_checkentry(const char *tablename,
printk("SNAT: multiple ranges no longer supported\n");
return 0;
}
-
- if (targinfosize != IPT_ALIGN(sizeof(struct ip_nat_multi_range_compat))) {
- DEBUGP("SNAT: Target size %u wrong for %u ranges\n",
- targinfosize, mr->rangesize);
- return 0;
- }
-
- /* Only allow these for NAT. */
- if (strcmp(tablename, "nat") != 0) {
- DEBUGP("SNAT: wrong table %s\n", tablename);
- return 0;
- }
-
- if (hook_mask & ~(1 << NF_IP_POST_ROUTING)) {
- DEBUGP("SNAT: hook mask 0x%x bad\n", hook_mask);
- return 0;
- }
return 1;
}
static int ipt_dnat_checkentry(const char *tablename,
const void *entry,
+ const struct ipt_target *target,
void *targinfo,
unsigned int targinfosize,
unsigned int hook_mask)
@@ -214,24 +201,6 @@ static int ipt_dnat_checkentry(const char *tablename,
printk("DNAT: multiple ranges no longer supported\n");
return 0;
}
-
- if (targinfosize != IPT_ALIGN(sizeof(struct ip_nat_multi_range_compat))) {
- DEBUGP("DNAT: Target size %u wrong for %u ranges\n",
- targinfosize, mr->rangesize);
- return 0;
- }
-
- /* Only allow these for NAT. */
- if (strcmp(tablename, "nat") != 0) {
- DEBUGP("DNAT: wrong table %s\n", tablename);
- return 0;
- }
-
- if (hook_mask & ~((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_OUT))) {
- DEBUGP("DNAT: hook mask 0x%x bad\n", hook_mask);
- return 0;
- }
-
return 1;
}
@@ -299,12 +268,18 @@ int ip_nat_rule_find(struct sk_buff **pskb,
static struct ipt_target ipt_snat_reg = {
.name = "SNAT",
.target = ipt_snat_target,
+ .targetsize = sizeof(struct ip_nat_multi_range_compat),
+ .table = "nat",
+ .hooks = 1 << NF_IP_POST_ROUTING,
.checkentry = ipt_snat_checkentry,
};
static struct ipt_target ipt_dnat_reg = {
.name = "DNAT",
.target = ipt_dnat_target,
+ .targetsize = sizeof(struct ip_nat_multi_range_compat),
+ .table = "nat",
+ .hooks = 1 << NF_IP_PRE_ROUTING,
.checkentry = ipt_dnat_checkentry,
};
diff --git a/net/ipv4/netfilter/ip_nat_snmp_basic.c b/net/ipv4/netfilter/ip_nat_snmp_basic.c
index 4f95d477805c..f029da2a60ee 100644
--- a/net/ipv4/netfilter/ip_nat_snmp_basic.c
+++ b/net/ipv4/netfilter/ip_nat_snmp_basic.c
@@ -250,6 +250,7 @@ static unsigned char asn1_header_decode(struct asn1_ctx *ctx,
if (!asn1_id_decode(ctx, cls, con, tag))
return 0;
+ def = len = 0;
if (!asn1_length_decode(ctx, &def, &len))
return 0;
@@ -669,7 +670,7 @@ static unsigned char snmp_object_decode(struct asn1_ctx *ctx,
unsigned char *eoc, *end, *p;
unsigned long *lp, *id;
unsigned long ul;
- long l;
+ long l;
*obj = NULL;
id = NULL;
@@ -699,11 +700,13 @@ static unsigned char snmp_object_decode(struct asn1_ctx *ctx,
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);
diff --git a/net/ipv4/netfilter/ip_nat_standalone.c b/net/ipv4/netfilter/ip_nat_standalone.c
index ab1f88fa21ec..380aef3d7865 100644
--- a/net/ipv4/netfilter/ip_nat_standalone.c
+++ b/net/ipv4/netfilter/ip_nat_standalone.c
@@ -394,7 +394,7 @@ static int init_or_cleanup(int init)
ret = nf_register_hook(&ip_nat_local_out_ops);
if (ret < 0) {
printk("ip_nat_init: can't register local out hook.\n");
- goto cleanup_adjustout_ops;;
+ goto cleanup_adjustout_ops;
}
ret = nf_register_hook(&ip_nat_local_in_ops);
if (ret < 0) {
diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c
index 08f80e2ea2aa..1655866c55b9 100644
--- a/net/ipv4/netfilter/ip_queue.c
+++ b/net/ipv4/netfilter/ip_queue.c
@@ -35,6 +35,7 @@
#include <linux/sysctl.h>
#include <linux/proc_fs.h>
#include <linux/security.h>
+#include <linux/mutex.h>
#include <net/sock.h>
#include <net/route.h>
@@ -61,7 +62,7 @@ static unsigned int queue_dropped = 0;
static unsigned int queue_user_dropped = 0;
static struct sock *ipqnl;
static LIST_HEAD(queue_list);
-static DECLARE_MUTEX(ipqnl_sem);
+static DEFINE_MUTEX(ipqnl_mutex);
static void
ipq_issue_verdict(struct ipq_queue_entry *entry, int verdict)
@@ -539,7 +540,7 @@ ipq_rcv_sk(struct sock *sk, int len)
struct sk_buff *skb;
unsigned int qlen;
- down(&ipqnl_sem);
+ mutex_lock(&ipqnl_mutex);
for (qlen = skb_queue_len(&sk->sk_receive_queue); qlen; qlen--) {
skb = skb_dequeue(&sk->sk_receive_queue);
@@ -547,7 +548,7 @@ ipq_rcv_sk(struct sock *sk, int len)
kfree_skb(skb);
}
- up(&ipqnl_sem);
+ mutex_unlock(&ipqnl_mutex);
}
static int
@@ -708,8 +709,8 @@ cleanup_sysctl:
cleanup_ipqnl:
sock_release(ipqnl->sk_socket);
- down(&ipqnl_sem);
- up(&ipqnl_sem);
+ mutex_lock(&ipqnl_mutex);
+ mutex_unlock(&ipqnl_mutex);
cleanup_netlink_notifier:
netlink_unregister_notifier(&ipq_nl_notifier);
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
index 16f47c675fef..a7b194c4d79d 100644
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -25,7 +25,7 @@
#include <linux/icmp.h>
#include <net/ip.h>
#include <asm/uaccess.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/err.h>
#include <linux/cpumask.h>
@@ -179,6 +179,7 @@ ipt_error(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,
void *userinfo)
{
@@ -197,8 +198,8 @@ int do_match(struct ipt_entry_match *m,
int *hotdrop)
{
/* Stop iteration if it doesn't match */
- if (!m->u.kernel.match->match(skb, in, out, m->data, offset,
- skb->nh.iph->ihl*4, hotdrop))
+ if (!m->u.kernel.match->match(skb, in, out, m->u.kernel.match, m->data,
+ offset, skb->nh.iph->ihl*4, hotdrop))
return 1;
else
return 0;
@@ -305,6 +306,7 @@ ipt_do_table(struct sk_buff **pskb,
verdict = t->u.kernel.target->target(pskb,
in, out,
hook,
+ t->u.kernel.target,
t->data,
userdata);
@@ -464,7 +466,7 @@ cleanup_match(struct ipt_entry_match *m, unsigned int *i)
return 1;
if (m->u.kernel.match->destroy)
- m->u.kernel.match->destroy(m->data,
+ m->u.kernel.match->destroy(m->u.kernel.match, m->data,
m->u.match_size - sizeof(*m));
module_put(m->u.kernel.match->me);
return 0;
@@ -477,21 +479,12 @@ standard_check(const struct ipt_entry_target *t,
struct ipt_standard_target *targ = (void *)t;
/* Check standard info. */
- if (t->u.target_size
- != IPT_ALIGN(sizeof(struct ipt_standard_target))) {
- duprintf("standard_check: target size %u != %u\n",
- t->u.target_size,
- IPT_ALIGN(sizeof(struct ipt_standard_target)));
- return 0;
- }
-
if (targ->verdict >= 0
&& targ->verdict > max_offset - sizeof(struct ipt_entry)) {
duprintf("ipt_standard_check: bad verdict (%i)\n",
targ->verdict);
return 0;
}
-
if (targ->verdict < -NF_MAX_VERDICT - 1) {
duprintf("ipt_standard_check: bad negative verdict (%i)\n",
targ->verdict);
@@ -508,6 +501,7 @@ check_match(struct ipt_entry_match *m,
unsigned int *i)
{
struct ipt_match *match;
+ int ret;
match = try_then_request_module(xt_find_match(AF_INET, m->u.user.name,
m->u.user.revision),
@@ -518,18 +512,27 @@ check_match(struct ipt_entry_match *m,
}
m->u.kernel.match = match;
+ ret = xt_check_match(match, AF_INET, m->u.match_size - sizeof(*m),
+ name, hookmask, ip->proto,
+ ip->invflags & IPT_INV_PROTO);
+ if (ret)
+ goto err;
+
if (m->u.kernel.match->checkentry
- && !m->u.kernel.match->checkentry(name, ip, m->data,
+ && !m->u.kernel.match->checkentry(name, ip, match, m->data,
m->u.match_size - sizeof(*m),
hookmask)) {
- module_put(m->u.kernel.match->me);
duprintf("ip_tables: check failed for `%s'.\n",
m->u.kernel.match->name);
- return -EINVAL;
+ ret = -EINVAL;
+ goto err;
}
(*i)++;
return 0;
+err:
+ module_put(m->u.kernel.match->me);
+ return ret;
}
static struct ipt_target ipt_standard_target;
@@ -565,26 +568,32 @@ check_entry(struct ipt_entry *e, const char *name, unsigned int size,
}
t->u.kernel.target = target;
+ ret = xt_check_target(target, AF_INET, t->u.target_size - sizeof(*t),
+ name, e->comefrom, e->ip.proto,
+ e->ip.invflags & IPT_INV_PROTO);
+ if (ret)
+ goto err;
+
if (t->u.kernel.target == &ipt_standard_target) {
if (!standard_check(t, size)) {
ret = -EINVAL;
goto cleanup_matches;
}
} else if (t->u.kernel.target->checkentry
- && !t->u.kernel.target->checkentry(name, e, t->data,
+ && !t->u.kernel.target->checkentry(name, e, target, t->data,
t->u.target_size
- sizeof(*t),
e->comefrom)) {
- module_put(t->u.kernel.target->me);
duprintf("ip_tables: check failed for `%s'.\n",
t->u.kernel.target->name);
ret = -EINVAL;
- goto cleanup_matches;
+ goto err;
}
(*i)++;
return 0;
-
+ err:
+ module_put(t->u.kernel.target->me);
cleanup_matches:
IPT_MATCH_ITERATE(e, cleanup_match, &j);
return ret;
@@ -645,7 +654,7 @@ cleanup_entry(struct ipt_entry *e, unsigned int *i)
IPT_MATCH_ITERATE(e, cleanup_match, NULL);
t = ipt_get_target(e);
if (t->u.kernel.target->destroy)
- t->u.kernel.target->destroy(t->data,
+ t->u.kernel.target->destroy(t->u.kernel.target, t->data,
t->u.target_size - sizeof(*t));
module_put(t->u.kernel.target->me);
return 0;
@@ -1277,6 +1286,7 @@ static int
icmp_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,
@@ -1310,28 +1320,29 @@ icmp_match(const struct sk_buff *skb,
static int
icmp_checkentry(const char *tablename,
const void *info,
+ const struct xt_match *match,
void *matchinfo,
unsigned int matchsize,
unsigned int hook_mask)
{
- const struct ipt_ip *ip = info;
const struct ipt_icmp *icmpinfo = matchinfo;
- /* Must specify proto == ICMP, and no unknown invflags */
- return ip->proto == IPPROTO_ICMP
- && !(ip->invflags & IPT_INV_PROTO)
- && matchsize == IPT_ALIGN(sizeof(struct ipt_icmp))
- && !(icmpinfo->invflags & ~IPT_ICMP_INV);
+ /* Must specify no unknown invflags */
+ return !(icmpinfo->invflags & ~IPT_ICMP_INV);
}
/* The built-in targets: standard (NULL) and error. */
static struct ipt_target ipt_standard_target = {
.name = IPT_STANDARD_TARGET,
+ .targetsize = sizeof(int),
+ .family = AF_INET,
};
static struct ipt_target ipt_error_target = {
.name = IPT_ERROR_TARGET,
.target = ipt_error,
+ .targetsize = IPT_FUNCTION_MAXNAMELEN,
+ .family = AF_INET,
};
static struct nf_sockopt_ops ipt_sockopts = {
@@ -1346,8 +1357,11 @@ static struct nf_sockopt_ops ipt_sockopts = {
static struct ipt_match icmp_matchstruct = {
.name = "icmp",
- .match = &icmp_match,
- .checkentry = &icmp_checkentry,
+ .match = icmp_match,
+ .matchsize = sizeof(struct ipt_icmp),
+ .proto = IPPROTO_ICMP,
+ .family = AF_INET,
+ .checkentry = icmp_checkentry,
};
static int __init init(void)
@@ -1357,9 +1371,9 @@ static int __init init(void)
xt_proto_init(AF_INET);
/* Noone else will be downing sem now, so we won't sleep */
- xt_register_target(AF_INET, &ipt_standard_target);
- xt_register_target(AF_INET, &ipt_error_target);
- xt_register_match(AF_INET, &icmp_matchstruct);
+ xt_register_target(&ipt_standard_target);
+ xt_register_target(&ipt_error_target);
+ xt_register_match(&icmp_matchstruct);
/* Register setsockopt */
ret = nf_register_sockopt(&ipt_sockopts);
@@ -1376,9 +1390,9 @@ static void __exit fini(void)
{
nf_unregister_sockopt(&ipt_sockopts);
- xt_unregister_match(AF_INET, &icmp_matchstruct);
- xt_unregister_target(AF_INET, &ipt_error_target);
- xt_unregister_target(AF_INET, &ipt_standard_target);
+ xt_unregister_match(&icmp_matchstruct);
+ xt_unregister_target(&ipt_error_target);
+ xt_unregister_target(&ipt_standard_target);
xt_proto_fini(AF_INET);
}
diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c
index d9bc971f03af..61e11edcd6af 100644
--- a/net/ipv4/netfilter/ipt_CLUSTERIP.c
+++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c
@@ -311,6 +311,7 @@ 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,
void *userinfo)
{
@@ -380,6 +381,7 @@ target(struct sk_buff **pskb,
static int
checkentry(const char *tablename,
const void *e_void,
+ const struct xt_target *target,
void *targinfo,
unsigned int targinfosize,
unsigned int hook_mask)
@@ -389,13 +391,6 @@ checkentry(const char *tablename,
struct clusterip_config *config;
- if (targinfosize != IPT_ALIGN(sizeof(struct ipt_clusterip_tgt_info))) {
- printk(KERN_WARNING "CLUSTERIP: targinfosize %u != %Zu\n",
- targinfosize,
- IPT_ALIGN(sizeof(struct ipt_clusterip_tgt_info)));
- return 0;
- }
-
if (cipinfo->hash_mode != CLUSTERIP_HASHMODE_SIP &&
cipinfo->hash_mode != CLUSTERIP_HASHMODE_SIP_SPT &&
cipinfo->hash_mode != CLUSTERIP_HASHMODE_SIP_SPT_DPT) {
@@ -465,9 +460,10 @@ checkentry(const char *tablename,
}
/* drop reference count of cluster config when rule is deleted */
-static void destroy(void *matchinfo, unsigned int matchinfosize)
+static void destroy(const struct xt_target *target, void *targinfo,
+ unsigned int targinfosize)
{
- struct ipt_clusterip_tgt_info *cipinfo = matchinfo;
+ struct ipt_clusterip_tgt_info *cipinfo = targinfo;
/* if no more entries are referencing the config, remove it
* from the list and destroy the proc entry */
@@ -476,12 +472,13 @@ static void destroy(void *matchinfo, unsigned int matchinfosize)
clusterip_config_put(cipinfo->config);
}
-static struct ipt_target clusterip_tgt = {
- .name = "CLUSTERIP",
- .target = &target,
- .checkentry = &checkentry,
- .destroy = &destroy,
- .me = THIS_MODULE
+static struct ipt_target clusterip_tgt = {
+ .name = "CLUSTERIP",
+ .target = target,
+ .targetsize = sizeof(struct ipt_clusterip_tgt_info),
+ .checkentry = checkentry,
+ .destroy = destroy,
+ .me = THIS_MODULE
};
diff --git a/net/ipv4/netfilter/ipt_DSCP.c b/net/ipv4/netfilter/ipt_DSCP.c
index 898cdf79ce18..cfb0b90e598a 100644
--- a/net/ipv4/netfilter/ipt_DSCP.c
+++ b/net/ipv4/netfilter/ipt_DSCP.c
@@ -29,6 +29,7 @@ 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,
void *userinfo)
{
@@ -58,35 +59,25 @@ target(struct sk_buff **pskb,
static int
checkentry(const char *tablename,
const void *e_void,
+ const struct xt_target *target,
void *targinfo,
unsigned int targinfosize,
unsigned int hook_mask)
{
const u_int8_t dscp = ((struct ipt_DSCP_info *)targinfo)->dscp;
- if (targinfosize != IPT_ALIGN(sizeof(struct ipt_DSCP_info))) {
- printk(KERN_WARNING "DSCP: targinfosize %u != %Zu\n",
- targinfosize,
- IPT_ALIGN(sizeof(struct ipt_DSCP_info)));
- return 0;
- }
-
- if (strcmp(tablename, "mangle") != 0) {
- printk(KERN_WARNING "DSCP: can only be called from \"mangle\" table, not \"%s\"\n", tablename);
- return 0;
- }
-
if ((dscp > IPT_DSCP_MAX)) {
printk(KERN_WARNING "DSCP: dscp %x out of range\n", dscp);
return 0;
}
-
return 1;
}
static struct ipt_target ipt_dscp_reg = {
.name = "DSCP",
.target = target,
+ .targetsize = sizeof(struct ipt_DSCP_info),
+ .table = "mangle",
.checkentry = checkentry,
.me = THIS_MODULE,
};
diff --git a/net/ipv4/netfilter/ipt_ECN.c b/net/ipv4/netfilter/ipt_ECN.c
index 706445426a6d..b9b80f90c84e 100644
--- a/net/ipv4/netfilter/ipt_ECN.c
+++ b/net/ipv4/netfilter/ipt_ECN.c
@@ -94,6 +94,7 @@ 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,
void *userinfo)
{
@@ -114,6 +115,7 @@ target(struct sk_buff **pskb,
static int
checkentry(const char *tablename,
const void *e_void,
+ const struct xt_target *target,
void *targinfo,
unsigned int targinfosize,
unsigned int hook_mask)
@@ -121,18 +123,6 @@ checkentry(const char *tablename,
const struct ipt_ECN_info *einfo = (struct ipt_ECN_info *)targinfo;
const struct ipt_entry *e = e_void;
- if (targinfosize != IPT_ALIGN(sizeof(struct ipt_ECN_info))) {
- printk(KERN_WARNING "ECN: targinfosize %u != %Zu\n",
- targinfosize,
- IPT_ALIGN(sizeof(struct ipt_ECN_info)));
- return 0;
- }
-
- if (strcmp(tablename, "mangle") != 0) {
- printk(KERN_WARNING "ECN: can only be called from \"mangle\" table, not \"%s\"\n", tablename);
- return 0;
- }
-
if (einfo->operation & IPT_ECN_OP_MASK) {
printk(KERN_WARNING "ECN: unsupported ECN operation %x\n",
einfo->operation);
@@ -143,20 +133,20 @@ checkentry(const char *tablename,
einfo->ip_ect);
return 0;
}
-
if ((einfo->operation & (IPT_ECN_OP_SET_ECE|IPT_ECN_OP_SET_CWR))
&& (e->ip.proto != IPPROTO_TCP || (e->ip.invflags & IPT_INV_PROTO))) {
printk(KERN_WARNING "ECN: cannot use TCP operations on a "
"non-tcp rule\n");
return 0;
}
-
return 1;
}
static struct ipt_target ipt_ecn_reg = {
.name = "ECN",
.target = target,
+ .targetsize = sizeof(struct ipt_ECN_info),
+ .table = "mangle",
.checkentry = checkentry,
.me = THIS_MODULE,
};
diff --git a/net/ipv4/netfilter/ipt_LOG.c b/net/ipv4/netfilter/ipt_LOG.c
index cc27545ff97f..750d3221b280 100644
--- a/net/ipv4/netfilter/ipt_LOG.c
+++ b/net/ipv4/netfilter/ipt_LOG.c
@@ -415,6 +415,7 @@ ipt_log_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,
void *userinfo)
{
@@ -437,35 +438,29 @@ ipt_log_target(struct sk_buff **pskb,
static int ipt_log_checkentry(const char *tablename,
const void *e,
+ const struct xt_target *target,
void *targinfo,
unsigned int targinfosize,
unsigned int hook_mask)
{
const struct ipt_log_info *loginfo = targinfo;
- if (targinfosize != IPT_ALIGN(sizeof(struct ipt_log_info))) {
- DEBUGP("LOG: targinfosize %u != %u\n",
- targinfosize, IPT_ALIGN(sizeof(struct ipt_log_info)));
- return 0;
- }
-
if (loginfo->level >= 8) {
DEBUGP("LOG: level %u >= 8\n", loginfo->level);
return 0;
}
-
if (loginfo->prefix[sizeof(loginfo->prefix)-1] != '\0') {
DEBUGP("LOG: prefix term %i\n",
loginfo->prefix[sizeof(loginfo->prefix)-1]);
return 0;
}
-
return 1;
}
static struct ipt_target ipt_log_reg = {
.name = "LOG",
.target = ipt_log_target,
+ .targetsize = sizeof(struct ipt_log_info),
.checkentry = ipt_log_checkentry,
.me = THIS_MODULE,
};
diff --git a/net/ipv4/netfilter/ipt_MASQUERADE.c b/net/ipv4/netfilter/ipt_MASQUERADE.c
index 12c56d3343ca..e0c321c3bae5 100644
--- a/net/ipv4/netfilter/ipt_MASQUERADE.c
+++ b/net/ipv4/netfilter/ipt_MASQUERADE.c
@@ -41,25 +41,13 @@ static DEFINE_RWLOCK(masq_lock);
static int
masquerade_check(const char *tablename,
const void *e,
+ const struct xt_target *target,
void *targinfo,
unsigned int targinfosize,
unsigned int hook_mask)
{
const struct ip_nat_multi_range_compat *mr = targinfo;
- if (strcmp(tablename, "nat") != 0) {
- DEBUGP("masquerade_check: bad table `%s'.\n", tablename);
- return 0;
- }
- if (targinfosize != IPT_ALIGN(sizeof(*mr))) {
- DEBUGP("masquerade_check: size %u != %u.\n",
- targinfosize, sizeof(*mr));
- return 0;
- }
- if (hook_mask & ~(1 << NF_IP_POST_ROUTING)) {
- DEBUGP("masquerade_check: bad hooks %x.\n", hook_mask);
- return 0;
- }
if (mr->range[0].flags & IP_NAT_RANGE_MAP_IPS) {
DEBUGP("masquerade_check: bad MAP_IPS.\n");
return 0;
@@ -76,6 +64,7 @@ masquerade_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,
void *userinfo)
{
@@ -179,6 +168,9 @@ static struct notifier_block masq_inet_notifier = {
static struct ipt_target masquerade = {
.name = "MASQUERADE",
.target = masquerade_target,
+ .targetsize = sizeof(struct ip_nat_multi_range_compat),
+ .table = "nat",
+ .hooks = 1 << NF_IP_POST_ROUTING,
.checkentry = masquerade_check,
.me = THIS_MODULE,
};
diff --git a/net/ipv4/netfilter/ipt_NETMAP.c b/net/ipv4/netfilter/ipt_NETMAP.c
index b074467fe67b..fba181c2a426 100644
--- a/net/ipv4/netfilter/ipt_NETMAP.c
+++ b/net/ipv4/netfilter/ipt_NETMAP.c
@@ -32,25 +32,13 @@ MODULE_DESCRIPTION("iptables 1:1 NAT mapping of IP networks target");
static int
check(const char *tablename,
const void *e,
+ const struct xt_target *target,
void *targinfo,
unsigned int targinfosize,
unsigned int hook_mask)
{
const struct ip_nat_multi_range_compat *mr = targinfo;
- if (strcmp(tablename, "nat") != 0) {
- DEBUGP(MODULENAME":check: bad table `%s'.\n", tablename);
- return 0;
- }
- if (targinfosize != IPT_ALIGN(sizeof(*mr))) {
- DEBUGP(MODULENAME":check: size %u.\n", targinfosize);
- return 0;
- }
- if (hook_mask & ~((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_POST_ROUTING) |
- (1 << NF_IP_LOCAL_OUT))) {
- DEBUGP(MODULENAME":check: bad hooks %x.\n", hook_mask);
- return 0;
- }
if (!(mr->range[0].flags & IP_NAT_RANGE_MAP_IPS)) {
DEBUGP(MODULENAME":check: bad MAP_IPS.\n");
return 0;
@@ -67,6 +55,7 @@ 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,
void *userinfo)
{
@@ -101,6 +90,10 @@ target(struct sk_buff **pskb,
static struct ipt_target target_module = {
.name = MODULENAME,
.target = target,
+ .targetsize = sizeof(struct ip_nat_multi_range_compat),
+ .table = "nat",
+ .hooks = (1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_POST_ROUTING) |
+ (1 << NF_IP_LOCAL_OUT),
.checkentry = check,
.me = THIS_MODULE
};
diff --git a/net/ipv4/netfilter/ipt_REDIRECT.c b/net/ipv4/netfilter/ipt_REDIRECT.c
index 140be51f2f01..be3da7c4b871 100644
--- a/net/ipv4/netfilter/ipt_REDIRECT.c
+++ b/net/ipv4/netfilter/ipt_REDIRECT.c
@@ -34,24 +34,13 @@ MODULE_DESCRIPTION("iptables REDIRECT target module");
static int
redirect_check(const char *tablename,
const void *e,
+ const struct xt_target *target,
void *targinfo,
unsigned int targinfosize,
unsigned int hook_mask)
{
const struct ip_nat_multi_range_compat *mr = targinfo;
- if (strcmp(tablename, "nat") != 0) {
- DEBUGP("redirect_check: bad table `%s'.\n", table);
- return 0;
- }
- if (targinfosize != IPT_ALIGN(sizeof(*mr))) {
- DEBUGP("redirect_check: size %u.\n", targinfosize);
- return 0;
- }
- if (hook_mask & ~((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_OUT))) {
- DEBUGP("redirect_check: bad hooks %x.\n", hook_mask);
- return 0;
- }
if (mr->range[0].flags & IP_NAT_RANGE_MAP_IPS) {
DEBUGP("redirect_check: bad MAP_IPS.\n");
return 0;
@@ -68,6 +57,7 @@ redirect_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,
void *userinfo)
{
@@ -115,6 +105,9 @@ redirect_target(struct sk_buff **pskb,
static struct ipt_target redirect_reg = {
.name = "REDIRECT",
.target = redirect_target,
+ .targetsize = sizeof(struct ip_nat_multi_range_compat),
+ .table = "nat",
+ .hooks = (1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_OUT),
.checkentry = redirect_check,
.me = THIS_MODULE,
};
diff --git a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c
index 3eb47aae78c5..9d3b3579f27c 100644
--- a/net/ipv4/netfilter/ipt_REJECT.c
+++ b/net/ipv4/netfilter/ipt_REJECT.c
@@ -154,10 +154,6 @@ 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;
-#ifdef CONFIG_BRIDGE_NETFILTER
- nf_bridge_put(nskb->nf_bridge);
- nskb->nf_bridge = NULL;
-#endif
tcph = (struct tcphdr *)((u_int32_t*)nskb->nh.iph + nskb->nh.iph->ihl);
@@ -236,6 +232,7 @@ static unsigned int reject(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,
void *userinfo)
{
@@ -283,6 +280,7 @@ static unsigned int reject(struct sk_buff **pskb,
static int check(const char *tablename,
const void *e_void,
+ const struct xt_target *target,
void *targinfo,
unsigned int targinfosize,
unsigned int hook_mask)
@@ -290,23 +288,6 @@ static int check(const char *tablename,
const struct ipt_reject_info *rejinfo = targinfo;
const struct ipt_entry *e = e_void;
- if (targinfosize != IPT_ALIGN(sizeof(struct ipt_reject_info))) {
- DEBUGP("REJECT: targinfosize %u != 0\n", targinfosize);
- return 0;
- }
-
- /* Only allow these for packet filtering. */
- if (strcmp(tablename, "filter") != 0) {
- DEBUGP("REJECT: bad table `%s'.\n", tablename);
- return 0;
- }
- if ((hook_mask & ~((1 << NF_IP_LOCAL_IN)
- | (1 << NF_IP_FORWARD)
- | (1 << NF_IP_LOCAL_OUT))) != 0) {
- DEBUGP("REJECT: bad hook mask %X\n", hook_mask);
- return 0;
- }
-
if (rejinfo->with == IPT_ICMP_ECHOREPLY) {
printk("REJECT: ECHOREPLY no longer supported.\n");
return 0;
@@ -318,13 +299,16 @@ static int check(const char *tablename,
return 0;
}
}
-
return 1;
}
static struct ipt_target ipt_reject_reg = {
.name = "REJECT",
.target = reject,
+ .targetsize = sizeof(struct ipt_reject_info),
+ .table = "filter",
+ .hooks = (1 << NF_IP_LOCAL_IN) | (1 << NF_IP_FORWARD) |
+ (1 << NF_IP_LOCAL_OUT),
.checkentry = check,
.me = THIS_MODULE,
};
diff --git a/net/ipv4/netfilter/ipt_SAME.c b/net/ipv4/netfilter/ipt_SAME.c
index a22de59bba0e..7e2ebc9d945e 100644
--- a/net/ipv4/netfilter/ipt_SAME.c
+++ b/net/ipv4/netfilter/ipt_SAME.c
@@ -50,6 +50,7 @@ MODULE_DESCRIPTION("iptables special SNAT module for consistent sourceip");
static int
same_check(const char *tablename,
const void *e,
+ const struct xt_target *target,
void *targinfo,
unsigned int targinfosize,
unsigned int hook_mask)
@@ -59,18 +60,6 @@ same_check(const char *tablename,
mr->ipnum = 0;
- if (strcmp(tablename, "nat") != 0) {
- DEBUGP("same_check: bad table `%s'.\n", tablename);
- return 0;
- }
- if (targinfosize != IPT_ALIGN(sizeof(*mr))) {
- DEBUGP("same_check: size %u.\n", targinfosize);
- return 0;
- }
- if (hook_mask & ~(1 << NF_IP_PRE_ROUTING | 1 << NF_IP_POST_ROUTING)) {
- DEBUGP("same_check: bad hooks %x.\n", hook_mask);
- return 0;
- }
if (mr->rangesize < 1) {
DEBUGP("same_check: need at least one dest range.\n");
return 0;
@@ -127,7 +116,7 @@ same_check(const char *tablename,
}
static void
-same_destroy(void *targinfo,
+same_destroy(const struct xt_target *target, void *targinfo,
unsigned int targinfosize)
{
struct ipt_same_info *mr = targinfo;
@@ -143,6 +132,7 @@ same_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,
void *userinfo)
{
@@ -191,6 +181,9 @@ same_target(struct sk_buff **pskb,
static struct ipt_target same_reg = {
.name = "SAME",
.target = same_target,
+ .targetsize = sizeof(struct ipt_same_info),
+ .table = "nat",
+ .hooks = (1 << NF_IP_PRE_ROUTING | 1 << NF_IP_POST_ROUTING),
.checkentry = same_check,
.destroy = same_destroy,
.me = THIS_MODULE,
diff --git a/net/ipv4/netfilter/ipt_TCPMSS.c b/net/ipv4/netfilter/ipt_TCPMSS.c
index c122841e182c..c4fc50ec2ddb 100644
--- a/net/ipv4/netfilter/ipt_TCPMSS.c
+++ b/net/ipv4/netfilter/ipt_TCPMSS.c
@@ -48,6 +48,7 @@ ipt_tcpmss_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,
void *userinfo)
{
@@ -211,6 +212,7 @@ static inline int find_syn_match(const struct ipt_entry_match *m)
static int
ipt_tcpmss_checkentry(const char *tablename,
const void *e_void,
+ const struct xt_target *target,
void *targinfo,
unsigned int targinfosize,
unsigned int hook_mask)
@@ -218,13 +220,6 @@ ipt_tcpmss_checkentry(const char *tablename,
const struct ipt_tcpmss_info *tcpmssinfo = targinfo;
const struct ipt_entry *e = e_void;
- if (targinfosize != IPT_ALIGN(sizeof(struct ipt_tcpmss_info))) {
- DEBUGP("ipt_tcpmss_checkentry: targinfosize %u != %u\n",
- targinfosize, IPT_ALIGN(sizeof(struct ipt_tcpmss_info)));
- return 0;
- }
-
-
if((tcpmssinfo->mss == IPT_TCPMSS_CLAMP_PMTU) &&
((hook_mask & ~((1 << NF_IP_FORWARD)
| (1 << NF_IP_LOCAL_OUT)
@@ -233,11 +228,8 @@ ipt_tcpmss_checkentry(const char *tablename,
return 0;
}
- if (e->ip.proto == IPPROTO_TCP
- && !(e->ip.invflags & IPT_INV_PROTO)
- && IPT_MATCH_ITERATE(e, find_syn_match))
+ if (IPT_MATCH_ITERATE(e, find_syn_match))
return 1;
-
printk("TCPMSS: Only works on TCP SYN packets\n");
return 0;
}
@@ -245,6 +237,8 @@ ipt_tcpmss_checkentry(const char *tablename,
static struct ipt_target ipt_tcpmss_reg = {
.name = "TCPMSS",
.target = ipt_tcpmss_target,
+ .targetsize = sizeof(struct ipt_tcpmss_info),
+ .proto = IPPROTO_TCP,
.checkentry = ipt_tcpmss_checkentry,
.me = THIS_MODULE,
};
diff --git a/net/ipv4/netfilter/ipt_TOS.c b/net/ipv4/netfilter/ipt_TOS.c
index 3a44a56db239..9aa7817657f0 100644
--- a/net/ipv4/netfilter/ipt_TOS.c
+++ b/net/ipv4/netfilter/ipt_TOS.c
@@ -25,6 +25,7 @@ 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,
void *userinfo)
{
@@ -53,24 +54,13 @@ target(struct sk_buff **pskb,
static int
checkentry(const char *tablename,
const void *e_void,
+ const struct xt_target *target,
void *targinfo,
unsigned int targinfosize,
unsigned int hook_mask)
{
const u_int8_t tos = ((struct ipt_tos_target_info *)targinfo)->tos;
- if (targinfosize != IPT_ALIGN(sizeof(struct ipt_tos_target_info))) {
- printk(KERN_WARNING "TOS: targinfosize %u != %Zu\n",
- targinfosize,
- IPT_ALIGN(sizeof(struct ipt_tos_target_info)));
- return 0;
- }
-
- if (strcmp(tablename, "mangle") != 0) {
- printk(KERN_WARNING "TOS: can only be called from \"mangle\" table, not \"%s\"\n", tablename);
- return 0;
- }
-
if (tos != IPTOS_LOWDELAY
&& tos != IPTOS_THROUGHPUT
&& tos != IPTOS_RELIABILITY
@@ -79,13 +69,14 @@ checkentry(const char *tablename,
printk(KERN_WARNING "TOS: bad tos value %#x\n", tos);
return 0;
}
-
return 1;
}
static struct ipt_target ipt_tos_reg = {
.name = "TOS",
.target = target,
+ .targetsize = sizeof(struct ipt_tos_target_info),
+ .table = "mangle",
.checkentry = checkentry,
.me = THIS_MODULE,
};
diff --git a/net/ipv4/netfilter/ipt_TTL.c b/net/ipv4/netfilter/ipt_TTL.c
index b769eb231970..5009a003d578 100644
--- a/net/ipv4/netfilter/ipt_TTL.c
+++ b/net/ipv4/netfilter/ipt_TTL.c
@@ -20,9 +20,10 @@ MODULE_DESCRIPTION("IP tables TTL modification module");
MODULE_LICENSE("GPL");
static unsigned int
-ipt_ttl_target(struct sk_buff **pskb, const struct net_device *in,
- const struct net_device *out, unsigned int hooknum,
- const void *targinfo, void *userinfo)
+ipt_ttl_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, void *userinfo)
{
struct iphdr *iph;
const struct ipt_TTL_info *info = targinfo;
@@ -67,40 +68,28 @@ ipt_ttl_target(struct sk_buff **pskb, const struct net_device *in,
static int ipt_ttl_checkentry(const char *tablename,
const void *e,
+ const struct xt_target *target,
void *targinfo,
unsigned int targinfosize,
unsigned int hook_mask)
{
struct ipt_TTL_info *info = targinfo;
- if (targinfosize != IPT_ALIGN(sizeof(struct ipt_TTL_info))) {
- printk(KERN_WARNING "ipt_TTL: targinfosize %u != %Zu\n",
- targinfosize,
- IPT_ALIGN(sizeof(struct ipt_TTL_info)));
- return 0;
- }
-
- if (strcmp(tablename, "mangle")) {
- printk(KERN_WARNING "ipt_TTL: can only be called from "
- "\"mangle\" table, not \"%s\"\n", tablename);
- return 0;
- }
-
if (info->mode > IPT_TTL_MAXMODE) {
printk(KERN_WARNING "ipt_TTL: invalid or unknown Mode %u\n",
info->mode);
return 0;
}
-
if ((info->mode != IPT_TTL_SET) && (info->ttl == 0))
return 0;
-
return 1;
}
static struct ipt_target ipt_TTL = {
.name = "TTL",
.target = ipt_ttl_target,
+ .targetsize = sizeof(struct ipt_TTL_info),
+ .table = "mangle",
.checkentry = ipt_ttl_checkentry,
.me = THIS_MODULE,
};
diff --git a/net/ipv4/netfilter/ipt_ULOG.c b/net/ipv4/netfilter/ipt_ULOG.c
index 180a9ea57b69..a82a32ed0e2f 100644
--- a/net/ipv4/netfilter/ipt_ULOG.c
+++ b/net/ipv4/netfilter/ipt_ULOG.c
@@ -303,6 +303,7 @@ static unsigned int ipt_ulog_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, void *userinfo)
{
struct ipt_ulog_info *loginfo = (struct ipt_ulog_info *) targinfo;
@@ -339,42 +340,37 @@ static void ipt_logfn(unsigned int pf,
static int ipt_ulog_checkentry(const char *tablename,
const void *e,
+ const struct xt_target *target,
void *targinfo,
unsigned int targinfosize,
unsigned int hookmask)
{
struct ipt_ulog_info *loginfo = (struct ipt_ulog_info *) targinfo;
- if (targinfosize != IPT_ALIGN(sizeof(struct ipt_ulog_info))) {
- DEBUGP("ipt_ULOG: targinfosize %u != 0\n", targinfosize);
- return 0;
- }
-
if (loginfo->prefix[sizeof(loginfo->prefix) - 1] != '\0') {
DEBUGP("ipt_ULOG: prefix term %i\n",
loginfo->prefix[sizeof(loginfo->prefix) - 1]);
return 0;
}
-
if (loginfo->qthreshold > ULOG_MAX_QLEN) {
DEBUGP("ipt_ULOG: queue threshold %i > MAX_QLEN\n",
loginfo->qthreshold);
return 0;
}
-
return 1;
}
static struct ipt_target ipt_ulog_reg = {
.name = "ULOG",
.target = ipt_ulog_target,
+ .targetsize = sizeof(struct ipt_ulog_info),
.checkentry = ipt_ulog_checkentry,
.me = THIS_MODULE,
};
static struct nf_logger ipt_ulog_logger = {
.name = "ipt_ULOG",
- .logfn = &ipt_logfn,
+ .logfn = ipt_logfn,
.me = THIS_MODULE,
};
diff --git a/net/ipv4/netfilter/ipt_addrtype.c b/net/ipv4/netfilter/ipt_addrtype.c
index d6b83a976518..5fdf85d0efcf 100644
--- a/net/ipv4/netfilter/ipt_addrtype.c
+++ b/net/ipv4/netfilter/ipt_addrtype.c
@@ -27,8 +27,9 @@ static inline int match_type(u_int32_t addr, u_int16_t mask)
return !!(mask & (1 << inet_addr_type(addr)));
}
-static int match(const struct sk_buff *skb, const struct net_device *in,
- const struct net_device *out, const void *matchinfo,
+static int 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)
{
const struct ipt_addrtype_info *info = matchinfo;
@@ -43,23 +44,10 @@ static int match(const struct sk_buff *skb, const struct net_device *in,
return ret;
}
-static int checkentry(const char *tablename, const void *ip,
- void *matchinfo, unsigned int matchsize,
- unsigned int hook_mask)
-{
- if (matchsize != IPT_ALIGN(sizeof(struct ipt_addrtype_info))) {
- printk(KERN_ERR "ipt_addrtype: invalid size (%u != %Zu)\n",
- matchsize, IPT_ALIGN(sizeof(struct ipt_addrtype_info)));
- return 0;
- }
-
- return 1;
-}
-
static struct ipt_match addrtype_match = {
.name = "addrtype",
.match = match,
- .checkentry = checkentry,
+ .matchsize = sizeof(struct ipt_addrtype_info),
.me = THIS_MODULE
};
diff --git a/net/ipv4/netfilter/ipt_ah.c b/net/ipv4/netfilter/ipt_ah.c
index 144adfec13cc..35a21fb1f8e0 100644
--- a/net/ipv4/netfilter/ipt_ah.c
+++ b/net/ipv4/netfilter/ipt_ah.c
@@ -39,6 +39,7 @@ static int
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,
@@ -71,37 +72,27 @@ match(const struct sk_buff *skb,
static int
checkentry(const char *tablename,
const void *ip_void,
+ const struct xt_match *match,
void *matchinfo,
unsigned int matchinfosize,
unsigned int hook_mask)
{
const struct ipt_ah *ahinfo = matchinfo;
- const struct ipt_ip *ip = ip_void;
- /* Must specify proto == AH, and no unknown invflags */
- if (ip->proto != IPPROTO_AH || (ip->invflags & IPT_INV_PROTO)) {
- duprintf("ipt_ah: Protocol %u != %u\n", ip->proto,
- IPPROTO_AH);
- return 0;
- }
- if (matchinfosize != IPT_ALIGN(sizeof(struct ipt_ah))) {
- duprintf("ipt_ah: matchsize %u != %u\n",
- matchinfosize, IPT_ALIGN(sizeof(struct ipt_ah)));
- return 0;
- }
+ /* Must specify no unknown invflags */
if (ahinfo->invflags & ~IPT_AH_INV_MASK) {
- duprintf("ipt_ah: unknown flags %X\n",
- ahinfo->invflags);
+ duprintf("ipt_ah: unknown flags %X\n", ahinfo->invflags);
return 0;
}
-
return 1;
}
static struct ipt_match ah_match = {
.name = "ah",
- .match = &match,
- .checkentry = &checkentry,
+ .match = match,
+ .matchsize = sizeof(struct ipt_ah),
+ .proto = IPPROTO_AH,
+ .checkentry = checkentry,
.me = THIS_MODULE,
};
diff --git a/net/ipv4/netfilter/ipt_dscp.c b/net/ipv4/netfilter/ipt_dscp.c
index 92063b4f8602..11963c385dea 100644
--- a/net/ipv4/netfilter/ipt_dscp.c
+++ b/net/ipv4/netfilter/ipt_dscp.c
@@ -19,8 +19,9 @@ MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
MODULE_DESCRIPTION("iptables DSCP matching module");
MODULE_LICENSE("GPL");
-static int match(const struct sk_buff *skb, const struct net_device *in,
- const struct net_device *out, const void *matchinfo,
+static int 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)
{
const struct ipt_dscp_info *info = matchinfo;
@@ -31,20 +32,10 @@ static int match(const struct sk_buff *skb, const struct net_device *in,
return ((iph->tos&IPT_DSCP_MASK) == sh_dscp) ^ info->invert;
}
-static int checkentry(const char *tablename, const void *ip,
- void *matchinfo, unsigned int matchsize,
- unsigned int hook_mask)
-{
- if (matchsize != IPT_ALIGN(sizeof(struct ipt_dscp_info)))
- return 0;
-
- return 1;
-}
-
static struct ipt_match dscp_match = {
.name = "dscp",
- .match = &match,
- .checkentry = &checkentry,
+ .match = match,
+ .matchsize = sizeof(struct ipt_dscp_info),
.me = THIS_MODULE,
};
diff --git a/net/ipv4/netfilter/ipt_ecn.c b/net/ipv4/netfilter/ipt_ecn.c
index e68b0c7981f0..d7e29f6a38d8 100644
--- a/net/ipv4/netfilter/ipt_ecn.c
+++ b/net/ipv4/netfilter/ipt_ecn.c
@@ -65,8 +65,9 @@ static inline int match_tcp(const struct sk_buff *skb,
return 1;
}
-static int match(const struct sk_buff *skb, const struct net_device *in,
- const struct net_device *out, const void *matchinfo,
+static int 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)
{
const struct ipt_ecn_info *info = matchinfo;
@@ -86,15 +87,13 @@ static int match(const struct sk_buff *skb, const struct net_device *in,
}
static int checkentry(const char *tablename, const void *ip_void,
+ const struct xt_match *match,
void *matchinfo, unsigned int matchsize,
unsigned int hook_mask)
{
const struct ipt_ecn_info *info = matchinfo;
const struct ipt_ip *ip = ip_void;
- if (matchsize != IPT_ALIGN(sizeof(struct ipt_ecn_info)))
- return 0;
-
if (info->operation & IPT_ECN_OP_MATCH_MASK)
return 0;
@@ -113,8 +112,9 @@ static int checkentry(const char *tablename, const void *ip_void,
static struct ipt_match ecn_match = {
.name = "ecn",
- .match = &match,
- .checkentry = &checkentry,
+ .match = match,
+ .matchsize = sizeof(struct ipt_ecn_info),
+ .checkentry = checkentry,
.me = THIS_MODULE,
};
diff --git a/net/ipv4/netfilter/ipt_esp.c b/net/ipv4/netfilter/ipt_esp.c
index 9de191a8162d..af0d5ec79cb5 100644
--- a/net/ipv4/netfilter/ipt_esp.c
+++ b/net/ipv4/netfilter/ipt_esp.c
@@ -40,6 +40,7 @@ static int
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,
@@ -72,37 +73,27 @@ match(const struct sk_buff *skb,
static int
checkentry(const char *tablename,
const void *ip_void,
+ const struct xt_match *match,
void *matchinfo,
unsigned int matchinfosize,
unsigned int hook_mask)
{
const struct ipt_esp *espinfo = matchinfo;
- const struct ipt_ip *ip = ip_void;
- /* Must specify proto == ESP, and no unknown invflags */
- if (ip->proto != IPPROTO_ESP || (ip->invflags & IPT_INV_PROTO)) {
- duprintf("ipt_esp: Protocol %u != %u\n", ip->proto,
- IPPROTO_ESP);
- return 0;
- }
- if (matchinfosize != IPT_ALIGN(sizeof(struct ipt_esp))) {
- duprintf("ipt_esp: matchsize %u != %u\n",
- matchinfosize, IPT_ALIGN(sizeof(struct ipt_esp)));
- return 0;
- }
+ /* Must specify no unknown invflags */
if (espinfo->invflags & ~IPT_ESP_INV_MASK) {
- duprintf("ipt_esp: unknown flags %X\n",
- espinfo->invflags);
+ duprintf("ipt_esp: unknown flags %X\n", espinfo->invflags);
return 0;
}
-
return 1;
}
static struct ipt_match esp_match = {
.name = "esp",
- .match = &match,
- .checkentry = &checkentry,
+ .match = match,
+ .matchsize = sizeof(struct ipt_esp),
+ .proto = IPPROTO_ESP,
+ .checkentry = checkentry,
.me = THIS_MODULE,
};
diff --git a/net/ipv4/netfilter/ipt_hashlimit.c b/net/ipv4/netfilter/ipt_hashlimit.c
index 4fe48c1bd5f3..dc1521c5aa81 100644
--- a/net/ipv4/netfilter/ipt_hashlimit.c
+++ b/net/ipv4/netfilter/ipt_hashlimit.c
@@ -427,6 +427,7 @@ 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,
@@ -506,15 +507,13 @@ hashlimit_match(const struct sk_buff *skb,
static int
hashlimit_checkentry(const char *tablename,
const void *inf,
+ const struct xt_match *match,
void *matchinfo,
unsigned int matchsize,
unsigned int hook_mask)
{
struct ipt_hashlimit_info *r = matchinfo;
- if (matchsize != IPT_ALIGN(sizeof(struct ipt_hashlimit_info)))
- return 0;
-
/* Check for overflow. */
if (r->cfg.burst == 0
|| user2credits(r->cfg.avg * r->cfg.burst) <
@@ -558,19 +557,21 @@ hashlimit_checkentry(const char *tablename,
}
static void
-hashlimit_destroy(void *matchinfo, unsigned int matchsize)
+hashlimit_destroy(const struct xt_match *match, void *matchinfo,
+ unsigned int matchsize)
{
struct ipt_hashlimit_info *r = (struct ipt_hashlimit_info *) matchinfo;
htable_put(r->hinfo);
}
-static struct ipt_match ipt_hashlimit = {
- .name = "hashlimit",
- .match = hashlimit_match,
- .checkentry = hashlimit_checkentry,
- .destroy = hashlimit_destroy,
- .me = THIS_MODULE
+static struct ipt_match ipt_hashlimit = {
+ .name = "hashlimit",
+ .match = hashlimit_match,
+ .matchsize = sizeof(struct ipt_hashlimit_info),
+ .checkentry = hashlimit_checkentry,
+ .destroy = hashlimit_destroy,
+ .me = THIS_MODULE
};
/* PROC stuff */
diff --git a/net/ipv4/netfilter/ipt_iprange.c b/net/ipv4/netfilter/ipt_iprange.c
index 13fb16fb7892..ae70112f5e06 100644
--- a/net/ipv4/netfilter/ipt_iprange.c
+++ b/net/ipv4/netfilter/ipt_iprange.c
@@ -27,6 +27,7 @@ static int
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)
{
@@ -62,27 +63,12 @@ match(const struct sk_buff *skb,
return 1;
}
-static int check(const char *tablename,
- const void *inf,
- void *matchinfo,
- unsigned int matchsize,
- unsigned int hook_mask)
-{
- /* verify size */
- if (matchsize != IPT_ALIGN(sizeof(struct ipt_iprange_info)))
- return 0;
-
- return 1;
-}
-
-static struct ipt_match iprange_match =
-{
- .list = { NULL, NULL },
- .name = "iprange",
- .match = &match,
- .checkentry = &check,
- .destroy = NULL,
- .me = THIS_MODULE
+static struct ipt_match iprange_match = {
+ .name = "iprange",
+ .match = match,
+ .matchsize = sizeof(struct ipt_iprange_info),
+ .destroy = NULL,
+ .me = THIS_MODULE
};
static int __init init(void)
diff --git a/net/ipv4/netfilter/ipt_multiport.c b/net/ipv4/netfilter/ipt_multiport.c
index 2d52326553f1..bd07f7c53872 100644
--- a/net/ipv4/netfilter/ipt_multiport.c
+++ b/net/ipv4/netfilter/ipt_multiport.c
@@ -95,6 +95,7 @@ static int
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,
@@ -127,6 +128,7 @@ static int
match_v1(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,
@@ -153,40 +155,19 @@ match_v1(const struct sk_buff *skb,
return ports_match_v1(multiinfo, ntohs(pptr[0]), ntohs(pptr[1]));
}
-/* Called when user tries to insert an entry of this type. */
-static int
-checkentry(const char *tablename,
- const void *ip,
- void *matchinfo,
- unsigned int matchsize,
- unsigned int hook_mask)
-{
- return (matchsize == IPT_ALIGN(sizeof(struct ipt_multiport)));
-}
-
-static int
-checkentry_v1(const char *tablename,
- const void *ip,
- void *matchinfo,
- unsigned int matchsize,
- unsigned int hook_mask)
-{
- return (matchsize == IPT_ALIGN(sizeof(struct ipt_multiport_v1)));
-}
-
static struct ipt_match multiport_match = {
.name = "multiport",
.revision = 0,
- .match = &match,
- .checkentry = &checkentry,
+ .match = match,
+ .matchsize = sizeof(struct ipt_multiport),
.me = THIS_MODULE,
};
static struct ipt_match multiport_match_v1 = {
.name = "multiport",
.revision = 1,
- .match = &match_v1,
- .checkentry = &checkentry_v1,
+ .match = match_v1,
+ .matchsize = sizeof(struct ipt_multiport_v1),
.me = THIS_MODULE,
};
diff --git a/net/ipv4/netfilter/ipt_owner.c b/net/ipv4/netfilter/ipt_owner.c
index 4843d0c9734f..3900428771f3 100644
--- a/net/ipv4/netfilter/ipt_owner.c
+++ b/net/ipv4/netfilter/ipt_owner.c
@@ -25,6 +25,7 @@ static int
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,
@@ -53,37 +54,27 @@ match(const struct sk_buff *skb,
static int
checkentry(const char *tablename,
const void *ip,
+ const struct xt_match *match,
void *matchinfo,
unsigned int matchsize,
unsigned int hook_mask)
{
const struct ipt_owner_info *info = matchinfo;
- if (hook_mask
- & ~((1 << NF_IP_LOCAL_OUT) | (1 << NF_IP_POST_ROUTING))) {
- printk("ipt_owner: only valid for LOCAL_OUT or POST_ROUTING.\n");
- return 0;
- }
-
- if (matchsize != IPT_ALIGN(sizeof(struct ipt_owner_info))) {
- printk("Matchsize %u != %Zu\n", matchsize,
- IPT_ALIGN(sizeof(struct ipt_owner_info)));
- return 0;
- }
-
if (info->match & (IPT_OWNER_PID|IPT_OWNER_SID|IPT_OWNER_COMM)) {
printk("ipt_owner: pid, sid and command matching "
"not supported anymore\n");
return 0;
}
-
return 1;
}
static struct ipt_match owner_match = {
.name = "owner",
- .match = &match,
- .checkentry = &checkentry,
+ .match = match,
+ .matchsize = sizeof(struct ipt_owner_info),
+ .hooks = (1 << NF_IP_LOCAL_OUT) | (1 << NF_IP_POST_ROUTING),
+ .checkentry = checkentry,
.me = THIS_MODULE,
};
diff --git a/net/ipv4/netfilter/ipt_policy.c b/net/ipv4/netfilter/ipt_policy.c
deleted file mode 100644
index 5a7a265280f9..000000000000
--- a/net/ipv4/netfilter/ipt_policy.c
+++ /dev/null
@@ -1,176 +0,0 @@
-/* IP tables module for matching IPsec policy
- *
- * Copyright (c) 2004,2005 Patrick McHardy, <kaber@trash.net>
- *
- * 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 <linux/kernel.h>
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/skbuff.h>
-#include <linux/init.h>
-#include <net/xfrm.h>
-
-#include <linux/netfilter_ipv4.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
-#include <linux/netfilter_ipv4/ipt_policy.h>
-
-MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
-MODULE_DESCRIPTION("IPtables IPsec policy matching module");
-MODULE_LICENSE("GPL");
-
-
-static inline int
-match_xfrm_state(struct xfrm_state *x, const struct ipt_policy_elem *e)
-{
-#define MATCH_ADDR(x,y,z) (!e->match.x || \
- ((e->x.a4.s_addr == (e->y.a4.s_addr & (z))) \
- ^ e->invert.x))
-#define MATCH(x,y) (!e->match.x || ((e->x == (y)) ^ e->invert.x))
-
- return MATCH_ADDR(saddr, smask, x->props.saddr.a4) &&
- MATCH_ADDR(daddr, dmask, x->id.daddr.a4) &&
- MATCH(proto, x->id.proto) &&
- MATCH(mode, x->props.mode) &&
- MATCH(spi, x->id.spi) &&
- MATCH(reqid, x->props.reqid);
-}
-
-static int
-match_policy_in(const struct sk_buff *skb, const struct ipt_policy_info *info)
-{
- const struct ipt_policy_elem *e;
- struct sec_path *sp = skb->sp;
- int strict = info->flags & IPT_POLICY_MATCH_STRICT;
- int i, pos;
-
- if (sp == NULL)
- return -1;
- if (strict && info->len != sp->len)
- return 0;
-
- for (i = sp->len - 1; i >= 0; i--) {
- pos = strict ? i - sp->len + 1 : 0;
- if (pos >= info->len)
- return 0;
- e = &info->pol[pos];
-
- if (match_xfrm_state(sp->x[i].xvec, e)) {
- if (!strict)
- return 1;
- } else if (strict)
- return 0;
- }
-
- return strict ? 1 : 0;
-}
-
-static int
-match_policy_out(const struct sk_buff *skb, const struct ipt_policy_info *info)
-{
- const struct ipt_policy_elem *e;
- struct dst_entry *dst = skb->dst;
- int strict = info->flags & IPT_POLICY_MATCH_STRICT;
- int i, pos;
-
- if (dst->xfrm == NULL)
- return -1;
-
- for (i = 0; dst && dst->xfrm; dst = dst->child, i++) {
- pos = strict ? i : 0;
- if (pos >= info->len)
- return 0;
- e = &info->pol[pos];
-
- if (match_xfrm_state(dst->xfrm, e)) {
- if (!strict)
- return 1;
- } else if (strict)
- return 0;
- }
-
- return strict ? i == info->len : 0;
-}
-
-static int match(const struct sk_buff *skb,
- const struct net_device *in,
- const struct net_device *out,
- const void *matchinfo,
- int offset,
- unsigned int protoff,
- int *hotdrop)
-{
- const struct ipt_policy_info *info = matchinfo;
- int ret;
-
- if (info->flags & IPT_POLICY_MATCH_IN)
- ret = match_policy_in(skb, info);
- else
- ret = match_policy_out(skb, info);
-
- if (ret < 0)
- ret = info->flags & IPT_POLICY_MATCH_NONE ? 1 : 0;
- else if (info->flags & IPT_POLICY_MATCH_NONE)
- ret = 0;
-
- return ret;
-}
-
-static int checkentry(const char *tablename, const void *ip_void,
- void *matchinfo, unsigned int matchsize,
- unsigned int hook_mask)
-{
- struct ipt_policy_info *info = matchinfo;
-
- if (matchsize != IPT_ALIGN(sizeof(*info))) {
- printk(KERN_ERR "ipt_policy: matchsize %u != %zu\n",
- matchsize, IPT_ALIGN(sizeof(*info)));
- return 0;
- }
- if (!(info->flags & (IPT_POLICY_MATCH_IN|IPT_POLICY_MATCH_OUT))) {
- printk(KERN_ERR "ipt_policy: neither incoming nor "
- "outgoing policy selected\n");
- return 0;
- }
- if (hook_mask & (1 << NF_IP_PRE_ROUTING | 1 << NF_IP_LOCAL_IN)
- && info->flags & IPT_POLICY_MATCH_OUT) {
- printk(KERN_ERR "ipt_policy: output policy not valid in "
- "PRE_ROUTING and INPUT\n");
- return 0;
- }
- if (hook_mask & (1 << NF_IP_POST_ROUTING | 1 << NF_IP_LOCAL_OUT)
- && info->flags & IPT_POLICY_MATCH_IN) {
- printk(KERN_ERR "ipt_policy: input policy not valid in "
- "POST_ROUTING and OUTPUT\n");
- return 0;
- }
- if (info->len > IPT_POLICY_MAX_ELEM) {
- printk(KERN_ERR "ipt_policy: too many policy elements\n");
- return 0;
- }
-
- return 1;
-}
-
-static struct ipt_match policy_match = {
- .name = "policy",
- .match = match,
- .checkentry = checkentry,
- .me = THIS_MODULE,
-};
-
-static int __init init(void)
-{
- return ipt_register_match(&policy_match);
-}
-
-static void __exit fini(void)
-{
- ipt_unregister_match(&policy_match);
-}
-
-module_init(init);
-module_exit(fini);
diff --git a/net/ipv4/netfilter/ipt_recent.c b/net/ipv4/netfilter/ipt_recent.c
index 44611d6d14f5..06792ead1da4 100644
--- a/net/ipv4/netfilter/ipt_recent.c
+++ b/net/ipv4/netfilter/ipt_recent.c
@@ -102,6 +102,7 @@ static int
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,
@@ -318,7 +319,7 @@ static int ip_recent_ctrl(struct file *file, const char __user *input, unsigned
skb->nh.iph->daddr = 0;
/* Clear ttl since we have no way of knowing it */
skb->nh.iph->ttl = 0;
- match(skb,NULL,NULL,info,0,0,NULL);
+ match(skb,NULL,NULL,NULL,info,0,0,NULL);
kfree(skb->nh.iph);
out_free_skb:
@@ -356,6 +357,7 @@ static int
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,
@@ -657,6 +659,7 @@ match(const struct sk_buff *skb,
static int
checkentry(const char *tablename,
const void *ip,
+ const struct xt_match *match,
void *matchinfo,
unsigned int matchsize,
unsigned int hook_mask)
@@ -670,8 +673,6 @@ checkentry(const char *tablename,
if(debug) printk(KERN_INFO RECENT_NAME ": checkentry() entered.\n");
#endif
- if (matchsize != IPT_ALIGN(sizeof(struct ipt_recent_info))) return 0;
-
/* seconds and hit_count only valid for CHECK/UPDATE */
if(info->check_set & IPT_RECENT_SET) { flag++; if(info->seconds || info->hit_count) return 0; }
if(info->check_set & IPT_RECENT_REMOVE) { flag++; if(info->seconds || info->hit_count) return 0; }
@@ -871,7 +872,7 @@ checkentry(const char *tablename,
* up its memory.
*/
static void
-destroy(void *matchinfo, unsigned int matchsize)
+destroy(const struct xt_match *match, void *matchinfo, unsigned int matchsize)
{
const struct ipt_recent_info *info = matchinfo;
struct recent_ip_tables *curr_table, *last_table;
@@ -951,12 +952,13 @@ destroy(void *matchinfo, unsigned int matchsize)
/* This is the structure we pass to ipt_register to register our
* module with iptables.
*/
-static struct ipt_match recent_match = {
- .name = "recent",
- .match = &match,
- .checkentry = &checkentry,
- .destroy = &destroy,
- .me = THIS_MODULE
+static struct ipt_match recent_match = {
+ .name = "recent",
+ .match = match,
+ .matchsize = sizeof(struct ipt_recent_info),
+ .checkentry = checkentry,
+ .destroy = destroy,
+ .me = THIS_MODULE
};
/* Kernel module initialization. */
diff --git a/net/ipv4/netfilter/ipt_tos.c b/net/ipv4/netfilter/ipt_tos.c
index 9ab765e126f2..e404e92ddd01 100644
--- a/net/ipv4/netfilter/ipt_tos.c
+++ b/net/ipv4/netfilter/ipt_tos.c
@@ -21,6 +21,7 @@ static int
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,
@@ -31,23 +32,10 @@ match(const struct sk_buff *skb,
return (skb->nh.iph->tos == info->tos) ^ info->invert;
}
-static int
-checkentry(const char *tablename,
- const void *ip,
- void *matchinfo,
- unsigned int matchsize,
- unsigned int hook_mask)
-{
- if (matchsize != IPT_ALIGN(sizeof(struct ipt_tos_info)))
- return 0;
-
- return 1;
-}
-
static struct ipt_match tos_match = {
.name = "tos",
- .match = &match,
- .checkentry = &checkentry,
+ .match = match,
+ .matchsize = sizeof(struct ipt_tos_info),
.me = THIS_MODULE,
};
diff --git a/net/ipv4/netfilter/ipt_ttl.c b/net/ipv4/netfilter/ipt_ttl.c
index 82da53f430ab..ae7ce4d8d90e 100644
--- a/net/ipv4/netfilter/ipt_ttl.c
+++ b/net/ipv4/netfilter/ipt_ttl.c
@@ -19,8 +19,9 @@ MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
MODULE_DESCRIPTION("IP tables TTL matching module");
MODULE_LICENSE("GPL");
-static int match(const struct sk_buff *skb, const struct net_device *in,
- const struct net_device *out, const void *matchinfo,
+static int 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)
{
const struct ipt_ttl_info *info = matchinfo;
@@ -47,20 +48,10 @@ static int match(const struct sk_buff *skb, const struct net_device *in,
return 0;
}
-static int checkentry(const char *tablename, const void *ip,
- void *matchinfo, unsigned int matchsize,
- unsigned int hook_mask)
-{
- if (matchsize != IPT_ALIGN(sizeof(struct ipt_ttl_info)))
- return 0;
-
- return 1;
-}
-
static struct ipt_match ttl_match = {
.name = "ttl",
- .match = &match,
- .checkentry = &checkentry,
+ .match = match,
+ .matchsize = sizeof(struct ipt_ttl_info),
.me = THIS_MODULE,
};
diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
index 6c8624a54933..c8abc9d859b9 100644
--- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
+++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
@@ -141,19 +141,21 @@ static unsigned int ipv4_conntrack_help(unsigned int hooknum,
{
struct nf_conn *ct;
enum ip_conntrack_info ctinfo;
+ struct nf_conn_help *help;
/* This is where we call the helper: as the packet goes out. */
ct = nf_ct_get(*pskb, &ctinfo);
- if (ct && ct->helper) {
- unsigned int ret;
- ret = ct->helper->help(pskb,
- (*pskb)->nh.raw - (*pskb)->data
- + (*pskb)->nh.iph->ihl*4,
- ct, ctinfo);
- if (ret != NF_ACCEPT)
- return ret;
- }
- return NF_ACCEPT;
+ if (!ct)
+ return NF_ACCEPT;
+
+ help = nfct_help(ct);
+ if (!help || !help->helper)
+ return NF_ACCEPT;
+
+ return help->helper->help(pskb,
+ (*pskb)->nh.raw - (*pskb)->data
+ + (*pskb)->nh.iph->ihl*4,
+ ct, ctinfo);
}
static unsigned int ipv4_conntrack_defrag(unsigned int hooknum,
@@ -566,6 +568,7 @@ static int init_or_cleanup(int init)
return ret;
}
+MODULE_ALIAS("nf_conntrack-" __stringify(AF_INET));
MODULE_LICENSE("GPL");
static int __init init(void)
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
index f29a12da5109..fc2562415555 100644
--- a/net/ipv4/raw.c
+++ b/net/ipv4/raw.c
@@ -660,12 +660,9 @@ static int raw_geticmpfilter(struct sock *sk, char __user *optval, int __user *o
out: return ret;
}
-static int raw_setsockopt(struct sock *sk, int level, int optname,
+static int do_raw_setsockopt(struct sock *sk, int level, int optname,
char __user *optval, int optlen)
{
- if (level != SOL_RAW)
- return ip_setsockopt(sk, level, optname, optval, optlen);
-
if (optname == ICMP_FILTER) {
if (inet_sk(sk)->num != IPPROTO_ICMP)
return -EOPNOTSUPP;
@@ -675,12 +672,27 @@ static int raw_setsockopt(struct sock *sk, int level, int optname,
return -ENOPROTOOPT;
}
-static int raw_getsockopt(struct sock *sk, int level, int optname,
- char __user *optval, int __user *optlen)
+static int raw_setsockopt(struct sock *sk, int level, int optname,
+ char __user *optval, int optlen)
{
if (level != SOL_RAW)
- return ip_getsockopt(sk, level, optname, optval, optlen);
+ return ip_setsockopt(sk, level, optname, optval, optlen);
+ return do_raw_setsockopt(sk, level, optname, optval, optlen);
+}
+#ifdef CONFIG_COMPAT
+static int compat_raw_setsockopt(struct sock *sk, int level, int optname,
+ char __user *optval, int optlen)
+{
+ if (level != SOL_RAW)
+ return compat_ip_setsockopt(sk, level, optname, optval, optlen);
+ return do_raw_setsockopt(sk, level, optname, optval, optlen);
+}
+#endif
+
+static int do_raw_getsockopt(struct sock *sk, int level, int optname,
+ char __user *optval, int __user *optlen)
+{
if (optname == ICMP_FILTER) {
if (inet_sk(sk)->num != IPPROTO_ICMP)
return -EOPNOTSUPP;
@@ -690,6 +702,24 @@ static int raw_getsockopt(struct sock *sk, int level, int optname,
return -ENOPROTOOPT;
}
+static int raw_getsockopt(struct sock *sk, int level, int optname,
+ char __user *optval, int __user *optlen)
+{
+ if (level != SOL_RAW)
+ return ip_getsockopt(sk, level, optname, optval, optlen);
+ return do_raw_getsockopt(sk, level, optname, optval, optlen);
+}
+
+#ifdef CONFIG_COMPAT
+static int compat_raw_getsockopt(struct sock *sk, int level, int optname,
+ char __user *optval, int __user *optlen)
+{
+ if (level != SOL_RAW)
+ return compat_ip_getsockopt(sk, level, optname, optval, optlen);
+ return do_raw_getsockopt(sk, level, optname, optval, optlen);
+}
+#endif
+
static int raw_ioctl(struct sock *sk, int cmd, unsigned long arg)
{
switch (cmd) {
@@ -719,22 +749,26 @@ static int raw_ioctl(struct sock *sk, int cmd, unsigned long arg)
}
struct proto raw_prot = {
- .name = "RAW",
- .owner = THIS_MODULE,
- .close = raw_close,
- .connect = ip4_datagram_connect,
- .disconnect = udp_disconnect,
- .ioctl = raw_ioctl,
- .init = raw_init,
- .setsockopt = raw_setsockopt,
- .getsockopt = raw_getsockopt,
- .sendmsg = raw_sendmsg,
- .recvmsg = raw_recvmsg,
- .bind = raw_bind,
- .backlog_rcv = raw_rcv_skb,
- .hash = raw_v4_hash,
- .unhash = raw_v4_unhash,
- .obj_size = sizeof(struct raw_sock),
+ .name = "RAW",
+ .owner = THIS_MODULE,
+ .close = raw_close,
+ .connect = ip4_datagram_connect,
+ .disconnect = udp_disconnect,
+ .ioctl = raw_ioctl,
+ .init = raw_init,
+ .setsockopt = raw_setsockopt,
+ .getsockopt = raw_getsockopt,
+ .sendmsg = raw_sendmsg,
+ .recvmsg = raw_recvmsg,
+ .bind = raw_bind,
+ .backlog_rcv = raw_rcv_skb,
+ .hash = raw_v4_hash,
+ .unhash = raw_v4_unhash,
+ .obj_size = sizeof(struct raw_sock),
+#ifdef CONFIG_COMPAT
+ .compat_setsockopt = compat_raw_setsockopt,
+ .compat_getsockopt = compat_raw_getsockopt,
+#endif
};
#ifdef CONFIG_PROC_FS
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index fca5fe0cf94a..94fcbc5e5a1b 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -55,6 +55,8 @@
* Robert Olsson : Added rt_cache statistics
* Arnaldo C. Melo : Convert proc stuff to seq_file
* Eric Dumazet : hashed spinlocks and rt_check_expire() fixes.
+ * Ilia Sotnikov : Ignore TOS on PMTUD and Redirect
+ * Ilia Sotnikov : Removed TOS from hash calculations
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -247,9 +249,9 @@ static DEFINE_PER_CPU(struct rt_cache_stat, rt_cache_stat);
static int rt_intern_hash(unsigned hash, struct rtable *rth,
struct rtable **res);
-static unsigned int rt_hash_code(u32 daddr, u32 saddr, u8 tos)
+static unsigned int rt_hash_code(u32 daddr, u32 saddr)
{
- return (jhash_3words(daddr, saddr, (u32) tos, rt_hash_rnd)
+ return (jhash_2words(daddr, saddr, rt_hash_rnd)
& rt_hash_mask);
}
@@ -1111,7 +1113,7 @@ static void rt_del(unsigned hash, struct rtable *rt)
}
void ip_rt_redirect(u32 old_gw, u32 daddr, u32 new_gw,
- u32 saddr, u8 tos, struct net_device *dev)
+ u32 saddr, struct net_device *dev)
{
int i, k;
struct in_device *in_dev = in_dev_get(dev);
@@ -1119,8 +1121,6 @@ void ip_rt_redirect(u32 old_gw, u32 daddr, u32 new_gw,
u32 skeys[2] = { saddr, 0 };
int ikeys[2] = { dev->ifindex, 0 };
- tos &= IPTOS_RT_MASK;
-
if (!in_dev)
return;
@@ -1141,8 +1141,7 @@ void ip_rt_redirect(u32 old_gw, u32 daddr, u32 new_gw,
for (i = 0; i < 2; i++) {
for (k = 0; k < 2; k++) {
unsigned hash = rt_hash_code(daddr,
- skeys[i] ^ (ikeys[k] << 5),
- tos);
+ skeys[i] ^ (ikeys[k] << 5));
rthp=&rt_hash_table[hash].chain;
@@ -1152,7 +1151,6 @@ void ip_rt_redirect(u32 old_gw, u32 daddr, u32 new_gw,
if (rth->fl.fl4_dst != daddr ||
rth->fl.fl4_src != skeys[i] ||
- rth->fl.fl4_tos != tos ||
rth->fl.oif != ikeys[k] ||
rth->fl.iif != 0) {
rthp = &rth->u.rt_next;
@@ -1232,10 +1230,9 @@ reject_redirect:
if (IN_DEV_LOG_MARTIANS(in_dev) && net_ratelimit())
printk(KERN_INFO "Redirect from %u.%u.%u.%u on %s about "
"%u.%u.%u.%u ignored.\n"
- " Advised path = %u.%u.%u.%u -> %u.%u.%u.%u, "
- "tos %02x\n",
+ " Advised path = %u.%u.%u.%u -> %u.%u.%u.%u\n",
NIPQUAD(old_gw), dev->name, NIPQUAD(new_gw),
- NIPQUAD(saddr), NIPQUAD(daddr), tos);
+ NIPQUAD(saddr), NIPQUAD(daddr));
#endif
in_dev_put(in_dev);
}
@@ -1253,8 +1250,7 @@ static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst)
rt->u.dst.expires) {
unsigned hash = rt_hash_code(rt->fl.fl4_dst,
rt->fl.fl4_src ^
- (rt->fl.oif << 5),
- rt->fl.fl4_tos);
+ (rt->fl.oif << 5));
#if RT_CACHE_DEBUG >= 1
printk(KERN_DEBUG "ip_rt_advice: redirect to "
"%u.%u.%u.%u/%02x dropped\n",
@@ -1391,14 +1387,13 @@ unsigned short ip_rt_frag_needed(struct iphdr *iph, unsigned short new_mtu)
struct rtable *rth;
u32 skeys[2] = { iph->saddr, 0, };
u32 daddr = iph->daddr;
- u8 tos = iph->tos & IPTOS_RT_MASK;
unsigned short est_mtu = 0;
if (ipv4_config.no_pmtu_disc)
return 0;
for (i = 0; i < 2; i++) {
- unsigned hash = rt_hash_code(daddr, skeys[i], tos);
+ unsigned hash = rt_hash_code(daddr, skeys[i]);
rcu_read_lock();
for (rth = rcu_dereference(rt_hash_table[hash].chain); rth;
@@ -1407,7 +1402,6 @@ unsigned short ip_rt_frag_needed(struct iphdr *iph, unsigned short new_mtu)
rth->fl.fl4_src == skeys[i] &&
rth->rt_dst == daddr &&
rth->rt_src == iph->saddr &&
- rth->fl.fl4_tos == tos &&
rth->fl.iif == 0 &&
!(dst_metric_locked(&rth->u.dst, RTAX_MTU))) {
unsigned short mtu = new_mtu;
@@ -1658,7 +1652,7 @@ static int ip_route_input_mc(struct sk_buff *skb, u32 daddr, u32 saddr,
RT_CACHE_STAT_INC(in_slow_mc);
in_dev_put(in_dev);
- hash = rt_hash_code(daddr, saddr ^ (dev->ifindex << 5), tos);
+ hash = rt_hash_code(daddr, saddr ^ (dev->ifindex << 5));
return rt_intern_hash(hash, rth, (struct rtable**) &skb->dst);
e_nobufs:
@@ -1823,7 +1817,7 @@ static inline int ip_mkroute_input_def(struct sk_buff *skb,
return err;
/* put it into the cache */
- hash = rt_hash_code(daddr, saddr ^ (fl->iif << 5), tos);
+ hash = rt_hash_code(daddr, saddr ^ (fl->iif << 5));
return rt_intern_hash(hash, rth, (struct rtable**)&skb->dst);
}
@@ -1864,7 +1858,7 @@ static inline int ip_mkroute_input(struct sk_buff *skb,
return err;
/* put it into the cache */
- hash = rt_hash_code(daddr, saddr ^ (fl->iif << 5), tos);
+ hash = rt_hash_code(daddr, saddr ^ (fl->iif << 5));
err = rt_intern_hash(hash, rth, &rtres);
if (err)
return err;
@@ -2041,7 +2035,7 @@ local_input:
rth->rt_flags &= ~RTCF_LOCAL;
}
rth->rt_type = res.type;
- hash = rt_hash_code(daddr, saddr ^ (fl.iif << 5), tos);
+ hash = rt_hash_code(daddr, saddr ^ (fl.iif << 5));
err = rt_intern_hash(hash, rth, (struct rtable**)&skb->dst);
goto done;
@@ -2088,7 +2082,7 @@ int ip_route_input(struct sk_buff *skb, u32 daddr, u32 saddr,
int iif = dev->ifindex;
tos &= IPTOS_RT_MASK;
- hash = rt_hash_code(daddr, saddr ^ (iif << 5), tos);
+ hash = rt_hash_code(daddr, saddr ^ (iif << 5));
rcu_read_lock();
for (rth = rcu_dereference(rt_hash_table[hash].chain); rth;
@@ -2286,10 +2280,8 @@ static inline int ip_mkroute_output_def(struct rtable **rp,
int err = __mkroute_output(&rth, res, fl, oldflp, dev_out, flags);
unsigned hash;
if (err == 0) {
- u32 tos = RT_FL_TOS(oldflp);
-
hash = rt_hash_code(oldflp->fl4_dst,
- oldflp->fl4_src ^ (oldflp->oif << 5), tos);
+ oldflp->fl4_src ^ (oldflp->oif << 5));
err = rt_intern_hash(hash, rth, rp);
}
@@ -2304,7 +2296,6 @@ static inline int ip_mkroute_output(struct rtable** rp,
unsigned flags)
{
#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
- u32 tos = RT_FL_TOS(oldflp);
unsigned char hop;
unsigned hash;
int err = -EINVAL;
@@ -2334,7 +2325,7 @@ static inline int ip_mkroute_output(struct rtable** rp,
hash = rt_hash_code(oldflp->fl4_dst,
oldflp->fl4_src ^
- (oldflp->oif << 5), tos);
+ (oldflp->oif << 5));
err = rt_intern_hash(hash, rth, rp);
/* forward hop information to multipath impl. */
@@ -2563,7 +2554,7 @@ int __ip_route_output_key(struct rtable **rp, const struct flowi *flp)
unsigned hash;
struct rtable *rth;
- hash = rt_hash_code(flp->fl4_dst, flp->fl4_src ^ (flp->oif << 5), flp->fl4_tos);
+ hash = rt_hash_code(flp->fl4_dst, flp->fl4_src ^ (flp->oif << 5));
rcu_read_lock_bh();
for (rth = rcu_dereference(rt_hash_table[hash].chain); rth;
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index 16984d4a8a06..6b6c3adfcf00 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -664,7 +664,30 @@ ctl_table ipv4_table[] = {
.mode = 0644,
.proc_handler = &proc_dointvec,
},
-
+ {
+ .ctl_name = NET_TCP_MTU_PROBING,
+ .procname = "tcp_mtu_probing",
+ .data = &sysctl_tcp_mtu_probing,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
+ {
+ .ctl_name = NET_TCP_BASE_MSS,
+ .procname = "tcp_base_mss",
+ .data = &sysctl_tcp_base_mss,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
+ {
+ .ctl_name = NET_IPV4_TCP_WORKAROUND_SIGNED_WINDOWS,
+ .procname = "tcp_workaround_signed_windows",
+ .data = &sysctl_tcp_workaround_signed_windows,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec
+ },
{ .ctl_name = 0 }
};
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 00aa80e93243..87f68e787d0c 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -257,6 +257,7 @@
#include <linux/fs.h>
#include <linux/random.h>
#include <linux/bootmem.h>
+#include <linux/cache.h>
#include <net/icmp.h>
#include <net/tcp.h>
@@ -275,9 +276,9 @@ atomic_t tcp_orphan_count = ATOMIC_INIT(0);
EXPORT_SYMBOL_GPL(tcp_orphan_count);
-int sysctl_tcp_mem[3];
-int sysctl_tcp_wmem[3] = { 4 * 1024, 16 * 1024, 128 * 1024 };
-int sysctl_tcp_rmem[3] = { 4 * 1024, 87380, 87380 * 2 };
+int sysctl_tcp_mem[3] __read_mostly;
+int sysctl_tcp_wmem[3] __read_mostly;
+int sysctl_tcp_rmem[3] __read_mostly;
EXPORT_SYMBOL(sysctl_tcp_mem);
EXPORT_SYMBOL(sysctl_tcp_rmem);
@@ -365,7 +366,7 @@ unsigned int tcp_poll(struct file *file, struct socket *sock, poll_table *wait)
if (sk->sk_shutdown == SHUTDOWN_MASK || sk->sk_state == TCP_CLOSE)
mask |= POLLHUP;
if (sk->sk_shutdown & RCV_SHUTDOWN)
- mask |= POLLIN | POLLRDNORM;
+ mask |= POLLIN | POLLRDNORM | POLLRDHUP;
/* Connected? */
if ((1 << sk->sk_state) & ~(TCPF_SYN_SENT | TCPF_SYN_RECV)) {
@@ -1687,18 +1688,14 @@ int tcp_disconnect(struct sock *sk, int flags)
/*
* Socket option code for TCP.
*/
-int tcp_setsockopt(struct sock *sk, int level, int optname, char __user *optval,
- int optlen)
+static int do_tcp_setsockopt(struct sock *sk, int level,
+ int optname, char __user *optval, int optlen)
{
struct tcp_sock *tp = tcp_sk(sk);
struct inet_connection_sock *icsk = inet_csk(sk);
int val;
int err = 0;
- if (level != SOL_TCP)
- return icsk->icsk_af_ops->setsockopt(sk, level, optname,
- optval, optlen);
-
/* This is a string value all the others are int's */
if (optname == TCP_CONGESTION) {
char name[TCP_CA_NAME_MAX];
@@ -1871,6 +1868,30 @@ int tcp_setsockopt(struct sock *sk, int level, int optname, char __user *optval,
return err;
}
+int tcp_setsockopt(struct sock *sk, int level, int optname, char __user *optval,
+ int optlen)
+{
+ struct inet_connection_sock *icsk = inet_csk(sk);
+
+ if (level != SOL_TCP)
+ return icsk->icsk_af_ops->setsockopt(sk, level, optname,
+ optval, optlen);
+ return do_tcp_setsockopt(sk, level, optname, optval, optlen);
+}
+
+#ifdef CONFIG_COMPAT
+int compat_tcp_setsockopt(struct sock *sk, int level, int optname,
+ char __user *optval, int optlen)
+{
+ if (level != SOL_TCP)
+ return inet_csk_compat_setsockopt(sk, level, optname,
+ optval, optlen);
+ return do_tcp_setsockopt(sk, level, optname, optval, optlen);
+}
+
+EXPORT_SYMBOL(compat_tcp_setsockopt);
+#endif
+
/* Return information about state of tcp endpoint in API format. */
void tcp_get_info(struct sock *sk, struct tcp_info *info)
{
@@ -1931,17 +1952,13 @@ void tcp_get_info(struct sock *sk, struct tcp_info *info)
EXPORT_SYMBOL_GPL(tcp_get_info);
-int tcp_getsockopt(struct sock *sk, int level, int optname, char __user *optval,
- int __user *optlen)
+static int do_tcp_getsockopt(struct sock *sk, int level,
+ int optname, char __user *optval, int __user *optlen)
{
struct inet_connection_sock *icsk = inet_csk(sk);
struct tcp_sock *tp = tcp_sk(sk);
int val, len;
- if (level != SOL_TCP)
- return icsk->icsk_af_ops->getsockopt(sk, level, optname,
- optval, optlen);
-
if (get_user(len, optlen))
return -EFAULT;
@@ -2025,6 +2042,29 @@ int tcp_getsockopt(struct sock *sk, int level, int optname, char __user *optval,
return 0;
}
+int tcp_getsockopt(struct sock *sk, int level, int optname, char __user *optval,
+ int __user *optlen)
+{
+ struct inet_connection_sock *icsk = inet_csk(sk);
+
+ if (level != SOL_TCP)
+ return icsk->icsk_af_ops->getsockopt(sk, level, optname,
+ optval, optlen);
+ return do_tcp_getsockopt(sk, level, optname, optval, optlen);
+}
+
+#ifdef CONFIG_COMPAT
+int compat_tcp_getsockopt(struct sock *sk, int level, int optname,
+ char __user *optval, int __user *optlen)
+{
+ if (level != SOL_TCP)
+ return inet_csk_compat_getsockopt(sk, level, optname,
+ optval, optlen);
+ return do_tcp_getsockopt(sk, level, optname, optval, optlen);
+}
+
+EXPORT_SYMBOL(compat_tcp_getsockopt);
+#endif
extern void __skb_cb_too_small_for_tcp(int, int);
extern struct tcp_congestion_ops tcp_reno;
@@ -2042,7 +2082,8 @@ __setup("thash_entries=", set_thash_entries);
void __init tcp_init(void)
{
struct sk_buff *skb = NULL;
- int order, i;
+ unsigned long limit;
+ int order, i, max_share;
if (sizeof(struct tcp_skb_cb) > sizeof(skb->cb))
__skb_cb_too_small_for_tcp(sizeof(struct tcp_skb_cb),
@@ -2116,12 +2157,16 @@ void __init tcp_init(void)
sysctl_tcp_mem[1] = 1024 << order;
sysctl_tcp_mem[2] = 1536 << order;
- if (order < 3) {
- sysctl_tcp_wmem[2] = 64 * 1024;
- sysctl_tcp_rmem[0] = PAGE_SIZE;
- sysctl_tcp_rmem[1] = 43689;
- sysctl_tcp_rmem[2] = 2 * 43689;
- }
+ limit = ((unsigned long)sysctl_tcp_mem[1]) << (PAGE_SHIFT - 7);
+ max_share = min(4UL*1024*1024, limit);
+
+ sysctl_tcp_wmem[0] = SK_STREAM_MEM_QUANTUM;
+ sysctl_tcp_wmem[1] = 16*1024;
+ sysctl_tcp_wmem[2] = max(64*1024, max_share);
+
+ sysctl_tcp_rmem[0] = SK_STREAM_MEM_QUANTUM;
+ sysctl_tcp_rmem[1] = 87380;
+ sysctl_tcp_rmem[2] = max(87380, max_share);
printk(KERN_INFO "TCP: Hash tables configured "
"(established %d bind %d)\n",
diff --git a/net/ipv4/tcp_htcp.c b/net/ipv4/tcp_htcp.c
index 128de4d7c0b7..1b2ff53f98ed 100644
--- a/net/ipv4/tcp_htcp.c
+++ b/net/ipv4/tcp_htcp.c
@@ -27,12 +27,12 @@ struct htcp {
u16 alpha; /* Fixed point arith, << 7 */
u8 beta; /* Fixed point arith, << 7 */
u8 modeswitch; /* Delay modeswitch until we had at least one congestion event */
- u8 ccount; /* Number of RTTs since last congestion event */
- u8 undo_ccount;
- u16 packetcount;
+ u32 last_cong; /* Time since last congestion event end */
+ u32 undo_last_cong;
+ u16 pkts_acked;
+ u32 packetcount;
u32 minRTT;
u32 maxRTT;
- u32 snd_cwnd_cnt2;
u32 undo_maxRTT;
u32 undo_old_maxB;
@@ -45,21 +45,30 @@ struct htcp {
u32 lasttime;
};
+static inline u32 htcp_cong_time(struct htcp *ca)
+{
+ return jiffies - ca->last_cong;
+}
+
+static inline u32 htcp_ccount(struct htcp *ca)
+{
+ return htcp_cong_time(ca)/ca->minRTT;
+}
+
static inline void htcp_reset(struct htcp *ca)
{
- ca->undo_ccount = ca->ccount;
+ ca->undo_last_cong = ca->last_cong;
ca->undo_maxRTT = ca->maxRTT;
ca->undo_old_maxB = ca->old_maxB;
- ca->ccount = 0;
- ca->snd_cwnd_cnt2 = 0;
+ ca->last_cong = jiffies;
}
static u32 htcp_cwnd_undo(struct sock *sk)
{
const struct tcp_sock *tp = tcp_sk(sk);
struct htcp *ca = inet_csk_ca(sk);
- ca->ccount = ca->undo_ccount;
+ ca->last_cong = ca->undo_last_cong;
ca->maxRTT = ca->undo_maxRTT;
ca->old_maxB = ca->undo_old_maxB;
return max(tp->snd_cwnd, (tp->snd_ssthresh<<7)/ca->beta);
@@ -77,10 +86,10 @@ static inline void measure_rtt(struct sock *sk)
ca->minRTT = srtt;
/* max RTT */
- if (icsk->icsk_ca_state == TCP_CA_Open && tp->snd_ssthresh < 0xFFFF && ca->ccount > 3) {
+ if (icsk->icsk_ca_state == TCP_CA_Open && tp->snd_ssthresh < 0xFFFF && htcp_ccount(ca) > 3) {
if (ca->maxRTT < ca->minRTT)
ca->maxRTT = ca->minRTT;
- if (ca->maxRTT < srtt && srtt <= ca->maxRTT+HZ/50)
+ if (ca->maxRTT < srtt && srtt <= ca->maxRTT+msecs_to_jiffies(20))
ca->maxRTT = srtt;
}
}
@@ -92,6 +101,12 @@ static void measure_achieved_throughput(struct sock *sk, u32 pkts_acked)
struct htcp *ca = inet_csk_ca(sk);
u32 now = tcp_time_stamp;
+ if (icsk->icsk_ca_state == TCP_CA_Open)
+ ca->pkts_acked = pkts_acked;
+
+ if (!use_bandwidth_switch)
+ return;
+
/* achieved throughput calculations */
if (icsk->icsk_ca_state != TCP_CA_Open &&
icsk->icsk_ca_state != TCP_CA_Disorder) {
@@ -106,7 +121,7 @@ static void measure_achieved_throughput(struct sock *sk, u32 pkts_acked)
&& now - ca->lasttime >= ca->minRTT
&& ca->minRTT > 0) {
__u32 cur_Bi = ca->packetcount*HZ/(now - ca->lasttime);
- if (ca->ccount <= 3) {
+ if (htcp_ccount(ca) <= 3) {
/* just after backoff */
ca->minB = ca->maxB = ca->Bi = cur_Bi;
} else {
@@ -135,7 +150,7 @@ static inline void htcp_beta_update(struct htcp *ca, u32 minRTT, u32 maxRTT)
}
}
- if (ca->modeswitch && minRTT > max(HZ/100, 1) && maxRTT) {
+ if (ca->modeswitch && minRTT > msecs_to_jiffies(10) && maxRTT) {
ca->beta = (minRTT<<7)/maxRTT;
if (ca->beta < BETA_MIN)
ca->beta = BETA_MIN;
@@ -151,7 +166,7 @@ static inline void htcp_alpha_update(struct htcp *ca)
{
u32 minRTT = ca->minRTT;
u32 factor = 1;
- u32 diff = ca->ccount * minRTT; /* time since last backoff */
+ u32 diff = htcp_cong_time(ca);
if (diff > HZ) {
diff -= HZ;
@@ -216,21 +231,18 @@ static void htcp_cong_avoid(struct sock *sk, u32 ack, u32 rtt,
measure_rtt(sk);
- /* keep track of number of round-trip times since last backoff event */
- if (ca->snd_cwnd_cnt2++ > tp->snd_cwnd) {
- ca->ccount++;
- ca->snd_cwnd_cnt2 = 0;
- htcp_alpha_update(ca);
- }
-
/* In dangerous area, increase slowly.
* In theory this is tp->snd_cwnd += alpha / tp->snd_cwnd
*/
- if ((tp->snd_cwnd_cnt++ * ca->alpha)>>7 >= tp->snd_cwnd) {
+ if ((tp->snd_cwnd_cnt * ca->alpha)>>7 >= tp->snd_cwnd) {
if (tp->snd_cwnd < tp->snd_cwnd_clamp)
tp->snd_cwnd++;
tp->snd_cwnd_cnt = 0;
- }
+ htcp_alpha_update(ca);
+ } else
+ tp->snd_cwnd_cnt += ca->pkts_acked;
+
+ ca->pkts_acked = 1;
}
}
@@ -249,11 +261,19 @@ static void htcp_init(struct sock *sk)
memset(ca, 0, sizeof(struct htcp));
ca->alpha = ALPHA_BASE;
ca->beta = BETA_MIN;
+ ca->pkts_acked = 1;
+ ca->last_cong = jiffies;
}
static void htcp_state(struct sock *sk, u8 new_state)
{
switch (new_state) {
+ case TCP_CA_Open:
+ {
+ struct htcp *ca = inet_csk_ca(sk);
+ ca->last_cong = jiffies;
+ }
+ break;
case TCP_CA_CWR:
case TCP_CA_Recovery:
case TCP_CA_Loss:
@@ -278,8 +298,6 @@ static int __init htcp_register(void)
{
BUG_ON(sizeof(struct htcp) > ICSK_CA_PRIV_SIZE);
BUILD_BUG_ON(BETA_MIN >= BETA_MAX);
- if (!use_bandwidth_switch)
- htcp.pkts_acked = NULL;
return tcp_register_congestion_control(&htcp);
}
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index e9a54ae7d690..195d83584558 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -1891,6 +1891,34 @@ static void tcp_try_to_open(struct sock *sk, struct tcp_sock *tp, int flag)
}
}
+static void tcp_mtup_probe_failed(struct sock *sk)
+{
+ struct inet_connection_sock *icsk = inet_csk(sk);
+
+ icsk->icsk_mtup.search_high = icsk->icsk_mtup.probe_size - 1;
+ icsk->icsk_mtup.probe_size = 0;
+}
+
+static void tcp_mtup_probe_success(struct sock *sk, struct sk_buff *skb)
+{
+ struct tcp_sock *tp = tcp_sk(sk);
+ struct inet_connection_sock *icsk = inet_csk(sk);
+
+ /* FIXME: breaks with very large cwnd */
+ tp->prior_ssthresh = tcp_current_ssthresh(sk);
+ tp->snd_cwnd = tp->snd_cwnd *
+ tcp_mss_to_mtu(sk, tp->mss_cache) /
+ icsk->icsk_mtup.probe_size;
+ tp->snd_cwnd_cnt = 0;
+ tp->snd_cwnd_stamp = tcp_time_stamp;
+ tp->rcv_ssthresh = tcp_current_ssthresh(sk);
+
+ icsk->icsk_mtup.search_low = icsk->icsk_mtup.probe_size;
+ icsk->icsk_mtup.probe_size = 0;
+ tcp_sync_mss(sk, icsk->icsk_pmtu_cookie);
+}
+
+
/* Process an event, which can update packets-in-flight not trivially.
* Main goal of this function is to calculate new estimate for left_out,
* taking into account both packets sitting in receiver's buffer and
@@ -2023,6 +2051,17 @@ tcp_fastretrans_alert(struct sock *sk, u32 prior_snd_una,
return;
}
+ /* MTU probe failure: don't reduce cwnd */
+ if (icsk->icsk_ca_state < TCP_CA_CWR &&
+ icsk->icsk_mtup.probe_size &&
+ tp->snd_una == tp->mtu_probe.probe_seq_start) {
+ tcp_mtup_probe_failed(sk);
+ /* Restores the reduction we did in tcp_mtup_probe() */
+ tp->snd_cwnd++;
+ tcp_simple_retransmit(sk);
+ return;
+ }
+
/* Otherwise enter Recovery state */
if (IsReno(tp))
@@ -2243,6 +2282,13 @@ static int tcp_clean_rtx_queue(struct sock *sk, __s32 *seq_rtt_p)
tp->retrans_stamp = 0;
}
+ /* MTU probing checks */
+ if (icsk->icsk_mtup.probe_size) {
+ if (!after(tp->mtu_probe.probe_seq_end, TCP_SKB_CB(skb)->end_seq)) {
+ tcp_mtup_probe_success(sk, skb);
+ }
+ }
+
if (sacked) {
if (sacked & TCPCB_RETRANS) {
if(sacked & TCPCB_SACKED_RETRANS)
@@ -4101,6 +4147,7 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
if (tp->rx_opt.sack_ok && sysctl_tcp_fack)
tp->rx_opt.sack_ok |= 2;
+ tcp_mtup_init(sk);
tcp_sync_mss(sk, icsk->icsk_pmtu_cookie);
tcp_initialize_rcv_mss(sk);
@@ -4211,6 +4258,7 @@ discard:
if (tp->ecn_flags&TCP_ECN_OK)
sock_set_flag(sk, SOCK_NO_LARGESEND);
+ tcp_mtup_init(sk);
tcp_sync_mss(sk, icsk->icsk_pmtu_cookie);
tcp_initialize_rcv_mss(sk);
@@ -4399,6 +4447,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
*/
tp->lsndtime = tcp_time_stamp;
+ tcp_mtup_init(sk);
tcp_initialize_rcv_mss(sk);
tcp_init_buffer_space(sk);
tcp_fast_path_on(tp);
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 233bdf259965..9e85c0416109 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -900,6 +900,7 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
inet_csk(newsk)->icsk_ext_hdr_len = newinet->opt->optlen;
newinet->id = newtp->write_seq ^ jiffies;
+ tcp_mtup_init(newsk);
tcp_sync_mss(newsk, dst_mtu(dst));
newtp->advmss = dst_metric(dst, RTAX_ADVMSS);
tcp_initialize_rcv_mss(newsk);
@@ -1216,17 +1217,21 @@ int tcp_v4_tw_remember_stamp(struct inet_timewait_sock *tw)
}
struct inet_connection_sock_af_ops ipv4_specific = {
- .queue_xmit = ip_queue_xmit,
- .send_check = tcp_v4_send_check,
- .rebuild_header = inet_sk_rebuild_header,
- .conn_request = tcp_v4_conn_request,
- .syn_recv_sock = tcp_v4_syn_recv_sock,
- .remember_stamp = tcp_v4_remember_stamp,
- .net_header_len = sizeof(struct iphdr),
- .setsockopt = ip_setsockopt,
- .getsockopt = ip_getsockopt,
- .addr2sockaddr = inet_csk_addr2sockaddr,
- .sockaddr_len = sizeof(struct sockaddr_in),
+ .queue_xmit = ip_queue_xmit,
+ .send_check = tcp_v4_send_check,
+ .rebuild_header = inet_sk_rebuild_header,
+ .conn_request = tcp_v4_conn_request,
+ .syn_recv_sock = tcp_v4_syn_recv_sock,
+ .remember_stamp = tcp_v4_remember_stamp,
+ .net_header_len = sizeof(struct iphdr),
+ .setsockopt = ip_setsockopt,
+ .getsockopt = ip_getsockopt,
+ .addr2sockaddr = inet_csk_addr2sockaddr,
+ .sockaddr_len = sizeof(struct sockaddr_in),
+#ifdef CONFIG_COMPAT
+ .compat_setsockopt = compat_ip_setsockopt,
+ .compat_getsockopt = compat_ip_getsockopt,
+#endif
};
/* NOTE: A lot of things set to zero explicitly by call to
@@ -1825,23 +1830,16 @@ struct proto tcp_prot = {
.obj_size = sizeof(struct tcp_sock),
.twsk_prot = &tcp_timewait_sock_ops,
.rsk_prot = &tcp_request_sock_ops,
+#ifdef CONFIG_COMPAT
+ .compat_setsockopt = compat_tcp_setsockopt,
+ .compat_getsockopt = compat_tcp_getsockopt,
+#endif
};
-
-
void __init tcp_v4_init(struct net_proto_family *ops)
{
- int err = sock_create_kern(PF_INET, SOCK_RAW, IPPROTO_TCP, &tcp_socket);
- if (err < 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");
- tcp_socket->sk->sk_allocation = GFP_ATOMIC;
- inet_sk(tcp_socket->sk)->uc_ttl = -1;
-
- /* Unhash it so that IP input processing does not even
- * see it, we do not wish this socket to see incoming
- * packets.
- */
- tcp_socket->sk->sk_prot->unhash(tcp_socket->sk);
}
EXPORT_SYMBOL(ipv4_specific);
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 9f498a6c8895..9d79546d384e 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -45,12 +45,23 @@
/* People can turn this off for buggy TCP's found in printers etc. */
int sysctl_tcp_retrans_collapse = 1;
+/* People can turn this on to work with those rare, broken TCPs that
+ * interpret the window field as a signed quantity.
+ */
+int sysctl_tcp_workaround_signed_windows = 0;
+
/* This limits the percentage of the congestion window which we
* will allow a single TSO frame to consume. Building TSO frames
* which are too large can cause TCP streams to be bursty.
*/
int sysctl_tcp_tso_win_divisor = 3;
+int sysctl_tcp_mtu_probing = 0;
+int sysctl_tcp_base_mss = 512;
+
+EXPORT_SYMBOL(sysctl_tcp_mtu_probing);
+EXPORT_SYMBOL(sysctl_tcp_base_mss);
+
static void update_send_head(struct sock *sk, struct tcp_sock *tp,
struct sk_buff *skb)
{
@@ -171,12 +182,18 @@ void tcp_select_initial_window(int __space, __u32 mss,
space = (space / mss) * mss;
/* NOTE: offering an initial window larger than 32767
- * will break some buggy TCP stacks. We try to be nice.
- * If we are not window scaling, then this truncates
- * our initial window offering to 32k. There should also
- * be a sysctl option to stop being nice.
+ * will break some buggy TCP stacks. If the admin tells us
+ * it is likely we could be speaking with such a buggy stack
+ * we will truncate our initial window offering to 32K-1
+ * unless the remote has sent us a window scaling option,
+ * which we interpret as a sign the remote TCP is not
+ * misinterpreting the window field as a signed quantity.
*/
- (*rcv_wnd) = min(space, MAX_TCP_WINDOW);
+ if (sysctl_tcp_workaround_signed_windows)
+ (*rcv_wnd) = min(space, MAX_TCP_WINDOW);
+ else
+ (*rcv_wnd) = space;
+
(*rcv_wscale) = 0;
if (wscale_ok) {
/* Set window scaling on max possible window
@@ -235,7 +252,7 @@ static u16 tcp_select_window(struct sock *sk)
/* Make sure we do not exceed the maximum possible
* scaled window.
*/
- if (!tp->rx_opt.rcv_wscale)
+ if (!tp->rx_opt.rcv_wscale && sysctl_tcp_workaround_signed_windows)
new_win = min(new_win, MAX_TCP_WINDOW);
else
new_win = min(new_win, (65535U << tp->rx_opt.rcv_wscale));
@@ -681,6 +698,62 @@ int tcp_trim_head(struct sock *sk, struct sk_buff *skb, u32 len)
return 0;
}
+/* Not accounting for SACKs here. */
+int tcp_mtu_to_mss(struct sock *sk, int pmtu)
+{
+ struct tcp_sock *tp = tcp_sk(sk);
+ struct inet_connection_sock *icsk = inet_csk(sk);
+ int mss_now;
+
+ /* Calculate base mss without TCP options:
+ It is MMS_S - sizeof(tcphdr) of rfc1122
+ */
+ mss_now = pmtu - icsk->icsk_af_ops->net_header_len - sizeof(struct tcphdr);
+
+ /* Clamp it (mss_clamp does not include tcp options) */
+ if (mss_now > tp->rx_opt.mss_clamp)
+ mss_now = tp->rx_opt.mss_clamp;
+
+ /* Now subtract optional transport overhead */
+ mss_now -= icsk->icsk_ext_hdr_len;
+
+ /* Then reserve room for full set of TCP options and 8 bytes of data */
+ if (mss_now < 48)
+ mss_now = 48;
+
+ /* Now subtract TCP options size, not including SACKs */
+ mss_now -= tp->tcp_header_len - sizeof(struct tcphdr);
+
+ return mss_now;
+}
+
+/* Inverse of above */
+int tcp_mss_to_mtu(struct sock *sk, int mss)
+{
+ struct tcp_sock *tp = tcp_sk(sk);
+ struct inet_connection_sock *icsk = inet_csk(sk);
+ int mtu;
+
+ mtu = mss +
+ tp->tcp_header_len +
+ icsk->icsk_ext_hdr_len +
+ icsk->icsk_af_ops->net_header_len;
+
+ return mtu;
+}
+
+void tcp_mtup_init(struct sock *sk)
+{
+ struct tcp_sock *tp = tcp_sk(sk);
+ struct inet_connection_sock *icsk = inet_csk(sk);
+
+ icsk->icsk_mtup.enabled = sysctl_tcp_mtu_probing > 1;
+ icsk->icsk_mtup.search_high = tp->rx_opt.mss_clamp + sizeof(struct tcphdr) +
+ icsk->icsk_af_ops->net_header_len;
+ icsk->icsk_mtup.search_low = tcp_mss_to_mtu(sk, sysctl_tcp_base_mss);
+ icsk->icsk_mtup.probe_size = 0;
+}
+
/* This function synchronize snd mss to current pmtu/exthdr set.
tp->rx_opt.user_mss is mss set by user by TCP_MAXSEG. It does NOT counts
@@ -708,25 +781,12 @@ unsigned int tcp_sync_mss(struct sock *sk, u32 pmtu)
{
struct tcp_sock *tp = tcp_sk(sk);
struct inet_connection_sock *icsk = inet_csk(sk);
- /* Calculate base mss without TCP options:
- It is MMS_S - sizeof(tcphdr) of rfc1122
- */
- int mss_now = (pmtu - icsk->icsk_af_ops->net_header_len -
- sizeof(struct tcphdr));
-
- /* Clamp it (mss_clamp does not include tcp options) */
- if (mss_now > tp->rx_opt.mss_clamp)
- mss_now = tp->rx_opt.mss_clamp;
-
- /* Now subtract optional transport overhead */
- mss_now -= icsk->icsk_ext_hdr_len;
+ int mss_now;
- /* Then reserve room for full set of TCP options and 8 bytes of data */
- if (mss_now < 48)
- mss_now = 48;
+ if (icsk->icsk_mtup.search_high > pmtu)
+ icsk->icsk_mtup.search_high = pmtu;
- /* Now subtract TCP options size, not including SACKs */
- mss_now -= tp->tcp_header_len - sizeof(struct tcphdr);
+ mss_now = tcp_mtu_to_mss(sk, pmtu);
/* Bound mss with half of window */
if (tp->max_window && mss_now > (tp->max_window>>1))
@@ -734,6 +794,8 @@ unsigned int tcp_sync_mss(struct sock *sk, u32 pmtu)
/* And store cached results */
icsk->icsk_pmtu_cookie = pmtu;
+ if (icsk->icsk_mtup.enabled)
+ mss_now = min(mss_now, tcp_mtu_to_mss(sk, icsk->icsk_mtup.search_low));
tp->mss_cache = mss_now;
return mss_now;
@@ -1063,6 +1125,140 @@ static int tcp_tso_should_defer(struct sock *sk, struct tcp_sock *tp, struct sk_
return 1;
}
+/* Create a new MTU probe if we are ready.
+ * Returns 0 if we should wait to probe (no cwnd available),
+ * 1 if a probe was sent,
+ * -1 otherwise */
+static int tcp_mtu_probe(struct sock *sk)
+{
+ struct tcp_sock *tp = tcp_sk(sk);
+ struct inet_connection_sock *icsk = inet_csk(sk);
+ struct sk_buff *skb, *nskb, *next;
+ int len;
+ int probe_size;
+ unsigned int pif;
+ int copy;
+ int mss_now;
+
+ /* Not currently probing/verifying,
+ * not in recovery,
+ * have enough cwnd, and
+ * not SACKing (the variable headers throw things off) */
+ if (!icsk->icsk_mtup.enabled ||
+ icsk->icsk_mtup.probe_size ||
+ inet_csk(sk)->icsk_ca_state != TCP_CA_Open ||
+ tp->snd_cwnd < 11 ||
+ tp->rx_opt.eff_sacks)
+ return -1;
+
+ /* Very simple search strategy: just double the MSS. */
+ mss_now = tcp_current_mss(sk, 0);
+ probe_size = 2*tp->mss_cache;
+ if (probe_size > tcp_mtu_to_mss(sk, icsk->icsk_mtup.search_high)) {
+ /* TODO: set timer for probe_converge_event */
+ return -1;
+ }
+
+ /* Have enough data in the send queue to probe? */
+ len = 0;
+ if ((skb = sk->sk_send_head) == NULL)
+ return -1;
+ while ((len += skb->len) < probe_size && !tcp_skb_is_last(sk, skb))
+ skb = skb->next;
+ if (len < probe_size)
+ return -1;
+
+ /* Receive window check. */
+ if (after(TCP_SKB_CB(skb)->seq + probe_size, tp->snd_una + tp->snd_wnd)) {
+ if (tp->snd_wnd < probe_size)
+ return -1;
+ else
+ return 0;
+ }
+
+ /* Do we need to wait to drain cwnd? */
+ pif = tcp_packets_in_flight(tp);
+ if (pif + 2 > tp->snd_cwnd) {
+ /* With no packets in flight, don't stall. */
+ if (pif == 0)
+ return -1;
+ else
+ return 0;
+ }
+
+ /* We're allowed to probe. Build it now. */
+ if ((nskb = sk_stream_alloc_skb(sk, probe_size, GFP_ATOMIC)) == NULL)
+ return -1;
+ sk_charge_skb(sk, nskb);
+
+ skb = sk->sk_send_head;
+ __skb_insert(nskb, skb->prev, skb, &sk->sk_write_queue);
+ sk->sk_send_head = nskb;
+
+ TCP_SKB_CB(nskb)->seq = TCP_SKB_CB(skb)->seq;
+ TCP_SKB_CB(nskb)->end_seq = TCP_SKB_CB(skb)->seq + probe_size;
+ TCP_SKB_CB(nskb)->flags = TCPCB_FLAG_ACK;
+ TCP_SKB_CB(nskb)->sacked = 0;
+ nskb->csum = 0;
+ if (skb->ip_summed == CHECKSUM_HW)
+ nskb->ip_summed = CHECKSUM_HW;
+
+ len = 0;
+ while (len < probe_size) {
+ next = skb->next;
+
+ copy = min_t(int, skb->len, probe_size - len);
+ if (nskb->ip_summed)
+ skb_copy_bits(skb, 0, skb_put(nskb, copy), copy);
+ else
+ nskb->csum = skb_copy_and_csum_bits(skb, 0,
+ skb_put(nskb, copy), copy, nskb->csum);
+
+ if (skb->len <= copy) {
+ /* We've eaten all the data from this skb.
+ * Throw it away. */
+ TCP_SKB_CB(nskb)->flags |= TCP_SKB_CB(skb)->flags;
+ __skb_unlink(skb, &sk->sk_write_queue);
+ sk_stream_free_skb(sk, skb);
+ } else {
+ TCP_SKB_CB(nskb)->flags |= TCP_SKB_CB(skb)->flags &
+ ~(TCPCB_FLAG_FIN|TCPCB_FLAG_PSH);
+ if (!skb_shinfo(skb)->nr_frags) {
+ skb_pull(skb, copy);
+ if (skb->ip_summed != CHECKSUM_HW)
+ skb->csum = csum_partial(skb->data, skb->len, 0);
+ } else {
+ __pskb_trim_head(skb, copy);
+ tcp_set_skb_tso_segs(sk, skb, mss_now);
+ }
+ TCP_SKB_CB(skb)->seq += copy;
+ }
+
+ len += copy;
+ skb = next;
+ }
+ tcp_init_tso_segs(sk, nskb, nskb->len);
+
+ /* We're ready to send. If this fails, the probe will
+ * be resegmented into mss-sized pieces by tcp_write_xmit(). */
+ TCP_SKB_CB(nskb)->when = tcp_time_stamp;
+ if (!tcp_transmit_skb(sk, nskb, 1, GFP_ATOMIC)) {
+ /* Decrement cwnd here because we are sending
+ * effectively two packets. */
+ tp->snd_cwnd--;
+ update_send_head(sk, tp, nskb);
+
+ icsk->icsk_mtup.probe_size = tcp_mss_to_mtu(sk, nskb->len);
+ tp->mtu_probe.probe_seq_start = TCP_SKB_CB(nskb)->seq;
+ tp->mtu_probe.probe_seq_end = TCP_SKB_CB(nskb)->end_seq;
+
+ return 1;
+ }
+
+ return -1;
+}
+
+
/* This routine writes packets to the network. It advances the
* send_head. This happens as incoming acks open up the remote
* window for us.
@@ -1076,6 +1272,7 @@ static int tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle)
struct sk_buff *skb;
unsigned int tso_segs, sent_pkts;
int cwnd_quota;
+ int result;
/* If we are closed, the bytes will have to remain here.
* In time closedown will finish, we empty the write queue and all
@@ -1085,6 +1282,14 @@ static int tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle)
return 0;
sent_pkts = 0;
+
+ /* Do MTU probing. */
+ if ((result = tcp_mtu_probe(sk)) == 0) {
+ return 0;
+ } else if (result > 0) {
+ sent_pkts = 1;
+ }
+
while ((skb = sk->sk_send_head)) {
unsigned int limit;
@@ -1455,9 +1660,15 @@ void tcp_simple_retransmit(struct sock *sk)
int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
{
struct tcp_sock *tp = tcp_sk(sk);
+ struct inet_connection_sock *icsk = inet_csk(sk);
unsigned int cur_mss = tcp_current_mss(sk, 0);
int err;
+ /* Inconslusive MTU probe */
+ if (icsk->icsk_mtup.probe_size) {
+ icsk->icsk_mtup.probe_size = 0;
+ }
+
/* Do not sent more than we queued. 1/4 is reserved for possible
* copying overhead: fragmentation, tunneling, mangling etc.
*/
@@ -1883,6 +2094,7 @@ static void tcp_connect_init(struct sock *sk)
if (tp->rx_opt.user_mss)
tp->rx_opt.mss_clamp = tp->rx_opt.user_mss;
tp->max_window = 0;
+ tcp_mtup_init(sk);
tcp_sync_mss(sk, dst_mtu(dst));
if (!tp->window_clamp)
@@ -2180,3 +2392,4 @@ EXPORT_SYMBOL(tcp_make_synack);
EXPORT_SYMBOL(tcp_simple_retransmit);
EXPORT_SYMBOL(tcp_sync_mss);
EXPORT_SYMBOL(sysctl_tcp_tso_win_divisor);
+EXPORT_SYMBOL(tcp_mtup_init);
diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
index e1880959614a..7c1bde3cd6cb 100644
--- a/net/ipv4/tcp_timer.c
+++ b/net/ipv4/tcp_timer.c
@@ -119,8 +119,10 @@ static int tcp_orphan_retries(struct sock *sk, int alive)
/* A write timeout has occurred. Process the after effects. */
static int tcp_write_timeout(struct sock *sk)
{
- const struct inet_connection_sock *icsk = inet_csk(sk);
+ struct inet_connection_sock *icsk = inet_csk(sk);
+ struct tcp_sock *tp = tcp_sk(sk);
int retry_until;
+ int mss;
if ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)) {
if (icsk->icsk_retransmits)
@@ -128,25 +130,19 @@ static int tcp_write_timeout(struct sock *sk)
retry_until = icsk->icsk_syn_retries ? : sysctl_tcp_syn_retries;
} else {
if (icsk->icsk_retransmits >= sysctl_tcp_retries1) {
- /* NOTE. draft-ietf-tcpimpl-pmtud-01.txt requires pmtu black
- hole detection. :-(
-
- It is place to make it. It is not made. I do not want
- to make it. It is disgusting. It does not work in any
- case. Let me to cite the same draft, which requires for
- us to implement this:
-
- "The one security concern raised by this memo is that ICMP black holes
- are often caused by over-zealous security administrators who block
- all ICMP messages. It is vitally important that those who design and
- deploy security systems understand the impact of strict filtering on
- upper-layer protocols. The safest web site in the world is worthless
- if most TCP implementations cannot transfer data from it. It would
- be far nicer to have all of the black holes fixed rather than fixing
- all of the TCP implementations."
-
- Golden words :-).
- */
+ /* Black hole detection */
+ if (sysctl_tcp_mtu_probing) {
+ if (!icsk->icsk_mtup.enabled) {
+ icsk->icsk_mtup.enabled = 1;
+ tcp_sync_mss(sk, icsk->icsk_pmtu_cookie);
+ } else {
+ mss = min(sysctl_tcp_base_mss,
+ tcp_mtu_to_mss(sk, icsk->icsk_mtup.search_low)/2);
+ mss = max(mss, 68 - tp->tcp_header_len);
+ icsk->icsk_mtup.search_low = tcp_mss_to_mtu(sk, mss);
+ tcp_sync_mss(sk, icsk->icsk_pmtu_cookie);
+ }
+ }
dst_negative_advice(&sk->sk_dst_cache);
}
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 00840474a449..3f93292b0ad8 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -1207,16 +1207,13 @@ static int udp_destroy_sock(struct sock *sk)
/*
* Socket option code for UDP
*/
-static int udp_setsockopt(struct sock *sk, int level, int optname,
+static int do_udp_setsockopt(struct sock *sk, int level, int optname,
char __user *optval, int optlen)
{
struct udp_sock *up = udp_sk(sk);
int val;
int err = 0;
- if (level != SOL_UDP)
- return ip_setsockopt(sk, level, optname, optval, optlen);
-
if(optlen<sizeof(int))
return -EINVAL;
@@ -1256,15 +1253,30 @@ static int udp_setsockopt(struct sock *sk, int level, int optname,
return err;
}
-static int udp_getsockopt(struct sock *sk, int level, int optname,
+static 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);
+}
+
+#ifdef CONFIG_COMPAT
+static 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);
+}
+#endif
+
+static int do_udp_getsockopt(struct sock *sk, int level, int optname,
char __user *optval, int __user *optlen)
{
struct udp_sock *up = udp_sk(sk);
int val, len;
- if (level != SOL_UDP)
- return ip_getsockopt(sk, level, optname, optval, optlen);
-
if(get_user(len,optlen))
return -EFAULT;
@@ -1293,6 +1305,23 @@ static int 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)
+{
+ if (level != SOL_UDP)
+ return ip_getsockopt(sk, level, optname, optval, optlen);
+ return do_udp_getsockopt(sk, level, optname, optval, optlen);
+}
+
+#ifdef CONFIG_COMPAT
+static 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);
+}
+#endif
/**
* udp_poll - wait for a UDP event.
* @file - file struct
@@ -1341,23 +1370,27 @@ 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,
- .connect = ip4_datagram_connect,
- .disconnect = udp_disconnect,
- .ioctl = udp_ioctl,
- .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_v4_hash,
- .unhash = udp_v4_unhash,
- .get_port = udp_v4_get_port,
- .obj_size = sizeof(struct udp_sock),
+ .name = "UDP",
+ .owner = THIS_MODULE,
+ .close = udp_close,
+ .connect = ip4_datagram_connect,
+ .disconnect = udp_disconnect,
+ .ioctl = udp_ioctl,
+ .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_v4_hash,
+ .unhash = udp_v4_unhash,
+ .get_port = udp_v4_get_port,
+ .obj_size = sizeof(struct udp_sock),
+#ifdef CONFIG_COMPAT
+ .compat_setsockopt = compat_udp_setsockopt,
+ .compat_getsockopt = compat_udp_getsockopt,
+#endif
};
/* ------------------------------------------------------------------------ */
diff --git a/net/ipv4/xfrm4_tunnel.c b/net/ipv4/xfrm4_tunnel.c
index afbb0d4cc305..b08d56b117f8 100644
--- a/net/ipv4/xfrm4_tunnel.c
+++ b/net/ipv4/xfrm4_tunnel.c
@@ -5,6 +5,7 @@
#include <linux/skbuff.h>
#include <linux/module.h>
+#include <linux/mutex.h>
#include <net/xfrm.h>
#include <net/ip.h>
#include <net/protocol.h>
@@ -26,19 +27,19 @@ static int ipip_xfrm_rcv(struct xfrm_state *x, struct xfrm_decap_state *decap, s
}
static struct xfrm_tunnel *ipip_handler;
-static DECLARE_MUTEX(xfrm4_tunnel_sem);
+static DEFINE_MUTEX(xfrm4_tunnel_mutex);
int xfrm4_tunnel_register(struct xfrm_tunnel *handler)
{
int ret;
- down(&xfrm4_tunnel_sem);
+ mutex_lock(&xfrm4_tunnel_mutex);
ret = 0;
if (ipip_handler != NULL)
ret = -EINVAL;
if (!ret)
ipip_handler = handler;
- up(&xfrm4_tunnel_sem);
+ mutex_unlock(&xfrm4_tunnel_mutex);
return ret;
}
@@ -49,13 +50,13 @@ int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler)
{
int ret;
- down(&xfrm4_tunnel_sem);
+ mutex_lock(&xfrm4_tunnel_mutex);
ret = 0;
if (ipip_handler != handler)
ret = -EINVAL;
if (!ret)
ipip_handler = NULL;
- up(&xfrm4_tunnel_sem);
+ mutex_unlock(&xfrm4_tunnel_mutex);
synchronize_net();