diff options
author | David Howells <dhowells@redhat.com> | 2006-12-05 09:37:56 -0500 |
---|---|---|
committer | David Howells <dhowells@warthog.cambridge.redhat.com> | 2006-12-05 09:37:56 -0500 |
commit | 4c1ac1b49122b805adfa4efc620592f68dccf5db (patch) | |
tree | 87557f4bc2fd4fe65b7570489c2f610c45c0adcd /net/ipv4 | |
parent | c4028958b6ecad064b1a6303a6a5906d4fe48d73 (diff) | |
parent | d916faace3efc0bf19fe9a615a1ab8fa1a24cd93 (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
Conflicts:
drivers/infiniband/core/iwcm.c
drivers/net/chelsio/cxgb2.c
drivers/net/wireless/bcm43xx/bcm43xx_main.c
drivers/net/wireless/prism54/islpci_eth.c
drivers/usb/core/hub.h
drivers/usb/input/hid-core.c
net/core/netpoll.c
Fix up merge failures with Linus's head and fix new compilation failures.
Signed-Off-By: David Howells <dhowells@redhat.com>
Diffstat (limited to 'net/ipv4')
110 files changed, 9193 insertions, 4922 deletions
diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig index 5572071af735..503e7059e312 100644 --- a/net/ipv4/Kconfig +++ b/net/ipv4/Kconfig | |||
@@ -104,13 +104,6 @@ config IP_MULTIPLE_TABLES | |||
104 | 104 | ||
105 | If unsure, say N. | 105 | If unsure, say N. |
106 | 106 | ||
107 | config IP_ROUTE_FWMARK | ||
108 | bool "IP: use netfilter MARK value as routing key" | ||
109 | depends on IP_MULTIPLE_TABLES && NETFILTER | ||
110 | help | ||
111 | If you say Y here, you will be able to specify different routes for | ||
112 | packets with different mark values (see iptables(8), MARK target). | ||
113 | |||
114 | config IP_ROUTE_MULTIPATH | 107 | config IP_ROUTE_MULTIPATH |
115 | bool "IP: equal cost multipath" | 108 | bool "IP: equal cost multipath" |
116 | depends on IP_ADVANCED_ROUTER | 109 | depends on IP_ADVANCED_ROUTER |
@@ -625,5 +618,17 @@ config DEFAULT_TCP_CONG | |||
625 | default "reno" if DEFAULT_RENO | 618 | default "reno" if DEFAULT_RENO |
626 | default "cubic" | 619 | default "cubic" |
627 | 620 | ||
621 | config TCP_MD5SIG | ||
622 | bool "TCP: MD5 Signature Option support (RFC2385) (EXPERIMENTAL)" | ||
623 | depends on EXPERIMENTAL | ||
624 | select CRYPTO | ||
625 | select CRYPTO_MD5 | ||
626 | ---help--- | ||
627 | RFC2385 specifices a method of giving MD5 protection to TCP sessions. | ||
628 | Its main (only?) use is to protect BGP sessions between core routers | ||
629 | on the Internet. | ||
630 | |||
631 | If unsure, say N. | ||
632 | |||
628 | source "net/ipv4/ipvs/Kconfig" | 633 | source "net/ipv4/ipvs/Kconfig" |
629 | 634 | ||
diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile index 15645c51520c..7a068626feea 100644 --- a/net/ipv4/Makefile +++ b/net/ipv4/Makefile | |||
@@ -8,7 +8,8 @@ obj-y := route.o inetpeer.o protocol.o \ | |||
8 | inet_timewait_sock.o inet_connection_sock.o \ | 8 | inet_timewait_sock.o inet_connection_sock.o \ |
9 | tcp.o tcp_input.o tcp_output.o tcp_timer.o tcp_ipv4.o \ | 9 | tcp.o tcp_input.o tcp_output.o tcp_timer.o tcp_ipv4.o \ |
10 | tcp_minisocks.o tcp_cong.o \ | 10 | tcp_minisocks.o tcp_cong.o \ |
11 | datagram.o raw.o udp.o arp.o icmp.o devinet.o af_inet.o igmp.o \ | 11 | datagram.o raw.o udp.o udplite.o \ |
12 | arp.o icmp.o devinet.o af_inet.o igmp.o \ | ||
12 | sysctl_net_ipv4.o fib_frontend.o fib_semantics.o | 13 | sysctl_net_ipv4.o fib_frontend.o fib_semantics.o |
13 | 14 | ||
14 | obj-$(CONFIG_IP_FIB_HASH) += fib_hash.o | 15 | obj-$(CONFIG_IP_FIB_HASH) += fib_hash.o |
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index edcf0932ac6d..1144900d37f6 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c | |||
@@ -104,6 +104,7 @@ | |||
104 | #include <net/inet_connection_sock.h> | 104 | #include <net/inet_connection_sock.h> |
105 | #include <net/tcp.h> | 105 | #include <net/tcp.h> |
106 | #include <net/udp.h> | 106 | #include <net/udp.h> |
107 | #include <net/udplite.h> | ||
107 | #include <linux/skbuff.h> | 108 | #include <linux/skbuff.h> |
108 | #include <net/sock.h> | 109 | #include <net/sock.h> |
109 | #include <net/raw.h> | 110 | #include <net/raw.h> |
@@ -204,7 +205,7 @@ int inet_listen(struct socket *sock, int backlog) | |||
204 | * we can only allow the backlog to be adjusted. | 205 | * we can only allow the backlog to be adjusted. |
205 | */ | 206 | */ |
206 | if (old_state != TCP_LISTEN) { | 207 | if (old_state != TCP_LISTEN) { |
207 | err = inet_csk_listen_start(sk, TCP_SYNQ_HSIZE); | 208 | err = inet_csk_listen_start(sk, backlog); |
208 | if (err) | 209 | if (err) |
209 | goto out; | 210 | goto out; |
210 | } | 211 | } |
@@ -643,7 +644,7 @@ int inet_getname(struct socket *sock, struct sockaddr *uaddr, | |||
643 | sin->sin_port = inet->dport; | 644 | sin->sin_port = inet->dport; |
644 | sin->sin_addr.s_addr = inet->daddr; | 645 | sin->sin_addr.s_addr = inet->daddr; |
645 | } else { | 646 | } else { |
646 | __u32 addr = inet->rcv_saddr; | 647 | __be32 addr = inet->rcv_saddr; |
647 | if (!addr) | 648 | if (!addr) |
648 | addr = inet->saddr; | 649 | addr = inet->saddr; |
649 | sin->sin_port = inet->sport; | 650 | sin->sin_port = inet->sport; |
@@ -994,8 +995,8 @@ static int inet_sk_reselect_saddr(struct sock *sk) | |||
994 | struct inet_sock *inet = inet_sk(sk); | 995 | struct inet_sock *inet = inet_sk(sk); |
995 | int err; | 996 | int err; |
996 | struct rtable *rt; | 997 | struct rtable *rt; |
997 | __u32 old_saddr = inet->saddr; | 998 | __be32 old_saddr = inet->saddr; |
998 | __u32 new_saddr; | 999 | __be32 new_saddr; |
999 | __be32 daddr = inet->daddr; | 1000 | __be32 daddr = inet->daddr; |
1000 | 1001 | ||
1001 | if (inet->opt && inet->opt->srr) | 1002 | if (inet->opt && inet->opt->srr) |
@@ -1223,10 +1224,13 @@ static int __init init_ipv4_mibs(void) | |||
1223 | tcp_statistics[1] = alloc_percpu(struct tcp_mib); | 1224 | tcp_statistics[1] = alloc_percpu(struct tcp_mib); |
1224 | udp_statistics[0] = alloc_percpu(struct udp_mib); | 1225 | udp_statistics[0] = alloc_percpu(struct udp_mib); |
1225 | udp_statistics[1] = alloc_percpu(struct udp_mib); | 1226 | udp_statistics[1] = alloc_percpu(struct udp_mib); |
1227 | udplite_statistics[0] = alloc_percpu(struct udp_mib); | ||
1228 | udplite_statistics[1] = alloc_percpu(struct udp_mib); | ||
1226 | if (! | 1229 | if (! |
1227 | (net_statistics[0] && net_statistics[1] && ip_statistics[0] | 1230 | (net_statistics[0] && net_statistics[1] && ip_statistics[0] |
1228 | && ip_statistics[1] && tcp_statistics[0] && tcp_statistics[1] | 1231 | && ip_statistics[1] && tcp_statistics[0] && tcp_statistics[1] |
1229 | && udp_statistics[0] && udp_statistics[1])) | 1232 | && udp_statistics[0] && udp_statistics[1] |
1233 | && udplite_statistics[0] && udplite_statistics[1] ) ) | ||
1230 | return -ENOMEM; | 1234 | return -ENOMEM; |
1231 | 1235 | ||
1232 | (void) tcp_mib_init(); | 1236 | (void) tcp_mib_init(); |
@@ -1313,6 +1317,8 @@ static int __init inet_init(void) | |||
1313 | /* Setup TCP slab cache for open requests. */ | 1317 | /* Setup TCP slab cache for open requests. */ |
1314 | tcp_init(); | 1318 | tcp_init(); |
1315 | 1319 | ||
1320 | /* Add UDP-Lite (RFC 3828) */ | ||
1321 | udplite4_register(); | ||
1316 | 1322 | ||
1317 | /* | 1323 | /* |
1318 | * Set the ICMP layer up | 1324 | * Set the ICMP layer up |
diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c index 99542977e47e..67a5509e26fc 100644 --- a/net/ipv4/ah4.c +++ b/net/ipv4/ah4.c | |||
@@ -14,7 +14,7 @@ | |||
14 | * into IP header for icv calculation. Options are already checked | 14 | * into IP header for icv calculation. Options are already checked |
15 | * for validity, so paranoia is not required. */ | 15 | * for validity, so paranoia is not required. */ |
16 | 16 | ||
17 | static int ip_clear_mutable_options(struct iphdr *iph, u32 *daddr) | 17 | static int ip_clear_mutable_options(struct iphdr *iph, __be32 *daddr) |
18 | { | 18 | { |
19 | unsigned char * optptr = (unsigned char*)(iph+1); | 19 | unsigned char * optptr = (unsigned char*)(iph+1); |
20 | int l = iph->ihl*4 - sizeof(struct iphdr); | 20 | int l = iph->ihl*4 - sizeof(struct iphdr); |
@@ -162,7 +162,7 @@ static int ah_input(struct xfrm_state *x, struct sk_buff *skb) | |||
162 | iph->frag_off = 0; | 162 | iph->frag_off = 0; |
163 | iph->check = 0; | 163 | iph->check = 0; |
164 | if (ihl > sizeof(*iph)) { | 164 | if (ihl > sizeof(*iph)) { |
165 | u32 dummy; | 165 | __be32 dummy; |
166 | if (ip_clear_mutable_options(iph, &dummy)) | 166 | if (ip_clear_mutable_options(iph, &dummy)) |
167 | goto out; | 167 | goto out; |
168 | } | 168 | } |
diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index cfb5d3de9c84..3981e8be9ab8 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c | |||
@@ -203,7 +203,7 @@ struct neigh_table arp_tbl = { | |||
203 | .gc_thresh3 = 1024, | 203 | .gc_thresh3 = 1024, |
204 | }; | 204 | }; |
205 | 205 | ||
206 | int arp_mc_map(u32 addr, u8 *haddr, struct net_device *dev, int dir) | 206 | int arp_mc_map(__be32 addr, u8 *haddr, struct net_device *dev, int dir) |
207 | { | 207 | { |
208 | switch (dev->type) { | 208 | switch (dev->type) { |
209 | case ARPHRD_ETHER: | 209 | case ARPHRD_ETHER: |
diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c index 6460233407c7..60aafb4a8adf 100644 --- a/net/ipv4/cipso_ipv4.c +++ b/net/ipv4/cipso_ipv4.c | |||
@@ -319,6 +319,7 @@ static int cipso_v4_cache_check(const unsigned char *key, | |||
319 | entry->activity += 1; | 319 | entry->activity += 1; |
320 | atomic_inc(&entry->lsm_data->refcount); | 320 | atomic_inc(&entry->lsm_data->refcount); |
321 | secattr->cache = entry->lsm_data; | 321 | secattr->cache = entry->lsm_data; |
322 | secattr->flags |= NETLBL_SECATTR_CACHE; | ||
322 | if (prev_entry == NULL) { | 323 | if (prev_entry == NULL) { |
323 | spin_unlock_bh(&cipso_v4_cache[bkt].lock); | 324 | spin_unlock_bh(&cipso_v4_cache[bkt].lock); |
324 | return 0; | 325 | return 0; |
@@ -377,12 +378,11 @@ int cipso_v4_cache_add(const struct sk_buff *skb, | |||
377 | entry = kzalloc(sizeof(*entry), GFP_ATOMIC); | 378 | entry = kzalloc(sizeof(*entry), GFP_ATOMIC); |
378 | if (entry == NULL) | 379 | if (entry == NULL) |
379 | return -ENOMEM; | 380 | return -ENOMEM; |
380 | entry->key = kmalloc(cipso_ptr_len, GFP_ATOMIC); | 381 | entry->key = kmemdup(cipso_ptr, cipso_ptr_len, GFP_ATOMIC); |
381 | if (entry->key == NULL) { | 382 | if (entry->key == NULL) { |
382 | ret_val = -ENOMEM; | 383 | ret_val = -ENOMEM; |
383 | goto cache_add_failure; | 384 | goto cache_add_failure; |
384 | } | 385 | } |
385 | memcpy(entry->key, cipso_ptr, cipso_ptr_len); | ||
386 | entry->key_len = cipso_ptr_len; | 386 | entry->key_len = cipso_ptr_len; |
387 | entry->hash = cipso_v4_map_cache_hash(cipso_ptr, cipso_ptr_len); | 387 | entry->hash = cipso_v4_map_cache_hash(cipso_ptr, cipso_ptr_len); |
388 | atomic_inc(&secattr->cache->refcount); | 388 | atomic_inc(&secattr->cache->refcount); |
@@ -447,8 +447,30 @@ static struct cipso_v4_doi *cipso_v4_doi_search(u32 doi) | |||
447 | */ | 447 | */ |
448 | int cipso_v4_doi_add(struct cipso_v4_doi *doi_def) | 448 | int cipso_v4_doi_add(struct cipso_v4_doi *doi_def) |
449 | { | 449 | { |
450 | u32 iter; | ||
451 | |||
450 | if (doi_def == NULL || doi_def->doi == CIPSO_V4_DOI_UNKNOWN) | 452 | if (doi_def == NULL || doi_def->doi == CIPSO_V4_DOI_UNKNOWN) |
451 | return -EINVAL; | 453 | return -EINVAL; |
454 | for (iter = 0; iter < CIPSO_V4_TAG_MAXCNT; iter++) { | ||
455 | switch (doi_def->tags[iter]) { | ||
456 | case CIPSO_V4_TAG_RBITMAP: | ||
457 | break; | ||
458 | case CIPSO_V4_TAG_RANGE: | ||
459 | if (doi_def->type != CIPSO_V4_MAP_PASS) | ||
460 | return -EINVAL; | ||
461 | break; | ||
462 | case CIPSO_V4_TAG_INVALID: | ||
463 | if (iter == 0) | ||
464 | return -EINVAL; | ||
465 | break; | ||
466 | case CIPSO_V4_TAG_ENUM: | ||
467 | if (doi_def->type != CIPSO_V4_MAP_PASS) | ||
468 | return -EINVAL; | ||
469 | break; | ||
470 | default: | ||
471 | return -EINVAL; | ||
472 | } | ||
473 | } | ||
452 | 474 | ||
453 | doi_def->valid = 1; | 475 | doi_def->valid = 1; |
454 | INIT_RCU_HEAD(&doi_def->rcu); | 476 | INIT_RCU_HEAD(&doi_def->rcu); |
@@ -805,8 +827,7 @@ static int cipso_v4_map_cat_rbm_valid(const struct cipso_v4_doi *doi_def, | |||
805 | /** | 827 | /** |
806 | * cipso_v4_map_cat_rbm_hton - Perform a category mapping from host to network | 828 | * cipso_v4_map_cat_rbm_hton - Perform a category mapping from host to network |
807 | * @doi_def: the DOI definition | 829 | * @doi_def: the DOI definition |
808 | * @host_cat: the category bitmap in host format | 830 | * @secattr: the security attributes |
809 | * @host_cat_len: the length of the host's category bitmap in bytes | ||
810 | * @net_cat: the zero'd out category bitmap in network/CIPSO format | 831 | * @net_cat: the zero'd out category bitmap in network/CIPSO format |
811 | * @net_cat_len: the length of the CIPSO bitmap in bytes | 832 | * @net_cat_len: the length of the CIPSO bitmap in bytes |
812 | * | 833 | * |
@@ -817,59 +838,51 @@ static int cipso_v4_map_cat_rbm_valid(const struct cipso_v4_doi *doi_def, | |||
817 | * | 838 | * |
818 | */ | 839 | */ |
819 | static int cipso_v4_map_cat_rbm_hton(const struct cipso_v4_doi *doi_def, | 840 | static int cipso_v4_map_cat_rbm_hton(const struct cipso_v4_doi *doi_def, |
820 | const unsigned char *host_cat, | 841 | const struct netlbl_lsm_secattr *secattr, |
821 | u32 host_cat_len, | ||
822 | unsigned char *net_cat, | 842 | unsigned char *net_cat, |
823 | u32 net_cat_len) | 843 | u32 net_cat_len) |
824 | { | 844 | { |
825 | int host_spot = -1; | 845 | int host_spot = -1; |
826 | u32 net_spot; | 846 | u32 net_spot = CIPSO_V4_INV_CAT; |
827 | u32 net_spot_max = 0; | 847 | u32 net_spot_max = 0; |
828 | u32 host_clen_bits = host_cat_len * 8; | ||
829 | u32 net_clen_bits = net_cat_len * 8; | 848 | u32 net_clen_bits = net_cat_len * 8; |
830 | u32 host_cat_size; | 849 | u32 host_cat_size = 0; |
831 | u32 *host_cat_array; | 850 | u32 *host_cat_array = NULL; |
832 | 851 | ||
833 | switch (doi_def->type) { | 852 | if (doi_def->type == CIPSO_V4_MAP_STD) { |
834 | case CIPSO_V4_MAP_PASS: | ||
835 | net_spot_max = host_cat_len; | ||
836 | while (net_spot_max > 0 && host_cat[net_spot_max - 1] == 0) | ||
837 | net_spot_max--; | ||
838 | if (net_spot_max > net_cat_len) | ||
839 | return -EINVAL; | ||
840 | memcpy(net_cat, host_cat, net_spot_max); | ||
841 | return net_spot_max; | ||
842 | case CIPSO_V4_MAP_STD: | ||
843 | host_cat_size = doi_def->map.std->cat.local_size; | 853 | host_cat_size = doi_def->map.std->cat.local_size; |
844 | host_cat_array = doi_def->map.std->cat.local; | 854 | host_cat_array = doi_def->map.std->cat.local; |
845 | for (;;) { | 855 | } |
846 | host_spot = cipso_v4_bitmap_walk(host_cat, | 856 | |
847 | host_clen_bits, | 857 | for (;;) { |
848 | host_spot + 1, | 858 | host_spot = netlbl_secattr_catmap_walk(secattr->mls_cat, |
849 | 1); | 859 | host_spot + 1); |
850 | if (host_spot < 0) | 860 | if (host_spot < 0) |
851 | break; | 861 | break; |
862 | |||
863 | switch (doi_def->type) { | ||
864 | case CIPSO_V4_MAP_PASS: | ||
865 | net_spot = host_spot; | ||
866 | break; | ||
867 | case CIPSO_V4_MAP_STD: | ||
852 | if (host_spot >= host_cat_size) | 868 | if (host_spot >= host_cat_size) |
853 | return -EPERM; | 869 | return -EPERM; |
854 | |||
855 | net_spot = host_cat_array[host_spot]; | 870 | net_spot = host_cat_array[host_spot]; |
856 | if (net_spot >= net_clen_bits) | 871 | if (net_spot >= CIPSO_V4_INV_CAT) |
857 | return -ENOSPC; | 872 | return -EPERM; |
858 | cipso_v4_bitmap_setbit(net_cat, net_spot, 1); | 873 | break; |
859 | |||
860 | if (net_spot > net_spot_max) | ||
861 | net_spot_max = net_spot; | ||
862 | } | 874 | } |
875 | if (net_spot >= net_clen_bits) | ||
876 | return -ENOSPC; | ||
877 | cipso_v4_bitmap_setbit(net_cat, net_spot, 1); | ||
863 | 878 | ||
864 | if (host_spot == -2) | 879 | if (net_spot > net_spot_max) |
865 | return -EFAULT; | 880 | net_spot_max = net_spot; |
866 | |||
867 | if (++net_spot_max % 8) | ||
868 | return net_spot_max / 8 + 1; | ||
869 | return net_spot_max / 8; | ||
870 | } | 881 | } |
871 | 882 | ||
872 | return -EINVAL; | 883 | if (++net_spot_max % 8) |
884 | return net_spot_max / 8 + 1; | ||
885 | return net_spot_max / 8; | ||
873 | } | 886 | } |
874 | 887 | ||
875 | /** | 888 | /** |
@@ -877,102 +890,333 @@ static int cipso_v4_map_cat_rbm_hton(const struct cipso_v4_doi *doi_def, | |||
877 | * @doi_def: the DOI definition | 890 | * @doi_def: the DOI definition |
878 | * @net_cat: the category bitmap in network/CIPSO format | 891 | * @net_cat: the category bitmap in network/CIPSO format |
879 | * @net_cat_len: the length of the CIPSO bitmap in bytes | 892 | * @net_cat_len: the length of the CIPSO bitmap in bytes |
880 | * @host_cat: the zero'd out category bitmap in host format | 893 | * @secattr: the security attributes |
881 | * @host_cat_len: the length of the host's category bitmap in bytes | ||
882 | * | 894 | * |
883 | * Description: | 895 | * Description: |
884 | * Perform a label mapping to translate a CIPSO bitmap to the correct local | 896 | * Perform a label mapping to translate a CIPSO bitmap to the correct local |
885 | * MLS category bitmap using the given DOI definition. Returns the minimum | 897 | * MLS category bitmap using the given DOI definition. Returns zero on |
886 | * size in bytes of the host bitmap on success, negative values otherwise. | 898 | * success, negative values on failure. |
887 | * | 899 | * |
888 | */ | 900 | */ |
889 | static int cipso_v4_map_cat_rbm_ntoh(const struct cipso_v4_doi *doi_def, | 901 | static int cipso_v4_map_cat_rbm_ntoh(const struct cipso_v4_doi *doi_def, |
890 | const unsigned char *net_cat, | 902 | const unsigned char *net_cat, |
891 | u32 net_cat_len, | 903 | u32 net_cat_len, |
892 | unsigned char *host_cat, | 904 | struct netlbl_lsm_secattr *secattr) |
893 | u32 host_cat_len) | ||
894 | { | 905 | { |
895 | u32 host_spot; | 906 | int ret_val; |
896 | u32 host_spot_max = 0; | ||
897 | int net_spot = -1; | 907 | int net_spot = -1; |
908 | u32 host_spot = CIPSO_V4_INV_CAT; | ||
898 | u32 net_clen_bits = net_cat_len * 8; | 909 | u32 net_clen_bits = net_cat_len * 8; |
899 | u32 host_clen_bits = host_cat_len * 8; | 910 | u32 net_cat_size = 0; |
900 | u32 net_cat_size; | 911 | u32 *net_cat_array = NULL; |
901 | u32 *net_cat_array; | ||
902 | 912 | ||
903 | switch (doi_def->type) { | 913 | if (doi_def->type == CIPSO_V4_MAP_STD) { |
904 | case CIPSO_V4_MAP_PASS: | ||
905 | if (net_cat_len > host_cat_len) | ||
906 | return -EINVAL; | ||
907 | memcpy(host_cat, net_cat, net_cat_len); | ||
908 | return net_cat_len; | ||
909 | case CIPSO_V4_MAP_STD: | ||
910 | net_cat_size = doi_def->map.std->cat.cipso_size; | 914 | net_cat_size = doi_def->map.std->cat.cipso_size; |
911 | net_cat_array = doi_def->map.std->cat.cipso; | 915 | net_cat_array = doi_def->map.std->cat.cipso; |
912 | for (;;) { | 916 | } |
913 | net_spot = cipso_v4_bitmap_walk(net_cat, | ||
914 | net_clen_bits, | ||
915 | net_spot + 1, | ||
916 | 1); | ||
917 | if (net_spot < 0) | ||
918 | break; | ||
919 | if (net_spot >= net_cat_size || | ||
920 | net_cat_array[net_spot] >= CIPSO_V4_INV_CAT) | ||
921 | return -EPERM; | ||
922 | 917 | ||
923 | host_spot = net_cat_array[net_spot]; | 918 | for (;;) { |
924 | if (host_spot >= host_clen_bits) | 919 | net_spot = cipso_v4_bitmap_walk(net_cat, |
925 | return -ENOSPC; | 920 | net_clen_bits, |
926 | cipso_v4_bitmap_setbit(host_cat, host_spot, 1); | 921 | net_spot + 1, |
922 | 1); | ||
923 | if (net_spot < 0) { | ||
924 | if (net_spot == -2) | ||
925 | return -EFAULT; | ||
926 | return 0; | ||
927 | } | ||
927 | 928 | ||
928 | if (host_spot > host_spot_max) | 929 | switch (doi_def->type) { |
929 | host_spot_max = host_spot; | 930 | case CIPSO_V4_MAP_PASS: |
931 | host_spot = net_spot; | ||
932 | break; | ||
933 | case CIPSO_V4_MAP_STD: | ||
934 | if (net_spot >= net_cat_size) | ||
935 | return -EPERM; | ||
936 | host_spot = net_cat_array[net_spot]; | ||
937 | if (host_spot >= CIPSO_V4_INV_CAT) | ||
938 | return -EPERM; | ||
939 | break; | ||
930 | } | 940 | } |
941 | ret_val = netlbl_secattr_catmap_setbit(secattr->mls_cat, | ||
942 | host_spot, | ||
943 | GFP_ATOMIC); | ||
944 | if (ret_val != 0) | ||
945 | return ret_val; | ||
946 | } | ||
947 | |||
948 | return -EINVAL; | ||
949 | } | ||
950 | |||
951 | /** | ||
952 | * cipso_v4_map_cat_enum_valid - Checks to see if the categories are valid | ||
953 | * @doi_def: the DOI definition | ||
954 | * @enumcat: category list | ||
955 | * @enumcat_len: length of the category list in bytes | ||
956 | * | ||
957 | * Description: | ||
958 | * Checks the given categories against the given DOI definition and returns a | ||
959 | * negative value if any of the categories do not have a valid mapping and a | ||
960 | * zero value if all of the categories are valid. | ||
961 | * | ||
962 | */ | ||
963 | static int cipso_v4_map_cat_enum_valid(const struct cipso_v4_doi *doi_def, | ||
964 | const unsigned char *enumcat, | ||
965 | u32 enumcat_len) | ||
966 | { | ||
967 | u16 cat; | ||
968 | int cat_prev = -1; | ||
969 | u32 iter; | ||
970 | |||
971 | if (doi_def->type != CIPSO_V4_MAP_PASS || enumcat_len & 0x01) | ||
972 | return -EFAULT; | ||
973 | |||
974 | for (iter = 0; iter < enumcat_len; iter += 2) { | ||
975 | cat = ntohs(*((__be16 *)&enumcat[iter])); | ||
976 | if (cat <= cat_prev) | ||
977 | return -EFAULT; | ||
978 | cat_prev = cat; | ||
979 | } | ||
980 | |||
981 | return 0; | ||
982 | } | ||
983 | |||
984 | /** | ||
985 | * cipso_v4_map_cat_enum_hton - Perform a category mapping from host to network | ||
986 | * @doi_def: the DOI definition | ||
987 | * @secattr: the security attributes | ||
988 | * @net_cat: the zero'd out category list in network/CIPSO format | ||
989 | * @net_cat_len: the length of the CIPSO category list in bytes | ||
990 | * | ||
991 | * Description: | ||
992 | * Perform a label mapping to translate a local MLS category bitmap to the | ||
993 | * correct CIPSO category list using the given DOI definition. Returns the | ||
994 | * size in bytes of the network category bitmap on success, negative values | ||
995 | * otherwise. | ||
996 | * | ||
997 | */ | ||
998 | static int cipso_v4_map_cat_enum_hton(const struct cipso_v4_doi *doi_def, | ||
999 | const struct netlbl_lsm_secattr *secattr, | ||
1000 | unsigned char *net_cat, | ||
1001 | u32 net_cat_len) | ||
1002 | { | ||
1003 | int cat = -1; | ||
1004 | u32 cat_iter = 0; | ||
1005 | |||
1006 | for (;;) { | ||
1007 | cat = netlbl_secattr_catmap_walk(secattr->mls_cat, cat + 1); | ||
1008 | if (cat < 0) | ||
1009 | break; | ||
1010 | if ((cat_iter + 2) > net_cat_len) | ||
1011 | return -ENOSPC; | ||
1012 | |||
1013 | *((__be16 *)&net_cat[cat_iter]) = htons(cat); | ||
1014 | cat_iter += 2; | ||
1015 | } | ||
1016 | |||
1017 | return cat_iter; | ||
1018 | } | ||
1019 | |||
1020 | /** | ||
1021 | * cipso_v4_map_cat_enum_ntoh - Perform a category mapping from network to host | ||
1022 | * @doi_def: the DOI definition | ||
1023 | * @net_cat: the category list in network/CIPSO format | ||
1024 | * @net_cat_len: the length of the CIPSO bitmap in bytes | ||
1025 | * @secattr: the security attributes | ||
1026 | * | ||
1027 | * Description: | ||
1028 | * Perform a label mapping to translate a CIPSO category list to the correct | ||
1029 | * local MLS category bitmap using the given DOI definition. Returns zero on | ||
1030 | * success, negative values on failure. | ||
1031 | * | ||
1032 | */ | ||
1033 | static int cipso_v4_map_cat_enum_ntoh(const struct cipso_v4_doi *doi_def, | ||
1034 | const unsigned char *net_cat, | ||
1035 | u32 net_cat_len, | ||
1036 | struct netlbl_lsm_secattr *secattr) | ||
1037 | { | ||
1038 | int ret_val; | ||
1039 | u32 iter; | ||
1040 | |||
1041 | for (iter = 0; iter < net_cat_len; iter += 2) { | ||
1042 | ret_val = netlbl_secattr_catmap_setbit(secattr->mls_cat, | ||
1043 | ntohs(*((__be16 *)&net_cat[iter])), | ||
1044 | GFP_ATOMIC); | ||
1045 | if (ret_val != 0) | ||
1046 | return ret_val; | ||
1047 | } | ||
1048 | |||
1049 | return 0; | ||
1050 | } | ||
1051 | |||
1052 | /** | ||
1053 | * cipso_v4_map_cat_rng_valid - Checks to see if the categories are valid | ||
1054 | * @doi_def: the DOI definition | ||
1055 | * @rngcat: category list | ||
1056 | * @rngcat_len: length of the category list in bytes | ||
1057 | * | ||
1058 | * Description: | ||
1059 | * Checks the given categories against the given DOI definition and returns a | ||
1060 | * negative value if any of the categories do not have a valid mapping and a | ||
1061 | * zero value if all of the categories are valid. | ||
1062 | * | ||
1063 | */ | ||
1064 | static int cipso_v4_map_cat_rng_valid(const struct cipso_v4_doi *doi_def, | ||
1065 | const unsigned char *rngcat, | ||
1066 | u32 rngcat_len) | ||
1067 | { | ||
1068 | u16 cat_high; | ||
1069 | u16 cat_low; | ||
1070 | u32 cat_prev = CIPSO_V4_MAX_REM_CATS + 1; | ||
1071 | u32 iter; | ||
931 | 1072 | ||
932 | if (net_spot == -2) | 1073 | if (doi_def->type != CIPSO_V4_MAP_PASS || rngcat_len & 0x01) |
1074 | return -EFAULT; | ||
1075 | |||
1076 | for (iter = 0; iter < rngcat_len; iter += 4) { | ||
1077 | cat_high = ntohs(*((__be16 *)&rngcat[iter])); | ||
1078 | if ((iter + 4) <= rngcat_len) | ||
1079 | cat_low = ntohs(*((__be16 *)&rngcat[iter + 2])); | ||
1080 | else | ||
1081 | cat_low = 0; | ||
1082 | |||
1083 | if (cat_high > cat_prev) | ||
933 | return -EFAULT; | 1084 | return -EFAULT; |
934 | 1085 | ||
935 | if (++host_spot_max % 8) | 1086 | cat_prev = cat_low; |
936 | return host_spot_max / 8 + 1; | ||
937 | return host_spot_max / 8; | ||
938 | } | 1087 | } |
939 | 1088 | ||
940 | return -EINVAL; | 1089 | return 0; |
1090 | } | ||
1091 | |||
1092 | /** | ||
1093 | * cipso_v4_map_cat_rng_hton - Perform a category mapping from host to network | ||
1094 | * @doi_def: the DOI definition | ||
1095 | * @secattr: the security attributes | ||
1096 | * @net_cat: the zero'd out category list in network/CIPSO format | ||
1097 | * @net_cat_len: the length of the CIPSO category list in bytes | ||
1098 | * | ||
1099 | * Description: | ||
1100 | * Perform a label mapping to translate a local MLS category bitmap to the | ||
1101 | * correct CIPSO category list using the given DOI definition. Returns the | ||
1102 | * size in bytes of the network category bitmap on success, negative values | ||
1103 | * otherwise. | ||
1104 | * | ||
1105 | */ | ||
1106 | static int cipso_v4_map_cat_rng_hton(const struct cipso_v4_doi *doi_def, | ||
1107 | const struct netlbl_lsm_secattr *secattr, | ||
1108 | unsigned char *net_cat, | ||
1109 | u32 net_cat_len) | ||
1110 | { | ||
1111 | /* The constant '16' is not random, it is the maximum number of | ||
1112 | * high/low category range pairs as permitted by the CIPSO draft based | ||
1113 | * on a maximum IPv4 header length of 60 bytes - the BUG_ON() assertion | ||
1114 | * does a sanity check to make sure we don't overflow the array. */ | ||
1115 | int iter = -1; | ||
1116 | u16 array[16]; | ||
1117 | u32 array_cnt = 0; | ||
1118 | u32 cat_size = 0; | ||
1119 | |||
1120 | BUG_ON(net_cat_len > 30); | ||
1121 | |||
1122 | for (;;) { | ||
1123 | iter = netlbl_secattr_catmap_walk(secattr->mls_cat, iter + 1); | ||
1124 | if (iter < 0) | ||
1125 | break; | ||
1126 | cat_size += (iter == 0 ? 0 : sizeof(u16)); | ||
1127 | if (cat_size > net_cat_len) | ||
1128 | return -ENOSPC; | ||
1129 | array[array_cnt++] = iter; | ||
1130 | |||
1131 | iter = netlbl_secattr_catmap_walk_rng(secattr->mls_cat, iter); | ||
1132 | if (iter < 0) | ||
1133 | return -EFAULT; | ||
1134 | cat_size += sizeof(u16); | ||
1135 | if (cat_size > net_cat_len) | ||
1136 | return -ENOSPC; | ||
1137 | array[array_cnt++] = iter; | ||
1138 | } | ||
1139 | |||
1140 | for (iter = 0; array_cnt > 0;) { | ||
1141 | *((__be16 *)&net_cat[iter]) = htons(array[--array_cnt]); | ||
1142 | iter += 2; | ||
1143 | array_cnt--; | ||
1144 | if (array[array_cnt] != 0) { | ||
1145 | *((__be16 *)&net_cat[iter]) = htons(array[array_cnt]); | ||
1146 | iter += 2; | ||
1147 | } | ||
1148 | } | ||
1149 | |||
1150 | return cat_size; | ||
1151 | } | ||
1152 | |||
1153 | /** | ||
1154 | * cipso_v4_map_cat_rng_ntoh - Perform a category mapping from network to host | ||
1155 | * @doi_def: the DOI definition | ||
1156 | * @net_cat: the category list in network/CIPSO format | ||
1157 | * @net_cat_len: the length of the CIPSO bitmap in bytes | ||
1158 | * @secattr: the security attributes | ||
1159 | * | ||
1160 | * Description: | ||
1161 | * Perform a label mapping to translate a CIPSO category list to the correct | ||
1162 | * local MLS category bitmap using the given DOI definition. Returns zero on | ||
1163 | * success, negative values on failure. | ||
1164 | * | ||
1165 | */ | ||
1166 | static int cipso_v4_map_cat_rng_ntoh(const struct cipso_v4_doi *doi_def, | ||
1167 | const unsigned char *net_cat, | ||
1168 | u32 net_cat_len, | ||
1169 | struct netlbl_lsm_secattr *secattr) | ||
1170 | { | ||
1171 | int ret_val; | ||
1172 | u32 net_iter; | ||
1173 | u16 cat_low; | ||
1174 | u16 cat_high; | ||
1175 | |||
1176 | for(net_iter = 0; net_iter < net_cat_len; net_iter += 4) { | ||
1177 | cat_high = ntohs(*((__be16 *)&net_cat[net_iter])); | ||
1178 | if ((net_iter + 4) <= net_cat_len) | ||
1179 | cat_low = ntohs(*((__be16 *)&net_cat[net_iter + 2])); | ||
1180 | else | ||
1181 | cat_low = 0; | ||
1182 | |||
1183 | ret_val = netlbl_secattr_catmap_setrng(secattr->mls_cat, | ||
1184 | cat_low, | ||
1185 | cat_high, | ||
1186 | GFP_ATOMIC); | ||
1187 | if (ret_val != 0) | ||
1188 | return ret_val; | ||
1189 | } | ||
1190 | |||
1191 | return 0; | ||
941 | } | 1192 | } |
942 | 1193 | ||
943 | /* | 1194 | /* |
944 | * Protocol Handling Functions | 1195 | * Protocol Handling Functions |
945 | */ | 1196 | */ |
946 | 1197 | ||
1198 | #define CIPSO_V4_OPT_LEN_MAX 40 | ||
947 | #define CIPSO_V4_HDR_LEN 6 | 1199 | #define CIPSO_V4_HDR_LEN 6 |
948 | 1200 | ||
949 | /** | 1201 | /** |
950 | * cipso_v4_gentag_hdr - Generate a CIPSO option header | 1202 | * cipso_v4_gentag_hdr - Generate a CIPSO option header |
951 | * @doi_def: the DOI definition | 1203 | * @doi_def: the DOI definition |
952 | * @len: the total tag length in bytes | 1204 | * @len: the total tag length in bytes, not including this header |
953 | * @buf: the CIPSO option buffer | 1205 | * @buf: the CIPSO option buffer |
954 | * | 1206 | * |
955 | * Description: | 1207 | * Description: |
956 | * Write a CIPSO header into the beginning of @buffer. Return zero on success, | 1208 | * Write a CIPSO header into the beginning of @buffer. |
957 | * negative values on failure. | ||
958 | * | 1209 | * |
959 | */ | 1210 | */ |
960 | static int cipso_v4_gentag_hdr(const struct cipso_v4_doi *doi_def, | 1211 | static void cipso_v4_gentag_hdr(const struct cipso_v4_doi *doi_def, |
961 | u32 len, | 1212 | unsigned char *buf, |
962 | unsigned char *buf) | 1213 | u32 len) |
963 | { | 1214 | { |
964 | if (CIPSO_V4_HDR_LEN + len > 40) | ||
965 | return -ENOSPC; | ||
966 | |||
967 | buf[0] = IPOPT_CIPSO; | 1215 | buf[0] = IPOPT_CIPSO; |
968 | buf[1] = CIPSO_V4_HDR_LEN + len; | 1216 | buf[1] = CIPSO_V4_HDR_LEN + len; |
969 | *(u32 *)&buf[2] = htonl(doi_def->doi); | 1217 | *(__be32 *)&buf[2] = htonl(doi_def->doi); |
970 | |||
971 | return 0; | ||
972 | } | 1218 | } |
973 | 1219 | ||
974 | #define CIPSO_V4_TAG1_CAT_LEN 30 | ||
975 | |||
976 | /** | 1220 | /** |
977 | * cipso_v4_gentag_rbm - Generate a CIPSO restricted bitmap tag (type #1) | 1221 | * cipso_v4_gentag_rbm - Generate a CIPSO restricted bitmap tag (type #1) |
978 | * @doi_def: the DOI definition | 1222 | * @doi_def: the DOI definition |
@@ -983,83 +1227,249 @@ static int cipso_v4_gentag_hdr(const struct cipso_v4_doi *doi_def, | |||
983 | * Description: | 1227 | * Description: |
984 | * Generate a CIPSO option using the restricted bitmap tag, tag type #1. The | 1228 | * Generate a CIPSO option using the restricted bitmap tag, tag type #1. The |
985 | * actual buffer length may be larger than the indicated size due to | 1229 | * actual buffer length may be larger than the indicated size due to |
986 | * translation between host and network category bitmaps. Returns zero on | 1230 | * translation between host and network category bitmaps. Returns the size of |
987 | * success, negative values on failure. | 1231 | * the tag on success, negative values on failure. |
988 | * | 1232 | * |
989 | */ | 1233 | */ |
990 | static int cipso_v4_gentag_rbm(const struct cipso_v4_doi *doi_def, | 1234 | static int cipso_v4_gentag_rbm(const struct cipso_v4_doi *doi_def, |
991 | const struct netlbl_lsm_secattr *secattr, | 1235 | const struct netlbl_lsm_secattr *secattr, |
992 | unsigned char **buffer, | 1236 | unsigned char *buffer, |
993 | u32 *buffer_len) | 1237 | u32 buffer_len) |
994 | { | 1238 | { |
995 | int ret_val = -EPERM; | 1239 | int ret_val; |
996 | unsigned char *buf = NULL; | 1240 | u32 tag_len; |
997 | u32 buf_len; | ||
998 | u32 level; | 1241 | u32 level; |
999 | 1242 | ||
1000 | if (secattr->mls_cat) { | 1243 | if ((secattr->flags & NETLBL_SECATTR_MLS_LVL) == 0) |
1001 | buf = kzalloc(CIPSO_V4_HDR_LEN + 4 + CIPSO_V4_TAG1_CAT_LEN, | 1244 | return -EPERM; |
1002 | GFP_ATOMIC); | 1245 | |
1003 | if (buf == NULL) | 1246 | ret_val = cipso_v4_map_lvl_hton(doi_def, secattr->mls_lvl, &level); |
1004 | return -ENOMEM; | 1247 | if (ret_val != 0) |
1248 | return ret_val; | ||
1005 | 1249 | ||
1250 | if (secattr->flags & NETLBL_SECATTR_MLS_CAT) { | ||
1006 | ret_val = cipso_v4_map_cat_rbm_hton(doi_def, | 1251 | ret_val = cipso_v4_map_cat_rbm_hton(doi_def, |
1007 | secattr->mls_cat, | 1252 | secattr, |
1008 | secattr->mls_cat_len, | 1253 | &buffer[4], |
1009 | &buf[CIPSO_V4_HDR_LEN + 4], | 1254 | buffer_len - 4); |
1010 | CIPSO_V4_TAG1_CAT_LEN); | ||
1011 | if (ret_val < 0) | 1255 | if (ret_val < 0) |
1012 | goto gentag_failure; | 1256 | return ret_val; |
1013 | 1257 | ||
1014 | /* This will send packets using the "optimized" format when | 1258 | /* This will send packets using the "optimized" format when |
1015 | * possibile as specified in section 3.4.2.6 of the | 1259 | * possibile as specified in section 3.4.2.6 of the |
1016 | * CIPSO draft. */ | 1260 | * CIPSO draft. */ |
1017 | if (cipso_v4_rbm_optfmt && (ret_val > 0 && ret_val < 10)) | 1261 | if (cipso_v4_rbm_optfmt && ret_val > 0 && ret_val <= 10) |
1018 | ret_val = 10; | 1262 | tag_len = 14; |
1263 | else | ||
1264 | tag_len = 4 + ret_val; | ||
1265 | } else | ||
1266 | tag_len = 4; | ||
1267 | |||
1268 | buffer[0] = 0x01; | ||
1269 | buffer[1] = tag_len; | ||
1270 | buffer[3] = level; | ||
1271 | |||
1272 | return tag_len; | ||
1273 | } | ||
1019 | 1274 | ||
1020 | buf_len = 4 + ret_val; | 1275 | /** |
1021 | } else { | 1276 | * cipso_v4_parsetag_rbm - Parse a CIPSO restricted bitmap tag |
1022 | buf = kzalloc(CIPSO_V4_HDR_LEN + 4, GFP_ATOMIC); | 1277 | * @doi_def: the DOI definition |
1023 | if (buf == NULL) | 1278 | * @tag: the CIPSO tag |
1279 | * @secattr: the security attributes | ||
1280 | * | ||
1281 | * Description: | ||
1282 | * Parse a CIPSO restricted bitmap tag (tag type #1) and return the security | ||
1283 | * attributes in @secattr. Return zero on success, negatives values on | ||
1284 | * failure. | ||
1285 | * | ||
1286 | */ | ||
1287 | static int cipso_v4_parsetag_rbm(const struct cipso_v4_doi *doi_def, | ||
1288 | const unsigned char *tag, | ||
1289 | struct netlbl_lsm_secattr *secattr) | ||
1290 | { | ||
1291 | int ret_val; | ||
1292 | u8 tag_len = tag[1]; | ||
1293 | u32 level; | ||
1294 | |||
1295 | ret_val = cipso_v4_map_lvl_ntoh(doi_def, tag[3], &level); | ||
1296 | if (ret_val != 0) | ||
1297 | return ret_val; | ||
1298 | secattr->mls_lvl = level; | ||
1299 | secattr->flags |= NETLBL_SECATTR_MLS_LVL; | ||
1300 | |||
1301 | if (tag_len > 4) { | ||
1302 | secattr->mls_cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC); | ||
1303 | if (secattr->mls_cat == NULL) | ||
1024 | return -ENOMEM; | 1304 | return -ENOMEM; |
1025 | buf_len = 4; | 1305 | |
1306 | ret_val = cipso_v4_map_cat_rbm_ntoh(doi_def, | ||
1307 | &tag[4], | ||
1308 | tag_len - 4, | ||
1309 | secattr); | ||
1310 | if (ret_val != 0) { | ||
1311 | netlbl_secattr_catmap_free(secattr->mls_cat); | ||
1312 | return ret_val; | ||
1313 | } | ||
1314 | |||
1315 | secattr->flags |= NETLBL_SECATTR_MLS_CAT; | ||
1026 | } | 1316 | } |
1027 | 1317 | ||
1318 | return 0; | ||
1319 | } | ||
1320 | |||
1321 | /** | ||
1322 | * cipso_v4_gentag_enum - Generate a CIPSO enumerated tag (type #2) | ||
1323 | * @doi_def: the DOI definition | ||
1324 | * @secattr: the security attributes | ||
1325 | * @buffer: the option buffer | ||
1326 | * @buffer_len: length of buffer in bytes | ||
1327 | * | ||
1328 | * Description: | ||
1329 | * Generate a CIPSO option using the enumerated tag, tag type #2. Returns the | ||
1330 | * size of the tag on success, negative values on failure. | ||
1331 | * | ||
1332 | */ | ||
1333 | static int cipso_v4_gentag_enum(const struct cipso_v4_doi *doi_def, | ||
1334 | const struct netlbl_lsm_secattr *secattr, | ||
1335 | unsigned char *buffer, | ||
1336 | u32 buffer_len) | ||
1337 | { | ||
1338 | int ret_val; | ||
1339 | u32 tag_len; | ||
1340 | u32 level; | ||
1341 | |||
1342 | if (!(secattr->flags & NETLBL_SECATTR_MLS_LVL)) | ||
1343 | return -EPERM; | ||
1344 | |||
1028 | ret_val = cipso_v4_map_lvl_hton(doi_def, secattr->mls_lvl, &level); | 1345 | ret_val = cipso_v4_map_lvl_hton(doi_def, secattr->mls_lvl, &level); |
1029 | if (ret_val != 0) | 1346 | if (ret_val != 0) |
1030 | goto gentag_failure; | 1347 | return ret_val; |
1348 | |||
1349 | if (secattr->flags & NETLBL_SECATTR_MLS_CAT) { | ||
1350 | ret_val = cipso_v4_map_cat_enum_hton(doi_def, | ||
1351 | secattr, | ||
1352 | &buffer[4], | ||
1353 | buffer_len - 4); | ||
1354 | if (ret_val < 0) | ||
1355 | return ret_val; | ||
1356 | |||
1357 | tag_len = 4 + ret_val; | ||
1358 | } else | ||
1359 | tag_len = 4; | ||
1360 | |||
1361 | buffer[0] = 0x02; | ||
1362 | buffer[1] = tag_len; | ||
1363 | buffer[3] = level; | ||
1031 | 1364 | ||
1032 | ret_val = cipso_v4_gentag_hdr(doi_def, buf_len, buf); | 1365 | return tag_len; |
1366 | } | ||
1367 | |||
1368 | /** | ||
1369 | * cipso_v4_parsetag_enum - Parse a CIPSO enumerated tag | ||
1370 | * @doi_def: the DOI definition | ||
1371 | * @tag: the CIPSO tag | ||
1372 | * @secattr: the security attributes | ||
1373 | * | ||
1374 | * Description: | ||
1375 | * Parse a CIPSO enumerated tag (tag type #2) and return the security | ||
1376 | * attributes in @secattr. Return zero on success, negatives values on | ||
1377 | * failure. | ||
1378 | * | ||
1379 | */ | ||
1380 | static int cipso_v4_parsetag_enum(const struct cipso_v4_doi *doi_def, | ||
1381 | const unsigned char *tag, | ||
1382 | struct netlbl_lsm_secattr *secattr) | ||
1383 | { | ||
1384 | int ret_val; | ||
1385 | u8 tag_len = tag[1]; | ||
1386 | u32 level; | ||
1387 | |||
1388 | ret_val = cipso_v4_map_lvl_ntoh(doi_def, tag[3], &level); | ||
1033 | if (ret_val != 0) | 1389 | if (ret_val != 0) |
1034 | goto gentag_failure; | 1390 | return ret_val; |
1391 | secattr->mls_lvl = level; | ||
1392 | secattr->flags |= NETLBL_SECATTR_MLS_LVL; | ||
1393 | |||
1394 | if (tag_len > 4) { | ||
1395 | secattr->mls_cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC); | ||
1396 | if (secattr->mls_cat == NULL) | ||
1397 | return -ENOMEM; | ||
1035 | 1398 | ||
1036 | buf[CIPSO_V4_HDR_LEN] = 0x01; | 1399 | ret_val = cipso_v4_map_cat_enum_ntoh(doi_def, |
1037 | buf[CIPSO_V4_HDR_LEN + 1] = buf_len; | 1400 | &tag[4], |
1038 | buf[CIPSO_V4_HDR_LEN + 3] = level; | 1401 | tag_len - 4, |
1402 | secattr); | ||
1403 | if (ret_val != 0) { | ||
1404 | netlbl_secattr_catmap_free(secattr->mls_cat); | ||
1405 | return ret_val; | ||
1406 | } | ||
1039 | 1407 | ||
1040 | *buffer = buf; | 1408 | secattr->flags |= NETLBL_SECATTR_MLS_CAT; |
1041 | *buffer_len = CIPSO_V4_HDR_LEN + buf_len; | 1409 | } |
1042 | 1410 | ||
1043 | return 0; | 1411 | return 0; |
1412 | } | ||
1044 | 1413 | ||
1045 | gentag_failure: | 1414 | /** |
1046 | kfree(buf); | 1415 | * cipso_v4_gentag_rng - Generate a CIPSO ranged tag (type #5) |
1047 | return ret_val; | 1416 | * @doi_def: the DOI definition |
1417 | * @secattr: the security attributes | ||
1418 | * @buffer: the option buffer | ||
1419 | * @buffer_len: length of buffer in bytes | ||
1420 | * | ||
1421 | * Description: | ||
1422 | * Generate a CIPSO option using the ranged tag, tag type #5. Returns the | ||
1423 | * size of the tag on success, negative values on failure. | ||
1424 | * | ||
1425 | */ | ||
1426 | static int cipso_v4_gentag_rng(const struct cipso_v4_doi *doi_def, | ||
1427 | const struct netlbl_lsm_secattr *secattr, | ||
1428 | unsigned char *buffer, | ||
1429 | u32 buffer_len) | ||
1430 | { | ||
1431 | int ret_val; | ||
1432 | u32 tag_len; | ||
1433 | u32 level; | ||
1434 | |||
1435 | if (!(secattr->flags & NETLBL_SECATTR_MLS_LVL)) | ||
1436 | return -EPERM; | ||
1437 | |||
1438 | ret_val = cipso_v4_map_lvl_hton(doi_def, secattr->mls_lvl, &level); | ||
1439 | if (ret_val != 0) | ||
1440 | return ret_val; | ||
1441 | |||
1442 | if (secattr->flags & NETLBL_SECATTR_MLS_CAT) { | ||
1443 | ret_val = cipso_v4_map_cat_rng_hton(doi_def, | ||
1444 | secattr, | ||
1445 | &buffer[4], | ||
1446 | buffer_len - 4); | ||
1447 | if (ret_val < 0) | ||
1448 | return ret_val; | ||
1449 | |||
1450 | tag_len = 4 + ret_val; | ||
1451 | } else | ||
1452 | tag_len = 4; | ||
1453 | |||
1454 | buffer[0] = 0x05; | ||
1455 | buffer[1] = tag_len; | ||
1456 | buffer[3] = level; | ||
1457 | |||
1458 | return tag_len; | ||
1048 | } | 1459 | } |
1049 | 1460 | ||
1050 | /** | 1461 | /** |
1051 | * cipso_v4_parsetag_rbm - Parse a CIPSO restricted bitmap tag | 1462 | * cipso_v4_parsetag_rng - Parse a CIPSO ranged tag |
1052 | * @doi_def: the DOI definition | 1463 | * @doi_def: the DOI definition |
1053 | * @tag: the CIPSO tag | 1464 | * @tag: the CIPSO tag |
1054 | * @secattr: the security attributes | 1465 | * @secattr: the security attributes |
1055 | * | 1466 | * |
1056 | * Description: | 1467 | * Description: |
1057 | * Parse a CIPSO restricted bitmap tag (tag type #1) and return the security | 1468 | * Parse a CIPSO ranged tag (tag type #5) and return the security attributes |
1058 | * attributes in @secattr. Return zero on success, negatives values on | 1469 | * in @secattr. Return zero on success, negatives values on failure. |
1059 | * failure. | ||
1060 | * | 1470 | * |
1061 | */ | 1471 | */ |
1062 | static int cipso_v4_parsetag_rbm(const struct cipso_v4_doi *doi_def, | 1472 | static int cipso_v4_parsetag_rng(const struct cipso_v4_doi *doi_def, |
1063 | const unsigned char *tag, | 1473 | const unsigned char *tag, |
1064 | struct netlbl_lsm_secattr *secattr) | 1474 | struct netlbl_lsm_secattr *secattr) |
1065 | { | 1475 | { |
@@ -1071,32 +1481,23 @@ static int cipso_v4_parsetag_rbm(const struct cipso_v4_doi *doi_def, | |||
1071 | if (ret_val != 0) | 1481 | if (ret_val != 0) |
1072 | return ret_val; | 1482 | return ret_val; |
1073 | secattr->mls_lvl = level; | 1483 | secattr->mls_lvl = level; |
1074 | secattr->mls_lvl_vld = 1; | 1484 | secattr->flags |= NETLBL_SECATTR_MLS_LVL; |
1075 | 1485 | ||
1076 | if (tag_len > 4) { | 1486 | if (tag_len > 4) { |
1077 | switch (doi_def->type) { | 1487 | secattr->mls_cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC); |
1078 | case CIPSO_V4_MAP_PASS: | ||
1079 | secattr->mls_cat_len = tag_len - 4; | ||
1080 | break; | ||
1081 | case CIPSO_V4_MAP_STD: | ||
1082 | secattr->mls_cat_len = | ||
1083 | doi_def->map.std->cat.local_size; | ||
1084 | break; | ||
1085 | } | ||
1086 | secattr->mls_cat = kzalloc(secattr->mls_cat_len, GFP_ATOMIC); | ||
1087 | if (secattr->mls_cat == NULL) | 1488 | if (secattr->mls_cat == NULL) |
1088 | return -ENOMEM; | 1489 | return -ENOMEM; |
1089 | 1490 | ||
1090 | ret_val = cipso_v4_map_cat_rbm_ntoh(doi_def, | 1491 | ret_val = cipso_v4_map_cat_rng_ntoh(doi_def, |
1091 | &tag[4], | 1492 | &tag[4], |
1092 | tag_len - 4, | 1493 | tag_len - 4, |
1093 | secattr->mls_cat, | 1494 | secattr); |
1094 | secattr->mls_cat_len); | 1495 | if (ret_val != 0) { |
1095 | if (ret_val < 0) { | 1496 | netlbl_secattr_catmap_free(secattr->mls_cat); |
1096 | kfree(secattr->mls_cat); | ||
1097 | return ret_val; | 1497 | return ret_val; |
1098 | } | 1498 | } |
1099 | secattr->mls_cat_len = ret_val; | 1499 | |
1500 | secattr->flags |= NETLBL_SECATTR_MLS_CAT; | ||
1100 | } | 1501 | } |
1101 | 1502 | ||
1102 | return 0; | 1503 | return 0; |
@@ -1140,7 +1541,7 @@ int cipso_v4_validate(unsigned char **option) | |||
1140 | } | 1541 | } |
1141 | 1542 | ||
1142 | rcu_read_lock(); | 1543 | rcu_read_lock(); |
1143 | doi_def = cipso_v4_doi_getdef(ntohl(*((u32 *)&opt[2]))); | 1544 | doi_def = cipso_v4_doi_search(ntohl(*((__be32 *)&opt[2]))); |
1144 | if (doi_def == NULL) { | 1545 | if (doi_def == NULL) { |
1145 | err_offset = 2; | 1546 | err_offset = 2; |
1146 | goto validate_return_locked; | 1547 | goto validate_return_locked; |
@@ -1191,6 +1592,44 @@ int cipso_v4_validate(unsigned char **option) | |||
1191 | } | 1592 | } |
1192 | } | 1593 | } |
1193 | break; | 1594 | break; |
1595 | case CIPSO_V4_TAG_ENUM: | ||
1596 | if (tag_len < 4) { | ||
1597 | err_offset = opt_iter + 1; | ||
1598 | goto validate_return_locked; | ||
1599 | } | ||
1600 | |||
1601 | if (cipso_v4_map_lvl_valid(doi_def, | ||
1602 | tag[3]) < 0) { | ||
1603 | err_offset = opt_iter + 3; | ||
1604 | goto validate_return_locked; | ||
1605 | } | ||
1606 | if (tag_len > 4 && | ||
1607 | cipso_v4_map_cat_enum_valid(doi_def, | ||
1608 | &tag[4], | ||
1609 | tag_len - 4) < 0) { | ||
1610 | err_offset = opt_iter + 4; | ||
1611 | goto validate_return_locked; | ||
1612 | } | ||
1613 | break; | ||
1614 | case CIPSO_V4_TAG_RANGE: | ||
1615 | if (tag_len < 4) { | ||
1616 | err_offset = opt_iter + 1; | ||
1617 | goto validate_return_locked; | ||
1618 | } | ||
1619 | |||
1620 | if (cipso_v4_map_lvl_valid(doi_def, | ||
1621 | tag[3]) < 0) { | ||
1622 | err_offset = opt_iter + 3; | ||
1623 | goto validate_return_locked; | ||
1624 | } | ||
1625 | if (tag_len > 4 && | ||
1626 | cipso_v4_map_cat_rng_valid(doi_def, | ||
1627 | &tag[4], | ||
1628 | tag_len - 4) < 0) { | ||
1629 | err_offset = opt_iter + 4; | ||
1630 | goto validate_return_locked; | ||
1631 | } | ||
1632 | break; | ||
1194 | default: | 1633 | default: |
1195 | err_offset = opt_iter; | 1634 | err_offset = opt_iter; |
1196 | goto validate_return_locked; | 1635 | goto validate_return_locked; |
@@ -1265,7 +1704,7 @@ int cipso_v4_socket_setattr(const struct socket *sock, | |||
1265 | { | 1704 | { |
1266 | int ret_val = -EPERM; | 1705 | int ret_val = -EPERM; |
1267 | u32 iter; | 1706 | u32 iter; |
1268 | unsigned char *buf = NULL; | 1707 | unsigned char *buf; |
1269 | u32 buf_len = 0; | 1708 | u32 buf_len = 0; |
1270 | u32 opt_len; | 1709 | u32 opt_len; |
1271 | struct ip_options *opt = NULL; | 1710 | struct ip_options *opt = NULL; |
@@ -1281,17 +1720,40 @@ int cipso_v4_socket_setattr(const struct socket *sock, | |||
1281 | if (sk == NULL) | 1720 | if (sk == NULL) |
1282 | return 0; | 1721 | return 0; |
1283 | 1722 | ||
1723 | /* We allocate the maximum CIPSO option size here so we are probably | ||
1724 | * being a little wasteful, but it makes our life _much_ easier later | ||
1725 | * on and after all we are only talking about 40 bytes. */ | ||
1726 | buf_len = CIPSO_V4_OPT_LEN_MAX; | ||
1727 | buf = kmalloc(buf_len, GFP_ATOMIC); | ||
1728 | if (buf == NULL) { | ||
1729 | ret_val = -ENOMEM; | ||
1730 | goto socket_setattr_failure; | ||
1731 | } | ||
1732 | |||
1284 | /* XXX - This code assumes only one tag per CIPSO option which isn't | 1733 | /* XXX - This code assumes only one tag per CIPSO option which isn't |
1285 | * really a good assumption to make but since we only support the MAC | 1734 | * really a good assumption to make but since we only support the MAC |
1286 | * tags right now it is a safe assumption. */ | 1735 | * tags right now it is a safe assumption. */ |
1287 | iter = 0; | 1736 | iter = 0; |
1288 | do { | 1737 | do { |
1738 | memset(buf, 0, buf_len); | ||
1289 | switch (doi_def->tags[iter]) { | 1739 | switch (doi_def->tags[iter]) { |
1290 | case CIPSO_V4_TAG_RBITMAP: | 1740 | case CIPSO_V4_TAG_RBITMAP: |
1291 | ret_val = cipso_v4_gentag_rbm(doi_def, | 1741 | ret_val = cipso_v4_gentag_rbm(doi_def, |
1292 | secattr, | 1742 | secattr, |
1293 | &buf, | 1743 | &buf[CIPSO_V4_HDR_LEN], |
1294 | &buf_len); | 1744 | buf_len - CIPSO_V4_HDR_LEN); |
1745 | break; | ||
1746 | case CIPSO_V4_TAG_ENUM: | ||
1747 | ret_val = cipso_v4_gentag_enum(doi_def, | ||
1748 | secattr, | ||
1749 | &buf[CIPSO_V4_HDR_LEN], | ||
1750 | buf_len - CIPSO_V4_HDR_LEN); | ||
1751 | break; | ||
1752 | case CIPSO_V4_TAG_RANGE: | ||
1753 | ret_val = cipso_v4_gentag_rng(doi_def, | ||
1754 | secattr, | ||
1755 | &buf[CIPSO_V4_HDR_LEN], | ||
1756 | buf_len - CIPSO_V4_HDR_LEN); | ||
1295 | break; | 1757 | break; |
1296 | default: | 1758 | default: |
1297 | ret_val = -EPERM; | 1759 | ret_val = -EPERM; |
@@ -1299,11 +1761,13 @@ int cipso_v4_socket_setattr(const struct socket *sock, | |||
1299 | } | 1761 | } |
1300 | 1762 | ||
1301 | iter++; | 1763 | iter++; |
1302 | } while (ret_val != 0 && | 1764 | } while (ret_val < 0 && |
1303 | iter < CIPSO_V4_TAG_MAXCNT && | 1765 | iter < CIPSO_V4_TAG_MAXCNT && |
1304 | doi_def->tags[iter] != CIPSO_V4_TAG_INVALID); | 1766 | doi_def->tags[iter] != CIPSO_V4_TAG_INVALID); |
1305 | if (ret_val != 0) | 1767 | if (ret_val < 0) |
1306 | goto socket_setattr_failure; | 1768 | goto socket_setattr_failure; |
1769 | cipso_v4_gentag_hdr(doi_def, buf, ret_val); | ||
1770 | buf_len = CIPSO_V4_HDR_LEN + ret_val; | ||
1307 | 1771 | ||
1308 | /* We can't use ip_options_get() directly because it makes a call to | 1772 | /* We can't use ip_options_get() directly because it makes a call to |
1309 | * ip_options_get_alloc() which allocates memory with GFP_KERNEL and | 1773 | * ip_options_get_alloc() which allocates memory with GFP_KERNEL and |
@@ -1370,19 +1834,33 @@ int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr) | |||
1370 | if (ret_val == 0) | 1834 | if (ret_val == 0) |
1371 | return ret_val; | 1835 | return ret_val; |
1372 | 1836 | ||
1373 | doi = ntohl(*(u32 *)&cipso_ptr[2]); | 1837 | doi = ntohl(*(__be32 *)&cipso_ptr[2]); |
1374 | rcu_read_lock(); | 1838 | rcu_read_lock(); |
1375 | doi_def = cipso_v4_doi_getdef(doi); | 1839 | doi_def = cipso_v4_doi_search(doi); |
1376 | if (doi_def == NULL) { | 1840 | if (doi_def == NULL) { |
1377 | rcu_read_unlock(); | 1841 | rcu_read_unlock(); |
1378 | return -ENOMSG; | 1842 | return -ENOMSG; |
1379 | } | 1843 | } |
1844 | |||
1845 | /* XXX - This code assumes only one tag per CIPSO option which isn't | ||
1846 | * really a good assumption to make but since we only support the MAC | ||
1847 | * tags right now it is a safe assumption. */ | ||
1380 | switch (cipso_ptr[6]) { | 1848 | switch (cipso_ptr[6]) { |
1381 | case CIPSO_V4_TAG_RBITMAP: | 1849 | case CIPSO_V4_TAG_RBITMAP: |
1382 | ret_val = cipso_v4_parsetag_rbm(doi_def, | 1850 | ret_val = cipso_v4_parsetag_rbm(doi_def, |
1383 | &cipso_ptr[6], | 1851 | &cipso_ptr[6], |
1384 | secattr); | 1852 | secattr); |
1385 | break; | 1853 | break; |
1854 | case CIPSO_V4_TAG_ENUM: | ||
1855 | ret_val = cipso_v4_parsetag_enum(doi_def, | ||
1856 | &cipso_ptr[6], | ||
1857 | secattr); | ||
1858 | break; | ||
1859 | case CIPSO_V4_TAG_RANGE: | ||
1860 | ret_val = cipso_v4_parsetag_rng(doi_def, | ||
1861 | &cipso_ptr[6], | ||
1862 | secattr); | ||
1863 | break; | ||
1386 | } | 1864 | } |
1387 | rcu_read_unlock(); | 1865 | rcu_read_unlock(); |
1388 | 1866 | ||
@@ -1430,23 +1908,30 @@ int cipso_v4_skbuff_getattr(const struct sk_buff *skb, | |||
1430 | u32 doi; | 1908 | u32 doi; |
1431 | struct cipso_v4_doi *doi_def; | 1909 | struct cipso_v4_doi *doi_def; |
1432 | 1910 | ||
1433 | if (!CIPSO_V4_OPTEXIST(skb)) | ||
1434 | return -ENOMSG; | ||
1435 | cipso_ptr = CIPSO_V4_OPTPTR(skb); | 1911 | cipso_ptr = CIPSO_V4_OPTPTR(skb); |
1436 | if (cipso_v4_cache_check(cipso_ptr, cipso_ptr[1], secattr) == 0) | 1912 | if (cipso_v4_cache_check(cipso_ptr, cipso_ptr[1], secattr) == 0) |
1437 | return 0; | 1913 | return 0; |
1438 | 1914 | ||
1439 | doi = ntohl(*(u32 *)&cipso_ptr[2]); | 1915 | doi = ntohl(*(__be32 *)&cipso_ptr[2]); |
1440 | rcu_read_lock(); | 1916 | rcu_read_lock(); |
1441 | doi_def = cipso_v4_doi_getdef(doi); | 1917 | doi_def = cipso_v4_doi_search(doi); |
1442 | if (doi_def == NULL) | 1918 | if (doi_def == NULL) |
1443 | goto skbuff_getattr_return; | 1919 | goto skbuff_getattr_return; |
1920 | |||
1921 | /* XXX - This code assumes only one tag per CIPSO option which isn't | ||
1922 | * really a good assumption to make but since we only support the MAC | ||
1923 | * tags right now it is a safe assumption. */ | ||
1444 | switch (cipso_ptr[6]) { | 1924 | switch (cipso_ptr[6]) { |
1445 | case CIPSO_V4_TAG_RBITMAP: | 1925 | case CIPSO_V4_TAG_RBITMAP: |
1446 | ret_val = cipso_v4_parsetag_rbm(doi_def, | 1926 | ret_val = cipso_v4_parsetag_rbm(doi_def, |
1447 | &cipso_ptr[6], | 1927 | &cipso_ptr[6], |
1448 | secattr); | 1928 | secattr); |
1449 | break; | 1929 | break; |
1930 | case CIPSO_V4_TAG_ENUM: | ||
1931 | ret_val = cipso_v4_parsetag_enum(doi_def, | ||
1932 | &cipso_ptr[6], | ||
1933 | secattr); | ||
1934 | break; | ||
1450 | } | 1935 | } |
1451 | 1936 | ||
1452 | skbuff_getattr_return: | 1937 | skbuff_getattr_return: |
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 7602c79a389b..2fd899160f85 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c | |||
@@ -577,20 +577,20 @@ static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg | |||
577 | * Determine a default network mask, based on the IP address. | 577 | * Determine a default network mask, based on the IP address. |
578 | */ | 578 | */ |
579 | 579 | ||
580 | static __inline__ int inet_abc_len(u32 addr) | 580 | static __inline__ int inet_abc_len(__be32 addr) |
581 | { | 581 | { |
582 | int rc = -1; /* Something else, probably a multicast. */ | 582 | int rc = -1; /* Something else, probably a multicast. */ |
583 | 583 | ||
584 | if (ZERONET(addr)) | 584 | if (ZERONET(addr)) |
585 | rc = 0; | 585 | rc = 0; |
586 | else { | 586 | else { |
587 | addr = ntohl(addr); | 587 | __u32 haddr = ntohl(addr); |
588 | 588 | ||
589 | if (IN_CLASSA(addr)) | 589 | if (IN_CLASSA(haddr)) |
590 | rc = 8; | 590 | rc = 8; |
591 | else if (IN_CLASSB(addr)) | 591 | else if (IN_CLASSB(haddr)) |
592 | rc = 16; | 592 | rc = 16; |
593 | else if (IN_CLASSC(addr)) | 593 | else if (IN_CLASSC(haddr)) |
594 | rc = 24; | 594 | rc = 24; |
595 | } | 595 | } |
596 | 596 | ||
@@ -1120,6 +1120,16 @@ static struct notifier_block ip_netdev_notifier = { | |||
1120 | .notifier_call =inetdev_event, | 1120 | .notifier_call =inetdev_event, |
1121 | }; | 1121 | }; |
1122 | 1122 | ||
1123 | static inline size_t inet_nlmsg_size(void) | ||
1124 | { | ||
1125 | return NLMSG_ALIGN(sizeof(struct ifaddrmsg)) | ||
1126 | + nla_total_size(4) /* IFA_ADDRESS */ | ||
1127 | + nla_total_size(4) /* IFA_LOCAL */ | ||
1128 | + nla_total_size(4) /* IFA_BROADCAST */ | ||
1129 | + nla_total_size(4) /* IFA_ANYCAST */ | ||
1130 | + nla_total_size(IFNAMSIZ); /* IFA_LABEL */ | ||
1131 | } | ||
1132 | |||
1123 | static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa, | 1133 | static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa, |
1124 | u32 pid, u32 seq, int event, unsigned int flags) | 1134 | u32 pid, u32 seq, int event, unsigned int flags) |
1125 | { | 1135 | { |
@@ -1208,15 +1218,13 @@ static void rtmsg_ifa(int event, struct in_ifaddr* ifa, struct nlmsghdr *nlh, | |||
1208 | u32 seq = nlh ? nlh->nlmsg_seq : 0; | 1218 | u32 seq = nlh ? nlh->nlmsg_seq : 0; |
1209 | int err = -ENOBUFS; | 1219 | int err = -ENOBUFS; |
1210 | 1220 | ||
1211 | skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | 1221 | skb = nlmsg_new(inet_nlmsg_size(), GFP_KERNEL); |
1212 | if (skb == NULL) | 1222 | if (skb == NULL) |
1213 | goto errout; | 1223 | goto errout; |
1214 | 1224 | ||
1215 | err = inet_fill_ifaddr(skb, ifa, pid, seq, event, 0); | 1225 | err = inet_fill_ifaddr(skb, ifa, pid, seq, event, 0); |
1216 | if (err < 0) { | 1226 | /* failure implies BUG in inet_nlmsg_size() */ |
1217 | kfree_skb(skb); | 1227 | BUG_ON(err < 0); |
1218 | goto errout; | ||
1219 | } | ||
1220 | 1228 | ||
1221 | err = rtnl_notify(skb, pid, RTNLGRP_IPV4_IFADDR, nlh, GFP_KERNEL); | 1229 | err = rtnl_notify(skb, pid, RTNLGRP_IPV4_IFADDR, nlh, GFP_KERNEL); |
1222 | errout: | 1230 | errout: |
@@ -1556,12 +1564,12 @@ static void devinet_sysctl_register(struct in_device *in_dev, | |||
1556 | { | 1564 | { |
1557 | int i; | 1565 | int i; |
1558 | struct net_device *dev = in_dev ? in_dev->dev : NULL; | 1566 | struct net_device *dev = in_dev ? in_dev->dev : NULL; |
1559 | struct devinet_sysctl_table *t = kmalloc(sizeof(*t), GFP_KERNEL); | 1567 | struct devinet_sysctl_table *t = kmemdup(&devinet_sysctl, sizeof(*t), |
1568 | GFP_KERNEL); | ||
1560 | char *dev_name = NULL; | 1569 | char *dev_name = NULL; |
1561 | 1570 | ||
1562 | if (!t) | 1571 | if (!t) |
1563 | return; | 1572 | return; |
1564 | memcpy(t, &devinet_sysctl, sizeof(*t)); | ||
1565 | for (i = 0; i < ARRAY_SIZE(t->devinet_vars) - 1; i++) { | 1573 | for (i = 0; i < ARRAY_SIZE(t->devinet_vars) - 1; i++) { |
1566 | t->devinet_vars[i].data += (char *)p - (char *)&ipv4_devconf; | 1574 | t->devinet_vars[i].data += (char *)p - (char *)&ipv4_devconf; |
1567 | t->devinet_vars[i].de = NULL; | 1575 | t->devinet_vars[i].de = NULL; |
diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c index b5c205b57669..f2c6776ea0e6 100644 --- a/net/ipv4/esp4.c +++ b/net/ipv4/esp4.c | |||
@@ -67,7 +67,7 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb) | |||
67 | if (x->encap) { | 67 | if (x->encap) { |
68 | struct xfrm_encap_tmpl *encap = x->encap; | 68 | struct xfrm_encap_tmpl *encap = x->encap; |
69 | struct udphdr *uh; | 69 | struct udphdr *uh; |
70 | u32 *udpdata32; | 70 | __be32 *udpdata32; |
71 | 71 | ||
72 | uh = (struct udphdr *)esph; | 72 | uh = (struct udphdr *)esph; |
73 | uh->source = encap->encap_sport; | 73 | uh->source = encap->encap_sport; |
@@ -81,7 +81,7 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb) | |||
81 | esph = (struct ip_esp_hdr *)(uh + 1); | 81 | esph = (struct ip_esp_hdr *)(uh + 1); |
82 | break; | 82 | break; |
83 | case UDP_ENCAP_ESPINUDP_NON_IKE: | 83 | case UDP_ENCAP_ESPINUDP_NON_IKE: |
84 | udpdata32 = (u32 *)(uh + 1); | 84 | udpdata32 = (__be32 *)(uh + 1); |
85 | udpdata32[0] = udpdata32[1] = 0; | 85 | udpdata32[0] = udpdata32[1] = 0; |
86 | esph = (struct ip_esp_hdr *)(udpdata32 + 2); | 86 | esph = (struct ip_esp_hdr *)(udpdata32 + 2); |
87 | break; | 87 | break; |
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index af0190d8b6c0..d47b72af89ed 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c | |||
@@ -768,8 +768,8 @@ static void nl_fib_lookup(struct fib_result_nl *frn, struct fib_table *tb ) | |||
768 | { | 768 | { |
769 | 769 | ||
770 | struct fib_result res; | 770 | struct fib_result res; |
771 | struct flowi fl = { .nl_u = { .ip4_u = { .daddr = frn->fl_addr, | 771 | struct flowi fl = { .mark = frn->fl_mark, |
772 | .fwmark = frn->fl_fwmark, | 772 | .nl_u = { .ip4_u = { .daddr = frn->fl_addr, |
773 | .tos = frn->fl_tos, | 773 | .tos = frn->fl_tos, |
774 | .scope = frn->fl_scope } } }; | 774 | .scope = frn->fl_scope } } }; |
775 | if (tb) { | 775 | if (tb) { |
@@ -811,7 +811,6 @@ static void nl_fib_input(struct sock *sk, int len) | |||
811 | 811 | ||
812 | pid = nlh->nlmsg_pid; /*pid of sending process */ | 812 | pid = nlh->nlmsg_pid; /*pid of sending process */ |
813 | NETLINK_CB(skb).pid = 0; /* from kernel */ | 813 | NETLINK_CB(skb).pid = 0; /* from kernel */ |
814 | NETLINK_CB(skb).dst_pid = pid; | ||
815 | NETLINK_CB(skb).dst_group = 0; /* unicast */ | 814 | NETLINK_CB(skb).dst_group = 0; /* unicast */ |
816 | netlink_unicast(sk, skb, pid, MSG_DONTWAIT); | 815 | netlink_unicast(sk, skb, pid, MSG_DONTWAIT); |
817 | } | 816 | } |
diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c index 0852b9cd065a..b837c33e0404 100644 --- a/net/ipv4/fib_rules.c +++ b/net/ipv4/fib_rules.c | |||
@@ -44,10 +44,6 @@ struct fib4_rule | |||
44 | __be32 srcmask; | 44 | __be32 srcmask; |
45 | __be32 dst; | 45 | __be32 dst; |
46 | __be32 dstmask; | 46 | __be32 dstmask; |
47 | #ifdef CONFIG_IP_ROUTE_FWMARK | ||
48 | u32 fwmark; | ||
49 | u32 fwmask; | ||
50 | #endif | ||
51 | #ifdef CONFIG_NET_CLS_ROUTE | 47 | #ifdef CONFIG_NET_CLS_ROUTE |
52 | u32 tclassid; | 48 | u32 tclassid; |
53 | #endif | 49 | #endif |
@@ -160,11 +156,6 @@ static int fib4_rule_match(struct fib_rule *rule, struct flowi *fl, int flags) | |||
160 | if (r->tos && (r->tos != fl->fl4_tos)) | 156 | if (r->tos && (r->tos != fl->fl4_tos)) |
161 | return 0; | 157 | return 0; |
162 | 158 | ||
163 | #ifdef CONFIG_IP_ROUTE_FWMARK | ||
164 | if ((r->fwmark ^ fl->fl4_fwmark) & r->fwmask) | ||
165 | return 0; | ||
166 | #endif | ||
167 | |||
168 | return 1; | 159 | return 1; |
169 | } | 160 | } |
170 | 161 | ||
@@ -179,14 +170,10 @@ static struct fib_table *fib_empty_table(void) | |||
179 | } | 170 | } |
180 | 171 | ||
181 | static struct nla_policy fib4_rule_policy[FRA_MAX+1] __read_mostly = { | 172 | static struct nla_policy fib4_rule_policy[FRA_MAX+1] __read_mostly = { |
182 | [FRA_IFNAME] = { .type = NLA_STRING, .len = IFNAMSIZ - 1 }, | 173 | FRA_GENERIC_POLICY, |
183 | [FRA_PRIORITY] = { .type = NLA_U32 }, | ||
184 | [FRA_SRC] = { .type = NLA_U32 }, | 174 | [FRA_SRC] = { .type = NLA_U32 }, |
185 | [FRA_DST] = { .type = NLA_U32 }, | 175 | [FRA_DST] = { .type = NLA_U32 }, |
186 | [FRA_FWMARK] = { .type = NLA_U32 }, | ||
187 | [FRA_FWMASK] = { .type = NLA_U32 }, | ||
188 | [FRA_FLOW] = { .type = NLA_U32 }, | 176 | [FRA_FLOW] = { .type = NLA_U32 }, |
189 | [FRA_TABLE] = { .type = NLA_U32 }, | ||
190 | }; | 177 | }; |
191 | 178 | ||
192 | static int fib4_rule_configure(struct fib_rule *rule, struct sk_buff *skb, | 179 | static int fib4_rule_configure(struct fib_rule *rule, struct sk_buff *skb, |
@@ -220,20 +207,6 @@ static int fib4_rule_configure(struct fib_rule *rule, struct sk_buff *skb, | |||
220 | if (tb[FRA_DST]) | 207 | if (tb[FRA_DST]) |
221 | rule4->dst = nla_get_be32(tb[FRA_DST]); | 208 | rule4->dst = nla_get_be32(tb[FRA_DST]); |
222 | 209 | ||
223 | #ifdef CONFIG_IP_ROUTE_FWMARK | ||
224 | if (tb[FRA_FWMARK]) { | ||
225 | rule4->fwmark = nla_get_u32(tb[FRA_FWMARK]); | ||
226 | if (rule4->fwmark) | ||
227 | /* compatibility: if the mark value is non-zero all bits | ||
228 | * are compared unless a mask is explicitly specified. | ||
229 | */ | ||
230 | rule4->fwmask = 0xFFFFFFFF; | ||
231 | } | ||
232 | |||
233 | if (tb[FRA_FWMASK]) | ||
234 | rule4->fwmask = nla_get_u32(tb[FRA_FWMASK]); | ||
235 | #endif | ||
236 | |||
237 | #ifdef CONFIG_NET_CLS_ROUTE | 210 | #ifdef CONFIG_NET_CLS_ROUTE |
238 | if (tb[FRA_FLOW]) | 211 | if (tb[FRA_FLOW]) |
239 | rule4->tclassid = nla_get_u32(tb[FRA_FLOW]); | 212 | rule4->tclassid = nla_get_u32(tb[FRA_FLOW]); |
@@ -264,14 +237,6 @@ static int fib4_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh, | |||
264 | if (frh->tos && (rule4->tos != frh->tos)) | 237 | if (frh->tos && (rule4->tos != frh->tos)) |
265 | return 0; | 238 | return 0; |
266 | 239 | ||
267 | #ifdef CONFIG_IP_ROUTE_FWMARK | ||
268 | if (tb[FRA_FWMARK] && (rule4->fwmark != nla_get_u32(tb[FRA_FWMARK]))) | ||
269 | return 0; | ||
270 | |||
271 | if (tb[FRA_FWMASK] && (rule4->fwmask != nla_get_u32(tb[FRA_FWMASK]))) | ||
272 | return 0; | ||
273 | #endif | ||
274 | |||
275 | #ifdef CONFIG_NET_CLS_ROUTE | 240 | #ifdef CONFIG_NET_CLS_ROUTE |
276 | if (tb[FRA_FLOW] && (rule4->tclassid != nla_get_u32(tb[FRA_FLOW]))) | 241 | if (tb[FRA_FLOW] && (rule4->tclassid != nla_get_u32(tb[FRA_FLOW]))) |
277 | return 0; | 242 | return 0; |
@@ -296,14 +261,6 @@ static int fib4_rule_fill(struct fib_rule *rule, struct sk_buff *skb, | |||
296 | frh->src_len = rule4->src_len; | 261 | frh->src_len = rule4->src_len; |
297 | frh->tos = rule4->tos; | 262 | frh->tos = rule4->tos; |
298 | 263 | ||
299 | #ifdef CONFIG_IP_ROUTE_FWMARK | ||
300 | if (rule4->fwmark) | ||
301 | NLA_PUT_U32(skb, FRA_FWMARK, rule4->fwmark); | ||
302 | |||
303 | if (rule4->fwmask || rule4->fwmark) | ||
304 | NLA_PUT_U32(skb, FRA_FWMASK, rule4->fwmask); | ||
305 | #endif | ||
306 | |||
307 | if (rule4->dst_len) | 264 | if (rule4->dst_len) |
308 | NLA_PUT_BE32(skb, FRA_DST, rule4->dst); | 265 | NLA_PUT_BE32(skb, FRA_DST, rule4->dst); |
309 | 266 | ||
@@ -342,6 +299,13 @@ static u32 fib4_rule_default_pref(void) | |||
342 | return 0; | 299 | return 0; |
343 | } | 300 | } |
344 | 301 | ||
302 | static size_t fib4_rule_nlmsg_payload(struct fib_rule *rule) | ||
303 | { | ||
304 | return nla_total_size(4) /* dst */ | ||
305 | + nla_total_size(4) /* src */ | ||
306 | + nla_total_size(4); /* flow */ | ||
307 | } | ||
308 | |||
345 | static struct fib_rules_ops fib4_rules_ops = { | 309 | static struct fib_rules_ops fib4_rules_ops = { |
346 | .family = AF_INET, | 310 | .family = AF_INET, |
347 | .rule_size = sizeof(struct fib4_rule), | 311 | .rule_size = sizeof(struct fib4_rule), |
@@ -351,6 +315,7 @@ static struct fib_rules_ops fib4_rules_ops = { | |||
351 | .compare = fib4_rule_compare, | 315 | .compare = fib4_rule_compare, |
352 | .fill = fib4_rule_fill, | 316 | .fill = fib4_rule_fill, |
353 | .default_pref = fib4_rule_default_pref, | 317 | .default_pref = fib4_rule_default_pref, |
318 | .nlmsg_payload = fib4_rule_nlmsg_payload, | ||
354 | .nlgroup = RTNLGRP_IPV4_RULE, | 319 | .nlgroup = RTNLGRP_IPV4_RULE, |
355 | .policy = fib4_rule_policy, | 320 | .policy = fib4_rule_policy, |
356 | .rules_list = &fib4_rules, | 321 | .rules_list = &fib4_rules, |
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index 884d176e0082..e63b8a98fb4d 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c | |||
@@ -273,25 +273,49 @@ int ip_fib_check_default(__be32 gw, struct net_device *dev) | |||
273 | return -1; | 273 | return -1; |
274 | } | 274 | } |
275 | 275 | ||
276 | static inline size_t fib_nlmsg_size(struct fib_info *fi) | ||
277 | { | ||
278 | size_t payload = NLMSG_ALIGN(sizeof(struct rtmsg)) | ||
279 | + nla_total_size(4) /* RTA_TABLE */ | ||
280 | + nla_total_size(4) /* RTA_DST */ | ||
281 | + nla_total_size(4) /* RTA_PRIORITY */ | ||
282 | + nla_total_size(4); /* RTA_PREFSRC */ | ||
283 | |||
284 | /* space for nested metrics */ | ||
285 | payload += nla_total_size((RTAX_MAX * nla_total_size(4))); | ||
286 | |||
287 | if (fi->fib_nhs) { | ||
288 | /* Also handles the special case fib_nhs == 1 */ | ||
289 | |||
290 | /* each nexthop is packed in an attribute */ | ||
291 | size_t nhsize = nla_total_size(sizeof(struct rtnexthop)); | ||
292 | |||
293 | /* may contain flow and gateway attribute */ | ||
294 | nhsize += 2 * nla_total_size(4); | ||
295 | |||
296 | /* all nexthops are packed in a nested attribute */ | ||
297 | payload += nla_total_size(fi->fib_nhs * nhsize); | ||
298 | } | ||
299 | |||
300 | return payload; | ||
301 | } | ||
302 | |||
276 | void rtmsg_fib(int event, __be32 key, struct fib_alias *fa, | 303 | void rtmsg_fib(int event, __be32 key, struct fib_alias *fa, |
277 | int dst_len, u32 tb_id, struct nl_info *info) | 304 | int dst_len, u32 tb_id, struct nl_info *info) |
278 | { | 305 | { |
279 | struct sk_buff *skb; | 306 | struct sk_buff *skb; |
280 | int payload = sizeof(struct rtmsg) + 256; | ||
281 | u32 seq = info->nlh ? info->nlh->nlmsg_seq : 0; | 307 | u32 seq = info->nlh ? info->nlh->nlmsg_seq : 0; |
282 | int err = -ENOBUFS; | 308 | int err = -ENOBUFS; |
283 | 309 | ||
284 | skb = nlmsg_new(nlmsg_total_size(payload), GFP_KERNEL); | 310 | skb = nlmsg_new(fib_nlmsg_size(fa->fa_info), GFP_KERNEL); |
285 | if (skb == NULL) | 311 | if (skb == NULL) |
286 | goto errout; | 312 | goto errout; |
287 | 313 | ||
288 | err = fib_dump_info(skb, info->pid, seq, event, tb_id, | 314 | err = fib_dump_info(skb, info->pid, seq, event, tb_id, |
289 | fa->fa_type, fa->fa_scope, key, dst_len, | 315 | fa->fa_type, fa->fa_scope, key, dst_len, |
290 | fa->fa_tos, fa->fa_info, 0); | 316 | fa->fa_tos, fa->fa_info, 0); |
291 | if (err < 0) { | 317 | /* failure implies BUG in fib_nlmsg_size() */ |
292 | kfree_skb(skb); | 318 | BUG_ON(err < 0); |
293 | goto errout; | ||
294 | } | ||
295 | 319 | ||
296 | err = rtnl_notify(skb, info->pid, RTNLGRP_IPV4_ROUTE, | 320 | err = rtnl_notify(skb, info->pid, RTNLGRP_IPV4_ROUTE, |
297 | info->nlh, GFP_KERNEL); | 321 | info->nlh, GFP_KERNEL); |
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index b39a37a47545..40cf0d0e1b83 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c | |||
@@ -332,7 +332,7 @@ static int icmp_glue_bits(void *from, char *to, int offset, int len, int odd, | |||
332 | struct sk_buff *skb) | 332 | struct sk_buff *skb) |
333 | { | 333 | { |
334 | struct icmp_bxm *icmp_param = (struct icmp_bxm *)from; | 334 | struct icmp_bxm *icmp_param = (struct icmp_bxm *)from; |
335 | unsigned int csum; | 335 | __wsum csum; |
336 | 336 | ||
337 | csum = skb_copy_and_csum_bits(icmp_param->skb, | 337 | csum = skb_copy_and_csum_bits(icmp_param->skb, |
338 | icmp_param->offset + offset, | 338 | icmp_param->offset + offset, |
@@ -356,7 +356,7 @@ static void icmp_push_reply(struct icmp_bxm *icmp_param, | |||
356 | ip_flush_pending_frames(icmp_socket->sk); | 356 | ip_flush_pending_frames(icmp_socket->sk); |
357 | else if ((skb = skb_peek(&icmp_socket->sk->sk_write_queue)) != NULL) { | 357 | else if ((skb = skb_peek(&icmp_socket->sk->sk_write_queue)) != NULL) { |
358 | struct icmphdr *icmph = skb->h.icmph; | 358 | struct icmphdr *icmph = skb->h.icmph; |
359 | unsigned int csum = 0; | 359 | __wsum csum = 0; |
360 | struct sk_buff *skb1; | 360 | struct sk_buff *skb1; |
361 | 361 | ||
362 | skb_queue_walk(&icmp_socket->sk->sk_write_queue, skb1) { | 362 | skb_queue_walk(&icmp_socket->sk->sk_write_queue, skb1) { |
@@ -931,7 +931,7 @@ int icmp_rcv(struct sk_buff *skb) | |||
931 | 931 | ||
932 | switch (skb->ip_summed) { | 932 | switch (skb->ip_summed) { |
933 | case CHECKSUM_COMPLETE: | 933 | case CHECKSUM_COMPLETE: |
934 | if (!(u16)csum_fold(skb->csum)) | 934 | if (!csum_fold(skb->csum)) |
935 | break; | 935 | break; |
936 | /* fall through */ | 936 | /* fall through */ |
937 | case CHECKSUM_NONE: | 937 | case CHECKSUM_NONE: |
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index 6eee71647b7c..0017ccb01d6d 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c | |||
@@ -932,7 +932,7 @@ int igmp_rcv(struct sk_buff *skb) | |||
932 | 932 | ||
933 | switch (skb->ip_summed) { | 933 | switch (skb->ip_summed) { |
934 | case CHECKSUM_COMPLETE: | 934 | case CHECKSUM_COMPLETE: |
935 | if (!(u16)csum_fold(skb->csum)) | 935 | if (!csum_fold(skb->csum)) |
936 | break; | 936 | break; |
937 | /* fall through */ | 937 | /* fall through */ |
938 | case CHECKSUM_NONE: | 938 | case CHECKSUM_NONE: |
diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index 96bbe2a0aa1b..9d68837888d3 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c | |||
@@ -343,7 +343,7 @@ struct dst_entry* inet_csk_route_req(struct sock *sk, | |||
343 | EXPORT_SYMBOL_GPL(inet_csk_route_req); | 343 | EXPORT_SYMBOL_GPL(inet_csk_route_req); |
344 | 344 | ||
345 | static inline u32 inet_synq_hash(const __be32 raddr, const __be16 rport, | 345 | static inline u32 inet_synq_hash(const __be32 raddr, const __be16 rport, |
346 | const u32 rnd, const u16 synq_hsize) | 346 | const u32 rnd, const u32 synq_hsize) |
347 | { | 347 | { |
348 | return jhash_2words((__force u32)raddr, (__force u32)rport, rnd) & (synq_hsize - 1); | 348 | return jhash_2words((__force u32)raddr, (__force u32)rport, rnd) & (synq_hsize - 1); |
349 | } | 349 | } |
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index d5b5dec075b8..476cb6084c75 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c | |||
@@ -144,7 +144,7 @@ static struct net_device *ipgre_fb_tunnel_dev; | |||
144 | */ | 144 | */ |
145 | 145 | ||
146 | #define HASH_SIZE 16 | 146 | #define HASH_SIZE 16 |
147 | #define HASH(addr) ((addr^(addr>>4))&0xF) | 147 | #define HASH(addr) (((__force u32)addr^((__force u32)addr>>4))&0xF) |
148 | 148 | ||
149 | static struct ip_tunnel *tunnels[4][HASH_SIZE]; | 149 | static struct ip_tunnel *tunnels[4][HASH_SIZE]; |
150 | 150 | ||
@@ -157,7 +157,7 @@ static DEFINE_RWLOCK(ipgre_lock); | |||
157 | 157 | ||
158 | /* Given src, dst and key, find appropriate for input tunnel. */ | 158 | /* Given src, dst and key, find appropriate for input tunnel. */ |
159 | 159 | ||
160 | static struct ip_tunnel * ipgre_tunnel_lookup(u32 remote, u32 local, u32 key) | 160 | static struct ip_tunnel * ipgre_tunnel_lookup(__be32 remote, __be32 local, __be32 key) |
161 | { | 161 | { |
162 | unsigned h0 = HASH(remote); | 162 | unsigned h0 = HASH(remote); |
163 | unsigned h1 = HASH(key); | 163 | unsigned h1 = HASH(key); |
@@ -194,9 +194,9 @@ static struct ip_tunnel * ipgre_tunnel_lookup(u32 remote, u32 local, u32 key) | |||
194 | 194 | ||
195 | static struct ip_tunnel **ipgre_bucket(struct ip_tunnel *t) | 195 | static struct ip_tunnel **ipgre_bucket(struct ip_tunnel *t) |
196 | { | 196 | { |
197 | u32 remote = t->parms.iph.daddr; | 197 | __be32 remote = t->parms.iph.daddr; |
198 | u32 local = t->parms.iph.saddr; | 198 | __be32 local = t->parms.iph.saddr; |
199 | u32 key = t->parms.i_key; | 199 | __be32 key = t->parms.i_key; |
200 | unsigned h = HASH(key); | 200 | unsigned h = HASH(key); |
201 | int prio = 0; | 201 | int prio = 0; |
202 | 202 | ||
@@ -236,9 +236,9 @@ static void ipgre_tunnel_unlink(struct ip_tunnel *t) | |||
236 | 236 | ||
237 | static struct ip_tunnel * ipgre_tunnel_locate(struct ip_tunnel_parm *parms, int create) | 237 | static struct ip_tunnel * ipgre_tunnel_locate(struct ip_tunnel_parm *parms, int create) |
238 | { | 238 | { |
239 | u32 remote = parms->iph.daddr; | 239 | __be32 remote = parms->iph.daddr; |
240 | u32 local = parms->iph.saddr; | 240 | __be32 local = parms->iph.saddr; |
241 | u32 key = parms->i_key; | 241 | __be32 key = parms->i_key; |
242 | struct ip_tunnel *t, **tp, *nt; | 242 | struct ip_tunnel *t, **tp, *nt; |
243 | struct net_device *dev; | 243 | struct net_device *dev; |
244 | unsigned h = HASH(key); | 244 | unsigned h = HASH(key); |
@@ -319,12 +319,12 @@ static void ipgre_err(struct sk_buff *skb, u32 info) | |||
319 | */ | 319 | */ |
320 | 320 | ||
321 | struct iphdr *iph = (struct iphdr*)skb->data; | 321 | struct iphdr *iph = (struct iphdr*)skb->data; |
322 | u16 *p = (u16*)(skb->data+(iph->ihl<<2)); | 322 | __be16 *p = (__be16*)(skb->data+(iph->ihl<<2)); |
323 | int grehlen = (iph->ihl<<2) + 4; | 323 | int grehlen = (iph->ihl<<2) + 4; |
324 | int type = skb->h.icmph->type; | 324 | int type = skb->h.icmph->type; |
325 | int code = skb->h.icmph->code; | 325 | int code = skb->h.icmph->code; |
326 | struct ip_tunnel *t; | 326 | struct ip_tunnel *t; |
327 | u16 flags; | 327 | __be16 flags; |
328 | 328 | ||
329 | flags = p[0]; | 329 | flags = p[0]; |
330 | if (flags&(GRE_CSUM|GRE_KEY|GRE_SEQ|GRE_ROUTING|GRE_VERSION)) { | 330 | if (flags&(GRE_CSUM|GRE_KEY|GRE_SEQ|GRE_ROUTING|GRE_VERSION)) { |
@@ -370,7 +370,7 @@ static void ipgre_err(struct sk_buff *skb, u32 info) | |||
370 | } | 370 | } |
371 | 371 | ||
372 | read_lock(&ipgre_lock); | 372 | read_lock(&ipgre_lock); |
373 | t = ipgre_tunnel_lookup(iph->daddr, iph->saddr, (flags&GRE_KEY) ? *(((u32*)p) + (grehlen>>2) - 1) : 0); | 373 | t = ipgre_tunnel_lookup(iph->daddr, iph->saddr, (flags&GRE_KEY) ? *(((__be32*)p) + (grehlen>>2) - 1) : 0); |
374 | if (t == NULL || t->parms.iph.daddr == 0 || MULTICAST(t->parms.iph.daddr)) | 374 | if (t == NULL || t->parms.iph.daddr == 0 || MULTICAST(t->parms.iph.daddr)) |
375 | goto out; | 375 | goto out; |
376 | 376 | ||
@@ -388,14 +388,14 @@ out: | |||
388 | #else | 388 | #else |
389 | struct iphdr *iph = (struct iphdr*)dp; | 389 | struct iphdr *iph = (struct iphdr*)dp; |
390 | struct iphdr *eiph; | 390 | struct iphdr *eiph; |
391 | u16 *p = (u16*)(dp+(iph->ihl<<2)); | 391 | __be16 *p = (__be16*)(dp+(iph->ihl<<2)); |
392 | int type = skb->h.icmph->type; | 392 | int type = skb->h.icmph->type; |
393 | int code = skb->h.icmph->code; | 393 | int code = skb->h.icmph->code; |
394 | int rel_type = 0; | 394 | int rel_type = 0; |
395 | int rel_code = 0; | 395 | int rel_code = 0; |
396 | __be32 rel_info = 0; | 396 | __be32 rel_info = 0; |
397 | __u32 n = 0; | 397 | __u32 n = 0; |
398 | u16 flags; | 398 | __be16 flags; |
399 | int grehlen = (iph->ihl<<2) + 4; | 399 | int grehlen = (iph->ihl<<2) + 4; |
400 | struct sk_buff *skb2; | 400 | struct sk_buff *skb2; |
401 | struct flowi fl; | 401 | struct flowi fl; |
@@ -556,9 +556,9 @@ static int ipgre_rcv(struct sk_buff *skb) | |||
556 | { | 556 | { |
557 | struct iphdr *iph; | 557 | struct iphdr *iph; |
558 | u8 *h; | 558 | u8 *h; |
559 | u16 flags; | 559 | __be16 flags; |
560 | u16 csum = 0; | 560 | __sum16 csum = 0; |
561 | u32 key = 0; | 561 | __be32 key = 0; |
562 | u32 seqno = 0; | 562 | u32 seqno = 0; |
563 | struct ip_tunnel *tunnel; | 563 | struct ip_tunnel *tunnel; |
564 | int offset = 4; | 564 | int offset = 4; |
@@ -568,7 +568,7 @@ static int ipgre_rcv(struct sk_buff *skb) | |||
568 | 568 | ||
569 | iph = skb->nh.iph; | 569 | iph = skb->nh.iph; |
570 | h = skb->data; | 570 | h = skb->data; |
571 | flags = *(u16*)h; | 571 | flags = *(__be16*)h; |
572 | 572 | ||
573 | if (flags&(GRE_CSUM|GRE_KEY|GRE_ROUTING|GRE_SEQ|GRE_VERSION)) { | 573 | if (flags&(GRE_CSUM|GRE_KEY|GRE_ROUTING|GRE_SEQ|GRE_VERSION)) { |
574 | /* - Version must be 0. | 574 | /* - Version must be 0. |
@@ -580,7 +580,7 @@ static int ipgre_rcv(struct sk_buff *skb) | |||
580 | if (flags&GRE_CSUM) { | 580 | if (flags&GRE_CSUM) { |
581 | switch (skb->ip_summed) { | 581 | switch (skb->ip_summed) { |
582 | case CHECKSUM_COMPLETE: | 582 | case CHECKSUM_COMPLETE: |
583 | csum = (u16)csum_fold(skb->csum); | 583 | csum = csum_fold(skb->csum); |
584 | if (!csum) | 584 | if (!csum) |
585 | break; | 585 | break; |
586 | /* fall through */ | 586 | /* fall through */ |
@@ -592,11 +592,11 @@ static int ipgre_rcv(struct sk_buff *skb) | |||
592 | offset += 4; | 592 | offset += 4; |
593 | } | 593 | } |
594 | if (flags&GRE_KEY) { | 594 | if (flags&GRE_KEY) { |
595 | key = *(u32*)(h + offset); | 595 | key = *(__be32*)(h + offset); |
596 | offset += 4; | 596 | offset += 4; |
597 | } | 597 | } |
598 | if (flags&GRE_SEQ) { | 598 | if (flags&GRE_SEQ) { |
599 | seqno = ntohl(*(u32*)(h + offset)); | 599 | seqno = ntohl(*(__be32*)(h + offset)); |
600 | offset += 4; | 600 | offset += 4; |
601 | } | 601 | } |
602 | } | 602 | } |
@@ -605,7 +605,7 @@ static int ipgre_rcv(struct sk_buff *skb) | |||
605 | if ((tunnel = ipgre_tunnel_lookup(iph->saddr, iph->daddr, key)) != NULL) { | 605 | if ((tunnel = ipgre_tunnel_lookup(iph->saddr, iph->daddr, key)) != NULL) { |
606 | secpath_reset(skb); | 606 | secpath_reset(skb); |
607 | 607 | ||
608 | skb->protocol = *(u16*)(h + 2); | 608 | skb->protocol = *(__be16*)(h + 2); |
609 | /* WCCP version 1 and 2 protocol decoding. | 609 | /* WCCP version 1 and 2 protocol decoding. |
610 | * - Change protocol to IP | 610 | * - Change protocol to IP |
611 | * - When dealing with WCCPv2, Skip extra 4 bytes in GRE header | 611 | * - When dealing with WCCPv2, Skip extra 4 bytes in GRE header |
@@ -673,13 +673,13 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) | |||
673 | struct iphdr *old_iph = skb->nh.iph; | 673 | struct iphdr *old_iph = skb->nh.iph; |
674 | struct iphdr *tiph; | 674 | struct iphdr *tiph; |
675 | u8 tos; | 675 | u8 tos; |
676 | u16 df; | 676 | __be16 df; |
677 | struct rtable *rt; /* Route to the other host */ | 677 | struct rtable *rt; /* Route to the other host */ |
678 | struct net_device *tdev; /* Device to other host */ | 678 | struct net_device *tdev; /* Device to other host */ |
679 | struct iphdr *iph; /* Our new IP header */ | 679 | struct iphdr *iph; /* Our new IP header */ |
680 | int max_headroom; /* The extra header space needed */ | 680 | int max_headroom; /* The extra header space needed */ |
681 | int gre_hlen; | 681 | int gre_hlen; |
682 | u32 dst; | 682 | __be32 dst; |
683 | int mtu; | 683 | int mtu; |
684 | 684 | ||
685 | if (tunnel->recursion++) { | 685 | if (tunnel->recursion++) { |
@@ -860,11 +860,11 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) | |||
860 | iph->ttl = dst_metric(&rt->u.dst, RTAX_HOPLIMIT); | 860 | iph->ttl = dst_metric(&rt->u.dst, RTAX_HOPLIMIT); |
861 | } | 861 | } |
862 | 862 | ||
863 | ((u16*)(iph+1))[0] = tunnel->parms.o_flags; | 863 | ((__be16*)(iph+1))[0] = tunnel->parms.o_flags; |
864 | ((u16*)(iph+1))[1] = skb->protocol; | 864 | ((__be16*)(iph+1))[1] = skb->protocol; |
865 | 865 | ||
866 | if (tunnel->parms.o_flags&(GRE_KEY|GRE_CSUM|GRE_SEQ)) { | 866 | if (tunnel->parms.o_flags&(GRE_KEY|GRE_CSUM|GRE_SEQ)) { |
867 | u32 *ptr = (u32*)(((u8*)iph) + tunnel->hlen - 4); | 867 | __be32 *ptr = (__be32*)(((u8*)iph) + tunnel->hlen - 4); |
868 | 868 | ||
869 | if (tunnel->parms.o_flags&GRE_SEQ) { | 869 | if (tunnel->parms.o_flags&GRE_SEQ) { |
870 | ++tunnel->o_seqno; | 870 | ++tunnel->o_seqno; |
@@ -877,7 +877,7 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) | |||
877 | } | 877 | } |
878 | if (tunnel->parms.o_flags&GRE_CSUM) { | 878 | if (tunnel->parms.o_flags&GRE_CSUM) { |
879 | *ptr = 0; | 879 | *ptr = 0; |
880 | *(__u16*)ptr = ip_compute_csum((void*)(iph+1), skb->len - sizeof(struct iphdr)); | 880 | *(__sum16*)ptr = ip_compute_csum((void*)(iph+1), skb->len - sizeof(struct iphdr)); |
881 | } | 881 | } |
882 | } | 882 | } |
883 | 883 | ||
@@ -1068,7 +1068,7 @@ static int ipgre_header(struct sk_buff *skb, struct net_device *dev, unsigned sh | |||
1068 | { | 1068 | { |
1069 | struct ip_tunnel *t = netdev_priv(dev); | 1069 | struct ip_tunnel *t = netdev_priv(dev); |
1070 | struct iphdr *iph = (struct iphdr *)skb_push(skb, t->hlen); | 1070 | struct iphdr *iph = (struct iphdr *)skb_push(skb, t->hlen); |
1071 | u16 *p = (u16*)(iph+1); | 1071 | __be16 *p = (__be16*)(iph+1); |
1072 | 1072 | ||
1073 | memcpy(iph, &t->parms.iph, sizeof(struct iphdr)); | 1073 | memcpy(iph, &t->parms.iph, sizeof(struct iphdr)); |
1074 | p[0] = t->parms.o_flags; | 1074 | p[0] = t->parms.o_flags; |
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index fc195a44fc2e..1da3d32f8289 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c | |||
@@ -288,9 +288,8 @@ int ip_output(struct sk_buff *skb) | |||
288 | !(IPCB(skb)->flags & IPSKB_REROUTED)); | 288 | !(IPCB(skb)->flags & IPSKB_REROUTED)); |
289 | } | 289 | } |
290 | 290 | ||
291 | int ip_queue_xmit(struct sk_buff *skb, int ipfragok) | 291 | int ip_queue_xmit(struct sk_buff *skb, struct sock *sk, int ipfragok) |
292 | { | 292 | { |
293 | struct sock *sk = skb->sk; | ||
294 | struct inet_sock *inet = inet_sk(sk); | 293 | struct inet_sock *inet = inet_sk(sk); |
295 | struct ip_options *opt = inet->opt; | 294 | struct ip_options *opt = inet->opt; |
296 | struct rtable *rt; | 295 | struct rtable *rt; |
@@ -342,7 +341,7 @@ packet_routed: | |||
342 | 341 | ||
343 | /* OK, we know where to send it, allocate and build IP header. */ | 342 | /* OK, we know where to send it, allocate and build IP header. */ |
344 | iph = (struct iphdr *) skb_push(skb, sizeof(struct iphdr) + (opt ? opt->optlen : 0)); | 343 | iph = (struct iphdr *) skb_push(skb, sizeof(struct iphdr) + (opt ? opt->optlen : 0)); |
345 | *((__u16 *)iph) = htons((4 << 12) | (5 << 8) | (inet->tos & 0xff)); | 344 | *((__be16 *)iph) = htons((4 << 12) | (5 << 8) | (inet->tos & 0xff)); |
346 | iph->tot_len = htons(skb->len); | 345 | iph->tot_len = htons(skb->len); |
347 | if (ip_dont_fragment(sk, &rt->u.dst) && !ipfragok) | 346 | if (ip_dont_fragment(sk, &rt->u.dst) && !ipfragok) |
348 | iph->frag_off = htons(IP_DF); | 347 | iph->frag_off = htons(IP_DF); |
@@ -386,6 +385,7 @@ static void ip_copy_metadata(struct sk_buff *to, struct sk_buff *from) | |||
386 | dst_release(to->dst); | 385 | dst_release(to->dst); |
387 | to->dst = dst_clone(from->dst); | 386 | to->dst = dst_clone(from->dst); |
388 | to->dev = from->dev; | 387 | to->dev = from->dev; |
388 | to->mark = from->mark; | ||
389 | 389 | ||
390 | /* Copy the flags to each fragment. */ | 390 | /* Copy the flags to each fragment. */ |
391 | IPCB(to)->flags = IPCB(from)->flags; | 391 | IPCB(to)->flags = IPCB(from)->flags; |
@@ -394,7 +394,6 @@ static void ip_copy_metadata(struct sk_buff *to, struct sk_buff *from) | |||
394 | to->tc_index = from->tc_index; | 394 | to->tc_index = from->tc_index; |
395 | #endif | 395 | #endif |
396 | #ifdef CONFIG_NETFILTER | 396 | #ifdef CONFIG_NETFILTER |
397 | to->nfmark = from->nfmark; | ||
398 | /* Connection association is same as pre-frag packet */ | 397 | /* Connection association is same as pre-frag packet */ |
399 | nf_conntrack_put(to->nfct); | 398 | nf_conntrack_put(to->nfct); |
400 | to->nfct = from->nfct; | 399 | to->nfct = from->nfct; |
@@ -683,7 +682,7 @@ ip_generic_getfrag(void *from, char *to, int offset, int len, int odd, struct sk | |||
683 | if (memcpy_fromiovecend(to, iov, offset, len) < 0) | 682 | if (memcpy_fromiovecend(to, iov, offset, len) < 0) |
684 | return -EFAULT; | 683 | return -EFAULT; |
685 | } else { | 684 | } else { |
686 | unsigned int csum = 0; | 685 | __wsum csum = 0; |
687 | if (csum_partial_copy_fromiovecend(to, iov, offset, len, &csum) < 0) | 686 | if (csum_partial_copy_fromiovecend(to, iov, offset, len, &csum) < 0) |
688 | return -EFAULT; | 687 | return -EFAULT; |
689 | skb->csum = csum_block_add(skb->csum, csum, odd); | 688 | skb->csum = csum_block_add(skb->csum, csum, odd); |
@@ -691,11 +690,11 @@ ip_generic_getfrag(void *from, char *to, int offset, int len, int odd, struct sk | |||
691 | return 0; | 690 | return 0; |
692 | } | 691 | } |
693 | 692 | ||
694 | static inline unsigned int | 693 | static inline __wsum |
695 | csum_page(struct page *page, int offset, int copy) | 694 | csum_page(struct page *page, int offset, int copy) |
696 | { | 695 | { |
697 | char *kaddr; | 696 | char *kaddr; |
698 | unsigned int csum; | 697 | __wsum csum; |
699 | kaddr = kmap(page); | 698 | kaddr = kmap(page); |
700 | csum = csum_partial(kaddr + offset, copy, 0); | 699 | csum = csum_partial(kaddr + offset, copy, 0); |
701 | kunmap(page); | 700 | kunmap(page); |
@@ -1167,7 +1166,7 @@ ssize_t ip_append_page(struct sock *sk, struct page *page, | |||
1167 | } | 1166 | } |
1168 | 1167 | ||
1169 | if (skb->ip_summed == CHECKSUM_NONE) { | 1168 | if (skb->ip_summed == CHECKSUM_NONE) { |
1170 | unsigned int csum; | 1169 | __wsum csum; |
1171 | csum = csum_page(page, offset, len); | 1170 | csum = csum_page(page, offset, len); |
1172 | skb->csum = csum_block_add(skb->csum, csum, skb->len); | 1171 | skb->csum = csum_block_add(skb->csum, csum, skb->len); |
1173 | } | 1172 | } |
@@ -1315,7 +1314,7 @@ void ip_flush_pending_frames(struct sock *sk) | |||
1315 | static int ip_reply_glue_bits(void *dptr, char *to, int offset, | 1314 | static int ip_reply_glue_bits(void *dptr, char *to, int offset, |
1316 | int len, int odd, struct sk_buff *skb) | 1315 | int len, int odd, struct sk_buff *skb) |
1317 | { | 1316 | { |
1318 | unsigned int csum; | 1317 | __wsum csum; |
1319 | 1318 | ||
1320 | csum = csum_partial_copy_nocheck(dptr+offset, to, len, 0); | 1319 | csum = csum_partial_copy_nocheck(dptr+offset, to, len, 0); |
1321 | skb->csum = csum_block_add(skb->csum, csum, odd); | 1320 | skb->csum = csum_block_add(skb->csum, csum, odd); |
@@ -1385,7 +1384,7 @@ void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *ar | |||
1385 | &ipc, rt, MSG_DONTWAIT); | 1384 | &ipc, rt, MSG_DONTWAIT); |
1386 | if ((skb = skb_peek(&sk->sk_write_queue)) != NULL) { | 1385 | if ((skb = skb_peek(&sk->sk_write_queue)) != NULL) { |
1387 | if (arg->csumoffset >= 0) | 1386 | if (arg->csumoffset >= 0) |
1388 | *((u16 *)skb->h.raw + arg->csumoffset) = csum_fold(csum_add(skb->csum, arg->csum)); | 1387 | *((__sum16 *)skb->h.raw + arg->csumoffset) = csum_fold(csum_add(skb->csum, arg->csum)); |
1389 | skb->ip_summed = CHECKSUM_NONE; | 1388 | skb->ip_summed = CHECKSUM_NONE; |
1390 | ip_push_pending_frames(sk); | 1389 | ip_push_pending_frames(sk); |
1391 | } | 1390 | } |
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 4b132953bcc2..57d4bae6f080 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c | |||
@@ -355,7 +355,7 @@ int ip_recv_error(struct sock *sk, struct msghdr *msg, int len) | |||
355 | sin = (struct sockaddr_in *)msg->msg_name; | 355 | sin = (struct sockaddr_in *)msg->msg_name; |
356 | if (sin) { | 356 | if (sin) { |
357 | sin->sin_family = AF_INET; | 357 | sin->sin_family = AF_INET; |
358 | sin->sin_addr.s_addr = *(u32*)(skb->nh.raw + serr->addr_offset); | 358 | sin->sin_addr.s_addr = *(__be32*)(skb->nh.raw + serr->addr_offset); |
359 | sin->sin_port = serr->port; | 359 | sin->sin_port = serr->port; |
360 | memset(&sin->sin_zero, 0, sizeof(sin->sin_zero)); | 360 | memset(&sin->sin_zero, 0, sizeof(sin->sin_zero)); |
361 | } | 361 | } |
diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index 955a07abb91d..afa60b9a003f 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c | |||
@@ -101,6 +101,7 @@ | |||
101 | #define CONF_NAMESERVERS_MAX 3 /* Maximum number of nameservers | 101 | #define CONF_NAMESERVERS_MAX 3 /* Maximum number of nameservers |
102 | - '3' from resolv.h */ | 102 | - '3' from resolv.h */ |
103 | 103 | ||
104 | #define NONE __constant_htonl(INADDR_NONE) | ||
104 | 105 | ||
105 | /* | 106 | /* |
106 | * Public IP configuration | 107 | * Public IP configuration |
@@ -129,19 +130,19 @@ int ic_proto_enabled __initdata = 0 | |||
129 | 130 | ||
130 | static int ic_host_name_set __initdata = 0; /* Host name set by us? */ | 131 | static int ic_host_name_set __initdata = 0; /* Host name set by us? */ |
131 | 132 | ||
132 | u32 ic_myaddr = INADDR_NONE; /* My IP address */ | 133 | __be32 ic_myaddr = NONE; /* My IP address */ |
133 | static u32 ic_netmask = INADDR_NONE; /* Netmask for local subnet */ | 134 | static __be32 ic_netmask = NONE; /* Netmask for local subnet */ |
134 | u32 ic_gateway = INADDR_NONE; /* Gateway IP address */ | 135 | __be32 ic_gateway = NONE; /* Gateway IP address */ |
135 | 136 | ||
136 | u32 ic_servaddr = INADDR_NONE; /* Boot server IP address */ | 137 | __be32 ic_servaddr = NONE; /* Boot server IP address */ |
137 | 138 | ||
138 | u32 root_server_addr = INADDR_NONE; /* Address of NFS server */ | 139 | __be32 root_server_addr = NONE; /* Address of NFS server */ |
139 | u8 root_server_path[256] = { 0, }; /* Path to mount as root */ | 140 | u8 root_server_path[256] = { 0, }; /* Path to mount as root */ |
140 | 141 | ||
141 | /* Persistent data: */ | 142 | /* Persistent data: */ |
142 | 143 | ||
143 | static int ic_proto_used; /* Protocol used, if any */ | 144 | static int ic_proto_used; /* Protocol used, if any */ |
144 | static u32 ic_nameservers[CONF_NAMESERVERS_MAX]; /* DNS Server IP addresses */ | 145 | static __be32 ic_nameservers[CONF_NAMESERVERS_MAX]; /* DNS Server IP addresses */ |
145 | static u8 ic_domain[64]; /* DNS (not NIS) domain name */ | 146 | static u8 ic_domain[64]; /* DNS (not NIS) domain name */ |
146 | 147 | ||
147 | /* | 148 | /* |
@@ -172,7 +173,7 @@ struct ic_device { | |||
172 | struct net_device *dev; | 173 | struct net_device *dev; |
173 | unsigned short flags; | 174 | unsigned short flags; |
174 | short able; | 175 | short able; |
175 | u32 xid; | 176 | __be32 xid; |
176 | }; | 177 | }; |
177 | 178 | ||
178 | static struct ic_device *ic_first_dev __initdata = NULL;/* List of open device */ | 179 | static struct ic_device *ic_first_dev __initdata = NULL;/* List of open device */ |
@@ -223,7 +224,7 @@ static int __init ic_open_devs(void) | |||
223 | d->flags = oflags; | 224 | d->flags = oflags; |
224 | d->able = able; | 225 | d->able = able; |
225 | if (able & IC_BOOTP) | 226 | if (able & IC_BOOTP) |
226 | get_random_bytes(&d->xid, sizeof(u32)); | 227 | get_random_bytes(&d->xid, sizeof(__be32)); |
227 | else | 228 | else |
228 | d->xid = 0; | 229 | d->xid = 0; |
229 | ic_proto_have_if |= able; | 230 | ic_proto_have_if |= able; |
@@ -269,7 +270,7 @@ static void __init ic_close_devs(void) | |||
269 | */ | 270 | */ |
270 | 271 | ||
271 | static inline void | 272 | static inline void |
272 | set_sockaddr(struct sockaddr_in *sin, u32 addr, u16 port) | 273 | set_sockaddr(struct sockaddr_in *sin, __be32 addr, __be16 port) |
273 | { | 274 | { |
274 | sin->sin_family = AF_INET; | 275 | sin->sin_family = AF_INET; |
275 | sin->sin_addr.s_addr = addr; | 276 | sin->sin_addr.s_addr = addr; |
@@ -332,7 +333,7 @@ static int __init ic_setup_routes(void) | |||
332 | { | 333 | { |
333 | /* No need to setup device routes, only the default route... */ | 334 | /* No need to setup device routes, only the default route... */ |
334 | 335 | ||
335 | if (ic_gateway != INADDR_NONE) { | 336 | if (ic_gateway != NONE) { |
336 | struct rtentry rm; | 337 | struct rtentry rm; |
337 | int err; | 338 | int err; |
338 | 339 | ||
@@ -368,10 +369,10 @@ static int __init ic_defaults(void) | |||
368 | if (!ic_host_name_set) | 369 | if (!ic_host_name_set) |
369 | sprintf(init_utsname()->nodename, "%u.%u.%u.%u", NIPQUAD(ic_myaddr)); | 370 | sprintf(init_utsname()->nodename, "%u.%u.%u.%u", NIPQUAD(ic_myaddr)); |
370 | 371 | ||
371 | if (root_server_addr == INADDR_NONE) | 372 | if (root_server_addr == NONE) |
372 | root_server_addr = ic_servaddr; | 373 | root_server_addr = ic_servaddr; |
373 | 374 | ||
374 | if (ic_netmask == INADDR_NONE) { | 375 | if (ic_netmask == NONE) { |
375 | if (IN_CLASSA(ntohl(ic_myaddr))) | 376 | if (IN_CLASSA(ntohl(ic_myaddr))) |
376 | ic_netmask = htonl(IN_CLASSA_NET); | 377 | ic_netmask = htonl(IN_CLASSA_NET); |
377 | else if (IN_CLASSB(ntohl(ic_myaddr))) | 378 | else if (IN_CLASSB(ntohl(ic_myaddr))) |
@@ -420,7 +421,7 @@ ic_rarp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt | |||
420 | { | 421 | { |
421 | struct arphdr *rarp; | 422 | struct arphdr *rarp; |
422 | unsigned char *rarp_ptr; | 423 | unsigned char *rarp_ptr; |
423 | u32 sip, tip; | 424 | __be32 sip, tip; |
424 | unsigned char *sha, *tha; /* s for "source", t for "target" */ | 425 | unsigned char *sha, *tha; /* s for "source", t for "target" */ |
425 | struct ic_device *d; | 426 | struct ic_device *d; |
426 | 427 | ||
@@ -485,12 +486,12 @@ ic_rarp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt | |||
485 | goto drop_unlock; | 486 | goto drop_unlock; |
486 | 487 | ||
487 | /* Discard packets which are not from specified server. */ | 488 | /* Discard packets which are not from specified server. */ |
488 | if (ic_servaddr != INADDR_NONE && ic_servaddr != sip) | 489 | if (ic_servaddr != NONE && ic_servaddr != sip) |
489 | goto drop_unlock; | 490 | goto drop_unlock; |
490 | 491 | ||
491 | /* We have a winner! */ | 492 | /* We have a winner! */ |
492 | ic_dev = dev; | 493 | ic_dev = dev; |
493 | if (ic_myaddr == INADDR_NONE) | 494 | if (ic_myaddr == NONE) |
494 | ic_myaddr = tip; | 495 | ic_myaddr = tip; |
495 | ic_servaddr = sip; | 496 | ic_servaddr = sip; |
496 | ic_got_reply = IC_RARP; | 497 | ic_got_reply = IC_RARP; |
@@ -530,13 +531,13 @@ struct bootp_pkt { /* BOOTP packet format */ | |||
530 | u8 htype; /* HW address type */ | 531 | u8 htype; /* HW address type */ |
531 | u8 hlen; /* HW address length */ | 532 | u8 hlen; /* HW address length */ |
532 | u8 hops; /* Used only by gateways */ | 533 | u8 hops; /* Used only by gateways */ |
533 | u32 xid; /* Transaction ID */ | 534 | __be32 xid; /* Transaction ID */ |
534 | u16 secs; /* Seconds since we started */ | 535 | __be16 secs; /* Seconds since we started */ |
535 | u16 flags; /* Just what it says */ | 536 | __be16 flags; /* Just what it says */ |
536 | u32 client_ip; /* Client's IP address if known */ | 537 | __be32 client_ip; /* Client's IP address if known */ |
537 | u32 your_ip; /* Assigned IP address */ | 538 | __be32 your_ip; /* Assigned IP address */ |
538 | u32 server_ip; /* (Next, e.g. NFS) Server's IP address */ | 539 | __be32 server_ip; /* (Next, e.g. NFS) Server's IP address */ |
539 | u32 relay_ip; /* IP address of BOOTP relay */ | 540 | __be32 relay_ip; /* IP address of BOOTP relay */ |
540 | u8 hw_addr[16]; /* Client's HW address */ | 541 | u8 hw_addr[16]; /* Client's HW address */ |
541 | u8 serv_name[64]; /* Server host name */ | 542 | u8 serv_name[64]; /* Server host name */ |
542 | u8 boot_file[128]; /* Name of boot file */ | 543 | u8 boot_file[128]; /* Name of boot file */ |
@@ -576,7 +577,7 @@ static const u8 ic_bootp_cookie[4] = { 99, 130, 83, 99 }; | |||
576 | static void __init | 577 | static void __init |
577 | ic_dhcp_init_options(u8 *options) | 578 | ic_dhcp_init_options(u8 *options) |
578 | { | 579 | { |
579 | u8 mt = ((ic_servaddr == INADDR_NONE) | 580 | u8 mt = ((ic_servaddr == NONE) |
580 | ? DHCPDISCOVER : DHCPREQUEST); | 581 | ? DHCPDISCOVER : DHCPREQUEST); |
581 | u8 *e = options; | 582 | u8 *e = options; |
582 | 583 | ||
@@ -666,7 +667,7 @@ static inline void ic_bootp_init(void) | |||
666 | int i; | 667 | int i; |
667 | 668 | ||
668 | for (i = 0; i < CONF_NAMESERVERS_MAX; i++) | 669 | for (i = 0; i < CONF_NAMESERVERS_MAX; i++) |
669 | ic_nameservers[i] = INADDR_NONE; | 670 | ic_nameservers[i] = NONE; |
670 | 671 | ||
671 | dev_add_pack(&bootp_packet_type); | 672 | dev_add_pack(&bootp_packet_type); |
672 | } | 673 | } |
@@ -708,7 +709,7 @@ static void __init ic_bootp_send_if(struct ic_device *d, unsigned long jiffies_d | |||
708 | h->frag_off = htons(IP_DF); | 709 | h->frag_off = htons(IP_DF); |
709 | h->ttl = 64; | 710 | h->ttl = 64; |
710 | h->protocol = IPPROTO_UDP; | 711 | h->protocol = IPPROTO_UDP; |
711 | h->daddr = INADDR_BROADCAST; | 712 | h->daddr = htonl(INADDR_BROADCAST); |
712 | h->check = ip_fast_csum((unsigned char *) h, h->ihl); | 713 | h->check = ip_fast_csum((unsigned char *) h, h->ihl); |
713 | 714 | ||
714 | /* Construct UDP header */ | 715 | /* Construct UDP header */ |
@@ -730,8 +731,8 @@ static void __init ic_bootp_send_if(struct ic_device *d, unsigned long jiffies_d | |||
730 | b->htype = dev->type; /* can cause undefined behavior */ | 731 | b->htype = dev->type; /* can cause undefined behavior */ |
731 | } | 732 | } |
732 | b->hlen = dev->addr_len; | 733 | b->hlen = dev->addr_len; |
733 | b->your_ip = INADDR_NONE; | 734 | b->your_ip = NONE; |
734 | b->server_ip = INADDR_NONE; | 735 | b->server_ip = NONE; |
735 | memcpy(b->hw_addr, dev->dev_addr, dev->addr_len); | 736 | memcpy(b->hw_addr, dev->dev_addr, dev->addr_len); |
736 | b->secs = htons(jiffies_diff / HZ); | 737 | b->secs = htons(jiffies_diff / HZ); |
737 | b->xid = d->xid; | 738 | b->xid = d->xid; |
@@ -788,11 +789,11 @@ static void __init ic_do_bootp_ext(u8 *ext) | |||
788 | 789 | ||
789 | switch (*ext++) { | 790 | switch (*ext++) { |
790 | case 1: /* Subnet mask */ | 791 | case 1: /* Subnet mask */ |
791 | if (ic_netmask == INADDR_NONE) | 792 | if (ic_netmask == NONE) |
792 | memcpy(&ic_netmask, ext+1, 4); | 793 | memcpy(&ic_netmask, ext+1, 4); |
793 | break; | 794 | break; |
794 | case 3: /* Default gateway */ | 795 | case 3: /* Default gateway */ |
795 | if (ic_gateway == INADDR_NONE) | 796 | if (ic_gateway == NONE) |
796 | memcpy(&ic_gateway, ext+1, 4); | 797 | memcpy(&ic_gateway, ext+1, 4); |
797 | break; | 798 | break; |
798 | case 6: /* DNS server */ | 799 | case 6: /* DNS server */ |
@@ -800,7 +801,7 @@ static void __init ic_do_bootp_ext(u8 *ext) | |||
800 | if (servers > CONF_NAMESERVERS_MAX) | 801 | if (servers > CONF_NAMESERVERS_MAX) |
801 | servers = CONF_NAMESERVERS_MAX; | 802 | servers = CONF_NAMESERVERS_MAX; |
802 | for (i = 0; i < servers; i++) { | 803 | for (i = 0; i < servers; i++) { |
803 | if (ic_nameservers[i] == INADDR_NONE) | 804 | if (ic_nameservers[i] == NONE) |
804 | memcpy(&ic_nameservers[i], ext+1+4*i, 4); | 805 | memcpy(&ic_nameservers[i], ext+1+4*i, 4); |
805 | } | 806 | } |
806 | break; | 807 | break; |
@@ -917,7 +918,7 @@ static int __init ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, str | |||
917 | 918 | ||
918 | #ifdef IPCONFIG_DHCP | 919 | #ifdef IPCONFIG_DHCP |
919 | if (ic_proto_enabled & IC_USE_DHCP) { | 920 | if (ic_proto_enabled & IC_USE_DHCP) { |
920 | u32 server_id = INADDR_NONE; | 921 | __be32 server_id = NONE; |
921 | int mt = 0; | 922 | int mt = 0; |
922 | 923 | ||
923 | ext = &b->exten[4]; | 924 | ext = &b->exten[4]; |
@@ -949,7 +950,7 @@ static int __init ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, str | |||
949 | /* While in the process of accepting one offer, | 950 | /* While in the process of accepting one offer, |
950 | * ignore all others. | 951 | * ignore all others. |
951 | */ | 952 | */ |
952 | if (ic_myaddr != INADDR_NONE) | 953 | if (ic_myaddr != NONE) |
953 | goto drop_unlock; | 954 | goto drop_unlock; |
954 | 955 | ||
955 | /* Let's accept that offer. */ | 956 | /* Let's accept that offer. */ |
@@ -965,7 +966,7 @@ static int __init ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, str | |||
965 | * precedence over the bootp header one if | 966 | * precedence over the bootp header one if |
966 | * they are different. | 967 | * they are different. |
967 | */ | 968 | */ |
968 | if ((server_id != INADDR_NONE) && | 969 | if ((server_id != NONE) && |
969 | (b->server_ip != server_id)) | 970 | (b->server_ip != server_id)) |
970 | b->server_ip = ic_servaddr; | 971 | b->server_ip = ic_servaddr; |
971 | break; | 972 | break; |
@@ -979,8 +980,8 @@ static int __init ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, str | |||
979 | 980 | ||
980 | default: | 981 | default: |
981 | /* Urque. Forget it*/ | 982 | /* Urque. Forget it*/ |
982 | ic_myaddr = INADDR_NONE; | 983 | ic_myaddr = NONE; |
983 | ic_servaddr = INADDR_NONE; | 984 | ic_servaddr = NONE; |
984 | goto drop_unlock; | 985 | goto drop_unlock; |
985 | }; | 986 | }; |
986 | 987 | ||
@@ -1004,9 +1005,9 @@ static int __init ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, str | |||
1004 | ic_dev = dev; | 1005 | ic_dev = dev; |
1005 | ic_myaddr = b->your_ip; | 1006 | ic_myaddr = b->your_ip; |
1006 | ic_servaddr = b->server_ip; | 1007 | ic_servaddr = b->server_ip; |
1007 | if (ic_gateway == INADDR_NONE && b->relay_ip) | 1008 | if (ic_gateway == NONE && b->relay_ip) |
1008 | ic_gateway = b->relay_ip; | 1009 | ic_gateway = b->relay_ip; |
1009 | if (ic_nameservers[0] == INADDR_NONE) | 1010 | if (ic_nameservers[0] == NONE) |
1010 | ic_nameservers[0] = ic_servaddr; | 1011 | ic_nameservers[0] = ic_servaddr; |
1011 | ic_got_reply = IC_BOOTP; | 1012 | ic_got_reply = IC_BOOTP; |
1012 | 1013 | ||
@@ -1150,7 +1151,7 @@ static int __init ic_dynamic(void) | |||
1150 | #endif | 1151 | #endif |
1151 | 1152 | ||
1152 | if (!ic_got_reply) { | 1153 | if (!ic_got_reply) { |
1153 | ic_myaddr = INADDR_NONE; | 1154 | ic_myaddr = NONE; |
1154 | return -1; | 1155 | return -1; |
1155 | } | 1156 | } |
1156 | 1157 | ||
@@ -1182,12 +1183,12 @@ static int pnp_seq_show(struct seq_file *seq, void *v) | |||
1182 | seq_printf(seq, | 1183 | seq_printf(seq, |
1183 | "domain %s\n", ic_domain); | 1184 | "domain %s\n", ic_domain); |
1184 | for (i = 0; i < CONF_NAMESERVERS_MAX; i++) { | 1185 | for (i = 0; i < CONF_NAMESERVERS_MAX; i++) { |
1185 | if (ic_nameservers[i] != INADDR_NONE) | 1186 | if (ic_nameservers[i] != NONE) |
1186 | seq_printf(seq, | 1187 | seq_printf(seq, |
1187 | "nameserver %u.%u.%u.%u\n", | 1188 | "nameserver %u.%u.%u.%u\n", |
1188 | NIPQUAD(ic_nameservers[i])); | 1189 | NIPQUAD(ic_nameservers[i])); |
1189 | } | 1190 | } |
1190 | if (ic_servaddr != INADDR_NONE) | 1191 | if (ic_servaddr != NONE) |
1191 | seq_printf(seq, | 1192 | seq_printf(seq, |
1192 | "bootserver %u.%u.%u.%u\n", | 1193 | "bootserver %u.%u.%u.%u\n", |
1193 | NIPQUAD(ic_servaddr)); | 1194 | NIPQUAD(ic_servaddr)); |
@@ -1213,9 +1214,9 @@ static struct file_operations pnp_seq_fops = { | |||
1213 | * need to have root_server_addr set _before_ IPConfig gets called as it | 1214 | * need to have root_server_addr set _before_ IPConfig gets called as it |
1214 | * can override it. | 1215 | * can override it. |
1215 | */ | 1216 | */ |
1216 | u32 __init root_nfs_parse_addr(char *name) | 1217 | __be32 __init root_nfs_parse_addr(char *name) |
1217 | { | 1218 | { |
1218 | u32 addr; | 1219 | __be32 addr; |
1219 | int octets = 0; | 1220 | int octets = 0; |
1220 | char *cp, *cq; | 1221 | char *cp, *cq; |
1221 | 1222 | ||
@@ -1237,7 +1238,7 @@ u32 __init root_nfs_parse_addr(char *name) | |||
1237 | addr = in_aton(name); | 1238 | addr = in_aton(name); |
1238 | memmove(name, cp, strlen(cp) + 1); | 1239 | memmove(name, cp, strlen(cp) + 1); |
1239 | } else | 1240 | } else |
1240 | addr = INADDR_NONE; | 1241 | addr = NONE; |
1241 | 1242 | ||
1242 | return addr; | 1243 | return addr; |
1243 | } | 1244 | } |
@@ -1248,7 +1249,7 @@ u32 __init root_nfs_parse_addr(char *name) | |||
1248 | 1249 | ||
1249 | static int __init ip_auto_config(void) | 1250 | static int __init ip_auto_config(void) |
1250 | { | 1251 | { |
1251 | u32 addr; | 1252 | __be32 addr; |
1252 | 1253 | ||
1253 | #ifdef CONFIG_PROC_FS | 1254 | #ifdef CONFIG_PROC_FS |
1254 | proc_net_fops_create("pnp", S_IRUGO, &pnp_seq_fops); | 1255 | proc_net_fops_create("pnp", S_IRUGO, &pnp_seq_fops); |
@@ -1277,11 +1278,11 @@ static int __init ip_auto_config(void) | |||
1277 | * interfaces and no default was set), use BOOTP or RARP to get the | 1278 | * interfaces and no default was set), use BOOTP or RARP to get the |
1278 | * missing values. | 1279 | * missing values. |
1279 | */ | 1280 | */ |
1280 | if (ic_myaddr == INADDR_NONE || | 1281 | if (ic_myaddr == NONE || |
1281 | #ifdef CONFIG_ROOT_NFS | 1282 | #ifdef CONFIG_ROOT_NFS |
1282 | (MAJOR(ROOT_DEV) == UNNAMED_MAJOR | 1283 | (MAJOR(ROOT_DEV) == UNNAMED_MAJOR |
1283 | && root_server_addr == INADDR_NONE | 1284 | && root_server_addr == NONE |
1284 | && ic_servaddr == INADDR_NONE) || | 1285 | && ic_servaddr == NONE) || |
1285 | #endif | 1286 | #endif |
1286 | ic_first_dev->next) { | 1287 | ic_first_dev->next) { |
1287 | #ifdef IPCONFIG_DYNAMIC | 1288 | #ifdef IPCONFIG_DYNAMIC |
@@ -1334,7 +1335,7 @@ static int __init ip_auto_config(void) | |||
1334 | } | 1335 | } |
1335 | 1336 | ||
1336 | addr = root_nfs_parse_addr(root_server_path); | 1337 | addr = root_nfs_parse_addr(root_server_path); |
1337 | if (root_server_addr == INADDR_NONE) | 1338 | if (root_server_addr == NONE) |
1338 | root_server_addr = addr; | 1339 | root_server_addr = addr; |
1339 | 1340 | ||
1340 | /* | 1341 | /* |
@@ -1461,19 +1462,19 @@ static int __init ip_auto_config_setup(char *addrs) | |||
1461 | switch (num) { | 1462 | switch (num) { |
1462 | case 0: | 1463 | case 0: |
1463 | if ((ic_myaddr = in_aton(ip)) == INADDR_ANY) | 1464 | if ((ic_myaddr = in_aton(ip)) == INADDR_ANY) |
1464 | ic_myaddr = INADDR_NONE; | 1465 | ic_myaddr = NONE; |
1465 | break; | 1466 | break; |
1466 | case 1: | 1467 | case 1: |
1467 | if ((ic_servaddr = in_aton(ip)) == INADDR_ANY) | 1468 | if ((ic_servaddr = in_aton(ip)) == INADDR_ANY) |
1468 | ic_servaddr = INADDR_NONE; | 1469 | ic_servaddr = NONE; |
1469 | break; | 1470 | break; |
1470 | case 2: | 1471 | case 2: |
1471 | if ((ic_gateway = in_aton(ip)) == INADDR_ANY) | 1472 | if ((ic_gateway = in_aton(ip)) == INADDR_ANY) |
1472 | ic_gateway = INADDR_NONE; | 1473 | ic_gateway = NONE; |
1473 | break; | 1474 | break; |
1474 | case 3: | 1475 | case 3: |
1475 | if ((ic_netmask = in_aton(ip)) == INADDR_ANY) | 1476 | if ((ic_netmask = in_aton(ip)) == INADDR_ANY) |
1476 | ic_netmask = INADDR_NONE; | 1477 | ic_netmask = NONE; |
1477 | break; | 1478 | break; |
1478 | case 4: | 1479 | case 4: |
1479 | if ((dp = strchr(ip, '.'))) { | 1480 | if ((dp = strchr(ip, '.'))) { |
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index 0c4556529228..9d719d664e5b 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c | |||
@@ -118,7 +118,7 @@ | |||
118 | #include <net/xfrm.h> | 118 | #include <net/xfrm.h> |
119 | 119 | ||
120 | #define HASH_SIZE 16 | 120 | #define HASH_SIZE 16 |
121 | #define HASH(addr) ((addr^(addr>>4))&0xF) | 121 | #define HASH(addr) (((__force u32)addr^((__force u32)addr>>4))&0xF) |
122 | 122 | ||
123 | static int ipip_fb_tunnel_init(struct net_device *dev); | 123 | static int ipip_fb_tunnel_init(struct net_device *dev); |
124 | static int ipip_tunnel_init(struct net_device *dev); | 124 | static int ipip_tunnel_init(struct net_device *dev); |
@@ -134,7 +134,7 @@ static struct ip_tunnel **tunnels[4] = { tunnels_wc, tunnels_l, tunnels_r, tunne | |||
134 | 134 | ||
135 | static DEFINE_RWLOCK(ipip_lock); | 135 | static DEFINE_RWLOCK(ipip_lock); |
136 | 136 | ||
137 | static struct ip_tunnel * ipip_tunnel_lookup(u32 remote, u32 local) | 137 | static struct ip_tunnel * ipip_tunnel_lookup(__be32 remote, __be32 local) |
138 | { | 138 | { |
139 | unsigned h0 = HASH(remote); | 139 | unsigned h0 = HASH(remote); |
140 | unsigned h1 = HASH(local); | 140 | unsigned h1 = HASH(local); |
@@ -160,8 +160,8 @@ static struct ip_tunnel * ipip_tunnel_lookup(u32 remote, u32 local) | |||
160 | 160 | ||
161 | static struct ip_tunnel **ipip_bucket(struct ip_tunnel *t) | 161 | static struct ip_tunnel **ipip_bucket(struct ip_tunnel *t) |
162 | { | 162 | { |
163 | u32 remote = t->parms.iph.daddr; | 163 | __be32 remote = t->parms.iph.daddr; |
164 | u32 local = t->parms.iph.saddr; | 164 | __be32 local = t->parms.iph.saddr; |
165 | unsigned h = 0; | 165 | unsigned h = 0; |
166 | int prio = 0; | 166 | int prio = 0; |
167 | 167 | ||
@@ -203,8 +203,8 @@ static void ipip_tunnel_link(struct ip_tunnel *t) | |||
203 | 203 | ||
204 | static struct ip_tunnel * ipip_tunnel_locate(struct ip_tunnel_parm *parms, int create) | 204 | static struct ip_tunnel * ipip_tunnel_locate(struct ip_tunnel_parm *parms, int create) |
205 | { | 205 | { |
206 | u32 remote = parms->iph.daddr; | 206 | __be32 remote = parms->iph.daddr; |
207 | u32 local = parms->iph.saddr; | 207 | __be32 local = parms->iph.saddr; |
208 | struct ip_tunnel *t, **tp, *nt; | 208 | struct ip_tunnel *t, **tp, *nt; |
209 | struct net_device *dev; | 209 | struct net_device *dev; |
210 | unsigned h = 0; | 210 | unsigned h = 0; |
@@ -519,13 +519,13 @@ static int ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) | |||
519 | struct net_device_stats *stats = &tunnel->stat; | 519 | struct net_device_stats *stats = &tunnel->stat; |
520 | struct iphdr *tiph = &tunnel->parms.iph; | 520 | struct iphdr *tiph = &tunnel->parms.iph; |
521 | u8 tos = tunnel->parms.iph.tos; | 521 | u8 tos = tunnel->parms.iph.tos; |
522 | u16 df = tiph->frag_off; | 522 | __be16 df = tiph->frag_off; |
523 | struct rtable *rt; /* Route to the other host */ | 523 | struct rtable *rt; /* Route to the other host */ |
524 | struct net_device *tdev; /* Device to other host */ | 524 | struct net_device *tdev; /* Device to other host */ |
525 | struct iphdr *old_iph = skb->nh.iph; | 525 | struct iphdr *old_iph = skb->nh.iph; |
526 | struct iphdr *iph; /* Our new IP header */ | 526 | struct iphdr *iph; /* Our new IP header */ |
527 | int max_headroom; /* The extra header space needed */ | 527 | int max_headroom; /* The extra header space needed */ |
528 | u32 dst = tiph->daddr; | 528 | __be32 dst = tiph->daddr; |
529 | int mtu; | 529 | int mtu; |
530 | 530 | ||
531 | if (tunnel->recursion++) { | 531 | if (tunnel->recursion++) { |
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 97cfa97c8abb..efcf45ecc818 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c | |||
@@ -1493,7 +1493,7 @@ static int pim_rcv(struct sk_buff * skb) | |||
1493 | if (pim->type != ((PIM_VERSION<<4)|(PIM_REGISTER)) || | 1493 | if (pim->type != ((PIM_VERSION<<4)|(PIM_REGISTER)) || |
1494 | (pim->flags&PIM_NULL_REGISTER) || | 1494 | (pim->flags&PIM_NULL_REGISTER) || |
1495 | (ip_compute_csum((void *)pim, sizeof(*pim)) != 0 && | 1495 | (ip_compute_csum((void *)pim, sizeof(*pim)) != 0 && |
1496 | (u16)csum_fold(skb_checksum(skb, 0, skb->len, 0)))) | 1496 | csum_fold(skb_checksum(skb, 0, skb->len, 0)))) |
1497 | goto drop; | 1497 | goto drop; |
1498 | 1498 | ||
1499 | /* check if the inner packet is destined to mcast group */ | 1499 | /* check if the inner packet is destined to mcast group */ |
diff --git a/net/ipv4/ipvs/ip_vs_app.c b/net/ipv4/ipvs/ip_vs_app.c index e7752334d296..6c40899aa161 100644 --- a/net/ipv4/ipvs/ip_vs_app.c +++ b/net/ipv4/ipvs/ip_vs_app.c | |||
@@ -80,10 +80,9 @@ ip_vs_app_inc_new(struct ip_vs_app *app, __u16 proto, __u16 port) | |||
80 | if (!pp->unregister_app) | 80 | if (!pp->unregister_app) |
81 | return -EOPNOTSUPP; | 81 | return -EOPNOTSUPP; |
82 | 82 | ||
83 | inc = kmalloc(sizeof(struct ip_vs_app), GFP_KERNEL); | 83 | inc = kmemdup(app, sizeof(*inc), GFP_KERNEL); |
84 | if (!inc) | 84 | if (!inc) |
85 | return -ENOMEM; | 85 | return -ENOMEM; |
86 | memcpy(inc, app, sizeof(*inc)); | ||
87 | INIT_LIST_HEAD(&inc->p_list); | 86 | INIT_LIST_HEAD(&inc->p_list); |
88 | INIT_LIST_HEAD(&inc->incs_list); | 87 | INIT_LIST_HEAD(&inc->incs_list); |
89 | inc->app = app; | 88 | inc->app = app; |
diff --git a/net/ipv4/ipvs/ip_vs_core.c b/net/ipv4/ipvs/ip_vs_core.c index 1445bb47fea4..34257520a3a6 100644 --- a/net/ipv4/ipvs/ip_vs_core.c +++ b/net/ipv4/ipvs/ip_vs_core.c | |||
@@ -536,9 +536,9 @@ static unsigned int ip_vs_post_routing(unsigned int hooknum, | |||
536 | return NF_STOP; | 536 | return NF_STOP; |
537 | } | 537 | } |
538 | 538 | ||
539 | u16 ip_vs_checksum_complete(struct sk_buff *skb, int offset) | 539 | __sum16 ip_vs_checksum_complete(struct sk_buff *skb, int offset) |
540 | { | 540 | { |
541 | return (u16) csum_fold(skb_checksum(skb, offset, skb->len - offset, 0)); | 541 | return csum_fold(skb_checksum(skb, offset, skb->len - offset, 0)); |
542 | } | 542 | } |
543 | 543 | ||
544 | static inline struct sk_buff * | 544 | static inline struct sk_buff * |
diff --git a/net/ipv4/ipvs/ip_vs_proto.c b/net/ipv4/ipvs/ip_vs_proto.c index c4528b5c800d..e844ddb82b9a 100644 --- a/net/ipv4/ipvs/ip_vs_proto.c +++ b/net/ipv4/ipvs/ip_vs_proto.c | |||
@@ -118,13 +118,7 @@ void ip_vs_protocol_timeout_change(int flags) | |||
118 | int * | 118 | int * |
119 | ip_vs_create_timeout_table(int *table, int size) | 119 | ip_vs_create_timeout_table(int *table, int size) |
120 | { | 120 | { |
121 | int *t; | 121 | return kmemdup(table, size, GFP_ATOMIC); |
122 | |||
123 | t = kmalloc(size, GFP_ATOMIC); | ||
124 | if (t == NULL) | ||
125 | return NULL; | ||
126 | memcpy(t, table, size); | ||
127 | return t; | ||
128 | } | 122 | } |
129 | 123 | ||
130 | 124 | ||
diff --git a/net/ipv4/ipvs/ip_vs_proto_tcp.c b/net/ipv4/ipvs/ip_vs_proto_tcp.c index 6ff05c3a32e6..16a9ebee2fe6 100644 --- a/net/ipv4/ipvs/ip_vs_proto_tcp.c +++ b/net/ipv4/ipvs/ip_vs_proto_tcp.c | |||
@@ -84,7 +84,7 @@ tcp_conn_schedule(struct sk_buff *skb, | |||
84 | } | 84 | } |
85 | 85 | ||
86 | if (th->syn && | 86 | if (th->syn && |
87 | (svc = ip_vs_service_get(skb->nfmark, skb->nh.iph->protocol, | 87 | (svc = ip_vs_service_get(skb->mark, skb->nh.iph->protocol, |
88 | skb->nh.iph->daddr, th->dest))) { | 88 | skb->nh.iph->daddr, th->dest))) { |
89 | if (ip_vs_todrop()) { | 89 | if (ip_vs_todrop()) { |
90 | /* | 90 | /* |
@@ -116,9 +116,9 @@ tcp_fast_csum_update(struct tcphdr *tcph, __be32 oldip, __be32 newip, | |||
116 | __be16 oldport, __be16 newport) | 116 | __be16 oldport, __be16 newport) |
117 | { | 117 | { |
118 | tcph->check = | 118 | tcph->check = |
119 | ip_vs_check_diff(~oldip, newip, | 119 | csum_fold(ip_vs_check_diff4(oldip, newip, |
120 | ip_vs_check_diff(oldport ^ htons(0xFFFF), | 120 | ip_vs_check_diff2(oldport, newport, |
121 | newport, tcph->check)); | 121 | ~csum_unfold(tcph->check)))); |
122 | } | 122 | } |
123 | 123 | ||
124 | 124 | ||
@@ -490,16 +490,18 @@ tcp_state_transition(struct ip_vs_conn *cp, int direction, | |||
490 | static struct list_head tcp_apps[TCP_APP_TAB_SIZE]; | 490 | static struct list_head tcp_apps[TCP_APP_TAB_SIZE]; |
491 | static DEFINE_SPINLOCK(tcp_app_lock); | 491 | static DEFINE_SPINLOCK(tcp_app_lock); |
492 | 492 | ||
493 | static inline __u16 tcp_app_hashkey(__u16 port) | 493 | static inline __u16 tcp_app_hashkey(__be16 port) |
494 | { | 494 | { |
495 | return ((port >> TCP_APP_TAB_BITS) ^ port) & TCP_APP_TAB_MASK; | 495 | return (((__force u16)port >> TCP_APP_TAB_BITS) ^ (__force u16)port) |
496 | & TCP_APP_TAB_MASK; | ||
496 | } | 497 | } |
497 | 498 | ||
498 | 499 | ||
499 | static int tcp_register_app(struct ip_vs_app *inc) | 500 | static int tcp_register_app(struct ip_vs_app *inc) |
500 | { | 501 | { |
501 | struct ip_vs_app *i; | 502 | struct ip_vs_app *i; |
502 | __u16 hash, port = inc->port; | 503 | __u16 hash; |
504 | __be16 port = inc->port; | ||
503 | int ret = 0; | 505 | int ret = 0; |
504 | 506 | ||
505 | hash = tcp_app_hashkey(port); | 507 | hash = tcp_app_hashkey(port); |
diff --git a/net/ipv4/ipvs/ip_vs_proto_udp.c b/net/ipv4/ipvs/ip_vs_proto_udp.c index 691c8b637b29..03f0a414cfa4 100644 --- a/net/ipv4/ipvs/ip_vs_proto_udp.c +++ b/net/ipv4/ipvs/ip_vs_proto_udp.c | |||
@@ -89,7 +89,7 @@ udp_conn_schedule(struct sk_buff *skb, struct ip_vs_protocol *pp, | |||
89 | return 0; | 89 | return 0; |
90 | } | 90 | } |
91 | 91 | ||
92 | if ((svc = ip_vs_service_get(skb->nfmark, skb->nh.iph->protocol, | 92 | if ((svc = ip_vs_service_get(skb->mark, skb->nh.iph->protocol, |
93 | skb->nh.iph->daddr, uh->dest))) { | 93 | skb->nh.iph->daddr, uh->dest))) { |
94 | if (ip_vs_todrop()) { | 94 | if (ip_vs_todrop()) { |
95 | /* | 95 | /* |
@@ -121,11 +121,11 @@ udp_fast_csum_update(struct udphdr *uhdr, __be32 oldip, __be32 newip, | |||
121 | __be16 oldport, __be16 newport) | 121 | __be16 oldport, __be16 newport) |
122 | { | 122 | { |
123 | uhdr->check = | 123 | uhdr->check = |
124 | ip_vs_check_diff(~oldip, newip, | 124 | csum_fold(ip_vs_check_diff4(oldip, newip, |
125 | ip_vs_check_diff(oldport ^ htons(0xFFFF), | 125 | ip_vs_check_diff2(oldport, newport, |
126 | newport, uhdr->check)); | 126 | ~csum_unfold(uhdr->check)))); |
127 | if (!uhdr->check) | 127 | if (!uhdr->check) |
128 | uhdr->check = -1; | 128 | uhdr->check = CSUM_MANGLED_0; |
129 | } | 129 | } |
130 | 130 | ||
131 | static int | 131 | static int |
@@ -173,7 +173,7 @@ udp_snat_handler(struct sk_buff **pskb, | |||
173 | cp->protocol, | 173 | cp->protocol, |
174 | (*pskb)->csum); | 174 | (*pskb)->csum); |
175 | if (udph->check == 0) | 175 | if (udph->check == 0) |
176 | udph->check = -1; | 176 | udph->check = CSUM_MANGLED_0; |
177 | IP_VS_DBG(11, "O-pkt: %s O-csum=%d (+%zd)\n", | 177 | IP_VS_DBG(11, "O-pkt: %s O-csum=%d (+%zd)\n", |
178 | pp->name, udph->check, | 178 | pp->name, udph->check, |
179 | (char*)&(udph->check) - (char*)udph); | 179 | (char*)&(udph->check) - (char*)udph); |
@@ -228,7 +228,7 @@ udp_dnat_handler(struct sk_buff **pskb, | |||
228 | cp->protocol, | 228 | cp->protocol, |
229 | (*pskb)->csum); | 229 | (*pskb)->csum); |
230 | if (udph->check == 0) | 230 | if (udph->check == 0) |
231 | udph->check = -1; | 231 | udph->check = CSUM_MANGLED_0; |
232 | (*pskb)->ip_summed = CHECKSUM_UNNECESSARY; | 232 | (*pskb)->ip_summed = CHECKSUM_UNNECESSARY; |
233 | } | 233 | } |
234 | return 1; | 234 | return 1; |
@@ -282,16 +282,18 @@ udp_csum_check(struct sk_buff *skb, struct ip_vs_protocol *pp) | |||
282 | static struct list_head udp_apps[UDP_APP_TAB_SIZE]; | 282 | static struct list_head udp_apps[UDP_APP_TAB_SIZE]; |
283 | static DEFINE_SPINLOCK(udp_app_lock); | 283 | static DEFINE_SPINLOCK(udp_app_lock); |
284 | 284 | ||
285 | static inline __u16 udp_app_hashkey(__u16 port) | 285 | static inline __u16 udp_app_hashkey(__be16 port) |
286 | { | 286 | { |
287 | return ((port >> UDP_APP_TAB_BITS) ^ port) & UDP_APP_TAB_MASK; | 287 | return (((__force u16)port >> UDP_APP_TAB_BITS) ^ (__force u16)port) |
288 | & UDP_APP_TAB_MASK; | ||
288 | } | 289 | } |
289 | 290 | ||
290 | 291 | ||
291 | static int udp_register_app(struct ip_vs_app *inc) | 292 | static int udp_register_app(struct ip_vs_app *inc) |
292 | { | 293 | { |
293 | struct ip_vs_app *i; | 294 | struct ip_vs_app *i; |
294 | __u16 hash, port = inc->port; | 295 | __u16 hash; |
296 | __be16 port = inc->port; | ||
295 | int ret = 0; | 297 | int ret = 0; |
296 | 298 | ||
297 | hash = udp_app_hashkey(port); | 299 | hash = udp_app_hashkey(port); |
diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c index e2005c6810a4..a68966059b50 100644 --- a/net/ipv4/netfilter.c +++ b/net/ipv4/netfilter.c | |||
@@ -27,9 +27,7 @@ int ip_route_me_harder(struct sk_buff **pskb, unsigned addr_type) | |||
27 | fl.nl_u.ip4_u.saddr = iph->saddr; | 27 | fl.nl_u.ip4_u.saddr = iph->saddr; |
28 | fl.nl_u.ip4_u.tos = RT_TOS(iph->tos); | 28 | fl.nl_u.ip4_u.tos = RT_TOS(iph->tos); |
29 | fl.oif = (*pskb)->sk ? (*pskb)->sk->sk_bound_dev_if : 0; | 29 | fl.oif = (*pskb)->sk ? (*pskb)->sk->sk_bound_dev_if : 0; |
30 | #ifdef CONFIG_IP_ROUTE_FWMARK | 30 | fl.mark = (*pskb)->mark; |
31 | fl.nl_u.ip4_u.fwmark = (*pskb)->nfmark; | ||
32 | #endif | ||
33 | if (ip_route_output_key(&rt, &fl) != 0) | 31 | if (ip_route_output_key(&rt, &fl) != 0) |
34 | return -1; | 32 | return -1; |
35 | 33 | ||
@@ -164,17 +162,17 @@ static int nf_ip_reroute(struct sk_buff **pskb, const struct nf_info *info) | |||
164 | return 0; | 162 | return 0; |
165 | } | 163 | } |
166 | 164 | ||
167 | unsigned int nf_ip_checksum(struct sk_buff *skb, unsigned int hook, | 165 | __sum16 nf_ip_checksum(struct sk_buff *skb, unsigned int hook, |
168 | unsigned int dataoff, u_int8_t protocol) | 166 | unsigned int dataoff, u_int8_t protocol) |
169 | { | 167 | { |
170 | struct iphdr *iph = skb->nh.iph; | 168 | struct iphdr *iph = skb->nh.iph; |
171 | unsigned int csum = 0; | 169 | __sum16 csum = 0; |
172 | 170 | ||
173 | switch (skb->ip_summed) { | 171 | switch (skb->ip_summed) { |
174 | case CHECKSUM_COMPLETE: | 172 | case CHECKSUM_COMPLETE: |
175 | if (hook != NF_IP_PRE_ROUTING && hook != NF_IP_LOCAL_IN) | 173 | if (hook != NF_IP_PRE_ROUTING && hook != NF_IP_LOCAL_IN) |
176 | break; | 174 | break; |
177 | if ((protocol == 0 && !(u16)csum_fold(skb->csum)) || | 175 | if ((protocol == 0 && !csum_fold(skb->csum)) || |
178 | !csum_tcpudp_magic(iph->saddr, iph->daddr, | 176 | !csum_tcpudp_magic(iph->saddr, iph->daddr, |
179 | skb->len - dataoff, protocol, | 177 | skb->len - dataoff, protocol, |
180 | skb->csum)) { | 178 | skb->csum)) { |
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index d88c292f118c..363df9976c9d 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig | |||
@@ -6,7 +6,7 @@ menu "IP: Netfilter Configuration" | |||
6 | depends on INET && NETFILTER | 6 | depends on INET && NETFILTER |
7 | 7 | ||
8 | config NF_CONNTRACK_IPV4 | 8 | config NF_CONNTRACK_IPV4 |
9 | tristate "IPv4 support for new connection tracking (EXPERIMENTAL)" | 9 | tristate "IPv4 connection tracking support (required for NAT) (EXPERIMENTAL)" |
10 | depends on EXPERIMENTAL && NF_CONNTRACK | 10 | depends on EXPERIMENTAL && NF_CONNTRACK |
11 | ---help--- | 11 | ---help--- |
12 | Connection tracking keeps a record of what packets have passed | 12 | Connection tracking keeps a record of what packets have passed |
@@ -19,21 +19,18 @@ config NF_CONNTRACK_IPV4 | |||
19 | 19 | ||
20 | To compile it as a module, choose M here. If unsure, say N. | 20 | To compile it as a module, choose M here. If unsure, say N. |
21 | 21 | ||
22 | # connection tracking, helpers and protocols | 22 | config NF_CONNTRACK_PROC_COMPAT |
23 | config IP_NF_CONNTRACK | 23 | bool "proc/sysctl compatibility with old connection tracking" |
24 | tristate "Connection tracking (required for masq/NAT)" | 24 | depends on NF_CONNTRACK_IPV4 |
25 | ---help--- | 25 | default y |
26 | Connection tracking keeps a record of what packets have passed | 26 | help |
27 | through your machine, in order to figure out how they are related | 27 | This option enables /proc and sysctl compatibility with the old |
28 | into connections. | 28 | layer 3 dependant connection tracking. This is needed to keep |
29 | 29 | old programs that have not been adapted to the new names working. | |
30 | This is required to do Masquerading or other kinds of Network | ||
31 | Address Translation (except for Fast NAT). It can also be used to | ||
32 | enhance packet filtering (see `Connection state match support' | ||
33 | below). | ||
34 | 30 | ||
35 | To compile it as a module, choose M here. If unsure, say N. | 31 | If unsure, say Y. |
36 | 32 | ||
33 | # connection tracking, helpers and protocols | ||
37 | config IP_NF_CT_ACCT | 34 | config IP_NF_CT_ACCT |
38 | bool "Connection tracking flow accounting" | 35 | bool "Connection tracking flow accounting" |
39 | depends on IP_NF_CONNTRACK | 36 | depends on IP_NF_CONNTRACK |
@@ -315,20 +312,6 @@ config IP_NF_MATCH_ADDRTYPE | |||
315 | If you want to compile it as a module, say M here and read | 312 | If you want to compile it as a module, say M here and read |
316 | <file:Documentation/modules.txt>. If unsure, say `N'. | 313 | <file:Documentation/modules.txt>. If unsure, say `N'. |
317 | 314 | ||
318 | config IP_NF_MATCH_HASHLIMIT | ||
319 | tristate 'hashlimit match support' | ||
320 | depends on IP_NF_IPTABLES | ||
321 | help | ||
322 | This option adds a new iptables `hashlimit' match. | ||
323 | |||
324 | As opposed to `limit', this match dynamically creates a hash table | ||
325 | of limit buckets, based on your selection of source/destination | ||
326 | ip addresses and/or ports. | ||
327 | |||
328 | It enables you to express policies like `10kpps for any given | ||
329 | destination IP' or `500pps from any given source IP' with a single | ||
330 | IPtables rule. | ||
331 | |||
332 | # `filter', generic and specific targets | 315 | # `filter', generic and specific targets |
333 | config IP_NF_FILTER | 316 | config IP_NF_FILTER |
334 | tristate "Packet filtering" | 317 | tristate "Packet filtering" |
@@ -404,7 +387,7 @@ config IP_NF_TARGET_TCPMSS | |||
404 | 387 | ||
405 | To compile it as a module, choose M here. If unsure, say N. | 388 | To compile it as a module, choose M here. If unsure, say N. |
406 | 389 | ||
407 | # NAT + specific targets | 390 | # NAT + specific targets: ip_conntrack |
408 | config IP_NF_NAT | 391 | config IP_NF_NAT |
409 | tristate "Full NAT" | 392 | tristate "Full NAT" |
410 | depends on IP_NF_IPTABLES && IP_NF_CONNTRACK | 393 | depends on IP_NF_IPTABLES && IP_NF_CONNTRACK |
@@ -415,14 +398,30 @@ config IP_NF_NAT | |||
415 | 398 | ||
416 | To compile it as a module, choose M here. If unsure, say N. | 399 | To compile it as a module, choose M here. If unsure, say N. |
417 | 400 | ||
401 | # NAT + specific targets: nf_conntrack | ||
402 | config NF_NAT | ||
403 | tristate "Full NAT" | ||
404 | depends on IP_NF_IPTABLES && NF_CONNTRACK | ||
405 | help | ||
406 | The Full NAT option allows masquerading, port forwarding and other | ||
407 | forms of full Network Address Port Translation. It is controlled by | ||
408 | the `nat' table in iptables: see the man page for iptables(8). | ||
409 | |||
410 | To compile it as a module, choose M here. If unsure, say N. | ||
411 | |||
418 | config IP_NF_NAT_NEEDED | 412 | config IP_NF_NAT_NEEDED |
419 | bool | 413 | bool |
420 | depends on IP_NF_NAT != n | 414 | depends on IP_NF_NAT |
415 | default y | ||
416 | |||
417 | config NF_NAT_NEEDED | ||
418 | bool | ||
419 | depends on NF_NAT | ||
421 | default y | 420 | default y |
422 | 421 | ||
423 | config IP_NF_TARGET_MASQUERADE | 422 | config IP_NF_TARGET_MASQUERADE |
424 | tristate "MASQUERADE target support" | 423 | tristate "MASQUERADE target support" |
425 | depends on IP_NF_NAT | 424 | depends on (NF_NAT || IP_NF_NAT) |
426 | help | 425 | help |
427 | Masquerading is a special case of NAT: all outgoing connections are | 426 | Masquerading is a special case of NAT: all outgoing connections are |
428 | changed to seem to come from a particular interface's address, and | 427 | changed to seem to come from a particular interface's address, and |
@@ -434,7 +433,7 @@ config IP_NF_TARGET_MASQUERADE | |||
434 | 433 | ||
435 | config IP_NF_TARGET_REDIRECT | 434 | config IP_NF_TARGET_REDIRECT |
436 | tristate "REDIRECT target support" | 435 | tristate "REDIRECT target support" |
437 | depends on IP_NF_NAT | 436 | depends on (NF_NAT || IP_NF_NAT) |
438 | help | 437 | help |
439 | REDIRECT is a special case of NAT: all incoming connections are | 438 | REDIRECT is a special case of NAT: all incoming connections are |
440 | mapped onto the incoming interface's address, causing the packets to | 439 | mapped onto the incoming interface's address, causing the packets to |
@@ -445,7 +444,7 @@ config IP_NF_TARGET_REDIRECT | |||
445 | 444 | ||
446 | config IP_NF_TARGET_NETMAP | 445 | config IP_NF_TARGET_NETMAP |
447 | tristate "NETMAP target support" | 446 | tristate "NETMAP target support" |
448 | depends on IP_NF_NAT | 447 | depends on (NF_NAT || IP_NF_NAT) |
449 | help | 448 | help |
450 | NETMAP is an implementation of static 1:1 NAT mapping of network | 449 | NETMAP is an implementation of static 1:1 NAT mapping of network |
451 | addresses. It maps the network address part, while keeping the host | 450 | addresses. It maps the network address part, while keeping the host |
@@ -456,7 +455,7 @@ config IP_NF_TARGET_NETMAP | |||
456 | 455 | ||
457 | config IP_NF_TARGET_SAME | 456 | config IP_NF_TARGET_SAME |
458 | tristate "SAME target support" | 457 | tristate "SAME target support" |
459 | depends on IP_NF_NAT | 458 | depends on (NF_NAT || IP_NF_NAT) |
460 | help | 459 | help |
461 | This option adds a `SAME' target, which works like the standard SNAT | 460 | This option adds a `SAME' target, which works like the standard SNAT |
462 | target, but attempts to give clients the same IP for all connections. | 461 | target, but attempts to give clients the same IP for all connections. |
@@ -478,19 +477,52 @@ config IP_NF_NAT_SNMP_BASIC | |||
478 | 477 | ||
479 | To compile it as a module, choose M here. If unsure, say N. | 478 | To compile it as a module, choose M here. If unsure, say N. |
480 | 479 | ||
480 | config NF_NAT_SNMP_BASIC | ||
481 | tristate "Basic SNMP-ALG support (EXPERIMENTAL)" | ||
482 | depends on EXPERIMENTAL && NF_NAT | ||
483 | ---help--- | ||
484 | |||
485 | This module implements an Application Layer Gateway (ALG) for | ||
486 | SNMP payloads. In conjunction with NAT, it allows a network | ||
487 | management system to access multiple private networks with | ||
488 | conflicting addresses. It works by modifying IP addresses | ||
489 | inside SNMP payloads to match IP-layer NAT mapping. | ||
490 | |||
491 | This is the "basic" form of SNMP-ALG, as described in RFC 2962 | ||
492 | |||
493 | To compile it as a module, choose M here. If unsure, say N. | ||
494 | |||
495 | # If they want FTP, set to $CONFIG_IP_NF_NAT (m or y), | ||
496 | # or $CONFIG_IP_NF_FTP (m or y), whichever is weaker. | ||
497 | # From kconfig-language.txt: | ||
498 | # | ||
499 | # <expr> '&&' <expr> (6) | ||
500 | # | ||
501 | # (6) Returns the result of min(/expr/, /expr/). | ||
502 | config NF_NAT_PROTO_GRE | ||
503 | tristate | ||
504 | depends on NF_NAT && NF_CT_PROTO_GRE | ||
505 | |||
506 | config IP_NF_NAT_FTP | ||
507 | tristate | ||
508 | depends on IP_NF_IPTABLES && IP_NF_CONNTRACK && IP_NF_NAT | ||
509 | default IP_NF_NAT && IP_NF_FTP | ||
510 | |||
511 | config NF_NAT_FTP | ||
512 | tristate | ||
513 | depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT | ||
514 | default NF_NAT && NF_CONNTRACK_FTP | ||
515 | |||
481 | config IP_NF_NAT_IRC | 516 | config IP_NF_NAT_IRC |
482 | tristate | 517 | tristate |
483 | depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n | 518 | depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n |
484 | default IP_NF_NAT if IP_NF_IRC=y | 519 | default IP_NF_NAT if IP_NF_IRC=y |
485 | default m if IP_NF_IRC=m | 520 | default m if IP_NF_IRC=m |
486 | 521 | ||
487 | # If they want FTP, set to $CONFIG_IP_NF_NAT (m or y), | 522 | config NF_NAT_IRC |
488 | # or $CONFIG_IP_NF_FTP (m or y), whichever is weaker. Argh. | ||
489 | config IP_NF_NAT_FTP | ||
490 | tristate | 523 | tristate |
491 | depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n | 524 | depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT |
492 | default IP_NF_NAT if IP_NF_FTP=y | 525 | default NF_NAT && NF_CONNTRACK_IRC |
493 | default m if IP_NF_FTP=m | ||
494 | 526 | ||
495 | config IP_NF_NAT_TFTP | 527 | config IP_NF_NAT_TFTP |
496 | tristate | 528 | tristate |
@@ -498,30 +530,56 @@ config IP_NF_NAT_TFTP | |||
498 | default IP_NF_NAT if IP_NF_TFTP=y | 530 | default IP_NF_NAT if IP_NF_TFTP=y |
499 | default m if IP_NF_TFTP=m | 531 | default m if IP_NF_TFTP=m |
500 | 532 | ||
533 | config NF_NAT_TFTP | ||
534 | tristate | ||
535 | depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT | ||
536 | default NF_NAT && NF_CONNTRACK_TFTP | ||
537 | |||
501 | config IP_NF_NAT_AMANDA | 538 | config IP_NF_NAT_AMANDA |
502 | tristate | 539 | tristate |
503 | depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n | 540 | depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n |
504 | default IP_NF_NAT if IP_NF_AMANDA=y | 541 | default IP_NF_NAT if IP_NF_AMANDA=y |
505 | default m if IP_NF_AMANDA=m | 542 | default m if IP_NF_AMANDA=m |
506 | 543 | ||
544 | config NF_NAT_AMANDA | ||
545 | tristate | ||
546 | depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT | ||
547 | default NF_NAT && NF_CONNTRACK_AMANDA | ||
548 | |||
507 | config IP_NF_NAT_PPTP | 549 | config IP_NF_NAT_PPTP |
508 | tristate | 550 | tristate |
509 | depends on IP_NF_NAT!=n && IP_NF_PPTP!=n | 551 | depends on IP_NF_NAT!=n && IP_NF_PPTP!=n |
510 | default IP_NF_NAT if IP_NF_PPTP=y | 552 | default IP_NF_NAT if IP_NF_PPTP=y |
511 | default m if IP_NF_PPTP=m | 553 | default m if IP_NF_PPTP=m |
512 | 554 | ||
555 | config NF_NAT_PPTP | ||
556 | tristate | ||
557 | depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT | ||
558 | default NF_NAT && NF_CONNTRACK_PPTP | ||
559 | select NF_NAT_PROTO_GRE | ||
560 | |||
513 | config IP_NF_NAT_H323 | 561 | config IP_NF_NAT_H323 |
514 | tristate | 562 | tristate |
515 | depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n | 563 | depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n |
516 | default IP_NF_NAT if IP_NF_H323=y | 564 | default IP_NF_NAT if IP_NF_H323=y |
517 | default m if IP_NF_H323=m | 565 | default m if IP_NF_H323=m |
518 | 566 | ||
567 | config NF_NAT_H323 | ||
568 | tristate | ||
569 | depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT | ||
570 | default NF_NAT && NF_CONNTRACK_H323 | ||
571 | |||
519 | config IP_NF_NAT_SIP | 572 | config IP_NF_NAT_SIP |
520 | tristate | 573 | tristate |
521 | depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n | 574 | depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n |
522 | default IP_NF_NAT if IP_NF_SIP=y | 575 | default IP_NF_NAT if IP_NF_SIP=y |
523 | default m if IP_NF_SIP=m | 576 | default m if IP_NF_SIP=m |
524 | 577 | ||
578 | config NF_NAT_SIP | ||
579 | tristate | ||
580 | depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT | ||
581 | default NF_NAT && NF_CONNTRACK_SIP | ||
582 | |||
525 | # mangle + specific targets | 583 | # mangle + specific targets |
526 | config IP_NF_MANGLE | 584 | config IP_NF_MANGLE |
527 | tristate "Packet mangling" | 585 | tristate "Packet mangling" |
diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index 09aaed1a8063..15e741aeb291 100644 --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile | |||
@@ -5,17 +5,23 @@ | |||
5 | # objects for the standalone - connection tracking / NAT | 5 | # objects for the standalone - connection tracking / NAT |
6 | ip_conntrack-objs := ip_conntrack_standalone.o ip_conntrack_core.o ip_conntrack_proto_generic.o ip_conntrack_proto_tcp.o ip_conntrack_proto_udp.o ip_conntrack_proto_icmp.o | 6 | ip_conntrack-objs := ip_conntrack_standalone.o ip_conntrack_core.o ip_conntrack_proto_generic.o ip_conntrack_proto_tcp.o ip_conntrack_proto_udp.o ip_conntrack_proto_icmp.o |
7 | ip_nat-objs := ip_nat_core.o ip_nat_helper.o ip_nat_proto_unknown.o ip_nat_proto_tcp.o ip_nat_proto_udp.o ip_nat_proto_icmp.o | 7 | ip_nat-objs := ip_nat_core.o ip_nat_helper.o ip_nat_proto_unknown.o ip_nat_proto_tcp.o ip_nat_proto_udp.o ip_nat_proto_icmp.o |
8 | nf_nat-objs := nf_nat_core.o nf_nat_helper.o nf_nat_proto_unknown.o nf_nat_proto_tcp.o nf_nat_proto_udp.o nf_nat_proto_icmp.o | ||
9 | ifneq ($(CONFIG_NF_NAT),) | ||
10 | iptable_nat-objs := nf_nat_rule.o nf_nat_standalone.o | ||
11 | else | ||
8 | iptable_nat-objs := ip_nat_rule.o ip_nat_standalone.o | 12 | iptable_nat-objs := ip_nat_rule.o ip_nat_standalone.o |
13 | endif | ||
9 | 14 | ||
10 | ip_conntrack_pptp-objs := ip_conntrack_helper_pptp.o ip_conntrack_proto_gre.o | 15 | ip_conntrack_pptp-objs := ip_conntrack_helper_pptp.o ip_conntrack_proto_gre.o |
11 | ip_nat_pptp-objs := ip_nat_helper_pptp.o ip_nat_proto_gre.o | 16 | ip_nat_pptp-objs := ip_nat_helper_pptp.o ip_nat_proto_gre.o |
12 | 17 | ||
13 | ip_conntrack_h323-objs := ip_conntrack_helper_h323.o ip_conntrack_helper_h323_asn1.o | 18 | ip_conntrack_h323-objs := ip_conntrack_helper_h323.o ../../netfilter/nf_conntrack_h323_asn1.o |
14 | ip_nat_h323-objs := ip_nat_helper_h323.o | 19 | ip_nat_h323-objs := ip_nat_helper_h323.o |
15 | 20 | ||
16 | # connection tracking | 21 | # connection tracking |
17 | obj-$(CONFIG_IP_NF_CONNTRACK) += ip_conntrack.o | 22 | obj-$(CONFIG_IP_NF_CONNTRACK) += ip_conntrack.o |
18 | obj-$(CONFIG_IP_NF_NAT) += ip_nat.o | 23 | obj-$(CONFIG_IP_NF_NAT) += ip_nat.o |
24 | obj-$(CONFIG_NF_NAT) += nf_nat.o | ||
19 | 25 | ||
20 | # conntrack netlink interface | 26 | # conntrack netlink interface |
21 | obj-$(CONFIG_IP_NF_CONNTRACK_NETLINK) += ip_conntrack_netlink.o | 27 | obj-$(CONFIG_IP_NF_CONNTRACK_NETLINK) += ip_conntrack_netlink.o |
@@ -34,7 +40,7 @@ obj-$(CONFIG_IP_NF_IRC) += ip_conntrack_irc.o | |||
34 | obj-$(CONFIG_IP_NF_SIP) += ip_conntrack_sip.o | 40 | obj-$(CONFIG_IP_NF_SIP) += ip_conntrack_sip.o |
35 | obj-$(CONFIG_IP_NF_NETBIOS_NS) += ip_conntrack_netbios_ns.o | 41 | obj-$(CONFIG_IP_NF_NETBIOS_NS) += ip_conntrack_netbios_ns.o |
36 | 42 | ||
37 | # NAT helpers | 43 | # NAT helpers (ip_conntrack) |
38 | obj-$(CONFIG_IP_NF_NAT_H323) += ip_nat_h323.o | 44 | obj-$(CONFIG_IP_NF_NAT_H323) += ip_nat_h323.o |
39 | obj-$(CONFIG_IP_NF_NAT_PPTP) += ip_nat_pptp.o | 45 | obj-$(CONFIG_IP_NF_NAT_PPTP) += ip_nat_pptp.o |
40 | obj-$(CONFIG_IP_NF_NAT_AMANDA) += ip_nat_amanda.o | 46 | obj-$(CONFIG_IP_NF_NAT_AMANDA) += ip_nat_amanda.o |
@@ -43,6 +49,19 @@ obj-$(CONFIG_IP_NF_NAT_FTP) += ip_nat_ftp.o | |||
43 | obj-$(CONFIG_IP_NF_NAT_IRC) += ip_nat_irc.o | 49 | obj-$(CONFIG_IP_NF_NAT_IRC) += ip_nat_irc.o |
44 | obj-$(CONFIG_IP_NF_NAT_SIP) += ip_nat_sip.o | 50 | obj-$(CONFIG_IP_NF_NAT_SIP) += ip_nat_sip.o |
45 | 51 | ||
52 | # NAT helpers (nf_conntrack) | ||
53 | obj-$(CONFIG_NF_NAT_AMANDA) += nf_nat_amanda.o | ||
54 | obj-$(CONFIG_NF_NAT_FTP) += nf_nat_ftp.o | ||
55 | obj-$(CONFIG_NF_NAT_H323) += nf_nat_h323.o | ||
56 | obj-$(CONFIG_NF_NAT_IRC) += nf_nat_irc.o | ||
57 | obj-$(CONFIG_NF_NAT_PPTP) += nf_nat_pptp.o | ||
58 | obj-$(CONFIG_NF_NAT_SIP) += nf_nat_sip.o | ||
59 | obj-$(CONFIG_NF_NAT_SNMP_BASIC) += nf_nat_snmp_basic.o | ||
60 | obj-$(CONFIG_NF_NAT_TFTP) += nf_nat_tftp.o | ||
61 | |||
62 | # NAT protocols (nf_nat) | ||
63 | obj-$(CONFIG_NF_NAT_PROTO_GRE) += nf_nat_proto_gre.o | ||
64 | |||
46 | # generic IP tables | 65 | # generic IP tables |
47 | obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o | 66 | obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o |
48 | 67 | ||
@@ -50,10 +69,10 @@ obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o | |||
50 | obj-$(CONFIG_IP_NF_FILTER) += iptable_filter.o | 69 | obj-$(CONFIG_IP_NF_FILTER) += iptable_filter.o |
51 | obj-$(CONFIG_IP_NF_MANGLE) += iptable_mangle.o | 70 | obj-$(CONFIG_IP_NF_MANGLE) += iptable_mangle.o |
52 | obj-$(CONFIG_IP_NF_NAT) += iptable_nat.o | 71 | obj-$(CONFIG_IP_NF_NAT) += iptable_nat.o |
72 | obj-$(CONFIG_NF_NAT) += iptable_nat.o | ||
53 | obj-$(CONFIG_IP_NF_RAW) += iptable_raw.o | 73 | obj-$(CONFIG_IP_NF_RAW) += iptable_raw.o |
54 | 74 | ||
55 | # matches | 75 | # matches |
56 | obj-$(CONFIG_IP_NF_MATCH_HASHLIMIT) += ipt_hashlimit.o | ||
57 | obj-$(CONFIG_IP_NF_MATCH_IPRANGE) += ipt_iprange.o | 76 | obj-$(CONFIG_IP_NF_MATCH_IPRANGE) += ipt_iprange.o |
58 | obj-$(CONFIG_IP_NF_MATCH_OWNER) += ipt_owner.o | 77 | obj-$(CONFIG_IP_NF_MATCH_OWNER) += ipt_owner.o |
59 | obj-$(CONFIG_IP_NF_MATCH_TOS) += ipt_tos.o | 78 | obj-$(CONFIG_IP_NF_MATCH_TOS) += ipt_tos.o |
@@ -89,6 +108,11 @@ obj-$(CONFIG_IP_NF_QUEUE) += ip_queue.o | |||
89 | 108 | ||
90 | # objects for l3 independent conntrack | 109 | # objects for l3 independent conntrack |
91 | nf_conntrack_ipv4-objs := nf_conntrack_l3proto_ipv4.o nf_conntrack_proto_icmp.o | 110 | nf_conntrack_ipv4-objs := nf_conntrack_l3proto_ipv4.o nf_conntrack_proto_icmp.o |
111 | ifeq ($(CONFIG_NF_CONNTRACK_PROC_COMPAT),y) | ||
112 | ifeq ($(CONFIG_PROC_FS),y) | ||
113 | nf_conntrack_ipv4-objs += nf_conntrack_l3proto_ipv4_compat.o | ||
114 | endif | ||
115 | endif | ||
92 | 116 | ||
93 | # l3 independent conntrack | 117 | # l3 independent conntrack |
94 | obj-$(CONFIG_NF_CONNTRACK_IPV4) += nf_conntrack_ipv4.o | 118 | obj-$(CONFIG_NF_CONNTRACK_IPV4) += nf_conntrack_ipv4.o |
diff --git a/net/ipv4/netfilter/ip_conntrack_amanda.c b/net/ipv4/netfilter/ip_conntrack_amanda.c index 6c7383a8e42b..ad246ba7790b 100644 --- a/net/ipv4/netfilter/ip_conntrack_amanda.c +++ b/net/ipv4/netfilter/ip_conntrack_amanda.c | |||
@@ -92,6 +92,7 @@ static int help(struct sk_buff **pskb, | |||
92 | char pbuf[sizeof("65535")], *tmp; | 92 | char pbuf[sizeof("65535")], *tmp; |
93 | u_int16_t port, len; | 93 | u_int16_t port, len; |
94 | int ret = NF_ACCEPT; | 94 | int ret = NF_ACCEPT; |
95 | typeof(ip_nat_amanda_hook) ip_nat_amanda; | ||
95 | 96 | ||
96 | /* Only look at packets from the Amanda server */ | 97 | /* Only look at packets from the Amanda server */ |
97 | if (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) | 98 | if (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) |
@@ -161,9 +162,11 @@ static int help(struct sk_buff **pskb, | |||
161 | exp->mask.dst.protonum = 0xFF; | 162 | exp->mask.dst.protonum = 0xFF; |
162 | exp->mask.dst.u.tcp.port = htons(0xFFFF); | 163 | exp->mask.dst.u.tcp.port = htons(0xFFFF); |
163 | 164 | ||
164 | if (ip_nat_amanda_hook) | 165 | /* RCU read locked by nf_hook_slow */ |
165 | ret = ip_nat_amanda_hook(pskb, ctinfo, off - dataoff, | 166 | ip_nat_amanda = rcu_dereference(ip_nat_amanda_hook); |
166 | len, exp); | 167 | if (ip_nat_amanda) |
168 | ret = ip_nat_amanda(pskb, ctinfo, off - dataoff, | ||
169 | len, exp); | ||
167 | else if (ip_conntrack_expect_related(exp) != 0) | 170 | else if (ip_conntrack_expect_related(exp) != 0) |
168 | ret = NF_DROP; | 171 | ret = NF_DROP; |
169 | ip_conntrack_expect_put(exp); | 172 | ip_conntrack_expect_put(exp); |
@@ -180,7 +183,7 @@ static struct ip_conntrack_helper amanda_helper = { | |||
180 | .help = help, | 183 | .help = help, |
181 | .name = "amanda", | 184 | .name = "amanda", |
182 | 185 | ||
183 | .tuple = { .src = { .u = { __constant_htons(10080) } }, | 186 | .tuple = { .src = { .u = { .udp = {.port = __constant_htons(10080) } } }, |
184 | .dst = { .protonum = IPPROTO_UDP }, | 187 | .dst = { .protonum = IPPROTO_UDP }, |
185 | }, | 188 | }, |
186 | .mask = { .src = { .u = { 0xFFFF } }, | 189 | .mask = { .src = { .u = { 0xFFFF } }, |
diff --git a/net/ipv4/netfilter/ip_conntrack_core.c b/net/ipv4/netfilter/ip_conntrack_core.c index 143c4668538b..f4b0e68a16d2 100644 --- a/net/ipv4/netfilter/ip_conntrack_core.c +++ b/net/ipv4/netfilter/ip_conntrack_core.c | |||
@@ -40,9 +40,6 @@ | |||
40 | 40 | ||
41 | /* ip_conntrack_lock protects the main hash table, protocol/helper/expected | 41 | /* ip_conntrack_lock protects the main hash table, protocol/helper/expected |
42 | registrations, conntrack timers*/ | 42 | registrations, conntrack timers*/ |
43 | #define ASSERT_READ_LOCK(x) | ||
44 | #define ASSERT_WRITE_LOCK(x) | ||
45 | |||
46 | #include <linux/netfilter_ipv4/ip_conntrack.h> | 43 | #include <linux/netfilter_ipv4/ip_conntrack.h> |
47 | #include <linux/netfilter_ipv4/ip_conntrack_protocol.h> | 44 | #include <linux/netfilter_ipv4/ip_conntrack_protocol.h> |
48 | #include <linux/netfilter_ipv4/ip_conntrack_helper.h> | 45 | #include <linux/netfilter_ipv4/ip_conntrack_helper.h> |
@@ -201,7 +198,6 @@ ip_ct_invert_tuple(struct ip_conntrack_tuple *inverse, | |||
201 | /* ip_conntrack_expect helper functions */ | 198 | /* ip_conntrack_expect helper functions */ |
202 | void ip_ct_unlink_expect(struct ip_conntrack_expect *exp) | 199 | void ip_ct_unlink_expect(struct ip_conntrack_expect *exp) |
203 | { | 200 | { |
204 | ASSERT_WRITE_LOCK(&ip_conntrack_lock); | ||
205 | IP_NF_ASSERT(!timer_pending(&exp->timeout)); | 201 | IP_NF_ASSERT(!timer_pending(&exp->timeout)); |
206 | list_del(&exp->list); | 202 | list_del(&exp->list); |
207 | CONNTRACK_STAT_INC(expect_delete); | 203 | CONNTRACK_STAT_INC(expect_delete); |
@@ -225,22 +221,22 @@ __ip_conntrack_expect_find(const struct ip_conntrack_tuple *tuple) | |||
225 | struct ip_conntrack_expect *i; | 221 | struct ip_conntrack_expect *i; |
226 | 222 | ||
227 | list_for_each_entry(i, &ip_conntrack_expect_list, list) { | 223 | list_for_each_entry(i, &ip_conntrack_expect_list, list) { |
228 | if (ip_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask)) { | 224 | if (ip_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask)) |
229 | atomic_inc(&i->use); | ||
230 | return i; | 225 | return i; |
231 | } | ||
232 | } | 226 | } |
233 | return NULL; | 227 | return NULL; |
234 | } | 228 | } |
235 | 229 | ||
236 | /* Just find a expectation corresponding to a tuple. */ | 230 | /* Just find a expectation corresponding to a tuple. */ |
237 | struct ip_conntrack_expect * | 231 | struct ip_conntrack_expect * |
238 | ip_conntrack_expect_find(const struct ip_conntrack_tuple *tuple) | 232 | ip_conntrack_expect_find_get(const struct ip_conntrack_tuple *tuple) |
239 | { | 233 | { |
240 | struct ip_conntrack_expect *i; | 234 | struct ip_conntrack_expect *i; |
241 | 235 | ||
242 | read_lock_bh(&ip_conntrack_lock); | 236 | read_lock_bh(&ip_conntrack_lock); |
243 | i = __ip_conntrack_expect_find(tuple); | 237 | i = __ip_conntrack_expect_find(tuple); |
238 | if (i) | ||
239 | atomic_inc(&i->use); | ||
244 | read_unlock_bh(&ip_conntrack_lock); | 240 | read_unlock_bh(&ip_conntrack_lock); |
245 | 241 | ||
246 | return i; | 242 | return i; |
@@ -294,7 +290,6 @@ static void | |||
294 | clean_from_lists(struct ip_conntrack *ct) | 290 | clean_from_lists(struct ip_conntrack *ct) |
295 | { | 291 | { |
296 | DEBUGP("clean_from_lists(%p)\n", ct); | 292 | DEBUGP("clean_from_lists(%p)\n", ct); |
297 | ASSERT_WRITE_LOCK(&ip_conntrack_lock); | ||
298 | list_del(&ct->tuplehash[IP_CT_DIR_ORIGINAL].list); | 293 | list_del(&ct->tuplehash[IP_CT_DIR_ORIGINAL].list); |
299 | list_del(&ct->tuplehash[IP_CT_DIR_REPLY].list); | 294 | list_del(&ct->tuplehash[IP_CT_DIR_REPLY].list); |
300 | 295 | ||
@@ -373,7 +368,6 @@ __ip_conntrack_find(const struct ip_conntrack_tuple *tuple, | |||
373 | struct ip_conntrack_tuple_hash *h; | 368 | struct ip_conntrack_tuple_hash *h; |
374 | unsigned int hash = hash_conntrack(tuple); | 369 | unsigned int hash = hash_conntrack(tuple); |
375 | 370 | ||
376 | ASSERT_READ_LOCK(&ip_conntrack_lock); | ||
377 | list_for_each_entry(h, &ip_conntrack_hash[hash], list) { | 371 | list_for_each_entry(h, &ip_conntrack_hash[hash], list) { |
378 | if (tuplehash_to_ctrack(h) != ignored_conntrack && | 372 | if (tuplehash_to_ctrack(h) != ignored_conntrack && |
379 | ip_ct_tuple_equal(tuple, &h->tuple)) { | 373 | ip_ct_tuple_equal(tuple, &h->tuple)) { |
diff --git a/net/ipv4/netfilter/ip_conntrack_ftp.c b/net/ipv4/netfilter/ip_conntrack_ftp.c index 93dcf960662f..0410c99cacae 100644 --- a/net/ipv4/netfilter/ip_conntrack_ftp.c +++ b/net/ipv4/netfilter/ip_conntrack_ftp.c | |||
@@ -310,6 +310,7 @@ static int help(struct sk_buff **pskb, | |||
310 | struct ip_conntrack_expect *exp; | 310 | struct ip_conntrack_expect *exp; |
311 | unsigned int i; | 311 | unsigned int i; |
312 | int found = 0, ends_in_nl; | 312 | int found = 0, ends_in_nl; |
313 | typeof(ip_nat_ftp_hook) ip_nat_ftp; | ||
313 | 314 | ||
314 | /* Until there's been traffic both ways, don't look in packets. */ | 315 | /* Until there's been traffic both ways, don't look in packets. */ |
315 | if (ctinfo != IP_CT_ESTABLISHED | 316 | if (ctinfo != IP_CT_ESTABLISHED |
@@ -433,9 +434,10 @@ static int help(struct sk_buff **pskb, | |||
433 | 434 | ||
434 | /* Now, NAT might want to mangle the packet, and register the | 435 | /* Now, NAT might want to mangle the packet, and register the |
435 | * (possibly changed) expectation itself. */ | 436 | * (possibly changed) expectation itself. */ |
436 | if (ip_nat_ftp_hook) | 437 | ip_nat_ftp = rcu_dereference(ip_nat_ftp_hook); |
437 | ret = ip_nat_ftp_hook(pskb, ctinfo, search[dir][i].ftptype, | 438 | if (ip_nat_ftp) |
438 | matchoff, matchlen, exp, &seq); | 439 | ret = ip_nat_ftp(pskb, ctinfo, search[dir][i].ftptype, |
440 | matchoff, matchlen, exp, &seq); | ||
439 | else { | 441 | else { |
440 | /* Can't expect this? Best to drop packet now. */ | 442 | /* Can't expect this? Best to drop packet now. */ |
441 | if (ip_conntrack_expect_related(exp) != 0) | 443 | if (ip_conntrack_expect_related(exp) != 0) |
diff --git a/net/ipv4/netfilter/ip_conntrack_helper_h323.c b/net/ipv4/netfilter/ip_conntrack_helper_h323.c index 7b7441202bfd..aabfe1c06905 100644 --- a/net/ipv4/netfilter/ip_conntrack_helper_h323.c +++ b/net/ipv4/netfilter/ip_conntrack_helper_h323.c | |||
@@ -237,6 +237,7 @@ static int expect_rtp_rtcp(struct sk_buff **pskb, struct ip_conntrack *ct, | |||
237 | u_int16_t rtp_port; | 237 | u_int16_t rtp_port; |
238 | struct ip_conntrack_expect *rtp_exp; | 238 | struct ip_conntrack_expect *rtp_exp; |
239 | struct ip_conntrack_expect *rtcp_exp; | 239 | struct ip_conntrack_expect *rtcp_exp; |
240 | typeof(nat_rtp_rtcp_hook) nat_rtp_rtcp; | ||
240 | 241 | ||
241 | /* Read RTP or RTCP address */ | 242 | /* Read RTP or RTCP address */ |
242 | if (!get_h245_addr(*data, addr, &ip, &port) || | 243 | if (!get_h245_addr(*data, addr, &ip, &port) || |
@@ -279,11 +280,11 @@ static int expect_rtp_rtcp(struct sk_buff **pskb, struct ip_conntrack *ct, | |||
279 | rtcp_exp->flags = 0; | 280 | rtcp_exp->flags = 0; |
280 | 281 | ||
281 | if (ct->tuplehash[dir].tuple.src.ip != | 282 | if (ct->tuplehash[dir].tuple.src.ip != |
282 | ct->tuplehash[!dir].tuple.dst.ip && nat_rtp_rtcp_hook) { | 283 | ct->tuplehash[!dir].tuple.dst.ip && |
284 | (nat_rtp_rtcp = rcu_dereference(nat_rtp_rtcp_hook))) { | ||
283 | /* NAT needed */ | 285 | /* NAT needed */ |
284 | ret = nat_rtp_rtcp_hook(pskb, ct, ctinfo, data, dataoff, | 286 | ret = nat_rtp_rtcp(pskb, ct, ctinfo, data, dataoff, |
285 | addr, port, rtp_port, rtp_exp, | 287 | addr, port, rtp_port, rtp_exp, rtcp_exp); |
286 | rtcp_exp); | ||
287 | } else { /* Conntrack only */ | 288 | } else { /* Conntrack only */ |
288 | rtp_exp->expectfn = NULL; | 289 | rtp_exp->expectfn = NULL; |
289 | rtcp_exp->expectfn = NULL; | 290 | rtcp_exp->expectfn = NULL; |
@@ -328,6 +329,7 @@ static int expect_t120(struct sk_buff **pskb, | |||
328 | __be32 ip; | 329 | __be32 ip; |
329 | u_int16_t port; | 330 | u_int16_t port; |
330 | struct ip_conntrack_expect *exp = NULL; | 331 | struct ip_conntrack_expect *exp = NULL; |
332 | typeof(nat_t120_hook) nat_t120; | ||
331 | 333 | ||
332 | /* Read T.120 address */ | 334 | /* Read T.120 address */ |
333 | if (!get_h245_addr(*data, addr, &ip, &port) || | 335 | if (!get_h245_addr(*data, addr, &ip, &port) || |
@@ -350,10 +352,11 @@ static int expect_t120(struct sk_buff **pskb, | |||
350 | exp->flags = IP_CT_EXPECT_PERMANENT; /* Accept multiple channels */ | 352 | exp->flags = IP_CT_EXPECT_PERMANENT; /* Accept multiple channels */ |
351 | 353 | ||
352 | if (ct->tuplehash[dir].tuple.src.ip != | 354 | if (ct->tuplehash[dir].tuple.src.ip != |
353 | ct->tuplehash[!dir].tuple.dst.ip && nat_t120_hook) { | 355 | ct->tuplehash[!dir].tuple.dst.ip && |
356 | (nat_t120 = rcu_dereference(nat_t120_hook))) { | ||
354 | /* NAT needed */ | 357 | /* NAT needed */ |
355 | ret = nat_t120_hook(pskb, ct, ctinfo, data, dataoff, addr, | 358 | ret = nat_t120(pskb, ct, ctinfo, data, dataoff, addr, |
356 | port, exp); | 359 | port, exp); |
357 | } else { /* Conntrack only */ | 360 | } else { /* Conntrack only */ |
358 | exp->expectfn = NULL; | 361 | exp->expectfn = NULL; |
359 | if (ip_conntrack_expect_related(exp) == 0) { | 362 | if (ip_conntrack_expect_related(exp) == 0) { |
@@ -651,6 +654,7 @@ static int expect_h245(struct sk_buff **pskb, struct ip_conntrack *ct, | |||
651 | __be32 ip; | 654 | __be32 ip; |
652 | u_int16_t port; | 655 | u_int16_t port; |
653 | struct ip_conntrack_expect *exp = NULL; | 656 | struct ip_conntrack_expect *exp = NULL; |
657 | typeof(nat_h245_hook) nat_h245; | ||
654 | 658 | ||
655 | /* Read h245Address */ | 659 | /* Read h245Address */ |
656 | if (!get_h225_addr(*data, addr, &ip, &port) || | 660 | if (!get_h225_addr(*data, addr, &ip, &port) || |
@@ -673,10 +677,11 @@ static int expect_h245(struct sk_buff **pskb, struct ip_conntrack *ct, | |||
673 | exp->flags = 0; | 677 | exp->flags = 0; |
674 | 678 | ||
675 | if (ct->tuplehash[dir].tuple.src.ip != | 679 | if (ct->tuplehash[dir].tuple.src.ip != |
676 | ct->tuplehash[!dir].tuple.dst.ip && nat_h245_hook) { | 680 | ct->tuplehash[!dir].tuple.dst.ip && |
681 | (nat_h245 = rcu_dereference(nat_h245_hook))) { | ||
677 | /* NAT needed */ | 682 | /* NAT needed */ |
678 | ret = nat_h245_hook(pskb, ct, ctinfo, data, dataoff, addr, | 683 | ret = nat_h245(pskb, ct, ctinfo, data, dataoff, addr, |
679 | port, exp); | 684 | port, exp); |
680 | } else { /* Conntrack only */ | 685 | } else { /* Conntrack only */ |
681 | exp->expectfn = ip_conntrack_h245_expect; | 686 | exp->expectfn = ip_conntrack_h245_expect; |
682 | 687 | ||
@@ -712,6 +717,7 @@ static int expect_callforwarding(struct sk_buff **pskb, | |||
712 | __be32 ip; | 717 | __be32 ip; |
713 | u_int16_t port; | 718 | u_int16_t port; |
714 | struct ip_conntrack_expect *exp = NULL; | 719 | struct ip_conntrack_expect *exp = NULL; |
720 | typeof(nat_callforwarding_hook) nat_callforwarding; | ||
715 | 721 | ||
716 | /* Read alternativeAddress */ | 722 | /* Read alternativeAddress */ |
717 | if (!get_h225_addr(*data, addr, &ip, &port) || port == 0) | 723 | if (!get_h225_addr(*data, addr, &ip, &port) || port == 0) |
@@ -759,10 +765,11 @@ static int expect_callforwarding(struct sk_buff **pskb, | |||
759 | exp->flags = 0; | 765 | exp->flags = 0; |
760 | 766 | ||
761 | if (ct->tuplehash[dir].tuple.src.ip != | 767 | if (ct->tuplehash[dir].tuple.src.ip != |
762 | ct->tuplehash[!dir].tuple.dst.ip && nat_callforwarding_hook) { | 768 | ct->tuplehash[!dir].tuple.dst.ip && |
769 | (nat_callforwarding = rcu_dereference(nat_callforwarding_hook))) { | ||
763 | /* Need NAT */ | 770 | /* Need NAT */ |
764 | ret = nat_callforwarding_hook(pskb, ct, ctinfo, data, dataoff, | 771 | ret = nat_callforwarding(pskb, ct, ctinfo, data, dataoff, |
765 | addr, port, exp); | 772 | addr, port, exp); |
766 | } else { /* Conntrack only */ | 773 | } else { /* Conntrack only */ |
767 | exp->expectfn = ip_conntrack_q931_expect; | 774 | exp->expectfn = ip_conntrack_q931_expect; |
768 | 775 | ||
@@ -793,6 +800,7 @@ static int process_setup(struct sk_buff **pskb, struct ip_conntrack *ct, | |||
793 | int i; | 800 | int i; |
794 | __be32 ip; | 801 | __be32 ip; |
795 | u_int16_t port; | 802 | u_int16_t port; |
803 | typeof(set_h225_addr_hook) set_h225_addr; | ||
796 | 804 | ||
797 | DEBUGP("ip_ct_q931: Setup\n"); | 805 | DEBUGP("ip_ct_q931: Setup\n"); |
798 | 806 | ||
@@ -803,8 +811,10 @@ static int process_setup(struct sk_buff **pskb, struct ip_conntrack *ct, | |||
803 | return -1; | 811 | return -1; |
804 | } | 812 | } |
805 | 813 | ||
814 | set_h225_addr = rcu_dereference(set_h225_addr_hook); | ||
815 | |||
806 | if ((setup->options & eSetup_UUIE_destCallSignalAddress) && | 816 | if ((setup->options & eSetup_UUIE_destCallSignalAddress) && |
807 | (set_h225_addr_hook) && | 817 | (set_h225_addr) && |
808 | get_h225_addr(*data, &setup->destCallSignalAddress, &ip, &port) && | 818 | get_h225_addr(*data, &setup->destCallSignalAddress, &ip, &port) && |
809 | ip != ct->tuplehash[!dir].tuple.src.ip) { | 819 | ip != ct->tuplehash[!dir].tuple.src.ip) { |
810 | DEBUGP("ip_ct_q931: set destCallSignalAddress " | 820 | DEBUGP("ip_ct_q931: set destCallSignalAddress " |
@@ -812,17 +822,17 @@ static int process_setup(struct sk_buff **pskb, struct ip_conntrack *ct, | |||
812 | NIPQUAD(ip), port, | 822 | NIPQUAD(ip), port, |
813 | NIPQUAD(ct->tuplehash[!dir].tuple.src.ip), | 823 | NIPQUAD(ct->tuplehash[!dir].tuple.src.ip), |
814 | ntohs(ct->tuplehash[!dir].tuple.src.u.tcp.port)); | 824 | ntohs(ct->tuplehash[!dir].tuple.src.u.tcp.port)); |
815 | ret = set_h225_addr_hook(pskb, data, dataoff, | 825 | ret = set_h225_addr(pskb, data, dataoff, |
816 | &setup->destCallSignalAddress, | 826 | &setup->destCallSignalAddress, |
817 | ct->tuplehash[!dir].tuple.src.ip, | 827 | ct->tuplehash[!dir].tuple.src.ip, |
818 | ntohs(ct->tuplehash[!dir].tuple.src. | 828 | ntohs(ct->tuplehash[!dir].tuple.src. |
819 | u.tcp.port)); | 829 | u.tcp.port)); |
820 | if (ret < 0) | 830 | if (ret < 0) |
821 | return -1; | 831 | return -1; |
822 | } | 832 | } |
823 | 833 | ||
824 | if ((setup->options & eSetup_UUIE_sourceCallSignalAddress) && | 834 | if ((setup->options & eSetup_UUIE_sourceCallSignalAddress) && |
825 | (set_h225_addr_hook) && | 835 | (set_h225_addr) && |
826 | get_h225_addr(*data, &setup->sourceCallSignalAddress, &ip, &port) | 836 | get_h225_addr(*data, &setup->sourceCallSignalAddress, &ip, &port) |
827 | && ip != ct->tuplehash[!dir].tuple.dst.ip) { | 837 | && ip != ct->tuplehash[!dir].tuple.dst.ip) { |
828 | DEBUGP("ip_ct_q931: set sourceCallSignalAddress " | 838 | DEBUGP("ip_ct_q931: set sourceCallSignalAddress " |
@@ -830,11 +840,11 @@ static int process_setup(struct sk_buff **pskb, struct ip_conntrack *ct, | |||
830 | NIPQUAD(ip), port, | 840 | NIPQUAD(ip), port, |
831 | NIPQUAD(ct->tuplehash[!dir].tuple.dst.ip), | 841 | NIPQUAD(ct->tuplehash[!dir].tuple.dst.ip), |
832 | ntohs(ct->tuplehash[!dir].tuple.dst.u.tcp.port)); | 842 | ntohs(ct->tuplehash[!dir].tuple.dst.u.tcp.port)); |
833 | ret = set_h225_addr_hook(pskb, data, dataoff, | 843 | ret = set_h225_addr(pskb, data, dataoff, |
834 | &setup->sourceCallSignalAddress, | 844 | &setup->sourceCallSignalAddress, |
835 | ct->tuplehash[!dir].tuple.dst.ip, | 845 | ct->tuplehash[!dir].tuple.dst.ip, |
836 | ntohs(ct->tuplehash[!dir].tuple.dst. | 846 | ntohs(ct->tuplehash[!dir].tuple.dst. |
837 | u.tcp.port)); | 847 | u.tcp.port)); |
838 | if (ret < 0) | 848 | if (ret < 0) |
839 | return -1; | 849 | return -1; |
840 | } | 850 | } |
@@ -1153,7 +1163,7 @@ static struct ip_conntrack_helper ip_conntrack_helper_q931 = { | |||
1153 | .me = THIS_MODULE, | 1163 | .me = THIS_MODULE, |
1154 | .max_expected = H323_RTP_CHANNEL_MAX * 4 + 4 /* T.120 and H.245 */ , | 1164 | .max_expected = H323_RTP_CHANNEL_MAX * 4 + 4 /* T.120 and H.245 */ , |
1155 | .timeout = 240, | 1165 | .timeout = 240, |
1156 | .tuple = {.src = {.u = {__constant_htons(Q931_PORT)}}, | 1166 | .tuple = {.src = {.u = {.tcp = {.port = __constant_htons(Q931_PORT)}}}, |
1157 | .dst = {.protonum = IPPROTO_TCP}}, | 1167 | .dst = {.protonum = IPPROTO_TCP}}, |
1158 | .mask = {.src = {.u = {0xFFFF}}, | 1168 | .mask = {.src = {.u = {0xFFFF}}, |
1159 | .dst = {.protonum = 0xFF}}, | 1169 | .dst = {.protonum = 0xFF}}, |
@@ -1231,6 +1241,7 @@ static int expect_q931(struct sk_buff **pskb, struct ip_conntrack *ct, | |||
1231 | __be32 ip; | 1241 | __be32 ip; |
1232 | u_int16_t port; | 1242 | u_int16_t port; |
1233 | struct ip_conntrack_expect *exp; | 1243 | struct ip_conntrack_expect *exp; |
1244 | typeof(nat_q931_hook) nat_q931; | ||
1234 | 1245 | ||
1235 | /* Look for the first related address */ | 1246 | /* Look for the first related address */ |
1236 | for (i = 0; i < count; i++) { | 1247 | for (i = 0; i < count; i++) { |
@@ -1258,9 +1269,9 @@ static int expect_q931(struct sk_buff **pskb, struct ip_conntrack *ct, | |||
1258 | exp->mask.dst.protonum = 0xFF; | 1269 | exp->mask.dst.protonum = 0xFF; |
1259 | exp->flags = IP_CT_EXPECT_PERMANENT; /* Accept multiple calls */ | 1270 | exp->flags = IP_CT_EXPECT_PERMANENT; /* Accept multiple calls */ |
1260 | 1271 | ||
1261 | if (nat_q931_hook) { /* Need NAT */ | 1272 | nat_q931 = rcu_dereference(nat_q931_hook); |
1262 | ret = nat_q931_hook(pskb, ct, ctinfo, data, addr, i, | 1273 | if (nat_q931) { /* Need NAT */ |
1263 | port, exp); | 1274 | ret = nat_q931(pskb, ct, ctinfo, data, addr, i, port, exp); |
1264 | } else { /* Conntrack only */ | 1275 | } else { /* Conntrack only */ |
1265 | exp->expectfn = ip_conntrack_q931_expect; | 1276 | exp->expectfn = ip_conntrack_q931_expect; |
1266 | 1277 | ||
@@ -1288,11 +1299,14 @@ static int process_grq(struct sk_buff **pskb, struct ip_conntrack *ct, | |||
1288 | enum ip_conntrack_info ctinfo, | 1299 | enum ip_conntrack_info ctinfo, |
1289 | unsigned char **data, GatekeeperRequest * grq) | 1300 | unsigned char **data, GatekeeperRequest * grq) |
1290 | { | 1301 | { |
1302 | typeof(set_ras_addr_hook) set_ras_addr; | ||
1303 | |||
1291 | DEBUGP("ip_ct_ras: GRQ\n"); | 1304 | DEBUGP("ip_ct_ras: GRQ\n"); |
1292 | 1305 | ||
1293 | if (set_ras_addr_hook) /* NATed */ | 1306 | set_ras_addr = rcu_dereference(set_ras_addr_hook); |
1294 | return set_ras_addr_hook(pskb, ct, ctinfo, data, | 1307 | if (set_ras_addr) /* NATed */ |
1295 | &grq->rasAddress, 1); | 1308 | return set_ras_addr(pskb, ct, ctinfo, data, |
1309 | &grq->rasAddress, 1); | ||
1296 | return 0; | 1310 | return 0; |
1297 | } | 1311 | } |
1298 | 1312 | ||
@@ -1362,6 +1376,7 @@ static int process_rrq(struct sk_buff **pskb, struct ip_conntrack *ct, | |||
1362 | { | 1376 | { |
1363 | struct ip_ct_h323_master *info = &ct->help.ct_h323_info; | 1377 | struct ip_ct_h323_master *info = &ct->help.ct_h323_info; |
1364 | int ret; | 1378 | int ret; |
1379 | typeof(set_ras_addr_hook) set_ras_addr; | ||
1365 | 1380 | ||
1366 | DEBUGP("ip_ct_ras: RRQ\n"); | 1381 | DEBUGP("ip_ct_ras: RRQ\n"); |
1367 | 1382 | ||
@@ -1371,10 +1386,11 @@ static int process_rrq(struct sk_buff **pskb, struct ip_conntrack *ct, | |||
1371 | if (ret < 0) | 1386 | if (ret < 0) |
1372 | return -1; | 1387 | return -1; |
1373 | 1388 | ||
1374 | if (set_ras_addr_hook) { | 1389 | set_ras_addr = rcu_dereference(set_ras_addr_hook); |
1375 | ret = set_ras_addr_hook(pskb, ct, ctinfo, data, | 1390 | if (set_ras_addr) { |
1376 | rrq->rasAddress.item, | 1391 | ret = set_ras_addr(pskb, ct, ctinfo, data, |
1377 | rrq->rasAddress.count); | 1392 | rrq->rasAddress.item, |
1393 | rrq->rasAddress.count); | ||
1378 | if (ret < 0) | 1394 | if (ret < 0) |
1379 | return -1; | 1395 | return -1; |
1380 | } | 1396 | } |
@@ -1397,13 +1413,15 @@ static int process_rcf(struct sk_buff **pskb, struct ip_conntrack *ct, | |||
1397 | int dir = CTINFO2DIR(ctinfo); | 1413 | int dir = CTINFO2DIR(ctinfo); |
1398 | int ret; | 1414 | int ret; |
1399 | struct ip_conntrack_expect *exp; | 1415 | struct ip_conntrack_expect *exp; |
1416 | typeof(set_sig_addr_hook) set_sig_addr; | ||
1400 | 1417 | ||
1401 | DEBUGP("ip_ct_ras: RCF\n"); | 1418 | DEBUGP("ip_ct_ras: RCF\n"); |
1402 | 1419 | ||
1403 | if (set_sig_addr_hook) { | 1420 | set_sig_addr = rcu_dereference(set_sig_addr_hook); |
1404 | ret = set_sig_addr_hook(pskb, ct, ctinfo, data, | 1421 | if (set_sig_addr) { |
1405 | rcf->callSignalAddress.item, | 1422 | ret = set_sig_addr(pskb, ct, ctinfo, data, |
1406 | rcf->callSignalAddress.count); | 1423 | rcf->callSignalAddress.item, |
1424 | rcf->callSignalAddress.count); | ||
1407 | if (ret < 0) | 1425 | if (ret < 0) |
1408 | return -1; | 1426 | return -1; |
1409 | } | 1427 | } |
@@ -1417,7 +1435,7 @@ static int process_rcf(struct sk_buff **pskb, struct ip_conntrack *ct, | |||
1417 | DEBUGP | 1435 | DEBUGP |
1418 | ("ip_ct_ras: set RAS connection timeout to %u seconds\n", | 1436 | ("ip_ct_ras: set RAS connection timeout to %u seconds\n", |
1419 | info->timeout); | 1437 | info->timeout); |
1420 | ip_ct_refresh_acct(ct, ctinfo, NULL, info->timeout * HZ); | 1438 | ip_ct_refresh(ct, *pskb, info->timeout * HZ); |
1421 | 1439 | ||
1422 | /* Set expect timeout */ | 1440 | /* Set expect timeout */ |
1423 | read_lock_bh(&ip_conntrack_lock); | 1441 | read_lock_bh(&ip_conntrack_lock); |
@@ -1448,13 +1466,15 @@ static int process_urq(struct sk_buff **pskb, struct ip_conntrack *ct, | |||
1448 | struct ip_ct_h323_master *info = &ct->help.ct_h323_info; | 1466 | struct ip_ct_h323_master *info = &ct->help.ct_h323_info; |
1449 | int dir = CTINFO2DIR(ctinfo); | 1467 | int dir = CTINFO2DIR(ctinfo); |
1450 | int ret; | 1468 | int ret; |
1469 | typeof(set_sig_addr_hook) set_sig_addr; | ||
1451 | 1470 | ||
1452 | DEBUGP("ip_ct_ras: URQ\n"); | 1471 | DEBUGP("ip_ct_ras: URQ\n"); |
1453 | 1472 | ||
1454 | if (set_sig_addr_hook) { | 1473 | set_sig_addr = rcu_dereference(set_sig_addr_hook); |
1455 | ret = set_sig_addr_hook(pskb, ct, ctinfo, data, | 1474 | if (set_sig_addr) { |
1456 | urq->callSignalAddress.item, | 1475 | ret = set_sig_addr(pskb, ct, ctinfo, data, |
1457 | urq->callSignalAddress.count); | 1476 | urq->callSignalAddress.item, |
1477 | urq->callSignalAddress.count); | ||
1458 | if (ret < 0) | 1478 | if (ret < 0) |
1459 | return -1; | 1479 | return -1; |
1460 | } | 1480 | } |
@@ -1465,7 +1485,7 @@ static int process_urq(struct sk_buff **pskb, struct ip_conntrack *ct, | |||
1465 | info->sig_port[!dir] = 0; | 1485 | info->sig_port[!dir] = 0; |
1466 | 1486 | ||
1467 | /* Give it 30 seconds for UCF or URJ */ | 1487 | /* Give it 30 seconds for UCF or URJ */ |
1468 | ip_ct_refresh_acct(ct, ctinfo, NULL, 30 * HZ); | 1488 | ip_ct_refresh(ct, *pskb, 30 * HZ); |
1469 | 1489 | ||
1470 | return 0; | 1490 | return 0; |
1471 | } | 1491 | } |
@@ -1479,28 +1499,30 @@ static int process_arq(struct sk_buff **pskb, struct ip_conntrack *ct, | |||
1479 | int dir = CTINFO2DIR(ctinfo); | 1499 | int dir = CTINFO2DIR(ctinfo); |
1480 | __be32 ip; | 1500 | __be32 ip; |
1481 | u_int16_t port; | 1501 | u_int16_t port; |
1502 | typeof(set_h225_addr_hook) set_h225_addr; | ||
1482 | 1503 | ||
1483 | DEBUGP("ip_ct_ras: ARQ\n"); | 1504 | DEBUGP("ip_ct_ras: ARQ\n"); |
1484 | 1505 | ||
1506 | set_h225_addr = rcu_dereference(set_h225_addr_hook); | ||
1485 | if ((arq->options & eAdmissionRequest_destCallSignalAddress) && | 1507 | if ((arq->options & eAdmissionRequest_destCallSignalAddress) && |
1486 | get_h225_addr(*data, &arq->destCallSignalAddress, &ip, &port) && | 1508 | get_h225_addr(*data, &arq->destCallSignalAddress, &ip, &port) && |
1487 | ip == ct->tuplehash[dir].tuple.src.ip && | 1509 | ip == ct->tuplehash[dir].tuple.src.ip && |
1488 | port == info->sig_port[dir] && set_h225_addr_hook) { | 1510 | port == info->sig_port[dir] && set_h225_addr) { |
1489 | /* Answering ARQ */ | 1511 | /* Answering ARQ */ |
1490 | return set_h225_addr_hook(pskb, data, 0, | 1512 | return set_h225_addr(pskb, data, 0, |
1491 | &arq->destCallSignalAddress, | 1513 | &arq->destCallSignalAddress, |
1492 | ct->tuplehash[!dir].tuple.dst.ip, | 1514 | ct->tuplehash[!dir].tuple.dst.ip, |
1493 | info->sig_port[!dir]); | 1515 | info->sig_port[!dir]); |
1494 | } | 1516 | } |
1495 | 1517 | ||
1496 | if ((arq->options & eAdmissionRequest_srcCallSignalAddress) && | 1518 | if ((arq->options & eAdmissionRequest_srcCallSignalAddress) && |
1497 | get_h225_addr(*data, &arq->srcCallSignalAddress, &ip, &port) && | 1519 | get_h225_addr(*data, &arq->srcCallSignalAddress, &ip, &port) && |
1498 | ip == ct->tuplehash[dir].tuple.src.ip && set_h225_addr_hook) { | 1520 | ip == ct->tuplehash[dir].tuple.src.ip && set_h225_addr) { |
1499 | /* Calling ARQ */ | 1521 | /* Calling ARQ */ |
1500 | return set_h225_addr_hook(pskb, data, 0, | 1522 | return set_h225_addr(pskb, data, 0, |
1501 | &arq->srcCallSignalAddress, | 1523 | &arq->srcCallSignalAddress, |
1502 | ct->tuplehash[!dir].tuple.dst.ip, | 1524 | ct->tuplehash[!dir].tuple.dst.ip, |
1503 | port); | 1525 | port); |
1504 | } | 1526 | } |
1505 | 1527 | ||
1506 | return 0; | 1528 | return 0; |
@@ -1516,6 +1538,7 @@ static int process_acf(struct sk_buff **pskb, struct ip_conntrack *ct, | |||
1516 | __be32 ip; | 1538 | __be32 ip; |
1517 | u_int16_t port; | 1539 | u_int16_t port; |
1518 | struct ip_conntrack_expect *exp; | 1540 | struct ip_conntrack_expect *exp; |
1541 | typeof(set_sig_addr_hook) set_sig_addr; | ||
1519 | 1542 | ||
1520 | DEBUGP("ip_ct_ras: ACF\n"); | 1543 | DEBUGP("ip_ct_ras: ACF\n"); |
1521 | 1544 | ||
@@ -1523,10 +1546,10 @@ static int process_acf(struct sk_buff **pskb, struct ip_conntrack *ct, | |||
1523 | return 0; | 1546 | return 0; |
1524 | 1547 | ||
1525 | if (ip == ct->tuplehash[dir].tuple.dst.ip) { /* Answering ACF */ | 1548 | if (ip == ct->tuplehash[dir].tuple.dst.ip) { /* Answering ACF */ |
1526 | if (set_sig_addr_hook) | 1549 | set_sig_addr = rcu_dereference(set_sig_addr_hook); |
1527 | return set_sig_addr_hook(pskb, ct, ctinfo, data, | 1550 | if (set_sig_addr) |
1528 | &acf->destCallSignalAddress, | 1551 | return set_sig_addr(pskb, ct, ctinfo, data, |
1529 | 1); | 1552 | &acf->destCallSignalAddress, 1); |
1530 | return 0; | 1553 | return 0; |
1531 | } | 1554 | } |
1532 | 1555 | ||
@@ -1566,11 +1589,14 @@ static int process_lrq(struct sk_buff **pskb, struct ip_conntrack *ct, | |||
1566 | enum ip_conntrack_info ctinfo, | 1589 | enum ip_conntrack_info ctinfo, |
1567 | unsigned char **data, LocationRequest * lrq) | 1590 | unsigned char **data, LocationRequest * lrq) |
1568 | { | 1591 | { |
1592 | typeof(set_ras_addr_hook) set_ras_addr; | ||
1593 | |||
1569 | DEBUGP("ip_ct_ras: LRQ\n"); | 1594 | DEBUGP("ip_ct_ras: LRQ\n"); |
1570 | 1595 | ||
1571 | if (set_ras_addr_hook) | 1596 | set_ras_addr = rcu_dereference(set_ras_addr_hook); |
1572 | return set_ras_addr_hook(pskb, ct, ctinfo, data, | 1597 | if (set_ras_addr) |
1573 | &lrq->replyAddress, 1); | 1598 | return set_ras_addr(pskb, ct, ctinfo, data, |
1599 | &lrq->replyAddress, 1); | ||
1574 | return 0; | 1600 | return 0; |
1575 | } | 1601 | } |
1576 | 1602 | ||
@@ -1629,20 +1655,24 @@ static int process_irr(struct sk_buff **pskb, struct ip_conntrack *ct, | |||
1629 | unsigned char **data, InfoRequestResponse * irr) | 1655 | unsigned char **data, InfoRequestResponse * irr) |
1630 | { | 1656 | { |
1631 | int ret; | 1657 | int ret; |
1658 | typeof(set_ras_addr_hook) set_ras_addr; | ||
1659 | typeof(set_sig_addr_hook) set_sig_addr; | ||
1632 | 1660 | ||
1633 | DEBUGP("ip_ct_ras: IRR\n"); | 1661 | DEBUGP("ip_ct_ras: IRR\n"); |
1634 | 1662 | ||
1635 | if (set_ras_addr_hook) { | 1663 | set_ras_addr = rcu_dereference(set_ras_addr_hook); |
1636 | ret = set_ras_addr_hook(pskb, ct, ctinfo, data, | 1664 | if (set_ras_addr) { |
1637 | &irr->rasAddress, 1); | 1665 | ret = set_ras_addr(pskb, ct, ctinfo, data, |
1666 | &irr->rasAddress, 1); | ||
1638 | if (ret < 0) | 1667 | if (ret < 0) |
1639 | return -1; | 1668 | return -1; |
1640 | } | 1669 | } |
1641 | 1670 | ||
1642 | if (set_sig_addr_hook) { | 1671 | set_sig_addr = rcu_dereference(set_sig_addr_hook); |
1643 | ret = set_sig_addr_hook(pskb, ct, ctinfo, data, | 1672 | if (set_sig_addr) { |
1644 | irr->callSignalAddress.item, | 1673 | ret = set_sig_addr(pskb, ct, ctinfo, data, |
1645 | irr->callSignalAddress.count); | 1674 | irr->callSignalAddress.item, |
1675 | irr->callSignalAddress.count); | ||
1646 | if (ret < 0) | 1676 | if (ret < 0) |
1647 | return -1; | 1677 | return -1; |
1648 | } | 1678 | } |
@@ -1746,7 +1776,7 @@ static struct ip_conntrack_helper ip_conntrack_helper_ras = { | |||
1746 | .me = THIS_MODULE, | 1776 | .me = THIS_MODULE, |
1747 | .max_expected = 32, | 1777 | .max_expected = 32, |
1748 | .timeout = 240, | 1778 | .timeout = 240, |
1749 | .tuple = {.src = {.u = {__constant_htons(RAS_PORT)}}, | 1779 | .tuple = {.src = {.u = {.tcp = {.port = __constant_htons(RAS_PORT)}}}, |
1750 | .dst = {.protonum = IPPROTO_UDP}}, | 1780 | .dst = {.protonum = IPPROTO_UDP}}, |
1751 | .mask = {.src = {.u = {0xFFFE}}, | 1781 | .mask = {.src = {.u = {0xFFFE}}, |
1752 | .dst = {.protonum = 0xFF}}, | 1782 | .dst = {.protonum = 0xFF}}, |
diff --git a/net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.c b/net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.c deleted file mode 100644 index 26dfecadb335..000000000000 --- a/net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.c +++ /dev/null | |||
@@ -1,874 +0,0 @@ | |||
1 | /**************************************************************************** | ||
2 | * ip_conntrack_helper_h323_asn1.c - BER and PER decoding library for H.323 | ||
3 | * conntrack/NAT module. | ||
4 | * | ||
5 | * Copyright (c) 2006 by Jing Min Zhao <zhaojingmin@users.sourceforge.net> | ||
6 | * | ||
7 | * This source code is licensed under General Public License version 2. | ||
8 | * | ||
9 | * See ip_conntrack_helper_h323_asn1.h for details. | ||
10 | * | ||
11 | ****************************************************************************/ | ||
12 | |||
13 | #ifdef __KERNEL__ | ||
14 | #include <linux/kernel.h> | ||
15 | #else | ||
16 | #include <stdio.h> | ||
17 | #endif | ||
18 | #include <linux/netfilter_ipv4/ip_conntrack_helper_h323_asn1.h> | ||
19 | |||
20 | /* Trace Flag */ | ||
21 | #ifndef H323_TRACE | ||
22 | #define H323_TRACE 0 | ||
23 | #endif | ||
24 | |||
25 | #if H323_TRACE | ||
26 | #define TAB_SIZE 4 | ||
27 | #define IFTHEN(cond, act) if(cond){act;} | ||
28 | #ifdef __KERNEL__ | ||
29 | #define PRINT printk | ||
30 | #else | ||
31 | #define PRINT printf | ||
32 | #endif | ||
33 | #define FNAME(name) name, | ||
34 | #else | ||
35 | #define IFTHEN(cond, act) | ||
36 | #define PRINT(fmt, args...) | ||
37 | #define FNAME(name) | ||
38 | #endif | ||
39 | |||
40 | /* ASN.1 Types */ | ||
41 | #define NUL 0 | ||
42 | #define BOOL 1 | ||
43 | #define OID 2 | ||
44 | #define INT 3 | ||
45 | #define ENUM 4 | ||
46 | #define BITSTR 5 | ||
47 | #define NUMSTR 6 | ||
48 | #define NUMDGT 6 | ||
49 | #define TBCDSTR 6 | ||
50 | #define OCTSTR 7 | ||
51 | #define PRTSTR 7 | ||
52 | #define IA5STR 7 | ||
53 | #define GENSTR 7 | ||
54 | #define BMPSTR 8 | ||
55 | #define SEQ 9 | ||
56 | #define SET 9 | ||
57 | #define SEQOF 10 | ||
58 | #define SETOF 10 | ||
59 | #define CHOICE 11 | ||
60 | |||
61 | /* Constraint Types */ | ||
62 | #define FIXD 0 | ||
63 | /* #define BITS 1-8 */ | ||
64 | #define BYTE 9 | ||
65 | #define WORD 10 | ||
66 | #define CONS 11 | ||
67 | #define SEMI 12 | ||
68 | #define UNCO 13 | ||
69 | |||
70 | /* ASN.1 Type Attributes */ | ||
71 | #define SKIP 0 | ||
72 | #define STOP 1 | ||
73 | #define DECODE 2 | ||
74 | #define EXT 4 | ||
75 | #define OPEN 8 | ||
76 | #define OPT 16 | ||
77 | |||
78 | |||
79 | /* ASN.1 Field Structure */ | ||
80 | typedef struct field_t { | ||
81 | #if H323_TRACE | ||
82 | char *name; | ||
83 | #endif | ||
84 | unsigned char type; | ||
85 | unsigned char sz; | ||
86 | unsigned char lb; | ||
87 | unsigned char ub; | ||
88 | unsigned short attr; | ||
89 | unsigned short offset; | ||
90 | struct field_t *fields; | ||
91 | } field_t; | ||
92 | |||
93 | /* Bit Stream */ | ||
94 | typedef struct { | ||
95 | unsigned char *buf; | ||
96 | unsigned char *beg; | ||
97 | unsigned char *end; | ||
98 | unsigned char *cur; | ||
99 | unsigned bit; | ||
100 | } bitstr_t; | ||
101 | |||
102 | /* Tool Functions */ | ||
103 | #define INC_BIT(bs) if((++bs->bit)>7){bs->cur++;bs->bit=0;} | ||
104 | #define INC_BITS(bs,b) if((bs->bit+=b)>7){bs->cur+=bs->bit>>3;bs->bit&=7;} | ||
105 | #define BYTE_ALIGN(bs) if(bs->bit){bs->cur++;bs->bit=0;} | ||
106 | #define CHECK_BOUND(bs,n) if(bs->cur+(n)>bs->end)return(H323_ERROR_BOUND) | ||
107 | static unsigned get_len(bitstr_t * bs); | ||
108 | static unsigned get_bit(bitstr_t * bs); | ||
109 | static unsigned get_bits(bitstr_t * bs, unsigned b); | ||
110 | static unsigned get_bitmap(bitstr_t * bs, unsigned b); | ||
111 | static unsigned get_uint(bitstr_t * bs, int b); | ||
112 | |||
113 | /* Decoder Functions */ | ||
114 | static int decode_nul(bitstr_t * bs, field_t * f, char *base, int level); | ||
115 | static int decode_bool(bitstr_t * bs, field_t * f, char *base, int level); | ||
116 | static int decode_oid(bitstr_t * bs, field_t * f, char *base, int level); | ||
117 | static int decode_int(bitstr_t * bs, field_t * f, char *base, int level); | ||
118 | static int decode_enum(bitstr_t * bs, field_t * f, char *base, int level); | ||
119 | static int decode_bitstr(bitstr_t * bs, field_t * f, char *base, int level); | ||
120 | static int decode_numstr(bitstr_t * bs, field_t * f, char *base, int level); | ||
121 | static int decode_octstr(bitstr_t * bs, field_t * f, char *base, int level); | ||
122 | static int decode_bmpstr(bitstr_t * bs, field_t * f, char *base, int level); | ||
123 | static int decode_seq(bitstr_t * bs, field_t * f, char *base, int level); | ||
124 | static int decode_seqof(bitstr_t * bs, field_t * f, char *base, int level); | ||
125 | static int decode_choice(bitstr_t * bs, field_t * f, char *base, int level); | ||
126 | |||
127 | /* Decoder Functions Vector */ | ||
128 | typedef int (*decoder_t) (bitstr_t *, field_t *, char *, int); | ||
129 | static decoder_t Decoders[] = { | ||
130 | decode_nul, | ||
131 | decode_bool, | ||
132 | decode_oid, | ||
133 | decode_int, | ||
134 | decode_enum, | ||
135 | decode_bitstr, | ||
136 | decode_numstr, | ||
137 | decode_octstr, | ||
138 | decode_bmpstr, | ||
139 | decode_seq, | ||
140 | decode_seqof, | ||
141 | decode_choice, | ||
142 | }; | ||
143 | |||
144 | /**************************************************************************** | ||
145 | * H.323 Types | ||
146 | ****************************************************************************/ | ||
147 | #include "ip_conntrack_helper_h323_types.c" | ||
148 | |||
149 | /**************************************************************************** | ||
150 | * Functions | ||
151 | ****************************************************************************/ | ||
152 | /* Assume bs is aligned && v < 16384 */ | ||
153 | unsigned get_len(bitstr_t * bs) | ||
154 | { | ||
155 | unsigned v; | ||
156 | |||
157 | v = *bs->cur++; | ||
158 | |||
159 | if (v & 0x80) { | ||
160 | v &= 0x3f; | ||
161 | v <<= 8; | ||
162 | v += *bs->cur++; | ||
163 | } | ||
164 | |||
165 | return v; | ||
166 | } | ||
167 | |||
168 | /****************************************************************************/ | ||
169 | unsigned get_bit(bitstr_t * bs) | ||
170 | { | ||
171 | unsigned b = (*bs->cur) & (0x80 >> bs->bit); | ||
172 | |||
173 | INC_BIT(bs); | ||
174 | |||
175 | return b; | ||
176 | } | ||
177 | |||
178 | /****************************************************************************/ | ||
179 | /* Assume b <= 8 */ | ||
180 | unsigned get_bits(bitstr_t * bs, unsigned b) | ||
181 | { | ||
182 | unsigned v, l; | ||
183 | |||
184 | v = (*bs->cur) & (0xffU >> bs->bit); | ||
185 | l = b + bs->bit; | ||
186 | |||
187 | if (l < 8) { | ||
188 | v >>= 8 - l; | ||
189 | bs->bit = l; | ||
190 | } else if (l == 8) { | ||
191 | bs->cur++; | ||
192 | bs->bit = 0; | ||
193 | } else { /* l > 8 */ | ||
194 | |||
195 | v <<= 8; | ||
196 | v += *(++bs->cur); | ||
197 | v >>= 16 - l; | ||
198 | bs->bit = l - 8; | ||
199 | } | ||
200 | |||
201 | return v; | ||
202 | } | ||
203 | |||
204 | /****************************************************************************/ | ||
205 | /* Assume b <= 32 */ | ||
206 | unsigned get_bitmap(bitstr_t * bs, unsigned b) | ||
207 | { | ||
208 | unsigned v, l, shift, bytes; | ||
209 | |||
210 | if (!b) | ||
211 | return 0; | ||
212 | |||
213 | l = bs->bit + b; | ||
214 | |||
215 | if (l < 8) { | ||
216 | v = (unsigned) (*bs->cur) << (bs->bit + 24); | ||
217 | bs->bit = l; | ||
218 | } else if (l == 8) { | ||
219 | v = (unsigned) (*bs->cur++) << (bs->bit + 24); | ||
220 | bs->bit = 0; | ||
221 | } else { | ||
222 | for (bytes = l >> 3, shift = 24, v = 0; bytes; | ||
223 | bytes--, shift -= 8) | ||
224 | v |= (unsigned) (*bs->cur++) << shift; | ||
225 | |||
226 | if (l < 32) { | ||
227 | v |= (unsigned) (*bs->cur) << shift; | ||
228 | v <<= bs->bit; | ||
229 | } else if (l > 32) { | ||
230 | v <<= bs->bit; | ||
231 | v |= (*bs->cur) >> (8 - bs->bit); | ||
232 | } | ||
233 | |||
234 | bs->bit = l & 0x7; | ||
235 | } | ||
236 | |||
237 | v &= 0xffffffff << (32 - b); | ||
238 | |||
239 | return v; | ||
240 | } | ||
241 | |||
242 | /**************************************************************************** | ||
243 | * Assume bs is aligned and sizeof(unsigned int) == 4 | ||
244 | ****************************************************************************/ | ||
245 | unsigned get_uint(bitstr_t * bs, int b) | ||
246 | { | ||
247 | unsigned v = 0; | ||
248 | |||
249 | switch (b) { | ||
250 | case 4: | ||
251 | v |= *bs->cur++; | ||
252 | v <<= 8; | ||
253 | case 3: | ||
254 | v |= *bs->cur++; | ||
255 | v <<= 8; | ||
256 | case 2: | ||
257 | v |= *bs->cur++; | ||
258 | v <<= 8; | ||
259 | case 1: | ||
260 | v |= *bs->cur++; | ||
261 | break; | ||
262 | } | ||
263 | return v; | ||
264 | } | ||
265 | |||
266 | /****************************************************************************/ | ||
267 | int decode_nul(bitstr_t * bs, field_t * f, char *base, int level) | ||
268 | { | ||
269 | PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); | ||
270 | |||
271 | return H323_ERROR_NONE; | ||
272 | } | ||
273 | |||
274 | /****************************************************************************/ | ||
275 | int decode_bool(bitstr_t * bs, field_t * f, char *base, int level) | ||
276 | { | ||
277 | PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); | ||
278 | |||
279 | INC_BIT(bs); | ||
280 | |||
281 | CHECK_BOUND(bs, 0); | ||
282 | return H323_ERROR_NONE; | ||
283 | } | ||
284 | |||
285 | /****************************************************************************/ | ||
286 | int decode_oid(bitstr_t * bs, field_t * f, char *base, int level) | ||
287 | { | ||
288 | int len; | ||
289 | |||
290 | PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); | ||
291 | |||
292 | BYTE_ALIGN(bs); | ||
293 | CHECK_BOUND(bs, 1); | ||
294 | len = *bs->cur++; | ||
295 | bs->cur += len; | ||
296 | |||
297 | CHECK_BOUND(bs, 0); | ||
298 | return H323_ERROR_NONE; | ||
299 | } | ||
300 | |||
301 | /****************************************************************************/ | ||
302 | int decode_int(bitstr_t * bs, field_t * f, char *base, int level) | ||
303 | { | ||
304 | unsigned len; | ||
305 | |||
306 | PRINT("%*.s%s", level * TAB_SIZE, " ", f->name); | ||
307 | |||
308 | switch (f->sz) { | ||
309 | case BYTE: /* Range == 256 */ | ||
310 | BYTE_ALIGN(bs); | ||
311 | bs->cur++; | ||
312 | break; | ||
313 | case WORD: /* 257 <= Range <= 64K */ | ||
314 | BYTE_ALIGN(bs); | ||
315 | bs->cur += 2; | ||
316 | break; | ||
317 | case CONS: /* 64K < Range < 4G */ | ||
318 | len = get_bits(bs, 2) + 1; | ||
319 | BYTE_ALIGN(bs); | ||
320 | if (base && (f->attr & DECODE)) { /* timeToLive */ | ||
321 | unsigned v = get_uint(bs, len) + f->lb; | ||
322 | PRINT(" = %u", v); | ||
323 | *((unsigned *) (base + f->offset)) = v; | ||
324 | } | ||
325 | bs->cur += len; | ||
326 | break; | ||
327 | case UNCO: | ||
328 | BYTE_ALIGN(bs); | ||
329 | CHECK_BOUND(bs, 2); | ||
330 | len = get_len(bs); | ||
331 | bs->cur += len; | ||
332 | break; | ||
333 | default: /* 2 <= Range <= 255 */ | ||
334 | INC_BITS(bs, f->sz); | ||
335 | break; | ||
336 | } | ||
337 | |||
338 | PRINT("\n"); | ||
339 | |||
340 | CHECK_BOUND(bs, 0); | ||
341 | return H323_ERROR_NONE; | ||
342 | } | ||
343 | |||
344 | /****************************************************************************/ | ||
345 | int decode_enum(bitstr_t * bs, field_t * f, char *base, int level) | ||
346 | { | ||
347 | PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); | ||
348 | |||
349 | if ((f->attr & EXT) && get_bit(bs)) { | ||
350 | INC_BITS(bs, 7); | ||
351 | } else { | ||
352 | INC_BITS(bs, f->sz); | ||
353 | } | ||
354 | |||
355 | CHECK_BOUND(bs, 0); | ||
356 | return H323_ERROR_NONE; | ||
357 | } | ||
358 | |||
359 | /****************************************************************************/ | ||
360 | int decode_bitstr(bitstr_t * bs, field_t * f, char *base, int level) | ||
361 | { | ||
362 | unsigned len; | ||
363 | |||
364 | PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); | ||
365 | |||
366 | BYTE_ALIGN(bs); | ||
367 | switch (f->sz) { | ||
368 | case FIXD: /* fixed length > 16 */ | ||
369 | len = f->lb; | ||
370 | break; | ||
371 | case WORD: /* 2-byte length */ | ||
372 | CHECK_BOUND(bs, 2); | ||
373 | len = (*bs->cur++) << 8; | ||
374 | len += (*bs->cur++) + f->lb; | ||
375 | break; | ||
376 | case SEMI: | ||
377 | CHECK_BOUND(bs, 2); | ||
378 | len = get_len(bs); | ||
379 | break; | ||
380 | default: | ||
381 | len = 0; | ||
382 | break; | ||
383 | } | ||
384 | |||
385 | bs->cur += len >> 3; | ||
386 | bs->bit = len & 7; | ||
387 | |||
388 | CHECK_BOUND(bs, 0); | ||
389 | return H323_ERROR_NONE; | ||
390 | } | ||
391 | |||
392 | /****************************************************************************/ | ||
393 | int decode_numstr(bitstr_t * bs, field_t * f, char *base, int level) | ||
394 | { | ||
395 | unsigned len; | ||
396 | |||
397 | PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); | ||
398 | |||
399 | /* 2 <= Range <= 255 */ | ||
400 | len = get_bits(bs, f->sz) + f->lb; | ||
401 | |||
402 | BYTE_ALIGN(bs); | ||
403 | INC_BITS(bs, (len << 2)); | ||
404 | |||
405 | CHECK_BOUND(bs, 0); | ||
406 | return H323_ERROR_NONE; | ||
407 | } | ||
408 | |||
409 | /****************************************************************************/ | ||
410 | int decode_octstr(bitstr_t * bs, field_t * f, char *base, int level) | ||
411 | { | ||
412 | unsigned len; | ||
413 | |||
414 | PRINT("%*.s%s", level * TAB_SIZE, " ", f->name); | ||
415 | |||
416 | switch (f->sz) { | ||
417 | case FIXD: /* Range == 1 */ | ||
418 | if (f->lb > 2) { | ||
419 | BYTE_ALIGN(bs); | ||
420 | if (base && (f->attr & DECODE)) { | ||
421 | /* The IP Address */ | ||
422 | IFTHEN(f->lb == 4, | ||
423 | PRINT(" = %d.%d.%d.%d:%d", | ||
424 | bs->cur[0], bs->cur[1], | ||
425 | bs->cur[2], bs->cur[3], | ||
426 | bs->cur[4] * 256 + bs->cur[5])); | ||
427 | *((unsigned *) (base + f->offset)) = | ||
428 | bs->cur - bs->buf; | ||
429 | } | ||
430 | } | ||
431 | len = f->lb; | ||
432 | break; | ||
433 | case BYTE: /* Range == 256 */ | ||
434 | BYTE_ALIGN(bs); | ||
435 | CHECK_BOUND(bs, 1); | ||
436 | len = (*bs->cur++) + f->lb; | ||
437 | break; | ||
438 | case SEMI: | ||
439 | BYTE_ALIGN(bs); | ||
440 | CHECK_BOUND(bs, 2); | ||
441 | len = get_len(bs) + f->lb; | ||
442 | break; | ||
443 | default: /* 2 <= Range <= 255 */ | ||
444 | len = get_bits(bs, f->sz) + f->lb; | ||
445 | BYTE_ALIGN(bs); | ||
446 | break; | ||
447 | } | ||
448 | |||
449 | bs->cur += len; | ||
450 | |||
451 | PRINT("\n"); | ||
452 | |||
453 | CHECK_BOUND(bs, 0); | ||
454 | return H323_ERROR_NONE; | ||
455 | } | ||
456 | |||
457 | /****************************************************************************/ | ||
458 | int decode_bmpstr(bitstr_t * bs, field_t * f, char *base, int level) | ||
459 | { | ||
460 | unsigned len; | ||
461 | |||
462 | PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); | ||
463 | |||
464 | switch (f->sz) { | ||
465 | case BYTE: /* Range == 256 */ | ||
466 | BYTE_ALIGN(bs); | ||
467 | CHECK_BOUND(bs, 1); | ||
468 | len = (*bs->cur++) + f->lb; | ||
469 | break; | ||
470 | default: /* 2 <= Range <= 255 */ | ||
471 | len = get_bits(bs, f->sz) + f->lb; | ||
472 | BYTE_ALIGN(bs); | ||
473 | break; | ||
474 | } | ||
475 | |||
476 | bs->cur += len << 1; | ||
477 | |||
478 | CHECK_BOUND(bs, 0); | ||
479 | return H323_ERROR_NONE; | ||
480 | } | ||
481 | |||
482 | /****************************************************************************/ | ||
483 | int decode_seq(bitstr_t * bs, field_t * f, char *base, int level) | ||
484 | { | ||
485 | unsigned ext, bmp, i, opt, len = 0, bmp2, bmp2_len; | ||
486 | int err; | ||
487 | field_t *son; | ||
488 | unsigned char *beg = NULL; | ||
489 | |||
490 | PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); | ||
491 | |||
492 | /* Decode? */ | ||
493 | base = (base && (f->attr & DECODE)) ? base + f->offset : NULL; | ||
494 | |||
495 | /* Extensible? */ | ||
496 | ext = (f->attr & EXT) ? get_bit(bs) : 0; | ||
497 | |||
498 | /* Get fields bitmap */ | ||
499 | bmp = get_bitmap(bs, f->sz); | ||
500 | if (base) | ||
501 | *(unsigned *) base = bmp; | ||
502 | |||
503 | /* Decode the root components */ | ||
504 | for (i = opt = 0, son = f->fields; i < f->lb; i++, son++) { | ||
505 | if (son->attr & STOP) { | ||
506 | PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, " ", | ||
507 | son->name); | ||
508 | return H323_ERROR_STOP; | ||
509 | } | ||
510 | |||
511 | if (son->attr & OPT) { /* Optional component */ | ||
512 | if (!((0x80000000U >> (opt++)) & bmp)) /* Not exist */ | ||
513 | continue; | ||
514 | } | ||
515 | |||
516 | /* Decode */ | ||
517 | if (son->attr & OPEN) { /* Open field */ | ||
518 | CHECK_BOUND(bs, 2); | ||
519 | len = get_len(bs); | ||
520 | CHECK_BOUND(bs, len); | ||
521 | if (!base) { | ||
522 | PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, | ||
523 | " ", son->name); | ||
524 | bs->cur += len; | ||
525 | continue; | ||
526 | } | ||
527 | beg = bs->cur; | ||
528 | |||
529 | /* Decode */ | ||
530 | if ((err = (Decoders[son->type]) (bs, son, base, | ||
531 | level + 1)) < | ||
532 | H323_ERROR_NONE) | ||
533 | return err; | ||
534 | |||
535 | bs->cur = beg + len; | ||
536 | bs->bit = 0; | ||
537 | } else if ((err = (Decoders[son->type]) (bs, son, base, | ||
538 | level + 1)) < | ||
539 | H323_ERROR_NONE) | ||
540 | return err; | ||
541 | } | ||
542 | |||
543 | /* No extension? */ | ||
544 | if (!ext) | ||
545 | return H323_ERROR_NONE; | ||
546 | |||
547 | /* Get the extension bitmap */ | ||
548 | bmp2_len = get_bits(bs, 7) + 1; | ||
549 | CHECK_BOUND(bs, (bmp2_len + 7) >> 3); | ||
550 | bmp2 = get_bitmap(bs, bmp2_len); | ||
551 | bmp |= bmp2 >> f->sz; | ||
552 | if (base) | ||
553 | *(unsigned *) base = bmp; | ||
554 | BYTE_ALIGN(bs); | ||
555 | |||
556 | /* Decode the extension components */ | ||
557 | for (opt = 0; opt < bmp2_len; opt++, i++, son++) { | ||
558 | if (i < f->ub && son->attr & STOP) { | ||
559 | PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, " ", | ||
560 | son->name); | ||
561 | return H323_ERROR_STOP; | ||
562 | } | ||
563 | |||
564 | if (!((0x80000000 >> opt) & bmp2)) /* Not present */ | ||
565 | continue; | ||
566 | |||
567 | /* Check Range */ | ||
568 | if (i >= f->ub) { /* Newer Version? */ | ||
569 | CHECK_BOUND(bs, 2); | ||
570 | len = get_len(bs); | ||
571 | CHECK_BOUND(bs, len); | ||
572 | bs->cur += len; | ||
573 | continue; | ||
574 | } | ||
575 | |||
576 | CHECK_BOUND(bs, 2); | ||
577 | len = get_len(bs); | ||
578 | CHECK_BOUND(bs, len); | ||
579 | if (!base || !(son->attr & DECODE)) { | ||
580 | PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, " ", | ||
581 | son->name); | ||
582 | bs->cur += len; | ||
583 | continue; | ||
584 | } | ||
585 | beg = bs->cur; | ||
586 | |||
587 | if ((err = (Decoders[son->type]) (bs, son, base, | ||
588 | level + 1)) < | ||
589 | H323_ERROR_NONE) | ||
590 | return err; | ||
591 | |||
592 | bs->cur = beg + len; | ||
593 | bs->bit = 0; | ||
594 | } | ||
595 | return H323_ERROR_NONE; | ||
596 | } | ||
597 | |||
598 | /****************************************************************************/ | ||
599 | int decode_seqof(bitstr_t * bs, field_t * f, char *base, int level) | ||
600 | { | ||
601 | unsigned count, effective_count = 0, i, len = 0; | ||
602 | int err; | ||
603 | field_t *son; | ||
604 | unsigned char *beg = NULL; | ||
605 | |||
606 | PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); | ||
607 | |||
608 | /* Decode? */ | ||
609 | base = (base && (f->attr & DECODE)) ? base + f->offset : NULL; | ||
610 | |||
611 | /* Decode item count */ | ||
612 | switch (f->sz) { | ||
613 | case BYTE: | ||
614 | BYTE_ALIGN(bs); | ||
615 | CHECK_BOUND(bs, 1); | ||
616 | count = *bs->cur++; | ||
617 | break; | ||
618 | case WORD: | ||
619 | BYTE_ALIGN(bs); | ||
620 | CHECK_BOUND(bs, 2); | ||
621 | count = *bs->cur++; | ||
622 | count <<= 8; | ||
623 | count = *bs->cur++; | ||
624 | break; | ||
625 | case SEMI: | ||
626 | BYTE_ALIGN(bs); | ||
627 | CHECK_BOUND(bs, 2); | ||
628 | count = get_len(bs); | ||
629 | break; | ||
630 | default: | ||
631 | count = get_bits(bs, f->sz); | ||
632 | break; | ||
633 | } | ||
634 | count += f->lb; | ||
635 | |||
636 | /* Write Count */ | ||
637 | if (base) { | ||
638 | effective_count = count > f->ub ? f->ub : count; | ||
639 | *(unsigned *) base = effective_count; | ||
640 | base += sizeof(unsigned); | ||
641 | } | ||
642 | |||
643 | /* Decode nested field */ | ||
644 | son = f->fields; | ||
645 | if (base) | ||
646 | base -= son->offset; | ||
647 | for (i = 0; i < count; i++) { | ||
648 | if (son->attr & OPEN) { | ||
649 | BYTE_ALIGN(bs); | ||
650 | len = get_len(bs); | ||
651 | CHECK_BOUND(bs, len); | ||
652 | if (!base || !(son->attr & DECODE)) { | ||
653 | PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, | ||
654 | " ", son->name); | ||
655 | bs->cur += len; | ||
656 | continue; | ||
657 | } | ||
658 | beg = bs->cur; | ||
659 | |||
660 | if ((err = (Decoders[son->type]) (bs, son, | ||
661 | i < | ||
662 | effective_count ? | ||
663 | base : NULL, | ||
664 | level + 1)) < | ||
665 | H323_ERROR_NONE) | ||
666 | return err; | ||
667 | |||
668 | bs->cur = beg + len; | ||
669 | bs->bit = 0; | ||
670 | } else | ||
671 | if ((err = (Decoders[son->type]) (bs, son, | ||
672 | i < | ||
673 | effective_count ? | ||
674 | base : NULL, | ||
675 | level + 1)) < | ||
676 | H323_ERROR_NONE) | ||
677 | return err; | ||
678 | |||
679 | if (base) | ||
680 | base += son->offset; | ||
681 | } | ||
682 | |||
683 | return H323_ERROR_NONE; | ||
684 | } | ||
685 | |||
686 | |||
687 | /****************************************************************************/ | ||
688 | int decode_choice(bitstr_t * bs, field_t * f, char *base, int level) | ||
689 | { | ||
690 | unsigned type, ext, len = 0; | ||
691 | int err; | ||
692 | field_t *son; | ||
693 | unsigned char *beg = NULL; | ||
694 | |||
695 | PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); | ||
696 | |||
697 | /* Decode? */ | ||
698 | base = (base && (f->attr & DECODE)) ? base + f->offset : NULL; | ||
699 | |||
700 | /* Decode the choice index number */ | ||
701 | if ((f->attr & EXT) && get_bit(bs)) { | ||
702 | ext = 1; | ||
703 | type = get_bits(bs, 7) + f->lb; | ||
704 | } else { | ||
705 | ext = 0; | ||
706 | type = get_bits(bs, f->sz); | ||
707 | } | ||
708 | |||
709 | /* Write Type */ | ||
710 | if (base) | ||
711 | *(unsigned *) base = type; | ||
712 | |||
713 | /* Check Range */ | ||
714 | if (type >= f->ub) { /* Newer version? */ | ||
715 | BYTE_ALIGN(bs); | ||
716 | len = get_len(bs); | ||
717 | CHECK_BOUND(bs, len); | ||
718 | bs->cur += len; | ||
719 | return H323_ERROR_NONE; | ||
720 | } | ||
721 | |||
722 | /* Transfer to son level */ | ||
723 | son = &f->fields[type]; | ||
724 | if (son->attr & STOP) { | ||
725 | PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, " ", son->name); | ||
726 | return H323_ERROR_STOP; | ||
727 | } | ||
728 | |||
729 | if (ext || (son->attr & OPEN)) { | ||
730 | BYTE_ALIGN(bs); | ||
731 | len = get_len(bs); | ||
732 | CHECK_BOUND(bs, len); | ||
733 | if (!base || !(son->attr & DECODE)) { | ||
734 | PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, " ", | ||
735 | son->name); | ||
736 | bs->cur += len; | ||
737 | return H323_ERROR_NONE; | ||
738 | } | ||
739 | beg = bs->cur; | ||
740 | |||
741 | if ((err = (Decoders[son->type]) (bs, son, base, level + 1)) < | ||
742 | H323_ERROR_NONE) | ||
743 | return err; | ||
744 | |||
745 | bs->cur = beg + len; | ||
746 | bs->bit = 0; | ||
747 | } else if ((err = (Decoders[son->type]) (bs, son, base, level + 1)) < | ||
748 | H323_ERROR_NONE) | ||
749 | return err; | ||
750 | |||
751 | return H323_ERROR_NONE; | ||
752 | } | ||
753 | |||
754 | /****************************************************************************/ | ||
755 | int DecodeRasMessage(unsigned char *buf, size_t sz, RasMessage * ras) | ||
756 | { | ||
757 | static field_t ras_message = { | ||
758 | FNAME("RasMessage") CHOICE, 5, 24, 32, DECODE | EXT, | ||
759 | 0, _RasMessage | ||
760 | }; | ||
761 | bitstr_t bs; | ||
762 | |||
763 | bs.buf = bs.beg = bs.cur = buf; | ||
764 | bs.end = buf + sz; | ||
765 | bs.bit = 0; | ||
766 | |||
767 | return decode_choice(&bs, &ras_message, (char *) ras, 0); | ||
768 | } | ||
769 | |||
770 | /****************************************************************************/ | ||
771 | static int DecodeH323_UserInformation(unsigned char *buf, unsigned char *beg, | ||
772 | size_t sz, H323_UserInformation * uuie) | ||
773 | { | ||
774 | static field_t h323_userinformation = { | ||
775 | FNAME("H323-UserInformation") SEQ, 1, 2, 2, DECODE | EXT, | ||
776 | 0, _H323_UserInformation | ||
777 | }; | ||
778 | bitstr_t bs; | ||
779 | |||
780 | bs.buf = buf; | ||
781 | bs.beg = bs.cur = beg; | ||
782 | bs.end = beg + sz; | ||
783 | bs.bit = 0; | ||
784 | |||
785 | return decode_seq(&bs, &h323_userinformation, (char *) uuie, 0); | ||
786 | } | ||
787 | |||
788 | /****************************************************************************/ | ||
789 | int DecodeMultimediaSystemControlMessage(unsigned char *buf, size_t sz, | ||
790 | MultimediaSystemControlMessage * | ||
791 | mscm) | ||
792 | { | ||
793 | static field_t multimediasystemcontrolmessage = { | ||
794 | FNAME("MultimediaSystemControlMessage") CHOICE, 2, 4, 4, | ||
795 | DECODE | EXT, 0, _MultimediaSystemControlMessage | ||
796 | }; | ||
797 | bitstr_t bs; | ||
798 | |||
799 | bs.buf = bs.beg = bs.cur = buf; | ||
800 | bs.end = buf + sz; | ||
801 | bs.bit = 0; | ||
802 | |||
803 | return decode_choice(&bs, &multimediasystemcontrolmessage, | ||
804 | (char *) mscm, 0); | ||
805 | } | ||
806 | |||
807 | /****************************************************************************/ | ||
808 | int DecodeQ931(unsigned char *buf, size_t sz, Q931 * q931) | ||
809 | { | ||
810 | unsigned char *p = buf; | ||
811 | int len; | ||
812 | |||
813 | if (!p || sz < 1) | ||
814 | return H323_ERROR_BOUND; | ||
815 | |||
816 | /* Protocol Discriminator */ | ||
817 | if (*p != 0x08) { | ||
818 | PRINT("Unknown Protocol Discriminator\n"); | ||
819 | return H323_ERROR_RANGE; | ||
820 | } | ||
821 | p++; | ||
822 | sz--; | ||
823 | |||
824 | /* CallReferenceValue */ | ||
825 | if (sz < 1) | ||
826 | return H323_ERROR_BOUND; | ||
827 | len = *p++; | ||
828 | sz--; | ||
829 | if (sz < len) | ||
830 | return H323_ERROR_BOUND; | ||
831 | p += len; | ||
832 | sz -= len; | ||
833 | |||
834 | /* Message Type */ | ||
835 | if (sz < 1) | ||
836 | return H323_ERROR_BOUND; | ||
837 | q931->MessageType = *p++; | ||
838 | PRINT("MessageType = %02X\n", q931->MessageType); | ||
839 | if (*p & 0x80) { | ||
840 | p++; | ||
841 | sz--; | ||
842 | } | ||
843 | |||
844 | /* Decode Information Elements */ | ||
845 | while (sz > 0) { | ||
846 | if (*p == 0x7e) { /* UserUserIE */ | ||
847 | if (sz < 3) | ||
848 | break; | ||
849 | p++; | ||
850 | len = *p++ << 8; | ||
851 | len |= *p++; | ||
852 | sz -= 3; | ||
853 | if (sz < len) | ||
854 | break; | ||
855 | p++; | ||
856 | len--; | ||
857 | return DecodeH323_UserInformation(buf, p, len, | ||
858 | &q931->UUIE); | ||
859 | } | ||
860 | p++; | ||
861 | sz--; | ||
862 | if (sz < 1) | ||
863 | break; | ||
864 | len = *p++; | ||
865 | if (sz < len) | ||
866 | break; | ||
867 | p += len; | ||
868 | sz -= len; | ||
869 | } | ||
870 | |||
871 | PRINT("Q.931 UUIE not found\n"); | ||
872 | |||
873 | return H323_ERROR_BOUND; | ||
874 | } | ||
diff --git a/net/ipv4/netfilter/ip_conntrack_helper_h323_types.c b/net/ipv4/netfilter/ip_conntrack_helper_h323_types.c deleted file mode 100644 index 4b359618bedd..000000000000 --- a/net/ipv4/netfilter/ip_conntrack_helper_h323_types.c +++ /dev/null | |||
@@ -1,1926 +0,0 @@ | |||
1 | /* Generated by Jing Min Zhao's ASN.1 parser, Apr 20 2006 | ||
2 | * | ||
3 | * Copyright (c) 2006 Jing Min Zhao <zhaojingmin@users.sourceforge.net> | ||
4 | * | ||
5 | * This source code is licensed under General Public License version 2. | ||
6 | */ | ||
7 | |||
8 | static field_t _TransportAddress_ipAddress[] = { /* SEQUENCE */ | ||
9 | {FNAME("ip") OCTSTR, FIXD, 4, 0, DECODE, | ||
10 | offsetof(TransportAddress_ipAddress, ip), NULL}, | ||
11 | {FNAME("port") INT, WORD, 0, 0, SKIP, 0, NULL}, | ||
12 | }; | ||
13 | |||
14 | static field_t _TransportAddress_ipSourceRoute_route[] = { /* SEQUENCE OF */ | ||
15 | {FNAME("item") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL}, | ||
16 | }; | ||
17 | |||
18 | static field_t _TransportAddress_ipSourceRoute_routing[] = { /* CHOICE */ | ||
19 | {FNAME("strict") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
20 | {FNAME("loose") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
21 | }; | ||
22 | |||
23 | static field_t _TransportAddress_ipSourceRoute[] = { /* SEQUENCE */ | ||
24 | {FNAME("ip") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL}, | ||
25 | {FNAME("port") INT, WORD, 0, 0, SKIP, 0, NULL}, | ||
26 | {FNAME("route") SEQOF, SEMI, 0, 0, SKIP, 0, | ||
27 | _TransportAddress_ipSourceRoute_route}, | ||
28 | {FNAME("routing") CHOICE, 1, 2, 2, SKIP | EXT, 0, | ||
29 | _TransportAddress_ipSourceRoute_routing}, | ||
30 | }; | ||
31 | |||
32 | static field_t _TransportAddress_ipxAddress[] = { /* SEQUENCE */ | ||
33 | {FNAME("node") OCTSTR, FIXD, 6, 0, SKIP, 0, NULL}, | ||
34 | {FNAME("netnum") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL}, | ||
35 | {FNAME("port") OCTSTR, FIXD, 2, 0, SKIP, 0, NULL}, | ||
36 | }; | ||
37 | |||
38 | static field_t _TransportAddress_ip6Address[] = { /* SEQUENCE */ | ||
39 | {FNAME("ip") OCTSTR, FIXD, 16, 0, SKIP, 0, NULL}, | ||
40 | {FNAME("port") INT, WORD, 0, 0, SKIP, 0, NULL}, | ||
41 | }; | ||
42 | |||
43 | static field_t _H221NonStandard[] = { /* SEQUENCE */ | ||
44 | {FNAME("t35CountryCode") INT, BYTE, 0, 0, SKIP, 0, NULL}, | ||
45 | {FNAME("t35Extension") INT, BYTE, 0, 0, SKIP, 0, NULL}, | ||
46 | {FNAME("manufacturerCode") INT, WORD, 0, 0, SKIP, 0, NULL}, | ||
47 | }; | ||
48 | |||
49 | static field_t _NonStandardIdentifier[] = { /* CHOICE */ | ||
50 | {FNAME("object") OID, BYTE, 0, 0, SKIP, 0, NULL}, | ||
51 | {FNAME("h221NonStandard") SEQ, 0, 3, 3, SKIP | EXT, 0, | ||
52 | _H221NonStandard}, | ||
53 | }; | ||
54 | |||
55 | static field_t _NonStandardParameter[] = { /* SEQUENCE */ | ||
56 | {FNAME("nonStandardIdentifier") CHOICE, 1, 2, 2, SKIP | EXT, 0, | ||
57 | _NonStandardIdentifier}, | ||
58 | {FNAME("data") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL}, | ||
59 | }; | ||
60 | |||
61 | static field_t _TransportAddress[] = { /* CHOICE */ | ||
62 | {FNAME("ipAddress") SEQ, 0, 2, 2, DECODE, | ||
63 | offsetof(TransportAddress, ipAddress), _TransportAddress_ipAddress}, | ||
64 | {FNAME("ipSourceRoute") SEQ, 0, 4, 4, SKIP | EXT, 0, | ||
65 | _TransportAddress_ipSourceRoute}, | ||
66 | {FNAME("ipxAddress") SEQ, 0, 3, 3, SKIP, 0, | ||
67 | _TransportAddress_ipxAddress}, | ||
68 | {FNAME("ip6Address") SEQ, 0, 2, 2, SKIP | EXT, 0, | ||
69 | _TransportAddress_ip6Address}, | ||
70 | {FNAME("netBios") OCTSTR, FIXD, 16, 0, SKIP, 0, NULL}, | ||
71 | {FNAME("nsap") OCTSTR, 5, 1, 0, SKIP, 0, NULL}, | ||
72 | {FNAME("nonStandardAddress") SEQ, 0, 2, 2, SKIP, 0, | ||
73 | _NonStandardParameter}, | ||
74 | }; | ||
75 | |||
76 | static field_t _AliasAddress[] = { /* CHOICE */ | ||
77 | {FNAME("dialedDigits") NUMDGT, 7, 1, 0, SKIP, 0, NULL}, | ||
78 | {FNAME("h323-ID") BMPSTR, BYTE, 1, 0, SKIP, 0, NULL}, | ||
79 | {FNAME("url-ID") IA5STR, WORD, 1, 0, SKIP, 0, NULL}, | ||
80 | {FNAME("transportID") CHOICE, 3, 7, 7, SKIP | EXT, 0, NULL}, | ||
81 | {FNAME("email-ID") IA5STR, WORD, 1, 0, SKIP, 0, NULL}, | ||
82 | {FNAME("partyNumber") CHOICE, 3, 5, 5, SKIP | EXT, 0, NULL}, | ||
83 | {FNAME("mobileUIM") CHOICE, 1, 2, 2, SKIP | EXT, 0, NULL}, | ||
84 | }; | ||
85 | |||
86 | static field_t _Setup_UUIE_sourceAddress[] = { /* SEQUENCE OF */ | ||
87 | {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, | ||
88 | }; | ||
89 | |||
90 | static field_t _VendorIdentifier[] = { /* SEQUENCE */ | ||
91 | {FNAME("vendor") SEQ, 0, 3, 3, SKIP | EXT, 0, _H221NonStandard}, | ||
92 | {FNAME("productId") OCTSTR, BYTE, 1, 0, SKIP | OPT, 0, NULL}, | ||
93 | {FNAME("versionId") OCTSTR, BYTE, 1, 0, SKIP | OPT, 0, NULL}, | ||
94 | }; | ||
95 | |||
96 | static field_t _GatekeeperInfo[] = { /* SEQUENCE */ | ||
97 | {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, | ||
98 | _NonStandardParameter}, | ||
99 | }; | ||
100 | |||
101 | static field_t _H310Caps[] = { /* SEQUENCE */ | ||
102 | {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, | ||
103 | _NonStandardParameter}, | ||
104 | {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
105 | {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL}, | ||
106 | }; | ||
107 | |||
108 | static field_t _H320Caps[] = { /* SEQUENCE */ | ||
109 | {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, | ||
110 | _NonStandardParameter}, | ||
111 | {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
112 | {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL}, | ||
113 | }; | ||
114 | |||
115 | static field_t _H321Caps[] = { /* SEQUENCE */ | ||
116 | {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, | ||
117 | _NonStandardParameter}, | ||
118 | {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
119 | {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL}, | ||
120 | }; | ||
121 | |||
122 | static field_t _H322Caps[] = { /* SEQUENCE */ | ||
123 | {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, | ||
124 | _NonStandardParameter}, | ||
125 | {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
126 | {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL}, | ||
127 | }; | ||
128 | |||
129 | static field_t _H323Caps[] = { /* SEQUENCE */ | ||
130 | {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, | ||
131 | _NonStandardParameter}, | ||
132 | {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
133 | {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL}, | ||
134 | }; | ||
135 | |||
136 | static field_t _H324Caps[] = { /* SEQUENCE */ | ||
137 | {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, | ||
138 | _NonStandardParameter}, | ||
139 | {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
140 | {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL}, | ||
141 | }; | ||
142 | |||
143 | static field_t _VoiceCaps[] = { /* SEQUENCE */ | ||
144 | {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, | ||
145 | _NonStandardParameter}, | ||
146 | {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
147 | {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL}, | ||
148 | }; | ||
149 | |||
150 | static field_t _T120OnlyCaps[] = { /* SEQUENCE */ | ||
151 | {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, | ||
152 | _NonStandardParameter}, | ||
153 | {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
154 | {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL}, | ||
155 | }; | ||
156 | |||
157 | static field_t _SupportedProtocols[] = { /* CHOICE */ | ||
158 | {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP, 0, | ||
159 | _NonStandardParameter}, | ||
160 | {FNAME("h310") SEQ, 1, 1, 3, SKIP | EXT, 0, _H310Caps}, | ||
161 | {FNAME("h320") SEQ, 1, 1, 3, SKIP | EXT, 0, _H320Caps}, | ||
162 | {FNAME("h321") SEQ, 1, 1, 3, SKIP | EXT, 0, _H321Caps}, | ||
163 | {FNAME("h322") SEQ, 1, 1, 3, SKIP | EXT, 0, _H322Caps}, | ||
164 | {FNAME("h323") SEQ, 1, 1, 3, SKIP | EXT, 0, _H323Caps}, | ||
165 | {FNAME("h324") SEQ, 1, 1, 3, SKIP | EXT, 0, _H324Caps}, | ||
166 | {FNAME("voice") SEQ, 1, 1, 3, SKIP | EXT, 0, _VoiceCaps}, | ||
167 | {FNAME("t120-only") SEQ, 1, 1, 3, SKIP | EXT, 0, _T120OnlyCaps}, | ||
168 | {FNAME("nonStandardProtocol") SEQ, 2, 3, 3, SKIP | EXT, 0, NULL}, | ||
169 | {FNAME("t38FaxAnnexbOnly") SEQ, 2, 5, 5, SKIP | EXT, 0, NULL}, | ||
170 | }; | ||
171 | |||
172 | static field_t _GatewayInfo_protocol[] = { /* SEQUENCE OF */ | ||
173 | {FNAME("item") CHOICE, 4, 9, 11, SKIP | EXT, 0, _SupportedProtocols}, | ||
174 | }; | ||
175 | |||
176 | static field_t _GatewayInfo[] = { /* SEQUENCE */ | ||
177 | {FNAME("protocol") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, | ||
178 | _GatewayInfo_protocol}, | ||
179 | {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, | ||
180 | _NonStandardParameter}, | ||
181 | }; | ||
182 | |||
183 | static field_t _McuInfo[] = { /* SEQUENCE */ | ||
184 | {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, | ||
185 | _NonStandardParameter}, | ||
186 | {FNAME("protocol") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
187 | }; | ||
188 | |||
189 | static field_t _TerminalInfo[] = { /* SEQUENCE */ | ||
190 | {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, | ||
191 | _NonStandardParameter}, | ||
192 | }; | ||
193 | |||
194 | static field_t _EndpointType[] = { /* SEQUENCE */ | ||
195 | {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, | ||
196 | _NonStandardParameter}, | ||
197 | {FNAME("vendor") SEQ, 2, 3, 3, SKIP | EXT | OPT, 0, | ||
198 | _VendorIdentifier}, | ||
199 | {FNAME("gatekeeper") SEQ, 1, 1, 1, SKIP | EXT | OPT, 0, | ||
200 | _GatekeeperInfo}, | ||
201 | {FNAME("gateway") SEQ, 2, 2, 2, SKIP | EXT | OPT, 0, _GatewayInfo}, | ||
202 | {FNAME("mcu") SEQ, 1, 1, 2, SKIP | EXT | OPT, 0, _McuInfo}, | ||
203 | {FNAME("terminal") SEQ, 1, 1, 1, SKIP | EXT | OPT, 0, _TerminalInfo}, | ||
204 | {FNAME("mc") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
205 | {FNAME("undefinedNode") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
206 | {FNAME("set") BITSTR, FIXD, 32, 0, SKIP | OPT, 0, NULL}, | ||
207 | {FNAME("supportedTunnelledProtocols") SEQOF, SEMI, 0, 0, SKIP | OPT, | ||
208 | 0, NULL}, | ||
209 | }; | ||
210 | |||
211 | static field_t _Setup_UUIE_destinationAddress[] = { /* SEQUENCE OF */ | ||
212 | {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, | ||
213 | }; | ||
214 | |||
215 | static field_t _Setup_UUIE_destExtraCallInfo[] = { /* SEQUENCE OF */ | ||
216 | {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, | ||
217 | }; | ||
218 | |||
219 | static field_t _Setup_UUIE_destExtraCRV[] = { /* SEQUENCE OF */ | ||
220 | {FNAME("item") INT, WORD, 0, 0, SKIP, 0, NULL}, | ||
221 | }; | ||
222 | |||
223 | static field_t _Setup_UUIE_conferenceGoal[] = { /* CHOICE */ | ||
224 | {FNAME("create") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
225 | {FNAME("join") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
226 | {FNAME("invite") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
227 | {FNAME("capability-negotiation") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
228 | {FNAME("callIndependentSupplementaryService") NUL, FIXD, 0, 0, SKIP, | ||
229 | 0, NULL}, | ||
230 | }; | ||
231 | |||
232 | static field_t _Q954Details[] = { /* SEQUENCE */ | ||
233 | {FNAME("conferenceCalling") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
234 | {FNAME("threePartyService") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
235 | }; | ||
236 | |||
237 | static field_t _QseriesOptions[] = { /* SEQUENCE */ | ||
238 | {FNAME("q932Full") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
239 | {FNAME("q951Full") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
240 | {FNAME("q952Full") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
241 | {FNAME("q953Full") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
242 | {FNAME("q955Full") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
243 | {FNAME("q956Full") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
244 | {FNAME("q957Full") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
245 | {FNAME("q954Info") SEQ, 0, 2, 2, SKIP | EXT, 0, _Q954Details}, | ||
246 | }; | ||
247 | |||
248 | static field_t _CallType[] = { /* CHOICE */ | ||
249 | {FNAME("pointToPoint") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
250 | {FNAME("oneToN") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
251 | {FNAME("nToOne") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
252 | {FNAME("nToN") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
253 | }; | ||
254 | |||
255 | static field_t _H245_NonStandardIdentifier_h221NonStandard[] = { /* SEQUENCE */ | ||
256 | {FNAME("t35CountryCode") INT, BYTE, 0, 0, SKIP, 0, NULL}, | ||
257 | {FNAME("t35Extension") INT, BYTE, 0, 0, SKIP, 0, NULL}, | ||
258 | {FNAME("manufacturerCode") INT, WORD, 0, 0, SKIP, 0, NULL}, | ||
259 | }; | ||
260 | |||
261 | static field_t _H245_NonStandardIdentifier[] = { /* CHOICE */ | ||
262 | {FNAME("object") OID, BYTE, 0, 0, SKIP, 0, NULL}, | ||
263 | {FNAME("h221NonStandard") SEQ, 0, 3, 3, SKIP, 0, | ||
264 | _H245_NonStandardIdentifier_h221NonStandard}, | ||
265 | }; | ||
266 | |||
267 | static field_t _H245_NonStandardParameter[] = { /* SEQUENCE */ | ||
268 | {FNAME("nonStandardIdentifier") CHOICE, 1, 2, 2, SKIP, 0, | ||
269 | _H245_NonStandardIdentifier}, | ||
270 | {FNAME("data") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL}, | ||
271 | }; | ||
272 | |||
273 | static field_t _H261VideoCapability[] = { /* SEQUENCE */ | ||
274 | {FNAME("qcifMPI") INT, 2, 1, 0, SKIP | OPT, 0, NULL}, | ||
275 | {FNAME("cifMPI") INT, 2, 1, 0, SKIP | OPT, 0, NULL}, | ||
276 | {FNAME("temporalSpatialTradeOffCapability") BOOL, FIXD, 0, 0, SKIP, 0, | ||
277 | NULL}, | ||
278 | {FNAME("maxBitRate") INT, WORD, 1, 0, SKIP, 0, NULL}, | ||
279 | {FNAME("stillImageTransmission") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
280 | {FNAME("videoBadMBsCap") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
281 | }; | ||
282 | |||
283 | static field_t _H262VideoCapability[] = { /* SEQUENCE */ | ||
284 | {FNAME("profileAndLevel-SPatML") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
285 | {FNAME("profileAndLevel-MPatLL") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
286 | {FNAME("profileAndLevel-MPatML") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
287 | {FNAME("profileAndLevel-MPatH-14") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
288 | {FNAME("profileAndLevel-MPatHL") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
289 | {FNAME("profileAndLevel-SNRatLL") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
290 | {FNAME("profileAndLevel-SNRatML") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
291 | {FNAME("profileAndLevel-SpatialatH-14") BOOL, FIXD, 0, 0, SKIP, 0, | ||
292 | NULL}, | ||
293 | {FNAME("profileAndLevel-HPatML") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
294 | {FNAME("profileAndLevel-HPatH-14") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
295 | {FNAME("profileAndLevel-HPatHL") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
296 | {FNAME("videoBitRate") INT, CONS, 0, 0, SKIP | OPT, 0, NULL}, | ||
297 | {FNAME("vbvBufferSize") INT, CONS, 0, 0, SKIP | OPT, 0, NULL}, | ||
298 | {FNAME("samplesPerLine") INT, WORD, 0, 0, SKIP | OPT, 0, NULL}, | ||
299 | {FNAME("linesPerFrame") INT, WORD, 0, 0, SKIP | OPT, 0, NULL}, | ||
300 | {FNAME("framesPerSecond") INT, 4, 0, 0, SKIP | OPT, 0, NULL}, | ||
301 | {FNAME("luminanceSampleRate") INT, CONS, 0, 0, SKIP | OPT, 0, NULL}, | ||
302 | {FNAME("videoBadMBsCap") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
303 | }; | ||
304 | |||
305 | static field_t _H263VideoCapability[] = { /* SEQUENCE */ | ||
306 | {FNAME("sqcifMPI") INT, 5, 1, 0, SKIP | OPT, 0, NULL}, | ||
307 | {FNAME("qcifMPI") INT, 5, 1, 0, SKIP | OPT, 0, NULL}, | ||
308 | {FNAME("cifMPI") INT, 5, 1, 0, SKIP | OPT, 0, NULL}, | ||
309 | {FNAME("cif4MPI") INT, 5, 1, 0, SKIP | OPT, 0, NULL}, | ||
310 | {FNAME("cif16MPI") INT, 5, 1, 0, SKIP | OPT, 0, NULL}, | ||
311 | {FNAME("maxBitRate") INT, CONS, 1, 0, SKIP, 0, NULL}, | ||
312 | {FNAME("unrestrictedVector") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
313 | {FNAME("arithmeticCoding") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
314 | {FNAME("advancedPrediction") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
315 | {FNAME("pbFrames") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
316 | {FNAME("temporalSpatialTradeOffCapability") BOOL, FIXD, 0, 0, SKIP, 0, | ||
317 | NULL}, | ||
318 | {FNAME("hrd-B") INT, CONS, 0, 0, SKIP | OPT, 0, NULL}, | ||
319 | {FNAME("bppMaxKb") INT, WORD, 0, 0, SKIP | OPT, 0, NULL}, | ||
320 | {FNAME("slowSqcifMPI") INT, WORD, 1, 0, SKIP | OPT, 0, NULL}, | ||
321 | {FNAME("slowQcifMPI") INT, WORD, 1, 0, SKIP | OPT, 0, NULL}, | ||
322 | {FNAME("slowCifMPI") INT, WORD, 1, 0, SKIP | OPT, 0, NULL}, | ||
323 | {FNAME("slowCif4MPI") INT, WORD, 1, 0, SKIP | OPT, 0, NULL}, | ||
324 | {FNAME("slowCif16MPI") INT, WORD, 1, 0, SKIP | OPT, 0, NULL}, | ||
325 | {FNAME("errorCompensation") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
326 | {FNAME("enhancementLayerInfo") SEQ, 3, 4, 4, SKIP | EXT | OPT, 0, | ||
327 | NULL}, | ||
328 | {FNAME("h263Options") SEQ, 5, 29, 31, SKIP | EXT | OPT, 0, NULL}, | ||
329 | }; | ||
330 | |||
331 | static field_t _IS11172VideoCapability[] = { /* SEQUENCE */ | ||
332 | {FNAME("constrainedBitstream") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
333 | {FNAME("videoBitRate") INT, CONS, 0, 0, SKIP | OPT, 0, NULL}, | ||
334 | {FNAME("vbvBufferSize") INT, CONS, 0, 0, SKIP | OPT, 0, NULL}, | ||
335 | {FNAME("samplesPerLine") INT, WORD, 0, 0, SKIP | OPT, 0, NULL}, | ||
336 | {FNAME("linesPerFrame") INT, WORD, 0, 0, SKIP | OPT, 0, NULL}, | ||
337 | {FNAME("pictureRate") INT, 4, 0, 0, SKIP | OPT, 0, NULL}, | ||
338 | {FNAME("luminanceSampleRate") INT, CONS, 0, 0, SKIP | OPT, 0, NULL}, | ||
339 | {FNAME("videoBadMBsCap") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
340 | }; | ||
341 | |||
342 | static field_t _VideoCapability[] = { /* CHOICE */ | ||
343 | {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0, | ||
344 | _H245_NonStandardParameter}, | ||
345 | {FNAME("h261VideoCapability") SEQ, 2, 5, 6, SKIP | EXT, 0, | ||
346 | _H261VideoCapability}, | ||
347 | {FNAME("h262VideoCapability") SEQ, 6, 17, 18, SKIP | EXT, 0, | ||
348 | _H262VideoCapability}, | ||
349 | {FNAME("h263VideoCapability") SEQ, 7, 13, 21, SKIP | EXT, 0, | ||
350 | _H263VideoCapability}, | ||
351 | {FNAME("is11172VideoCapability") SEQ, 6, 7, 8, SKIP | EXT, 0, | ||
352 | _IS11172VideoCapability}, | ||
353 | {FNAME("genericVideoCapability") SEQ, 5, 6, 6, SKIP | EXT, 0, NULL}, | ||
354 | }; | ||
355 | |||
356 | static field_t _AudioCapability_g7231[] = { /* SEQUENCE */ | ||
357 | {FNAME("maxAl-sduAudioFrames") INT, BYTE, 1, 0, SKIP, 0, NULL}, | ||
358 | {FNAME("silenceSuppression") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
359 | }; | ||
360 | |||
361 | static field_t _IS11172AudioCapability[] = { /* SEQUENCE */ | ||
362 | {FNAME("audioLayer1") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
363 | {FNAME("audioLayer2") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
364 | {FNAME("audioLayer3") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
365 | {FNAME("audioSampling32k") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
366 | {FNAME("audioSampling44k1") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
367 | {FNAME("audioSampling48k") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
368 | {FNAME("singleChannel") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
369 | {FNAME("twoChannels") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
370 | {FNAME("bitRate") INT, WORD, 1, 0, SKIP, 0, NULL}, | ||
371 | }; | ||
372 | |||
373 | static field_t _IS13818AudioCapability[] = { /* SEQUENCE */ | ||
374 | {FNAME("audioLayer1") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
375 | {FNAME("audioLayer2") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
376 | {FNAME("audioLayer3") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
377 | {FNAME("audioSampling16k") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
378 | {FNAME("audioSampling22k05") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
379 | {FNAME("audioSampling24k") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
380 | {FNAME("audioSampling32k") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
381 | {FNAME("audioSampling44k1") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
382 | {FNAME("audioSampling48k") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
383 | {FNAME("singleChannel") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
384 | {FNAME("twoChannels") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
385 | {FNAME("threeChannels2-1") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
386 | {FNAME("threeChannels3-0") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
387 | {FNAME("fourChannels2-0-2-0") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
388 | {FNAME("fourChannels2-2") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
389 | {FNAME("fourChannels3-1") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
390 | {FNAME("fiveChannels3-0-2-0") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
391 | {FNAME("fiveChannels3-2") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
392 | {FNAME("lowFrequencyEnhancement") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
393 | {FNAME("multilingual") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
394 | {FNAME("bitRate") INT, WORD, 1, 0, SKIP, 0, NULL}, | ||
395 | }; | ||
396 | |||
397 | static field_t _AudioCapability[] = { /* CHOICE */ | ||
398 | {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0, | ||
399 | _H245_NonStandardParameter}, | ||
400 | {FNAME("g711Alaw64k") INT, BYTE, 1, 0, SKIP, 0, NULL}, | ||
401 | {FNAME("g711Alaw56k") INT, BYTE, 1, 0, SKIP, 0, NULL}, | ||
402 | {FNAME("g711Ulaw64k") INT, BYTE, 1, 0, SKIP, 0, NULL}, | ||
403 | {FNAME("g711Ulaw56k") INT, BYTE, 1, 0, SKIP, 0, NULL}, | ||
404 | {FNAME("g722-64k") INT, BYTE, 1, 0, SKIP, 0, NULL}, | ||
405 | {FNAME("g722-56k") INT, BYTE, 1, 0, SKIP, 0, NULL}, | ||
406 | {FNAME("g722-48k") INT, BYTE, 1, 0, SKIP, 0, NULL}, | ||
407 | {FNAME("g7231") SEQ, 0, 2, 2, SKIP, 0, _AudioCapability_g7231}, | ||
408 | {FNAME("g728") INT, BYTE, 1, 0, SKIP, 0, NULL}, | ||
409 | {FNAME("g729") INT, BYTE, 1, 0, SKIP, 0, NULL}, | ||
410 | {FNAME("g729AnnexA") INT, BYTE, 1, 0, SKIP, 0, NULL}, | ||
411 | {FNAME("is11172AudioCapability") SEQ, 0, 9, 9, SKIP | EXT, 0, | ||
412 | _IS11172AudioCapability}, | ||
413 | {FNAME("is13818AudioCapability") SEQ, 0, 21, 21, SKIP | EXT, 0, | ||
414 | _IS13818AudioCapability}, | ||
415 | {FNAME("g729wAnnexB") INT, BYTE, 1, 0, SKIP, 0, NULL}, | ||
416 | {FNAME("g729AnnexAwAnnexB") INT, BYTE, 1, 0, SKIP, 0, NULL}, | ||
417 | {FNAME("g7231AnnexCCapability") SEQ, 1, 3, 3, SKIP | EXT, 0, NULL}, | ||
418 | {FNAME("gsmFullRate") SEQ, 0, 3, 3, SKIP | EXT, 0, NULL}, | ||
419 | {FNAME("gsmHalfRate") SEQ, 0, 3, 3, SKIP | EXT, 0, NULL}, | ||
420 | {FNAME("gsmEnhancedFullRate") SEQ, 0, 3, 3, SKIP | EXT, 0, NULL}, | ||
421 | {FNAME("genericAudioCapability") SEQ, 5, 6, 6, SKIP | EXT, 0, NULL}, | ||
422 | {FNAME("g729Extensions") SEQ, 1, 8, 8, SKIP | EXT, 0, NULL}, | ||
423 | }; | ||
424 | |||
425 | static field_t _DataProtocolCapability[] = { /* CHOICE */ | ||
426 | {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0, | ||
427 | _H245_NonStandardParameter}, | ||
428 | {FNAME("v14buffered") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
429 | {FNAME("v42lapm") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
430 | {FNAME("hdlcFrameTunnelling") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
431 | {FNAME("h310SeparateVCStack") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
432 | {FNAME("h310SingleVCStack") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
433 | {FNAME("transparent") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
434 | {FNAME("segmentationAndReassembly") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
435 | {FNAME("hdlcFrameTunnelingwSAR") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
436 | {FNAME("v120") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
437 | {FNAME("separateLANStack") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
438 | {FNAME("v76wCompression") CHOICE, 2, 3, 3, SKIP | EXT, 0, NULL}, | ||
439 | {FNAME("tcp") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
440 | {FNAME("udp") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
441 | }; | ||
442 | |||
443 | static field_t _T84Profile_t84Restricted[] = { /* SEQUENCE */ | ||
444 | {FNAME("qcif") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
445 | {FNAME("cif") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
446 | {FNAME("ccir601Seq") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
447 | {FNAME("ccir601Prog") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
448 | {FNAME("hdtvSeq") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
449 | {FNAME("hdtvProg") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
450 | {FNAME("g3FacsMH200x100") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
451 | {FNAME("g3FacsMH200x200") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
452 | {FNAME("g4FacsMMR200x100") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
453 | {FNAME("g4FacsMMR200x200") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
454 | {FNAME("jbig200x200Seq") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
455 | {FNAME("jbig200x200Prog") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
456 | {FNAME("jbig300x300Seq") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
457 | {FNAME("jbig300x300Prog") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
458 | {FNAME("digPhotoLow") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
459 | {FNAME("digPhotoMedSeq") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
460 | {FNAME("digPhotoMedProg") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
461 | {FNAME("digPhotoHighSeq") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
462 | {FNAME("digPhotoHighProg") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
463 | }; | ||
464 | |||
465 | static field_t _T84Profile[] = { /* CHOICE */ | ||
466 | {FNAME("t84Unrestricted") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
467 | {FNAME("t84Restricted") SEQ, 0, 19, 19, SKIP | EXT, 0, | ||
468 | _T84Profile_t84Restricted}, | ||
469 | }; | ||
470 | |||
471 | static field_t _DataApplicationCapability_application_t84[] = { /* SEQUENCE */ | ||
472 | {FNAME("t84Protocol") CHOICE, 3, 7, 14, SKIP | EXT, 0, | ||
473 | _DataProtocolCapability}, | ||
474 | {FNAME("t84Profile") CHOICE, 1, 2, 2, SKIP, 0, _T84Profile}, | ||
475 | }; | ||
476 | |||
477 | static field_t _DataApplicationCapability_application_nlpid[] = { /* SEQUENCE */ | ||
478 | {FNAME("nlpidProtocol") CHOICE, 3, 7, 14, SKIP | EXT, 0, | ||
479 | _DataProtocolCapability}, | ||
480 | {FNAME("nlpidData") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL}, | ||
481 | }; | ||
482 | |||
483 | static field_t _DataApplicationCapability_application[] = { /* CHOICE */ | ||
484 | {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0, | ||
485 | _H245_NonStandardParameter}, | ||
486 | {FNAME("t120") CHOICE, 3, 7, 14, DECODE | EXT, | ||
487 | offsetof(DataApplicationCapability_application, t120), | ||
488 | _DataProtocolCapability}, | ||
489 | {FNAME("dsm-cc") CHOICE, 3, 7, 14, SKIP | EXT, 0, | ||
490 | _DataProtocolCapability}, | ||
491 | {FNAME("userData") CHOICE, 3, 7, 14, SKIP | EXT, 0, | ||
492 | _DataProtocolCapability}, | ||
493 | {FNAME("t84") SEQ, 0, 2, 2, SKIP, 0, | ||
494 | _DataApplicationCapability_application_t84}, | ||
495 | {FNAME("t434") CHOICE, 3, 7, 14, SKIP | EXT, 0, | ||
496 | _DataProtocolCapability}, | ||
497 | {FNAME("h224") CHOICE, 3, 7, 14, SKIP | EXT, 0, | ||
498 | _DataProtocolCapability}, | ||
499 | {FNAME("nlpid") SEQ, 0, 2, 2, SKIP, 0, | ||
500 | _DataApplicationCapability_application_nlpid}, | ||
501 | {FNAME("dsvdControl") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
502 | {FNAME("h222DataPartitioning") CHOICE, 3, 7, 14, SKIP | EXT, 0, | ||
503 | _DataProtocolCapability}, | ||
504 | {FNAME("t30fax") CHOICE, 3, 7, 14, SKIP | EXT, 0, NULL}, | ||
505 | {FNAME("t140") CHOICE, 3, 7, 14, SKIP | EXT, 0, NULL}, | ||
506 | {FNAME("t38fax") SEQ, 0, 2, 2, SKIP, 0, NULL}, | ||
507 | {FNAME("genericDataCapability") SEQ, 5, 6, 6, SKIP | EXT, 0, NULL}, | ||
508 | }; | ||
509 | |||
510 | static field_t _DataApplicationCapability[] = { /* SEQUENCE */ | ||
511 | {FNAME("application") CHOICE, 4, 10, 14, DECODE | EXT, | ||
512 | offsetof(DataApplicationCapability, application), | ||
513 | _DataApplicationCapability_application}, | ||
514 | {FNAME("maxBitRate") INT, CONS, 0, 0, SKIP, 0, NULL}, | ||
515 | }; | ||
516 | |||
517 | static field_t _EncryptionMode[] = { /* CHOICE */ | ||
518 | {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0, | ||
519 | _H245_NonStandardParameter}, | ||
520 | {FNAME("h233Encryption") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
521 | }; | ||
522 | |||
523 | static field_t _DataType[] = { /* CHOICE */ | ||
524 | {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0, | ||
525 | _H245_NonStandardParameter}, | ||
526 | {FNAME("nullData") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
527 | {FNAME("videoData") CHOICE, 3, 5, 6, SKIP | EXT, 0, _VideoCapability}, | ||
528 | {FNAME("audioData") CHOICE, 4, 14, 22, SKIP | EXT, 0, | ||
529 | _AudioCapability}, | ||
530 | {FNAME("data") SEQ, 0, 2, 2, DECODE | EXT, offsetof(DataType, data), | ||
531 | _DataApplicationCapability}, | ||
532 | {FNAME("encryptionData") CHOICE, 1, 2, 2, SKIP | EXT, 0, | ||
533 | _EncryptionMode}, | ||
534 | {FNAME("h235Control") SEQ, 0, 2, 2, SKIP, 0, NULL}, | ||
535 | {FNAME("h235Media") SEQ, 0, 2, 2, SKIP | EXT, 0, NULL}, | ||
536 | {FNAME("multiplexedStream") SEQ, 0, 2, 2, SKIP | EXT, 0, NULL}, | ||
537 | }; | ||
538 | |||
539 | static field_t _H222LogicalChannelParameters[] = { /* SEQUENCE */ | ||
540 | {FNAME("resourceID") INT, WORD, 0, 0, SKIP, 0, NULL}, | ||
541 | {FNAME("subChannelID") INT, WORD, 0, 0, SKIP, 0, NULL}, | ||
542 | {FNAME("pcr-pid") INT, WORD, 0, 0, SKIP | OPT, 0, NULL}, | ||
543 | {FNAME("programDescriptors") OCTSTR, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
544 | {FNAME("streamDescriptors") OCTSTR, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
545 | }; | ||
546 | |||
547 | static field_t _H223LogicalChannelParameters_adaptationLayerType_al3[] = { /* SEQUENCE */ | ||
548 | {FNAME("controlFieldOctets") INT, 2, 0, 0, SKIP, 0, NULL}, | ||
549 | {FNAME("sendBufferSize") INT, CONS, 0, 0, SKIP, 0, NULL}, | ||
550 | }; | ||
551 | |||
552 | static field_t _H223LogicalChannelParameters_adaptationLayerType[] = { /* CHOICE */ | ||
553 | {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0, | ||
554 | _H245_NonStandardParameter}, | ||
555 | {FNAME("al1Framed") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
556 | {FNAME("al1NotFramed") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
557 | {FNAME("al2WithoutSequenceNumbers") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
558 | {FNAME("al2WithSequenceNumbers") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
559 | {FNAME("al3") SEQ, 0, 2, 2, SKIP, 0, | ||
560 | _H223LogicalChannelParameters_adaptationLayerType_al3}, | ||
561 | {FNAME("al1M") SEQ, 0, 7, 8, SKIP | EXT, 0, NULL}, | ||
562 | {FNAME("al2M") SEQ, 0, 2, 2, SKIP | EXT, 0, NULL}, | ||
563 | {FNAME("al3M") SEQ, 0, 5, 6, SKIP | EXT, 0, NULL}, | ||
564 | }; | ||
565 | |||
566 | static field_t _H223LogicalChannelParameters[] = { /* SEQUENCE */ | ||
567 | {FNAME("adaptationLayerType") CHOICE, 3, 6, 9, SKIP | EXT, 0, | ||
568 | _H223LogicalChannelParameters_adaptationLayerType}, | ||
569 | {FNAME("segmentableFlag") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
570 | }; | ||
571 | |||
572 | static field_t _CRCLength[] = { /* CHOICE */ | ||
573 | {FNAME("crc8bit") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
574 | {FNAME("crc16bit") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
575 | {FNAME("crc32bit") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
576 | }; | ||
577 | |||
578 | static field_t _V76HDLCParameters[] = { /* SEQUENCE */ | ||
579 | {FNAME("crcLength") CHOICE, 2, 3, 3, SKIP | EXT, 0, _CRCLength}, | ||
580 | {FNAME("n401") INT, WORD, 1, 0, SKIP, 0, NULL}, | ||
581 | {FNAME("loopbackTestProcedure") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
582 | }; | ||
583 | |||
584 | static field_t _V76LogicalChannelParameters_suspendResume[] = { /* CHOICE */ | ||
585 | {FNAME("noSuspendResume") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
586 | {FNAME("suspendResumewAddress") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
587 | {FNAME("suspendResumewoAddress") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
588 | }; | ||
589 | |||
590 | static field_t _V76LogicalChannelParameters_mode_eRM_recovery[] = { /* CHOICE */ | ||
591 | {FNAME("rej") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
592 | {FNAME("sREJ") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
593 | {FNAME("mSREJ") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
594 | }; | ||
595 | |||
596 | static field_t _V76LogicalChannelParameters_mode_eRM[] = { /* SEQUENCE */ | ||
597 | {FNAME("windowSize") INT, 7, 1, 0, SKIP, 0, NULL}, | ||
598 | {FNAME("recovery") CHOICE, 2, 3, 3, SKIP | EXT, 0, | ||
599 | _V76LogicalChannelParameters_mode_eRM_recovery}, | ||
600 | }; | ||
601 | |||
602 | static field_t _V76LogicalChannelParameters_mode[] = { /* CHOICE */ | ||
603 | {FNAME("eRM") SEQ, 0, 2, 2, SKIP | EXT, 0, | ||
604 | _V76LogicalChannelParameters_mode_eRM}, | ||
605 | {FNAME("uNERM") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
606 | }; | ||
607 | |||
608 | static field_t _V75Parameters[] = { /* SEQUENCE */ | ||
609 | {FNAME("audioHeaderPresent") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
610 | }; | ||
611 | |||
612 | static field_t _V76LogicalChannelParameters[] = { /* SEQUENCE */ | ||
613 | {FNAME("hdlcParameters") SEQ, 0, 3, 3, SKIP | EXT, 0, | ||
614 | _V76HDLCParameters}, | ||
615 | {FNAME("suspendResume") CHOICE, 2, 3, 3, SKIP | EXT, 0, | ||
616 | _V76LogicalChannelParameters_suspendResume}, | ||
617 | {FNAME("uIH") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
618 | {FNAME("mode") CHOICE, 1, 2, 2, SKIP | EXT, 0, | ||
619 | _V76LogicalChannelParameters_mode}, | ||
620 | {FNAME("v75Parameters") SEQ, 0, 1, 1, SKIP | EXT, 0, _V75Parameters}, | ||
621 | }; | ||
622 | |||
623 | static field_t _H2250LogicalChannelParameters_nonStandard[] = { /* SEQUENCE OF */ | ||
624 | {FNAME("item") SEQ, 0, 2, 2, SKIP, 0, _H245_NonStandardParameter}, | ||
625 | }; | ||
626 | |||
627 | static field_t _UnicastAddress_iPAddress[] = { /* SEQUENCE */ | ||
628 | {FNAME("network") OCTSTR, FIXD, 4, 0, DECODE, | ||
629 | offsetof(UnicastAddress_iPAddress, network), NULL}, | ||
630 | {FNAME("tsapIdentifier") INT, WORD, 0, 0, SKIP, 0, NULL}, | ||
631 | }; | ||
632 | |||
633 | static field_t _UnicastAddress_iPXAddress[] = { /* SEQUENCE */ | ||
634 | {FNAME("node") OCTSTR, FIXD, 6, 0, SKIP, 0, NULL}, | ||
635 | {FNAME("netnum") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL}, | ||
636 | {FNAME("tsapIdentifier") OCTSTR, FIXD, 2, 0, SKIP, 0, NULL}, | ||
637 | }; | ||
638 | |||
639 | static field_t _UnicastAddress_iP6Address[] = { /* SEQUENCE */ | ||
640 | {FNAME("network") OCTSTR, FIXD, 16, 0, SKIP, 0, NULL}, | ||
641 | {FNAME("tsapIdentifier") INT, WORD, 0, 0, SKIP, 0, NULL}, | ||
642 | }; | ||
643 | |||
644 | static field_t _UnicastAddress_iPSourceRouteAddress_routing[] = { /* CHOICE */ | ||
645 | {FNAME("strict") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
646 | {FNAME("loose") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
647 | }; | ||
648 | |||
649 | static field_t _UnicastAddress_iPSourceRouteAddress_route[] = { /* SEQUENCE OF */ | ||
650 | {FNAME("item") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL}, | ||
651 | }; | ||
652 | |||
653 | static field_t _UnicastAddress_iPSourceRouteAddress[] = { /* SEQUENCE */ | ||
654 | {FNAME("routing") CHOICE, 1, 2, 2, SKIP, 0, | ||
655 | _UnicastAddress_iPSourceRouteAddress_routing}, | ||
656 | {FNAME("network") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL}, | ||
657 | {FNAME("tsapIdentifier") INT, WORD, 0, 0, SKIP, 0, NULL}, | ||
658 | {FNAME("route") SEQOF, SEMI, 0, 0, SKIP, 0, | ||
659 | _UnicastAddress_iPSourceRouteAddress_route}, | ||
660 | }; | ||
661 | |||
662 | static field_t _UnicastAddress[] = { /* CHOICE */ | ||
663 | {FNAME("iPAddress") SEQ, 0, 2, 2, DECODE | EXT, | ||
664 | offsetof(UnicastAddress, iPAddress), _UnicastAddress_iPAddress}, | ||
665 | {FNAME("iPXAddress") SEQ, 0, 3, 3, SKIP | EXT, 0, | ||
666 | _UnicastAddress_iPXAddress}, | ||
667 | {FNAME("iP6Address") SEQ, 0, 2, 2, SKIP | EXT, 0, | ||
668 | _UnicastAddress_iP6Address}, | ||
669 | {FNAME("netBios") OCTSTR, FIXD, 16, 0, SKIP, 0, NULL}, | ||
670 | {FNAME("iPSourceRouteAddress") SEQ, 0, 4, 4, SKIP | EXT, 0, | ||
671 | _UnicastAddress_iPSourceRouteAddress}, | ||
672 | {FNAME("nsap") OCTSTR, 5, 1, 0, SKIP, 0, NULL}, | ||
673 | {FNAME("nonStandardAddress") SEQ, 0, 2, 2, SKIP, 0, NULL}, | ||
674 | }; | ||
675 | |||
676 | static field_t _MulticastAddress_iPAddress[] = { /* SEQUENCE */ | ||
677 | {FNAME("network") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL}, | ||
678 | {FNAME("tsapIdentifier") INT, WORD, 0, 0, SKIP, 0, NULL}, | ||
679 | }; | ||
680 | |||
681 | static field_t _MulticastAddress_iP6Address[] = { /* SEQUENCE */ | ||
682 | {FNAME("network") OCTSTR, FIXD, 16, 0, SKIP, 0, NULL}, | ||
683 | {FNAME("tsapIdentifier") INT, WORD, 0, 0, SKIP, 0, NULL}, | ||
684 | }; | ||
685 | |||
686 | static field_t _MulticastAddress[] = { /* CHOICE */ | ||
687 | {FNAME("iPAddress") SEQ, 0, 2, 2, SKIP | EXT, 0, | ||
688 | _MulticastAddress_iPAddress}, | ||
689 | {FNAME("iP6Address") SEQ, 0, 2, 2, SKIP | EXT, 0, | ||
690 | _MulticastAddress_iP6Address}, | ||
691 | {FNAME("nsap") OCTSTR, 5, 1, 0, SKIP, 0, NULL}, | ||
692 | {FNAME("nonStandardAddress") SEQ, 0, 2, 2, SKIP, 0, NULL}, | ||
693 | }; | ||
694 | |||
695 | static field_t _H245_TransportAddress[] = { /* CHOICE */ | ||
696 | {FNAME("unicastAddress") CHOICE, 3, 5, 7, DECODE | EXT, | ||
697 | offsetof(H245_TransportAddress, unicastAddress), _UnicastAddress}, | ||
698 | {FNAME("multicastAddress") CHOICE, 1, 2, 4, SKIP | EXT, 0, | ||
699 | _MulticastAddress}, | ||
700 | }; | ||
701 | |||
702 | static field_t _H2250LogicalChannelParameters[] = { /* SEQUENCE */ | ||
703 | {FNAME("nonStandard") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, | ||
704 | _H2250LogicalChannelParameters_nonStandard}, | ||
705 | {FNAME("sessionID") INT, BYTE, 0, 0, SKIP, 0, NULL}, | ||
706 | {FNAME("associatedSessionID") INT, 8, 1, 0, SKIP | OPT, 0, NULL}, | ||
707 | {FNAME("mediaChannel") CHOICE, 1, 2, 2, DECODE | EXT | OPT, | ||
708 | offsetof(H2250LogicalChannelParameters, mediaChannel), | ||
709 | _H245_TransportAddress}, | ||
710 | {FNAME("mediaGuaranteedDelivery") BOOL, FIXD, 0, 0, SKIP | OPT, 0, | ||
711 | NULL}, | ||
712 | {FNAME("mediaControlChannel") CHOICE, 1, 2, 2, DECODE | EXT | OPT, | ||
713 | offsetof(H2250LogicalChannelParameters, mediaControlChannel), | ||
714 | _H245_TransportAddress}, | ||
715 | {FNAME("mediaControlGuaranteedDelivery") BOOL, FIXD, 0, 0, STOP | OPT, | ||
716 | 0, NULL}, | ||
717 | {FNAME("silenceSuppression") BOOL, FIXD, 0, 0, STOP | OPT, 0, NULL}, | ||
718 | {FNAME("destination") SEQ, 0, 2, 2, STOP | EXT | OPT, 0, NULL}, | ||
719 | {FNAME("dynamicRTPPayloadType") INT, 5, 96, 0, STOP | OPT, 0, NULL}, | ||
720 | {FNAME("mediaPacketization") CHOICE, 0, 1, 2, STOP | EXT | OPT, 0, | ||
721 | NULL}, | ||
722 | {FNAME("transportCapability") SEQ, 3, 3, 3, STOP | EXT | OPT, 0, | ||
723 | NULL}, | ||
724 | {FNAME("redundancyEncoding") SEQ, 1, 2, 2, STOP | EXT | OPT, 0, NULL}, | ||
725 | {FNAME("source") SEQ, 0, 2, 2, SKIP | EXT | OPT, 0, NULL}, | ||
726 | }; | ||
727 | |||
728 | static field_t _OpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters[] = { /* CHOICE */ | ||
729 | {FNAME("h222LogicalChannelParameters") SEQ, 3, 5, 5, SKIP | EXT, 0, | ||
730 | _H222LogicalChannelParameters}, | ||
731 | {FNAME("h223LogicalChannelParameters") SEQ, 0, 2, 2, SKIP | EXT, 0, | ||
732 | _H223LogicalChannelParameters}, | ||
733 | {FNAME("v76LogicalChannelParameters") SEQ, 0, 5, 5, SKIP | EXT, 0, | ||
734 | _V76LogicalChannelParameters}, | ||
735 | {FNAME("h2250LogicalChannelParameters") SEQ, 10, 11, 14, DECODE | EXT, | ||
736 | offsetof | ||
737 | (OpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters, | ||
738 | h2250LogicalChannelParameters), _H2250LogicalChannelParameters}, | ||
739 | {FNAME("none") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
740 | }; | ||
741 | |||
742 | static field_t _OpenLogicalChannel_forwardLogicalChannelParameters[] = { /* SEQUENCE */ | ||
743 | {FNAME("portNumber") INT, WORD, 0, 0, SKIP | OPT, 0, NULL}, | ||
744 | {FNAME("dataType") CHOICE, 3, 6, 9, DECODE | EXT, | ||
745 | offsetof(OpenLogicalChannel_forwardLogicalChannelParameters, | ||
746 | dataType), _DataType}, | ||
747 | {FNAME("multiplexParameters") CHOICE, 2, 3, 5, DECODE | EXT, | ||
748 | offsetof(OpenLogicalChannel_forwardLogicalChannelParameters, | ||
749 | multiplexParameters), | ||
750 | _OpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters}, | ||
751 | {FNAME("forwardLogicalChannelDependency") INT, WORD, 1, 0, SKIP | OPT, | ||
752 | 0, NULL}, | ||
753 | {FNAME("replacementFor") INT, WORD, 1, 0, SKIP | OPT, 0, NULL}, | ||
754 | }; | ||
755 | |||
756 | static field_t _OpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters[] = { /* CHOICE */ | ||
757 | {FNAME("h223LogicalChannelParameters") SEQ, 0, 2, 2, SKIP | EXT, 0, | ||
758 | _H223LogicalChannelParameters}, | ||
759 | {FNAME("v76LogicalChannelParameters") SEQ, 0, 5, 5, SKIP | EXT, 0, | ||
760 | _V76LogicalChannelParameters}, | ||
761 | {FNAME("h2250LogicalChannelParameters") SEQ, 10, 11, 14, DECODE | EXT, | ||
762 | offsetof | ||
763 | (OpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters, | ||
764 | h2250LogicalChannelParameters), _H2250LogicalChannelParameters}, | ||
765 | }; | ||
766 | |||
767 | static field_t _OpenLogicalChannel_reverseLogicalChannelParameters[] = { /* SEQUENCE */ | ||
768 | {FNAME("dataType") CHOICE, 3, 6, 9, SKIP | EXT, 0, _DataType}, | ||
769 | {FNAME("multiplexParameters") CHOICE, 1, 2, 3, DECODE | EXT | OPT, | ||
770 | offsetof(OpenLogicalChannel_reverseLogicalChannelParameters, | ||
771 | multiplexParameters), | ||
772 | _OpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters}, | ||
773 | {FNAME("reverseLogicalChannelDependency") INT, WORD, 1, 0, SKIP | OPT, | ||
774 | 0, NULL}, | ||
775 | {FNAME("replacementFor") INT, WORD, 1, 0, SKIP | OPT, 0, NULL}, | ||
776 | }; | ||
777 | |||
778 | static field_t _NetworkAccessParameters_distribution[] = { /* CHOICE */ | ||
779 | {FNAME("unicast") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
780 | {FNAME("multicast") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
781 | }; | ||
782 | |||
783 | static field_t _Q2931Address_address[] = { /* CHOICE */ | ||
784 | {FNAME("internationalNumber") NUMSTR, 4, 1, 0, SKIP, 0, NULL}, | ||
785 | {FNAME("nsapAddress") OCTSTR, 5, 1, 0, SKIP, 0, NULL}, | ||
786 | }; | ||
787 | |||
788 | static field_t _Q2931Address[] = { /* SEQUENCE */ | ||
789 | {FNAME("address") CHOICE, 1, 2, 2, SKIP | EXT, 0, | ||
790 | _Q2931Address_address}, | ||
791 | {FNAME("subaddress") OCTSTR, 5, 1, 0, SKIP | OPT, 0, NULL}, | ||
792 | }; | ||
793 | |||
794 | static field_t _NetworkAccessParameters_networkAddress[] = { /* CHOICE */ | ||
795 | {FNAME("q2931Address") SEQ, 1, 2, 2, SKIP | EXT, 0, _Q2931Address}, | ||
796 | {FNAME("e164Address") NUMDGT, 7, 1, 0, SKIP, 0, NULL}, | ||
797 | {FNAME("localAreaAddress") CHOICE, 1, 2, 2, DECODE | EXT, | ||
798 | offsetof(NetworkAccessParameters_networkAddress, localAreaAddress), | ||
799 | _H245_TransportAddress}, | ||
800 | }; | ||
801 | |||
802 | static field_t _NetworkAccessParameters[] = { /* SEQUENCE */ | ||
803 | {FNAME("distribution") CHOICE, 1, 2, 2, SKIP | EXT | OPT, 0, | ||
804 | _NetworkAccessParameters_distribution}, | ||
805 | {FNAME("networkAddress") CHOICE, 2, 3, 3, DECODE | EXT, | ||
806 | offsetof(NetworkAccessParameters, networkAddress), | ||
807 | _NetworkAccessParameters_networkAddress}, | ||
808 | {FNAME("associateConference") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
809 | {FNAME("externalReference") OCTSTR, 8, 1, 0, SKIP | OPT, 0, NULL}, | ||
810 | {FNAME("t120SetupProcedure") CHOICE, 2, 3, 3, SKIP | EXT | OPT, 0, | ||
811 | NULL}, | ||
812 | }; | ||
813 | |||
814 | static field_t _OpenLogicalChannel[] = { /* SEQUENCE */ | ||
815 | {FNAME("forwardLogicalChannelNumber") INT, WORD, 1, 0, SKIP, 0, NULL}, | ||
816 | {FNAME("forwardLogicalChannelParameters") SEQ, 1, 3, 5, DECODE | EXT, | ||
817 | offsetof(OpenLogicalChannel, forwardLogicalChannelParameters), | ||
818 | _OpenLogicalChannel_forwardLogicalChannelParameters}, | ||
819 | {FNAME("reverseLogicalChannelParameters") SEQ, 1, 2, 4, | ||
820 | DECODE | EXT | OPT, offsetof(OpenLogicalChannel, | ||
821 | reverseLogicalChannelParameters), | ||
822 | _OpenLogicalChannel_reverseLogicalChannelParameters}, | ||
823 | {FNAME("separateStack") SEQ, 2, 4, 5, DECODE | EXT | OPT, | ||
824 | offsetof(OpenLogicalChannel, separateStack), | ||
825 | _NetworkAccessParameters}, | ||
826 | {FNAME("encryptionSync") SEQ, 2, 4, 4, STOP | EXT | OPT, 0, NULL}, | ||
827 | }; | ||
828 | |||
829 | static field_t _Setup_UUIE_fastStart[] = { /* SEQUENCE OF */ | ||
830 | {FNAME("item") SEQ, 1, 3, 5, DECODE | OPEN | EXT, | ||
831 | sizeof(OpenLogicalChannel), _OpenLogicalChannel} | ||
832 | , | ||
833 | }; | ||
834 | |||
835 | static field_t _Setup_UUIE[] = { /* SEQUENCE */ | ||
836 | {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, | ||
837 | {FNAME("h245Address") CHOICE, 3, 7, 7, DECODE | EXT | OPT, | ||
838 | offsetof(Setup_UUIE, h245Address), _TransportAddress}, | ||
839 | {FNAME("sourceAddress") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, | ||
840 | _Setup_UUIE_sourceAddress}, | ||
841 | {FNAME("sourceInfo") SEQ, 6, 8, 10, SKIP | EXT, 0, _EndpointType}, | ||
842 | {FNAME("destinationAddress") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, | ||
843 | _Setup_UUIE_destinationAddress}, | ||
844 | {FNAME("destCallSignalAddress") CHOICE, 3, 7, 7, DECODE | EXT | OPT, | ||
845 | offsetof(Setup_UUIE, destCallSignalAddress), _TransportAddress}, | ||
846 | {FNAME("destExtraCallInfo") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, | ||
847 | _Setup_UUIE_destExtraCallInfo}, | ||
848 | {FNAME("destExtraCRV") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, | ||
849 | _Setup_UUIE_destExtraCRV}, | ||
850 | {FNAME("activeMC") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
851 | {FNAME("conferenceID") OCTSTR, FIXD, 16, 0, SKIP, 0, NULL}, | ||
852 | {FNAME("conferenceGoal") CHOICE, 2, 3, 5, SKIP | EXT, 0, | ||
853 | _Setup_UUIE_conferenceGoal}, | ||
854 | {FNAME("callServices") SEQ, 0, 8, 8, SKIP | EXT | OPT, 0, | ||
855 | _QseriesOptions}, | ||
856 | {FNAME("callType") CHOICE, 2, 4, 4, SKIP | EXT, 0, _CallType}, | ||
857 | {FNAME("sourceCallSignalAddress") CHOICE, 3, 7, 7, DECODE | EXT | OPT, | ||
858 | offsetof(Setup_UUIE, sourceCallSignalAddress), _TransportAddress}, | ||
859 | {FNAME("remoteExtensionAddress") CHOICE, 1, 2, 7, SKIP | EXT | OPT, 0, | ||
860 | NULL}, | ||
861 | {FNAME("callIdentifier") SEQ, 0, 1, 1, SKIP | EXT, 0, NULL}, | ||
862 | {FNAME("h245SecurityCapability") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, | ||
863 | NULL}, | ||
864 | {FNAME("tokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
865 | {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
866 | {FNAME("fastStart") SEQOF, SEMI, 0, 30, DECODE | OPT, | ||
867 | offsetof(Setup_UUIE, fastStart), _Setup_UUIE_fastStart}, | ||
868 | {FNAME("mediaWaitForConnect") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
869 | {FNAME("canOverlapSend") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
870 | {FNAME("endpointIdentifier") BMPSTR, 7, 1, 0, STOP | OPT, 0, NULL}, | ||
871 | {FNAME("multipleCalls") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
872 | {FNAME("maintainConnection") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
873 | {FNAME("connectionParameters") SEQ, 0, 3, 3, SKIP | EXT | OPT, 0, | ||
874 | NULL}, | ||
875 | {FNAME("language") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
876 | {FNAME("presentationIndicator") CHOICE, 2, 3, 3, SKIP | EXT | OPT, 0, | ||
877 | NULL}, | ||
878 | {FNAME("screeningIndicator") ENUM, 2, 0, 0, SKIP | EXT | OPT, 0, | ||
879 | NULL}, | ||
880 | {FNAME("serviceControl") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
881 | {FNAME("symmetricOperationRequired") NUL, FIXD, 0, 0, SKIP | OPT, 0, | ||
882 | NULL}, | ||
883 | {FNAME("capacity") SEQ, 2, 2, 2, SKIP | EXT | OPT, 0, NULL}, | ||
884 | {FNAME("circuitInfo") SEQ, 3, 3, 3, SKIP | EXT | OPT, 0, NULL}, | ||
885 | {FNAME("desiredProtocols") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
886 | {FNAME("neededFeatures") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
887 | {FNAME("desiredFeatures") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
888 | {FNAME("supportedFeatures") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
889 | {FNAME("parallelH245Control") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
890 | {FNAME("additionalSourceAddresses") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, | ||
891 | NULL}, | ||
892 | }; | ||
893 | |||
894 | static field_t _CallProceeding_UUIE_fastStart[] = { /* SEQUENCE OF */ | ||
895 | {FNAME("item") SEQ, 1, 3, 5, DECODE | OPEN | EXT, | ||
896 | sizeof(OpenLogicalChannel), _OpenLogicalChannel} | ||
897 | , | ||
898 | }; | ||
899 | |||
900 | static field_t _CallProceeding_UUIE[] = { /* SEQUENCE */ | ||
901 | {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, | ||
902 | {FNAME("destinationInfo") SEQ, 6, 8, 10, SKIP | EXT, 0, | ||
903 | _EndpointType}, | ||
904 | {FNAME("h245Address") CHOICE, 3, 7, 7, DECODE | EXT | OPT, | ||
905 | offsetof(CallProceeding_UUIE, h245Address), _TransportAddress}, | ||
906 | {FNAME("callIdentifier") SEQ, 0, 1, 1, SKIP | EXT, 0, NULL}, | ||
907 | {FNAME("h245SecurityMode") CHOICE, 2, 4, 4, SKIP | EXT | OPT, 0, | ||
908 | NULL}, | ||
909 | {FNAME("tokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
910 | {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
911 | {FNAME("fastStart") SEQOF, SEMI, 0, 30, DECODE | OPT, | ||
912 | offsetof(CallProceeding_UUIE, fastStart), | ||
913 | _CallProceeding_UUIE_fastStart}, | ||
914 | {FNAME("multipleCalls") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
915 | {FNAME("maintainConnection") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
916 | {FNAME("fastConnectRefused") NUL, FIXD, 0, 0, SKIP | OPT, 0, NULL}, | ||
917 | {FNAME("featureSet") SEQ, 3, 4, 4, SKIP | EXT | OPT, 0, NULL}, | ||
918 | }; | ||
919 | |||
920 | static field_t _Connect_UUIE_fastStart[] = { /* SEQUENCE OF */ | ||
921 | {FNAME("item") SEQ, 1, 3, 5, DECODE | OPEN | EXT, | ||
922 | sizeof(OpenLogicalChannel), _OpenLogicalChannel} | ||
923 | , | ||
924 | }; | ||
925 | |||
926 | static field_t _Connect_UUIE[] = { /* SEQUENCE */ | ||
927 | {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, | ||
928 | {FNAME("h245Address") CHOICE, 3, 7, 7, DECODE | EXT | OPT, | ||
929 | offsetof(Connect_UUIE, h245Address), _TransportAddress}, | ||
930 | {FNAME("destinationInfo") SEQ, 6, 8, 10, SKIP | EXT, 0, | ||
931 | _EndpointType}, | ||
932 | {FNAME("conferenceID") OCTSTR, FIXD, 16, 0, SKIP, 0, NULL}, | ||
933 | {FNAME("callIdentifier") SEQ, 0, 1, 1, SKIP | EXT, 0, NULL}, | ||
934 | {FNAME("h245SecurityMode") CHOICE, 2, 4, 4, SKIP | EXT | OPT, 0, | ||
935 | NULL}, | ||
936 | {FNAME("tokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
937 | {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
938 | {FNAME("fastStart") SEQOF, SEMI, 0, 30, DECODE | OPT, | ||
939 | offsetof(Connect_UUIE, fastStart), _Connect_UUIE_fastStart}, | ||
940 | {FNAME("multipleCalls") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
941 | {FNAME("maintainConnection") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
942 | {FNAME("language") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
943 | {FNAME("connectedAddress") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
944 | {FNAME("presentationIndicator") CHOICE, 2, 3, 3, SKIP | EXT | OPT, 0, | ||
945 | NULL}, | ||
946 | {FNAME("screeningIndicator") ENUM, 2, 0, 0, SKIP | EXT | OPT, 0, | ||
947 | NULL}, | ||
948 | {FNAME("fastConnectRefused") NUL, FIXD, 0, 0, SKIP | OPT, 0, NULL}, | ||
949 | {FNAME("serviceControl") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
950 | {FNAME("capacity") SEQ, 2, 2, 2, SKIP | EXT | OPT, 0, NULL}, | ||
951 | {FNAME("featureSet") SEQ, 3, 4, 4, SKIP | EXT | OPT, 0, NULL}, | ||
952 | }; | ||
953 | |||
954 | static field_t _Alerting_UUIE_fastStart[] = { /* SEQUENCE OF */ | ||
955 | {FNAME("item") SEQ, 1, 3, 5, DECODE | OPEN | EXT, | ||
956 | sizeof(OpenLogicalChannel), _OpenLogicalChannel} | ||
957 | , | ||
958 | }; | ||
959 | |||
960 | static field_t _Alerting_UUIE[] = { /* SEQUENCE */ | ||
961 | {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, | ||
962 | {FNAME("destinationInfo") SEQ, 6, 8, 10, SKIP | EXT, 0, | ||
963 | _EndpointType}, | ||
964 | {FNAME("h245Address") CHOICE, 3, 7, 7, DECODE | EXT | OPT, | ||
965 | offsetof(Alerting_UUIE, h245Address), _TransportAddress}, | ||
966 | {FNAME("callIdentifier") SEQ, 0, 1, 1, SKIP | EXT, 0, NULL}, | ||
967 | {FNAME("h245SecurityMode") CHOICE, 2, 4, 4, SKIP | EXT | OPT, 0, | ||
968 | NULL}, | ||
969 | {FNAME("tokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
970 | {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
971 | {FNAME("fastStart") SEQOF, SEMI, 0, 30, DECODE | OPT, | ||
972 | offsetof(Alerting_UUIE, fastStart), _Alerting_UUIE_fastStart}, | ||
973 | {FNAME("multipleCalls") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
974 | {FNAME("maintainConnection") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
975 | {FNAME("alertingAddress") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
976 | {FNAME("presentationIndicator") CHOICE, 2, 3, 3, SKIP | EXT | OPT, 0, | ||
977 | NULL}, | ||
978 | {FNAME("screeningIndicator") ENUM, 2, 0, 0, SKIP | EXT | OPT, 0, | ||
979 | NULL}, | ||
980 | {FNAME("fastConnectRefused") NUL, FIXD, 0, 0, SKIP | OPT, 0, NULL}, | ||
981 | {FNAME("serviceControl") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
982 | {FNAME("capacity") SEQ, 2, 2, 2, SKIP | EXT | OPT, 0, NULL}, | ||
983 | {FNAME("featureSet") SEQ, 3, 4, 4, SKIP | EXT | OPT, 0, NULL}, | ||
984 | }; | ||
985 | |||
986 | static field_t _Information_UUIE_fastStart[] = { /* SEQUENCE OF */ | ||
987 | {FNAME("item") SEQ, 1, 3, 5, DECODE | OPEN | EXT, | ||
988 | sizeof(OpenLogicalChannel), _OpenLogicalChannel} | ||
989 | , | ||
990 | }; | ||
991 | |||
992 | static field_t _Information_UUIE[] = { /* SEQUENCE */ | ||
993 | {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, | ||
994 | {FNAME("callIdentifier") SEQ, 0, 1, 1, SKIP | EXT, 0, NULL}, | ||
995 | {FNAME("tokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
996 | {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
997 | {FNAME("fastStart") SEQOF, SEMI, 0, 30, DECODE | OPT, | ||
998 | offsetof(Information_UUIE, fastStart), _Information_UUIE_fastStart}, | ||
999 | {FNAME("fastConnectRefused") NUL, FIXD, 0, 0, SKIP | OPT, 0, NULL}, | ||
1000 | {FNAME("circuitInfo") SEQ, 3, 3, 3, SKIP | EXT | OPT, 0, NULL}, | ||
1001 | }; | ||
1002 | |||
1003 | static field_t _ReleaseCompleteReason[] = { /* CHOICE */ | ||
1004 | {FNAME("noBandwidth") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1005 | {FNAME("gatekeeperResources") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1006 | {FNAME("unreachableDestination") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1007 | {FNAME("destinationRejection") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1008 | {FNAME("invalidRevision") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1009 | {FNAME("noPermission") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1010 | {FNAME("unreachableGatekeeper") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1011 | {FNAME("gatewayResources") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1012 | {FNAME("badFormatAddress") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1013 | {FNAME("adaptiveBusy") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1014 | {FNAME("inConf") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1015 | {FNAME("undefinedReason") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1016 | {FNAME("facilityCallDeflection") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1017 | {FNAME("securityDenied") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1018 | {FNAME("calledPartyNotRegistered") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1019 | {FNAME("callerNotRegistered") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1020 | {FNAME("newConnectionNeeded") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1021 | {FNAME("nonStandardReason") SEQ, 0, 2, 2, SKIP, 0, NULL}, | ||
1022 | {FNAME("replaceWithConferenceInvite") OCTSTR, FIXD, 16, 0, SKIP, 0, | ||
1023 | NULL}, | ||
1024 | {FNAME("genericDataReason") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1025 | {FNAME("neededFeatureNotSupported") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1026 | {FNAME("tunnelledSignallingRejected") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1027 | }; | ||
1028 | |||
1029 | static field_t _ReleaseComplete_UUIE[] = { /* SEQUENCE */ | ||
1030 | {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, | ||
1031 | {FNAME("reason") CHOICE, 4, 12, 22, SKIP | EXT | OPT, 0, | ||
1032 | _ReleaseCompleteReason}, | ||
1033 | {FNAME("callIdentifier") SEQ, 0, 1, 1, SKIP | EXT, 0, NULL}, | ||
1034 | {FNAME("tokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
1035 | {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
1036 | {FNAME("busyAddress") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
1037 | {FNAME("presentationIndicator") CHOICE, 2, 3, 3, SKIP | EXT | OPT, 0, | ||
1038 | NULL}, | ||
1039 | {FNAME("screeningIndicator") ENUM, 2, 0, 0, SKIP | EXT | OPT, 0, | ||
1040 | NULL}, | ||
1041 | {FNAME("capacity") SEQ, 2, 2, 2, SKIP | EXT | OPT, 0, NULL}, | ||
1042 | {FNAME("serviceControl") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
1043 | {FNAME("featureSet") SEQ, 3, 4, 4, SKIP | EXT | OPT, 0, NULL}, | ||
1044 | }; | ||
1045 | |||
1046 | static field_t _Facility_UUIE_alternativeAliasAddress[] = { /* SEQUENCE OF */ | ||
1047 | {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, | ||
1048 | }; | ||
1049 | |||
1050 | static field_t _FacilityReason[] = { /* CHOICE */ | ||
1051 | {FNAME("routeCallToGatekeeper") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1052 | {FNAME("callForwarded") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1053 | {FNAME("routeCallToMC") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1054 | {FNAME("undefinedReason") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1055 | {FNAME("conferenceListChoice") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1056 | {FNAME("startH245") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1057 | {FNAME("noH245") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1058 | {FNAME("newTokens") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1059 | {FNAME("featureSetUpdate") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1060 | {FNAME("forwardedElements") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1061 | {FNAME("transportedInformation") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1062 | }; | ||
1063 | |||
1064 | static field_t _Facility_UUIE_fastStart[] = { /* SEQUENCE OF */ | ||
1065 | {FNAME("item") SEQ, 1, 3, 5, DECODE | OPEN | EXT, | ||
1066 | sizeof(OpenLogicalChannel), _OpenLogicalChannel} | ||
1067 | , | ||
1068 | }; | ||
1069 | |||
1070 | static field_t _Facility_UUIE[] = { /* SEQUENCE */ | ||
1071 | {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, | ||
1072 | {FNAME("alternativeAddress") CHOICE, 3, 7, 7, DECODE | EXT | OPT, | ||
1073 | offsetof(Facility_UUIE, alternativeAddress), _TransportAddress}, | ||
1074 | {FNAME("alternativeAliasAddress") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, | ||
1075 | _Facility_UUIE_alternativeAliasAddress}, | ||
1076 | {FNAME("conferenceID") OCTSTR, FIXD, 16, 0, SKIP | OPT, 0, NULL}, | ||
1077 | {FNAME("reason") CHOICE, 2, 4, 11, DECODE | EXT, | ||
1078 | offsetof(Facility_UUIE, reason), _FacilityReason}, | ||
1079 | {FNAME("callIdentifier") SEQ, 0, 1, 1, SKIP | EXT, 0, NULL}, | ||
1080 | {FNAME("destExtraCallInfo") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
1081 | {FNAME("remoteExtensionAddress") CHOICE, 1, 2, 7, SKIP | EXT | OPT, 0, | ||
1082 | NULL}, | ||
1083 | {FNAME("tokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
1084 | {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
1085 | {FNAME("conferences") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
1086 | {FNAME("h245Address") CHOICE, 3, 7, 7, DECODE | EXT | OPT, | ||
1087 | offsetof(Facility_UUIE, h245Address), _TransportAddress}, | ||
1088 | {FNAME("fastStart") SEQOF, SEMI, 0, 30, DECODE | OPT, | ||
1089 | offsetof(Facility_UUIE, fastStart), _Facility_UUIE_fastStart}, | ||
1090 | {FNAME("multipleCalls") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1091 | {FNAME("maintainConnection") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1092 | {FNAME("fastConnectRefused") NUL, FIXD, 0, 0, SKIP | OPT, 0, NULL}, | ||
1093 | {FNAME("serviceControl") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
1094 | {FNAME("circuitInfo") SEQ, 3, 3, 3, SKIP | EXT | OPT, 0, NULL}, | ||
1095 | {FNAME("featureSet") SEQ, 3, 4, 4, SKIP | EXT | OPT, 0, NULL}, | ||
1096 | {FNAME("destinationInfo") SEQ, 6, 8, 10, SKIP | EXT | OPT, 0, NULL}, | ||
1097 | {FNAME("h245SecurityMode") CHOICE, 2, 4, 4, SKIP | EXT | OPT, 0, | ||
1098 | NULL}, | ||
1099 | }; | ||
1100 | |||
1101 | static field_t _CallIdentifier[] = { /* SEQUENCE */ | ||
1102 | {FNAME("guid") OCTSTR, FIXD, 16, 0, SKIP, 0, NULL}, | ||
1103 | }; | ||
1104 | |||
1105 | static field_t _SecurityServiceMode[] = { /* CHOICE */ | ||
1106 | {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0, _NonStandardParameter}, | ||
1107 | {FNAME("none") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1108 | {FNAME("default") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1109 | }; | ||
1110 | |||
1111 | static field_t _SecurityCapabilities[] = { /* SEQUENCE */ | ||
1112 | {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP | OPT, 0, | ||
1113 | _NonStandardParameter}, | ||
1114 | {FNAME("encryption") CHOICE, 2, 3, 3, SKIP | EXT, 0, | ||
1115 | _SecurityServiceMode}, | ||
1116 | {FNAME("authenticaton") CHOICE, 2, 3, 3, SKIP | EXT, 0, | ||
1117 | _SecurityServiceMode}, | ||
1118 | {FNAME("integrity") CHOICE, 2, 3, 3, SKIP | EXT, 0, | ||
1119 | _SecurityServiceMode}, | ||
1120 | }; | ||
1121 | |||
1122 | static field_t _H245Security[] = { /* CHOICE */ | ||
1123 | {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0, _NonStandardParameter}, | ||
1124 | {FNAME("noSecurity") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1125 | {FNAME("tls") SEQ, 1, 4, 4, SKIP | EXT, 0, _SecurityCapabilities}, | ||
1126 | {FNAME("ipsec") SEQ, 1, 4, 4, SKIP | EXT, 0, _SecurityCapabilities}, | ||
1127 | }; | ||
1128 | |||
1129 | static field_t _DHset[] = { /* SEQUENCE */ | ||
1130 | {FNAME("halfkey") BITSTR, WORD, 0, 0, SKIP, 0, NULL}, | ||
1131 | {FNAME("modSize") BITSTR, WORD, 0, 0, SKIP, 0, NULL}, | ||
1132 | {FNAME("generator") BITSTR, WORD, 0, 0, SKIP, 0, NULL}, | ||
1133 | }; | ||
1134 | |||
1135 | static field_t _TypedCertificate[] = { /* SEQUENCE */ | ||
1136 | {FNAME("type") OID, BYTE, 0, 0, SKIP, 0, NULL}, | ||
1137 | {FNAME("certificate") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL}, | ||
1138 | }; | ||
1139 | |||
1140 | static field_t _H235_NonStandardParameter[] = { /* SEQUENCE */ | ||
1141 | {FNAME("nonStandardIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, | ||
1142 | {FNAME("data") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL}, | ||
1143 | }; | ||
1144 | |||
1145 | static field_t _ClearToken[] = { /* SEQUENCE */ | ||
1146 | {FNAME("tokenOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, | ||
1147 | {FNAME("timeStamp") INT, CONS, 1, 0, SKIP | OPT, 0, NULL}, | ||
1148 | {FNAME("password") BMPSTR, 7, 1, 0, SKIP | OPT, 0, NULL}, | ||
1149 | {FNAME("dhkey") SEQ, 0, 3, 3, SKIP | EXT | OPT, 0, _DHset}, | ||
1150 | {FNAME("challenge") OCTSTR, 7, 8, 0, SKIP | OPT, 0, NULL}, | ||
1151 | {FNAME("random") INT, UNCO, 0, 0, SKIP | OPT, 0, NULL}, | ||
1152 | {FNAME("certificate") SEQ, 0, 2, 2, SKIP | EXT | OPT, 0, | ||
1153 | _TypedCertificate}, | ||
1154 | {FNAME("generalID") BMPSTR, 7, 1, 0, SKIP | OPT, 0, NULL}, | ||
1155 | {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP | OPT, 0, | ||
1156 | _H235_NonStandardParameter}, | ||
1157 | {FNAME("eckasdhkey") CHOICE, 1, 2, 2, SKIP | EXT | OPT, 0, NULL}, | ||
1158 | {FNAME("sendersID") BMPSTR, 7, 1, 0, SKIP | OPT, 0, NULL}, | ||
1159 | }; | ||
1160 | |||
1161 | static field_t _Progress_UUIE_tokens[] = { /* SEQUENCE OF */ | ||
1162 | {FNAME("item") SEQ, 8, 9, 11, SKIP | EXT, 0, _ClearToken}, | ||
1163 | }; | ||
1164 | |||
1165 | static field_t _Params[] = { /* SEQUENCE */ | ||
1166 | {FNAME("ranInt") INT, UNCO, 0, 0, SKIP | OPT, 0, NULL}, | ||
1167 | {FNAME("iv8") OCTSTR, FIXD, 8, 0, SKIP | OPT, 0, NULL}, | ||
1168 | {FNAME("iv16") OCTSTR, FIXD, 16, 0, SKIP | OPT, 0, NULL}, | ||
1169 | }; | ||
1170 | |||
1171 | static field_t _CryptoH323Token_cryptoEPPwdHash_token[] = { /* SEQUENCE */ | ||
1172 | {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, | ||
1173 | {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, | ||
1174 | {FNAME("hash") BITSTR, SEMI, 0, 0, SKIP, 0, NULL}, | ||
1175 | }; | ||
1176 | |||
1177 | static field_t _CryptoH323Token_cryptoEPPwdHash[] = { /* SEQUENCE */ | ||
1178 | {FNAME("alias") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, | ||
1179 | {FNAME("timeStamp") INT, CONS, 1, 0, SKIP, 0, NULL}, | ||
1180 | {FNAME("token") SEQ, 0, 3, 3, SKIP, 0, | ||
1181 | _CryptoH323Token_cryptoEPPwdHash_token}, | ||
1182 | }; | ||
1183 | |||
1184 | static field_t _CryptoH323Token_cryptoGKPwdHash_token[] = { /* SEQUENCE */ | ||
1185 | {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, | ||
1186 | {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, | ||
1187 | {FNAME("hash") BITSTR, SEMI, 0, 0, SKIP, 0, NULL}, | ||
1188 | }; | ||
1189 | |||
1190 | static field_t _CryptoH323Token_cryptoGKPwdHash[] = { /* SEQUENCE */ | ||
1191 | {FNAME("gatekeeperId") BMPSTR, 7, 1, 0, SKIP, 0, NULL}, | ||
1192 | {FNAME("timeStamp") INT, CONS, 1, 0, SKIP, 0, NULL}, | ||
1193 | {FNAME("token") SEQ, 0, 3, 3, SKIP, 0, | ||
1194 | _CryptoH323Token_cryptoGKPwdHash_token}, | ||
1195 | }; | ||
1196 | |||
1197 | static field_t _CryptoH323Token_cryptoEPPwdEncr[] = { /* SEQUENCE */ | ||
1198 | {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, | ||
1199 | {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, | ||
1200 | {FNAME("encryptedData") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL}, | ||
1201 | }; | ||
1202 | |||
1203 | static field_t _CryptoH323Token_cryptoGKPwdEncr[] = { /* SEQUENCE */ | ||
1204 | {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, | ||
1205 | {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, | ||
1206 | {FNAME("encryptedData") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL}, | ||
1207 | }; | ||
1208 | |||
1209 | static field_t _CryptoH323Token_cryptoEPCert[] = { /* SEQUENCE */ | ||
1210 | {FNAME("toBeSigned") SEQ, 8, 9, 11, SKIP | OPEN | EXT, 0, NULL}, | ||
1211 | {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, | ||
1212 | {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, | ||
1213 | {FNAME("signature") BITSTR, SEMI, 0, 0, SKIP, 0, NULL}, | ||
1214 | }; | ||
1215 | |||
1216 | static field_t _CryptoH323Token_cryptoGKCert[] = { /* SEQUENCE */ | ||
1217 | {FNAME("toBeSigned") SEQ, 8, 9, 11, SKIP | OPEN | EXT, 0, NULL}, | ||
1218 | {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, | ||
1219 | {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, | ||
1220 | {FNAME("signature") BITSTR, SEMI, 0, 0, SKIP, 0, NULL}, | ||
1221 | }; | ||
1222 | |||
1223 | static field_t _CryptoH323Token_cryptoFastStart[] = { /* SEQUENCE */ | ||
1224 | {FNAME("toBeSigned") SEQ, 8, 9, 11, SKIP | OPEN | EXT, 0, NULL}, | ||
1225 | {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, | ||
1226 | {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, | ||
1227 | {FNAME("signature") BITSTR, SEMI, 0, 0, SKIP, 0, NULL}, | ||
1228 | }; | ||
1229 | |||
1230 | static field_t _CryptoToken_cryptoEncryptedToken_token[] = { /* SEQUENCE */ | ||
1231 | {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, | ||
1232 | {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, | ||
1233 | {FNAME("encryptedData") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL}, | ||
1234 | }; | ||
1235 | |||
1236 | static field_t _CryptoToken_cryptoEncryptedToken[] = { /* SEQUENCE */ | ||
1237 | {FNAME("tokenOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, | ||
1238 | {FNAME("token") SEQ, 0, 3, 3, SKIP, 0, | ||
1239 | _CryptoToken_cryptoEncryptedToken_token}, | ||
1240 | }; | ||
1241 | |||
1242 | static field_t _CryptoToken_cryptoSignedToken_token[] = { /* SEQUENCE */ | ||
1243 | {FNAME("toBeSigned") SEQ, 8, 9, 11, SKIP | OPEN | EXT, 0, NULL}, | ||
1244 | {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, | ||
1245 | {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, | ||
1246 | {FNAME("signature") BITSTR, SEMI, 0, 0, SKIP, 0, NULL}, | ||
1247 | }; | ||
1248 | |||
1249 | static field_t _CryptoToken_cryptoSignedToken[] = { /* SEQUENCE */ | ||
1250 | {FNAME("tokenOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, | ||
1251 | {FNAME("token") SEQ, 0, 4, 4, SKIP, 0, | ||
1252 | _CryptoToken_cryptoSignedToken_token}, | ||
1253 | }; | ||
1254 | |||
1255 | static field_t _CryptoToken_cryptoHashedToken_token[] = { /* SEQUENCE */ | ||
1256 | {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, | ||
1257 | {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, | ||
1258 | {FNAME("hash") BITSTR, SEMI, 0, 0, SKIP, 0, NULL}, | ||
1259 | }; | ||
1260 | |||
1261 | static field_t _CryptoToken_cryptoHashedToken[] = { /* SEQUENCE */ | ||
1262 | {FNAME("tokenOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, | ||
1263 | {FNAME("hashedVals") SEQ, 8, 9, 11, SKIP | EXT, 0, _ClearToken}, | ||
1264 | {FNAME("token") SEQ, 0, 3, 3, SKIP, 0, | ||
1265 | _CryptoToken_cryptoHashedToken_token}, | ||
1266 | }; | ||
1267 | |||
1268 | static field_t _CryptoToken_cryptoPwdEncr[] = { /* SEQUENCE */ | ||
1269 | {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, | ||
1270 | {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, | ||
1271 | {FNAME("encryptedData") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL}, | ||
1272 | }; | ||
1273 | |||
1274 | static field_t _CryptoToken[] = { /* CHOICE */ | ||
1275 | {FNAME("cryptoEncryptedToken") SEQ, 0, 2, 2, SKIP, 0, | ||
1276 | _CryptoToken_cryptoEncryptedToken}, | ||
1277 | {FNAME("cryptoSignedToken") SEQ, 0, 2, 2, SKIP, 0, | ||
1278 | _CryptoToken_cryptoSignedToken}, | ||
1279 | {FNAME("cryptoHashedToken") SEQ, 0, 3, 3, SKIP, 0, | ||
1280 | _CryptoToken_cryptoHashedToken}, | ||
1281 | {FNAME("cryptoPwdEncr") SEQ, 0, 3, 3, SKIP, 0, | ||
1282 | _CryptoToken_cryptoPwdEncr}, | ||
1283 | }; | ||
1284 | |||
1285 | static field_t _CryptoH323Token[] = { /* CHOICE */ | ||
1286 | {FNAME("cryptoEPPwdHash") SEQ, 0, 3, 3, SKIP, 0, | ||
1287 | _CryptoH323Token_cryptoEPPwdHash}, | ||
1288 | {FNAME("cryptoGKPwdHash") SEQ, 0, 3, 3, SKIP, 0, | ||
1289 | _CryptoH323Token_cryptoGKPwdHash}, | ||
1290 | {FNAME("cryptoEPPwdEncr") SEQ, 0, 3, 3, SKIP, 0, | ||
1291 | _CryptoH323Token_cryptoEPPwdEncr}, | ||
1292 | {FNAME("cryptoGKPwdEncr") SEQ, 0, 3, 3, SKIP, 0, | ||
1293 | _CryptoH323Token_cryptoGKPwdEncr}, | ||
1294 | {FNAME("cryptoEPCert") SEQ, 0, 4, 4, SKIP, 0, | ||
1295 | _CryptoH323Token_cryptoEPCert}, | ||
1296 | {FNAME("cryptoGKCert") SEQ, 0, 4, 4, SKIP, 0, | ||
1297 | _CryptoH323Token_cryptoGKCert}, | ||
1298 | {FNAME("cryptoFastStart") SEQ, 0, 4, 4, SKIP, 0, | ||
1299 | _CryptoH323Token_cryptoFastStart}, | ||
1300 | {FNAME("nestedcryptoToken") CHOICE, 2, 4, 4, SKIP | EXT, 0, | ||
1301 | _CryptoToken}, | ||
1302 | }; | ||
1303 | |||
1304 | static field_t _Progress_UUIE_cryptoTokens[] = { /* SEQUENCE OF */ | ||
1305 | {FNAME("item") CHOICE, 3, 8, 8, SKIP | EXT, 0, _CryptoH323Token}, | ||
1306 | }; | ||
1307 | |||
1308 | static field_t _Progress_UUIE_fastStart[] = { /* SEQUENCE OF */ | ||
1309 | {FNAME("item") SEQ, 1, 3, 5, DECODE | OPEN | EXT, | ||
1310 | sizeof(OpenLogicalChannel), _OpenLogicalChannel} | ||
1311 | , | ||
1312 | }; | ||
1313 | |||
1314 | static field_t _Progress_UUIE[] = { /* SEQUENCE */ | ||
1315 | {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, | ||
1316 | {FNAME("destinationInfo") SEQ, 6, 8, 10, SKIP | EXT, 0, | ||
1317 | _EndpointType}, | ||
1318 | {FNAME("h245Address") CHOICE, 3, 7, 7, DECODE | EXT | OPT, | ||
1319 | offsetof(Progress_UUIE, h245Address), _TransportAddress}, | ||
1320 | {FNAME("callIdentifier") SEQ, 0, 1, 1, SKIP | EXT, 0, | ||
1321 | _CallIdentifier}, | ||
1322 | {FNAME("h245SecurityMode") CHOICE, 2, 4, 4, SKIP | EXT | OPT, 0, | ||
1323 | _H245Security}, | ||
1324 | {FNAME("tokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, | ||
1325 | _Progress_UUIE_tokens}, | ||
1326 | {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, | ||
1327 | _Progress_UUIE_cryptoTokens}, | ||
1328 | {FNAME("fastStart") SEQOF, SEMI, 0, 30, DECODE | OPT, | ||
1329 | offsetof(Progress_UUIE, fastStart), _Progress_UUIE_fastStart}, | ||
1330 | {FNAME("multipleCalls") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1331 | {FNAME("maintainConnection") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1332 | {FNAME("fastConnectRefused") NUL, FIXD, 0, 0, SKIP | OPT, 0, NULL}, | ||
1333 | }; | ||
1334 | |||
1335 | static field_t _H323_UU_PDU_h323_message_body[] = { /* CHOICE */ | ||
1336 | {FNAME("setup") SEQ, 7, 13, 39, DECODE | EXT, | ||
1337 | offsetof(H323_UU_PDU_h323_message_body, setup), _Setup_UUIE}, | ||
1338 | {FNAME("callProceeding") SEQ, 1, 3, 12, DECODE | EXT, | ||
1339 | offsetof(H323_UU_PDU_h323_message_body, callProceeding), | ||
1340 | _CallProceeding_UUIE}, | ||
1341 | {FNAME("connect") SEQ, 1, 4, 19, DECODE | EXT, | ||
1342 | offsetof(H323_UU_PDU_h323_message_body, connect), _Connect_UUIE}, | ||
1343 | {FNAME("alerting") SEQ, 1, 3, 17, DECODE | EXT, | ||
1344 | offsetof(H323_UU_PDU_h323_message_body, alerting), _Alerting_UUIE}, | ||
1345 | {FNAME("information") SEQ, 0, 1, 7, DECODE | EXT, | ||
1346 | offsetof(H323_UU_PDU_h323_message_body, information), | ||
1347 | _Information_UUIE}, | ||
1348 | {FNAME("releaseComplete") SEQ, 1, 2, 11, SKIP | EXT, 0, | ||
1349 | _ReleaseComplete_UUIE}, | ||
1350 | {FNAME("facility") SEQ, 3, 5, 21, DECODE | EXT, | ||
1351 | offsetof(H323_UU_PDU_h323_message_body, facility), _Facility_UUIE}, | ||
1352 | {FNAME("progress") SEQ, 5, 8, 11, DECODE | EXT, | ||
1353 | offsetof(H323_UU_PDU_h323_message_body, progress), _Progress_UUIE}, | ||
1354 | {FNAME("empty") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1355 | {FNAME("status") SEQ, 2, 4, 4, SKIP | EXT, 0, NULL}, | ||
1356 | {FNAME("statusInquiry") SEQ, 2, 4, 4, SKIP | EXT, 0, NULL}, | ||
1357 | {FNAME("setupAcknowledge") SEQ, 2, 4, 4, SKIP | EXT, 0, NULL}, | ||
1358 | {FNAME("notify") SEQ, 2, 4, 4, SKIP | EXT, 0, NULL}, | ||
1359 | }; | ||
1360 | |||
1361 | static field_t _RequestMessage[] = { /* CHOICE */ | ||
1362 | {FNAME("nonStandard") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, | ||
1363 | {FNAME("masterSlaveDetermination") SEQ, 0, 2, 2, STOP | EXT, 0, NULL}, | ||
1364 | {FNAME("terminalCapabilitySet") SEQ, 3, 5, 5, STOP | EXT, 0, NULL}, | ||
1365 | {FNAME("openLogicalChannel") SEQ, 1, 3, 5, DECODE | EXT, | ||
1366 | offsetof(RequestMessage, openLogicalChannel), _OpenLogicalChannel}, | ||
1367 | {FNAME("closeLogicalChannel") SEQ, 0, 2, 3, STOP | EXT, 0, NULL}, | ||
1368 | {FNAME("requestChannelClose") SEQ, 0, 1, 3, STOP | EXT, 0, NULL}, | ||
1369 | {FNAME("multiplexEntrySend") SEQ, 0, 2, 2, STOP | EXT, 0, NULL}, | ||
1370 | {FNAME("requestMultiplexEntry") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, | ||
1371 | {FNAME("requestMode") SEQ, 0, 2, 2, STOP | EXT, 0, NULL}, | ||
1372 | {FNAME("roundTripDelayRequest") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, | ||
1373 | {FNAME("maintenanceLoopRequest") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, | ||
1374 | {FNAME("communicationModeRequest") SEQ, 0, 0, 0, STOP | EXT, 0, NULL}, | ||
1375 | {FNAME("conferenceRequest") CHOICE, 3, 8, 16, STOP | EXT, 0, NULL}, | ||
1376 | {FNAME("multilinkRequest") CHOICE, 3, 5, 5, STOP | EXT, 0, NULL}, | ||
1377 | {FNAME("logicalChannelRateRequest") SEQ, 0, 3, 3, STOP | EXT, 0, | ||
1378 | NULL}, | ||
1379 | }; | ||
1380 | |||
1381 | static field_t _OpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters[] = { /* CHOICE */ | ||
1382 | {FNAME("h222LogicalChannelParameters") SEQ, 3, 5, 5, SKIP | EXT, 0, | ||
1383 | _H222LogicalChannelParameters}, | ||
1384 | {FNAME("h2250LogicalChannelParameters") SEQ, 10, 11, 14, DECODE | EXT, | ||
1385 | offsetof | ||
1386 | (OpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters, | ||
1387 | h2250LogicalChannelParameters), _H2250LogicalChannelParameters}, | ||
1388 | }; | ||
1389 | |||
1390 | static field_t _OpenLogicalChannelAck_reverseLogicalChannelParameters[] = { /* SEQUENCE */ | ||
1391 | {FNAME("reverseLogicalChannelNumber") INT, WORD, 1, 0, SKIP, 0, NULL}, | ||
1392 | {FNAME("portNumber") INT, WORD, 0, 0, SKIP | OPT, 0, NULL}, | ||
1393 | {FNAME("multiplexParameters") CHOICE, 0, 1, 2, DECODE | EXT | OPT, | ||
1394 | offsetof(OpenLogicalChannelAck_reverseLogicalChannelParameters, | ||
1395 | multiplexParameters), | ||
1396 | _OpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters}, | ||
1397 | {FNAME("replacementFor") INT, WORD, 1, 0, SKIP | OPT, 0, NULL}, | ||
1398 | }; | ||
1399 | |||
1400 | static field_t _H2250LogicalChannelAckParameters_nonStandard[] = { /* SEQUENCE OF */ | ||
1401 | {FNAME("item") SEQ, 0, 2, 2, SKIP, 0, _H245_NonStandardParameter}, | ||
1402 | }; | ||
1403 | |||
1404 | static field_t _H2250LogicalChannelAckParameters[] = { /* SEQUENCE */ | ||
1405 | {FNAME("nonStandard") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, | ||
1406 | _H2250LogicalChannelAckParameters_nonStandard}, | ||
1407 | {FNAME("sessionID") INT, 8, 1, 0, SKIP | OPT, 0, NULL}, | ||
1408 | {FNAME("mediaChannel") CHOICE, 1, 2, 2, DECODE | EXT | OPT, | ||
1409 | offsetof(H2250LogicalChannelAckParameters, mediaChannel), | ||
1410 | _H245_TransportAddress}, | ||
1411 | {FNAME("mediaControlChannel") CHOICE, 1, 2, 2, DECODE | EXT | OPT, | ||
1412 | offsetof(H2250LogicalChannelAckParameters, mediaControlChannel), | ||
1413 | _H245_TransportAddress}, | ||
1414 | {FNAME("dynamicRTPPayloadType") INT, 5, 96, 0, SKIP | OPT, 0, NULL}, | ||
1415 | {FNAME("flowControlToZero") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1416 | {FNAME("portNumber") INT, WORD, 0, 0, SKIP | OPT, 0, NULL}, | ||
1417 | }; | ||
1418 | |||
1419 | static field_t _OpenLogicalChannelAck_forwardMultiplexAckParameters[] = { /* CHOICE */ | ||
1420 | {FNAME("h2250LogicalChannelAckParameters") SEQ, 5, 5, 7, DECODE | EXT, | ||
1421 | offsetof(OpenLogicalChannelAck_forwardMultiplexAckParameters, | ||
1422 | h2250LogicalChannelAckParameters), | ||
1423 | _H2250LogicalChannelAckParameters}, | ||
1424 | }; | ||
1425 | |||
1426 | static field_t _OpenLogicalChannelAck[] = { /* SEQUENCE */ | ||
1427 | {FNAME("forwardLogicalChannelNumber") INT, WORD, 1, 0, SKIP, 0, NULL}, | ||
1428 | {FNAME("reverseLogicalChannelParameters") SEQ, 2, 3, 4, | ||
1429 | DECODE | EXT | OPT, offsetof(OpenLogicalChannelAck, | ||
1430 | reverseLogicalChannelParameters), | ||
1431 | _OpenLogicalChannelAck_reverseLogicalChannelParameters}, | ||
1432 | {FNAME("separateStack") SEQ, 2, 4, 5, SKIP | EXT | OPT, 0, NULL}, | ||
1433 | {FNAME("forwardMultiplexAckParameters") CHOICE, 0, 1, 1, | ||
1434 | DECODE | EXT | OPT, offsetof(OpenLogicalChannelAck, | ||
1435 | forwardMultiplexAckParameters), | ||
1436 | _OpenLogicalChannelAck_forwardMultiplexAckParameters}, | ||
1437 | {FNAME("encryptionSync") SEQ, 2, 4, 4, STOP | EXT | OPT, 0, NULL}, | ||
1438 | }; | ||
1439 | |||
1440 | static field_t _ResponseMessage[] = { /* CHOICE */ | ||
1441 | {FNAME("nonStandard") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, | ||
1442 | {FNAME("masterSlaveDeterminationAck") SEQ, 0, 1, 1, STOP | EXT, 0, | ||
1443 | NULL}, | ||
1444 | {FNAME("masterSlaveDeterminationReject") SEQ, 0, 1, 1, STOP | EXT, 0, | ||
1445 | NULL}, | ||
1446 | {FNAME("terminalCapabilitySetAck") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, | ||
1447 | {FNAME("terminalCapabilitySetReject") SEQ, 0, 2, 2, STOP | EXT, 0, | ||
1448 | NULL}, | ||
1449 | {FNAME("openLogicalChannelAck") SEQ, 1, 2, 5, DECODE | EXT, | ||
1450 | offsetof(ResponseMessage, openLogicalChannelAck), | ||
1451 | _OpenLogicalChannelAck}, | ||
1452 | {FNAME("openLogicalChannelReject") SEQ, 0, 2, 2, STOP | EXT, 0, NULL}, | ||
1453 | {FNAME("closeLogicalChannelAck") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, | ||
1454 | {FNAME("requestChannelCloseAck") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, | ||
1455 | {FNAME("requestChannelCloseReject") SEQ, 0, 2, 2, STOP | EXT, 0, | ||
1456 | NULL}, | ||
1457 | {FNAME("multiplexEntrySendAck") SEQ, 0, 2, 2, STOP | EXT, 0, NULL}, | ||
1458 | {FNAME("multiplexEntrySendReject") SEQ, 0, 2, 2, STOP | EXT, 0, NULL}, | ||
1459 | {FNAME("requestMultiplexEntryAck") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, | ||
1460 | {FNAME("requestMultiplexEntryReject") SEQ, 0, 2, 2, STOP | EXT, 0, | ||
1461 | NULL}, | ||
1462 | {FNAME("requestModeAck") SEQ, 0, 2, 2, STOP | EXT, 0, NULL}, | ||
1463 | {FNAME("requestModeReject") SEQ, 0, 2, 2, STOP | EXT, 0, NULL}, | ||
1464 | {FNAME("roundTripDelayResponse") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, | ||
1465 | {FNAME("maintenanceLoopAck") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, | ||
1466 | {FNAME("maintenanceLoopReject") SEQ, 0, 2, 2, STOP | EXT, 0, NULL}, | ||
1467 | {FNAME("communicationModeResponse") CHOICE, 0, 1, 1, STOP | EXT, 0, | ||
1468 | NULL}, | ||
1469 | {FNAME("conferenceResponse") CHOICE, 3, 8, 16, STOP | EXT, 0, NULL}, | ||
1470 | {FNAME("multilinkResponse") CHOICE, 3, 5, 5, STOP | EXT, 0, NULL}, | ||
1471 | {FNAME("logicalChannelRateAcknowledge") SEQ, 0, 3, 3, STOP | EXT, 0, | ||
1472 | NULL}, | ||
1473 | {FNAME("logicalChannelRateReject") SEQ, 1, 4, 4, STOP | EXT, 0, NULL}, | ||
1474 | }; | ||
1475 | |||
1476 | static field_t _MultimediaSystemControlMessage[] = { /* CHOICE */ | ||
1477 | {FNAME("request") CHOICE, 4, 11, 15, DECODE | EXT, | ||
1478 | offsetof(MultimediaSystemControlMessage, request), _RequestMessage}, | ||
1479 | {FNAME("response") CHOICE, 5, 19, 24, DECODE | EXT, | ||
1480 | offsetof(MultimediaSystemControlMessage, response), | ||
1481 | _ResponseMessage}, | ||
1482 | {FNAME("command") CHOICE, 3, 7, 12, STOP | EXT, 0, NULL}, | ||
1483 | {FNAME("indication") CHOICE, 4, 14, 23, STOP | EXT, 0, NULL}, | ||
1484 | }; | ||
1485 | |||
1486 | static field_t _H323_UU_PDU_h245Control[] = { /* SEQUENCE OF */ | ||
1487 | {FNAME("item") CHOICE, 2, 4, 4, DECODE | OPEN | EXT, | ||
1488 | sizeof(MultimediaSystemControlMessage), | ||
1489 | _MultimediaSystemControlMessage} | ||
1490 | , | ||
1491 | }; | ||
1492 | |||
1493 | static field_t _H323_UU_PDU[] = { /* SEQUENCE */ | ||
1494 | {FNAME("h323-message-body") CHOICE, 3, 7, 13, DECODE | EXT, | ||
1495 | offsetof(H323_UU_PDU, h323_message_body), | ||
1496 | _H323_UU_PDU_h323_message_body}, | ||
1497 | {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, | ||
1498 | _NonStandardParameter}, | ||
1499 | {FNAME("h4501SupplementaryService") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, | ||
1500 | NULL}, | ||
1501 | {FNAME("h245Tunneling") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1502 | {FNAME("h245Control") SEQOF, SEMI, 0, 4, DECODE | OPT, | ||
1503 | offsetof(H323_UU_PDU, h245Control), _H323_UU_PDU_h245Control}, | ||
1504 | {FNAME("nonStandardControl") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1505 | {FNAME("callLinkage") SEQ, 2, 2, 2, STOP | EXT | OPT, 0, NULL}, | ||
1506 | {FNAME("tunnelledSignallingMessage") SEQ, 2, 4, 4, STOP | EXT | OPT, | ||
1507 | 0, NULL}, | ||
1508 | {FNAME("provisionalRespToH245Tunneling") NUL, FIXD, 0, 0, STOP | OPT, | ||
1509 | 0, NULL}, | ||
1510 | {FNAME("stimulusControl") SEQ, 3, 3, 3, STOP | EXT | OPT, 0, NULL}, | ||
1511 | {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1512 | }; | ||
1513 | |||
1514 | static field_t _H323_UserInformation[] = { /* SEQUENCE */ | ||
1515 | {FNAME("h323-uu-pdu") SEQ, 1, 2, 11, DECODE | EXT, | ||
1516 | offsetof(H323_UserInformation, h323_uu_pdu), _H323_UU_PDU}, | ||
1517 | {FNAME("user-data") SEQ, 0, 2, 2, STOP | EXT | OPT, 0, NULL}, | ||
1518 | }; | ||
1519 | |||
1520 | static field_t _GatekeeperRequest[] = { /* SEQUENCE */ | ||
1521 | {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, | ||
1522 | {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, | ||
1523 | {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, | ||
1524 | _NonStandardParameter}, | ||
1525 | {FNAME("rasAddress") CHOICE, 3, 7, 7, DECODE | EXT, | ||
1526 | offsetof(GatekeeperRequest, rasAddress), _TransportAddress}, | ||
1527 | {FNAME("endpointType") SEQ, 6, 8, 10, STOP | EXT, 0, NULL}, | ||
1528 | {FNAME("gatekeeperIdentifier") BMPSTR, 7, 1, 0, STOP | OPT, 0, NULL}, | ||
1529 | {FNAME("callServices") SEQ, 0, 8, 8, STOP | EXT | OPT, 0, NULL}, | ||
1530 | {FNAME("endpointAlias") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1531 | {FNAME("alternateEndpoints") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1532 | {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1533 | {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1534 | {FNAME("authenticationCapability") SEQOF, SEMI, 0, 0, STOP | OPT, 0, | ||
1535 | NULL}, | ||
1536 | {FNAME("algorithmOIDs") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1537 | {FNAME("integrity") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1538 | {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, | ||
1539 | {FNAME("supportsAltGK") NUL, FIXD, 0, 0, STOP | OPT, 0, NULL}, | ||
1540 | {FNAME("featureSet") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, NULL}, | ||
1541 | {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1542 | }; | ||
1543 | |||
1544 | static field_t _GatekeeperConfirm[] = { /* SEQUENCE */ | ||
1545 | {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, | ||
1546 | {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, | ||
1547 | {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, | ||
1548 | _NonStandardParameter}, | ||
1549 | {FNAME("gatekeeperIdentifier") BMPSTR, 7, 1, 0, SKIP | OPT, 0, NULL}, | ||
1550 | {FNAME("rasAddress") CHOICE, 3, 7, 7, DECODE | EXT, | ||
1551 | offsetof(GatekeeperConfirm, rasAddress), _TransportAddress}, | ||
1552 | {FNAME("alternateGatekeeper") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1553 | {FNAME("authenticationMode") CHOICE, 3, 7, 8, STOP | EXT | OPT, 0, | ||
1554 | NULL}, | ||
1555 | {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1556 | {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1557 | {FNAME("algorithmOID") OID, BYTE, 0, 0, STOP | OPT, 0, NULL}, | ||
1558 | {FNAME("integrity") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1559 | {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, | ||
1560 | {FNAME("featureSet") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, NULL}, | ||
1561 | {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1562 | }; | ||
1563 | |||
1564 | static field_t _RegistrationRequest_callSignalAddress[] = { /* SEQUENCE OF */ | ||
1565 | {FNAME("item") CHOICE, 3, 7, 7, DECODE | EXT, | ||
1566 | sizeof(TransportAddress), _TransportAddress} | ||
1567 | , | ||
1568 | }; | ||
1569 | |||
1570 | static field_t _RegistrationRequest_rasAddress[] = { /* SEQUENCE OF */ | ||
1571 | {FNAME("item") CHOICE, 3, 7, 7, DECODE | EXT, | ||
1572 | sizeof(TransportAddress), _TransportAddress} | ||
1573 | , | ||
1574 | }; | ||
1575 | |||
1576 | static field_t _RegistrationRequest_terminalAlias[] = { /* SEQUENCE OF */ | ||
1577 | {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, | ||
1578 | }; | ||
1579 | |||
1580 | static field_t _RegistrationRequest[] = { /* SEQUENCE */ | ||
1581 | {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, | ||
1582 | {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, | ||
1583 | {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, | ||
1584 | _NonStandardParameter}, | ||
1585 | {FNAME("discoveryComplete") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1586 | {FNAME("callSignalAddress") SEQOF, SEMI, 0, 10, DECODE, | ||
1587 | offsetof(RegistrationRequest, callSignalAddress), | ||
1588 | _RegistrationRequest_callSignalAddress}, | ||
1589 | {FNAME("rasAddress") SEQOF, SEMI, 0, 10, DECODE, | ||
1590 | offsetof(RegistrationRequest, rasAddress), | ||
1591 | _RegistrationRequest_rasAddress}, | ||
1592 | {FNAME("terminalType") SEQ, 6, 8, 10, SKIP | EXT, 0, _EndpointType}, | ||
1593 | {FNAME("terminalAlias") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, | ||
1594 | _RegistrationRequest_terminalAlias}, | ||
1595 | {FNAME("gatekeeperIdentifier") BMPSTR, 7, 1, 0, SKIP | OPT, 0, NULL}, | ||
1596 | {FNAME("endpointVendor") SEQ, 2, 3, 3, SKIP | EXT, 0, | ||
1597 | _VendorIdentifier}, | ||
1598 | {FNAME("alternateEndpoints") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
1599 | {FNAME("timeToLive") INT, CONS, 1, 0, DECODE | OPT, | ||
1600 | offsetof(RegistrationRequest, timeToLive), NULL}, | ||
1601 | {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1602 | {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1603 | {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, | ||
1604 | {FNAME("keepAlive") BOOL, FIXD, 0, 0, STOP, 0, NULL}, | ||
1605 | {FNAME("endpointIdentifier") BMPSTR, 7, 1, 0, STOP | OPT, 0, NULL}, | ||
1606 | {FNAME("willSupplyUUIEs") BOOL, FIXD, 0, 0, STOP, 0, NULL}, | ||
1607 | {FNAME("maintainConnection") BOOL, FIXD, 0, 0, STOP, 0, NULL}, | ||
1608 | {FNAME("alternateTransportAddresses") SEQ, 1, 1, 1, STOP | EXT | OPT, | ||
1609 | 0, NULL}, | ||
1610 | {FNAME("additiveRegistration") NUL, FIXD, 0, 0, STOP | OPT, 0, NULL}, | ||
1611 | {FNAME("terminalAliasPattern") SEQOF, SEMI, 0, 0, STOP | OPT, 0, | ||
1612 | NULL}, | ||
1613 | {FNAME("supportsAltGK") NUL, FIXD, 0, 0, STOP | OPT, 0, NULL}, | ||
1614 | {FNAME("usageReportingCapability") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, | ||
1615 | NULL}, | ||
1616 | {FNAME("multipleCalls") BOOL, FIXD, 0, 0, STOP | OPT, 0, NULL}, | ||
1617 | {FNAME("supportedH248Packages") SEQOF, SEMI, 0, 0, STOP | OPT, 0, | ||
1618 | NULL}, | ||
1619 | {FNAME("callCreditCapability") SEQ, 2, 2, 2, STOP | EXT | OPT, 0, | ||
1620 | NULL}, | ||
1621 | {FNAME("capacityReportingCapability") SEQ, 0, 1, 1, STOP | EXT | OPT, | ||
1622 | 0, NULL}, | ||
1623 | {FNAME("capacity") SEQ, 2, 2, 2, STOP | EXT | OPT, 0, NULL}, | ||
1624 | {FNAME("featureSet") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, NULL}, | ||
1625 | {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1626 | }; | ||
1627 | |||
1628 | static field_t _RegistrationConfirm_callSignalAddress[] = { /* SEQUENCE OF */ | ||
1629 | {FNAME("item") CHOICE, 3, 7, 7, DECODE | EXT, | ||
1630 | sizeof(TransportAddress), _TransportAddress} | ||
1631 | , | ||
1632 | }; | ||
1633 | |||
1634 | static field_t _RegistrationConfirm_terminalAlias[] = { /* SEQUENCE OF */ | ||
1635 | {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, | ||
1636 | }; | ||
1637 | |||
1638 | static field_t _RegistrationConfirm[] = { /* SEQUENCE */ | ||
1639 | {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, | ||
1640 | {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, | ||
1641 | {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, | ||
1642 | _NonStandardParameter}, | ||
1643 | {FNAME("callSignalAddress") SEQOF, SEMI, 0, 10, DECODE, | ||
1644 | offsetof(RegistrationConfirm, callSignalAddress), | ||
1645 | _RegistrationConfirm_callSignalAddress}, | ||
1646 | {FNAME("terminalAlias") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, | ||
1647 | _RegistrationConfirm_terminalAlias}, | ||
1648 | {FNAME("gatekeeperIdentifier") BMPSTR, 7, 1, 0, SKIP | OPT, 0, NULL}, | ||
1649 | {FNAME("endpointIdentifier") BMPSTR, 7, 1, 0, SKIP, 0, NULL}, | ||
1650 | {FNAME("alternateGatekeeper") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
1651 | {FNAME("timeToLive") INT, CONS, 1, 0, DECODE | OPT, | ||
1652 | offsetof(RegistrationConfirm, timeToLive), NULL}, | ||
1653 | {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1654 | {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1655 | {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, | ||
1656 | {FNAME("willRespondToIRR") BOOL, FIXD, 0, 0, STOP, 0, NULL}, | ||
1657 | {FNAME("preGrantedARQ") SEQ, 0, 4, 8, STOP | EXT | OPT, 0, NULL}, | ||
1658 | {FNAME("maintainConnection") BOOL, FIXD, 0, 0, STOP, 0, NULL}, | ||
1659 | {FNAME("serviceControl") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1660 | {FNAME("supportsAdditiveRegistration") NUL, FIXD, 0, 0, STOP | OPT, 0, | ||
1661 | NULL}, | ||
1662 | {FNAME("terminalAliasPattern") SEQOF, SEMI, 0, 0, STOP | OPT, 0, | ||
1663 | NULL}, | ||
1664 | {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1665 | {FNAME("usageSpec") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1666 | {FNAME("featureServerAlias") CHOICE, 1, 2, 7, STOP | EXT | OPT, 0, | ||
1667 | NULL}, | ||
1668 | {FNAME("capacityReportingSpec") SEQ, 0, 1, 1, STOP | EXT | OPT, 0, | ||
1669 | NULL}, | ||
1670 | {FNAME("featureSet") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, NULL}, | ||
1671 | {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1672 | }; | ||
1673 | |||
1674 | static field_t _UnregistrationRequest_callSignalAddress[] = { /* SEQUENCE OF */ | ||
1675 | {FNAME("item") CHOICE, 3, 7, 7, DECODE | EXT, | ||
1676 | sizeof(TransportAddress), _TransportAddress} | ||
1677 | , | ||
1678 | }; | ||
1679 | |||
1680 | static field_t _UnregistrationRequest[] = { /* SEQUENCE */ | ||
1681 | {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, | ||
1682 | {FNAME("callSignalAddress") SEQOF, SEMI, 0, 10, DECODE, | ||
1683 | offsetof(UnregistrationRequest, callSignalAddress), | ||
1684 | _UnregistrationRequest_callSignalAddress}, | ||
1685 | {FNAME("endpointAlias") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1686 | {FNAME("nonStandardData") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, | ||
1687 | {FNAME("endpointIdentifier") BMPSTR, 7, 1, 0, STOP | OPT, 0, NULL}, | ||
1688 | {FNAME("alternateEndpoints") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1689 | {FNAME("gatekeeperIdentifier") BMPSTR, 7, 1, 0, STOP | OPT, 0, NULL}, | ||
1690 | {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1691 | {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1692 | {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, | ||
1693 | {FNAME("reason") CHOICE, 2, 4, 5, STOP | EXT | OPT, 0, NULL}, | ||
1694 | {FNAME("endpointAliasPattern") SEQOF, SEMI, 0, 0, STOP | OPT, 0, | ||
1695 | NULL}, | ||
1696 | {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1697 | {FNAME("alternateGatekeeper") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1698 | {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1699 | }; | ||
1700 | |||
1701 | static field_t _CallModel[] = { /* CHOICE */ | ||
1702 | {FNAME("direct") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1703 | {FNAME("gatekeeperRouted") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1704 | }; | ||
1705 | |||
1706 | static field_t _AdmissionRequest_destinationInfo[] = { /* SEQUENCE OF */ | ||
1707 | {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, | ||
1708 | }; | ||
1709 | |||
1710 | static field_t _AdmissionRequest_destExtraCallInfo[] = { /* SEQUENCE OF */ | ||
1711 | {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, | ||
1712 | }; | ||
1713 | |||
1714 | static field_t _AdmissionRequest_srcInfo[] = { /* SEQUENCE OF */ | ||
1715 | {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, | ||
1716 | }; | ||
1717 | |||
1718 | static field_t _AdmissionRequest[] = { /* SEQUENCE */ | ||
1719 | {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, | ||
1720 | {FNAME("callType") CHOICE, 2, 4, 4, SKIP | EXT, 0, _CallType}, | ||
1721 | {FNAME("callModel") CHOICE, 1, 2, 2, SKIP | EXT | OPT, 0, _CallModel}, | ||
1722 | {FNAME("endpointIdentifier") BMPSTR, 7, 1, 0, SKIP, 0, NULL}, | ||
1723 | {FNAME("destinationInfo") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, | ||
1724 | _AdmissionRequest_destinationInfo}, | ||
1725 | {FNAME("destCallSignalAddress") CHOICE, 3, 7, 7, DECODE | EXT | OPT, | ||
1726 | offsetof(AdmissionRequest, destCallSignalAddress), | ||
1727 | _TransportAddress}, | ||
1728 | {FNAME("destExtraCallInfo") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, | ||
1729 | _AdmissionRequest_destExtraCallInfo}, | ||
1730 | {FNAME("srcInfo") SEQOF, SEMI, 0, 0, SKIP, 0, | ||
1731 | _AdmissionRequest_srcInfo}, | ||
1732 | {FNAME("srcCallSignalAddress") CHOICE, 3, 7, 7, DECODE | EXT | OPT, | ||
1733 | offsetof(AdmissionRequest, srcCallSignalAddress), _TransportAddress}, | ||
1734 | {FNAME("bandWidth") INT, CONS, 0, 0, STOP, 0, NULL}, | ||
1735 | {FNAME("callReferenceValue") INT, WORD, 0, 0, STOP, 0, NULL}, | ||
1736 | {FNAME("nonStandardData") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, | ||
1737 | {FNAME("callServices") SEQ, 0, 8, 8, STOP | EXT | OPT, 0, NULL}, | ||
1738 | {FNAME("conferenceID") OCTSTR, FIXD, 16, 0, STOP, 0, NULL}, | ||
1739 | {FNAME("activeMC") BOOL, FIXD, 0, 0, STOP, 0, NULL}, | ||
1740 | {FNAME("answerCall") BOOL, FIXD, 0, 0, STOP, 0, NULL}, | ||
1741 | {FNAME("canMapAlias") BOOL, FIXD, 0, 0, STOP, 0, NULL}, | ||
1742 | {FNAME("callIdentifier") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, | ||
1743 | {FNAME("srcAlternatives") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1744 | {FNAME("destAlternatives") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1745 | {FNAME("gatekeeperIdentifier") BMPSTR, 7, 1, 0, STOP | OPT, 0, NULL}, | ||
1746 | {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1747 | {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1748 | {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, | ||
1749 | {FNAME("transportQOS") CHOICE, 2, 3, 3, STOP | EXT | OPT, 0, NULL}, | ||
1750 | {FNAME("willSupplyUUIEs") BOOL, FIXD, 0, 0, STOP, 0, NULL}, | ||
1751 | {FNAME("callLinkage") SEQ, 2, 2, 2, STOP | EXT | OPT, 0, NULL}, | ||
1752 | {FNAME("gatewayDataRate") SEQ, 2, 3, 3, STOP | EXT | OPT, 0, NULL}, | ||
1753 | {FNAME("capacity") SEQ, 2, 2, 2, STOP | EXT | OPT, 0, NULL}, | ||
1754 | {FNAME("circuitInfo") SEQ, 3, 3, 3, STOP | EXT | OPT, 0, NULL}, | ||
1755 | {FNAME("desiredProtocols") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1756 | {FNAME("desiredTunnelledProtocol") SEQ, 1, 2, 2, STOP | EXT | OPT, 0, | ||
1757 | NULL}, | ||
1758 | {FNAME("featureSet") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, NULL}, | ||
1759 | {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1760 | }; | ||
1761 | |||
1762 | static field_t _AdmissionConfirm[] = { /* SEQUENCE */ | ||
1763 | {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, | ||
1764 | {FNAME("bandWidth") INT, CONS, 0, 0, SKIP, 0, NULL}, | ||
1765 | {FNAME("callModel") CHOICE, 1, 2, 2, SKIP | EXT, 0, _CallModel}, | ||
1766 | {FNAME("destCallSignalAddress") CHOICE, 3, 7, 7, DECODE | EXT, | ||
1767 | offsetof(AdmissionConfirm, destCallSignalAddress), | ||
1768 | _TransportAddress}, | ||
1769 | {FNAME("irrFrequency") INT, WORD, 1, 0, STOP | OPT, 0, NULL}, | ||
1770 | {FNAME("nonStandardData") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, | ||
1771 | {FNAME("destinationInfo") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1772 | {FNAME("destExtraCallInfo") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1773 | {FNAME("destinationType") SEQ, 6, 8, 10, STOP | EXT | OPT, 0, NULL}, | ||
1774 | {FNAME("remoteExtensionAddress") SEQOF, SEMI, 0, 0, STOP | OPT, 0, | ||
1775 | NULL}, | ||
1776 | {FNAME("alternateEndpoints") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1777 | {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1778 | {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1779 | {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, | ||
1780 | {FNAME("transportQOS") CHOICE, 2, 3, 3, STOP | EXT | OPT, 0, NULL}, | ||
1781 | {FNAME("willRespondToIRR") BOOL, FIXD, 0, 0, STOP, 0, NULL}, | ||
1782 | {FNAME("uuiesRequested") SEQ, 0, 9, 13, STOP | EXT, 0, NULL}, | ||
1783 | {FNAME("language") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1784 | {FNAME("alternateTransportAddresses") SEQ, 1, 1, 1, STOP | EXT | OPT, | ||
1785 | 0, NULL}, | ||
1786 | {FNAME("useSpecifiedTransport") CHOICE, 1, 2, 2, STOP | EXT | OPT, 0, | ||
1787 | NULL}, | ||
1788 | {FNAME("circuitInfo") SEQ, 3, 3, 3, STOP | EXT | OPT, 0, NULL}, | ||
1789 | {FNAME("usageSpec") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1790 | {FNAME("supportedProtocols") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1791 | {FNAME("serviceControl") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1792 | {FNAME("multipleCalls") BOOL, FIXD, 0, 0, STOP | OPT, 0, NULL}, | ||
1793 | {FNAME("featureSet") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, NULL}, | ||
1794 | {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1795 | }; | ||
1796 | |||
1797 | static field_t _LocationRequest_destinationInfo[] = { /* SEQUENCE OF */ | ||
1798 | {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, | ||
1799 | }; | ||
1800 | |||
1801 | static field_t _LocationRequest[] = { /* SEQUENCE */ | ||
1802 | {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, | ||
1803 | {FNAME("endpointIdentifier") BMPSTR, 7, 1, 0, SKIP | OPT, 0, NULL}, | ||
1804 | {FNAME("destinationInfo") SEQOF, SEMI, 0, 0, SKIP, 0, | ||
1805 | _LocationRequest_destinationInfo}, | ||
1806 | {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, | ||
1807 | _NonStandardParameter}, | ||
1808 | {FNAME("replyAddress") CHOICE, 3, 7, 7, DECODE | EXT, | ||
1809 | offsetof(LocationRequest, replyAddress), _TransportAddress}, | ||
1810 | {FNAME("sourceInfo") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1811 | {FNAME("canMapAlias") BOOL, FIXD, 0, 0, STOP, 0, NULL}, | ||
1812 | {FNAME("gatekeeperIdentifier") BMPSTR, 7, 1, 0, STOP | OPT, 0, NULL}, | ||
1813 | {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1814 | {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1815 | {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, | ||
1816 | {FNAME("desiredProtocols") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1817 | {FNAME("desiredTunnelledProtocol") SEQ, 1, 2, 2, STOP | EXT | OPT, 0, | ||
1818 | NULL}, | ||
1819 | {FNAME("featureSet") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, NULL}, | ||
1820 | {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1821 | {FNAME("hopCount") INT, 8, 1, 0, STOP | OPT, 0, NULL}, | ||
1822 | {FNAME("circuitInfo") SEQ, 3, 3, 3, STOP | EXT | OPT, 0, NULL}, | ||
1823 | }; | ||
1824 | |||
1825 | static field_t _LocationConfirm[] = { /* SEQUENCE */ | ||
1826 | {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, | ||
1827 | {FNAME("callSignalAddress") CHOICE, 3, 7, 7, DECODE | EXT, | ||
1828 | offsetof(LocationConfirm, callSignalAddress), _TransportAddress}, | ||
1829 | {FNAME("rasAddress") CHOICE, 3, 7, 7, DECODE | EXT, | ||
1830 | offsetof(LocationConfirm, rasAddress), _TransportAddress}, | ||
1831 | {FNAME("nonStandardData") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, | ||
1832 | {FNAME("destinationInfo") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1833 | {FNAME("destExtraCallInfo") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1834 | {FNAME("destinationType") SEQ, 6, 8, 10, STOP | EXT | OPT, 0, NULL}, | ||
1835 | {FNAME("remoteExtensionAddress") SEQOF, SEMI, 0, 0, STOP | OPT, 0, | ||
1836 | NULL}, | ||
1837 | {FNAME("alternateEndpoints") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1838 | {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1839 | {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1840 | {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, | ||
1841 | {FNAME("alternateTransportAddresses") SEQ, 1, 1, 1, STOP | EXT | OPT, | ||
1842 | 0, NULL}, | ||
1843 | {FNAME("supportedProtocols") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1844 | {FNAME("multipleCalls") BOOL, FIXD, 0, 0, STOP | OPT, 0, NULL}, | ||
1845 | {FNAME("featureSet") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, NULL}, | ||
1846 | {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1847 | {FNAME("circuitInfo") SEQ, 3, 3, 3, STOP | EXT | OPT, 0, NULL}, | ||
1848 | {FNAME("serviceControl") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1849 | }; | ||
1850 | |||
1851 | static field_t _InfoRequestResponse_callSignalAddress[] = { /* SEQUENCE OF */ | ||
1852 | {FNAME("item") CHOICE, 3, 7, 7, DECODE | EXT, | ||
1853 | sizeof(TransportAddress), _TransportAddress} | ||
1854 | , | ||
1855 | }; | ||
1856 | |||
1857 | static field_t _InfoRequestResponse[] = { /* SEQUENCE */ | ||
1858 | {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, | ||
1859 | _NonStandardParameter}, | ||
1860 | {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, | ||
1861 | {FNAME("endpointType") SEQ, 6, 8, 10, SKIP | EXT, 0, _EndpointType}, | ||
1862 | {FNAME("endpointIdentifier") BMPSTR, 7, 1, 0, SKIP, 0, NULL}, | ||
1863 | {FNAME("rasAddress") CHOICE, 3, 7, 7, DECODE | EXT, | ||
1864 | offsetof(InfoRequestResponse, rasAddress), _TransportAddress}, | ||
1865 | {FNAME("callSignalAddress") SEQOF, SEMI, 0, 10, DECODE, | ||
1866 | offsetof(InfoRequestResponse, callSignalAddress), | ||
1867 | _InfoRequestResponse_callSignalAddress}, | ||
1868 | {FNAME("endpointAlias") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1869 | {FNAME("perCallInfo") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1870 | {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1871 | {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1872 | {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, | ||
1873 | {FNAME("needResponse") BOOL, FIXD, 0, 0, STOP, 0, NULL}, | ||
1874 | {FNAME("capacity") SEQ, 2, 2, 2, STOP | EXT | OPT, 0, NULL}, | ||
1875 | {FNAME("irrStatus") CHOICE, 2, 4, 4, STOP | EXT | OPT, 0, NULL}, | ||
1876 | {FNAME("unsolicited") BOOL, FIXD, 0, 0, STOP, 0, NULL}, | ||
1877 | {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1878 | }; | ||
1879 | |||
1880 | static field_t _RasMessage[] = { /* CHOICE */ | ||
1881 | {FNAME("gatekeeperRequest") SEQ, 4, 8, 18, DECODE | EXT, | ||
1882 | offsetof(RasMessage, gatekeeperRequest), _GatekeeperRequest}, | ||
1883 | {FNAME("gatekeeperConfirm") SEQ, 2, 5, 14, DECODE | EXT, | ||
1884 | offsetof(RasMessage, gatekeeperConfirm), _GatekeeperConfirm}, | ||
1885 | {FNAME("gatekeeperReject") SEQ, 2, 5, 11, STOP | EXT, 0, NULL}, | ||
1886 | {FNAME("registrationRequest") SEQ, 3, 10, 31, DECODE | EXT, | ||
1887 | offsetof(RasMessage, registrationRequest), _RegistrationRequest}, | ||
1888 | {FNAME("registrationConfirm") SEQ, 3, 7, 24, DECODE | EXT, | ||
1889 | offsetof(RasMessage, registrationConfirm), _RegistrationConfirm}, | ||
1890 | {FNAME("registrationReject") SEQ, 2, 5, 11, STOP | EXT, 0, NULL}, | ||
1891 | {FNAME("unregistrationRequest") SEQ, 3, 5, 15, DECODE | EXT, | ||
1892 | offsetof(RasMessage, unregistrationRequest), _UnregistrationRequest}, | ||
1893 | {FNAME("unregistrationConfirm") SEQ, 1, 2, 6, STOP | EXT, 0, NULL}, | ||
1894 | {FNAME("unregistrationReject") SEQ, 1, 3, 8, STOP | EXT, 0, NULL}, | ||
1895 | {FNAME("admissionRequest") SEQ, 7, 16, 34, DECODE | EXT, | ||
1896 | offsetof(RasMessage, admissionRequest), _AdmissionRequest}, | ||
1897 | {FNAME("admissionConfirm") SEQ, 2, 6, 27, DECODE | EXT, | ||
1898 | offsetof(RasMessage, admissionConfirm), _AdmissionConfirm}, | ||
1899 | {FNAME("admissionReject") SEQ, 1, 3, 11, STOP | EXT, 0, NULL}, | ||
1900 | {FNAME("bandwidthRequest") SEQ, 2, 7, 18, STOP | EXT, 0, NULL}, | ||
1901 | {FNAME("bandwidthConfirm") SEQ, 1, 3, 8, STOP | EXT, 0, NULL}, | ||
1902 | {FNAME("bandwidthReject") SEQ, 1, 4, 9, STOP | EXT, 0, NULL}, | ||
1903 | {FNAME("disengageRequest") SEQ, 1, 6, 19, STOP | EXT, 0, NULL}, | ||
1904 | {FNAME("disengageConfirm") SEQ, 1, 2, 9, STOP | EXT, 0, NULL}, | ||
1905 | {FNAME("disengageReject") SEQ, 1, 3, 8, STOP | EXT, 0, NULL}, | ||
1906 | {FNAME("locationRequest") SEQ, 2, 5, 17, DECODE | EXT, | ||
1907 | offsetof(RasMessage, locationRequest), _LocationRequest}, | ||
1908 | {FNAME("locationConfirm") SEQ, 1, 4, 19, DECODE | EXT, | ||
1909 | offsetof(RasMessage, locationConfirm), _LocationConfirm}, | ||
1910 | {FNAME("locationReject") SEQ, 1, 3, 10, STOP | EXT, 0, NULL}, | ||
1911 | {FNAME("infoRequest") SEQ, 2, 4, 15, STOP | EXT, 0, NULL}, | ||
1912 | {FNAME("infoRequestResponse") SEQ, 3, 8, 16, DECODE | EXT, | ||
1913 | offsetof(RasMessage, infoRequestResponse), _InfoRequestResponse}, | ||
1914 | {FNAME("nonStandardMessage") SEQ, 0, 2, 7, STOP | EXT, 0, NULL}, | ||
1915 | {FNAME("unknownMessageResponse") SEQ, 0, 1, 5, STOP | EXT, 0, NULL}, | ||
1916 | {FNAME("requestInProgress") SEQ, 4, 6, 6, STOP | EXT, 0, NULL}, | ||
1917 | {FNAME("resourcesAvailableIndicate") SEQ, 4, 9, 11, STOP | EXT, 0, | ||
1918 | NULL}, | ||
1919 | {FNAME("resourcesAvailableConfirm") SEQ, 4, 6, 7, STOP | EXT, 0, | ||
1920 | NULL}, | ||
1921 | {FNAME("infoRequestAck") SEQ, 4, 5, 5, STOP | EXT, 0, NULL}, | ||
1922 | {FNAME("infoRequestNak") SEQ, 5, 7, 7, STOP | EXT, 0, NULL}, | ||
1923 | {FNAME("serviceControlIndication") SEQ, 8, 10, 10, STOP | EXT, 0, | ||
1924 | NULL}, | ||
1925 | {FNAME("serviceControlResponse") SEQ, 7, 8, 8, STOP | EXT, 0, NULL}, | ||
1926 | }; | ||
diff --git a/net/ipv4/netfilter/ip_conntrack_helper_pptp.c b/net/ipv4/netfilter/ip_conntrack_helper_pptp.c index a2af5e0c7f99..4d19373bbf0d 100644 --- a/net/ipv4/netfilter/ip_conntrack_helper_pptp.c +++ b/net/ipv4/netfilter/ip_conntrack_helper_pptp.c | |||
@@ -124,6 +124,8 @@ EXPORT_SYMBOL(pptp_msg_name); | |||
124 | static void pptp_expectfn(struct ip_conntrack *ct, | 124 | static void pptp_expectfn(struct ip_conntrack *ct, |
125 | struct ip_conntrack_expect *exp) | 125 | struct ip_conntrack_expect *exp) |
126 | { | 126 | { |
127 | typeof(ip_nat_pptp_hook_expectfn) ip_nat_pptp_expectfn; | ||
128 | |||
127 | DEBUGP("increasing timeouts\n"); | 129 | DEBUGP("increasing timeouts\n"); |
128 | 130 | ||
129 | /* increase timeout of GRE data channel conntrack entry */ | 131 | /* increase timeout of GRE data channel conntrack entry */ |
@@ -133,7 +135,9 @@ static void pptp_expectfn(struct ip_conntrack *ct, | |||
133 | /* Can you see how rusty this code is, compared with the pre-2.6.11 | 135 | /* Can you see how rusty this code is, compared with the pre-2.6.11 |
134 | * one? That's what happened to my shiny newnat of 2002 ;( -HW */ | 136 | * one? That's what happened to my shiny newnat of 2002 ;( -HW */ |
135 | 137 | ||
136 | if (!ip_nat_pptp_hook_expectfn) { | 138 | rcu_read_lock(); |
139 | ip_nat_pptp_expectfn = rcu_dereference(ip_nat_pptp_hook_expectfn); | ||
140 | if (!ip_nat_pptp_expectfn) { | ||
137 | struct ip_conntrack_tuple inv_t; | 141 | struct ip_conntrack_tuple inv_t; |
138 | struct ip_conntrack_expect *exp_other; | 142 | struct ip_conntrack_expect *exp_other; |
139 | 143 | ||
@@ -142,7 +146,7 @@ static void pptp_expectfn(struct ip_conntrack *ct, | |||
142 | DEBUGP("trying to unexpect other dir: "); | 146 | DEBUGP("trying to unexpect other dir: "); |
143 | DUMP_TUPLE(&inv_t); | 147 | DUMP_TUPLE(&inv_t); |
144 | 148 | ||
145 | exp_other = ip_conntrack_expect_find(&inv_t); | 149 | exp_other = ip_conntrack_expect_find_get(&inv_t); |
146 | if (exp_other) { | 150 | if (exp_other) { |
147 | /* delete other expectation. */ | 151 | /* delete other expectation. */ |
148 | DEBUGP("found\n"); | 152 | DEBUGP("found\n"); |
@@ -153,8 +157,9 @@ static void pptp_expectfn(struct ip_conntrack *ct, | |||
153 | } | 157 | } |
154 | } else { | 158 | } else { |
155 | /* we need more than simple inversion */ | 159 | /* we need more than simple inversion */ |
156 | ip_nat_pptp_hook_expectfn(ct, exp); | 160 | ip_nat_pptp_expectfn(ct, exp); |
157 | } | 161 | } |
162 | rcu_read_unlock(); | ||
158 | } | 163 | } |
159 | 164 | ||
160 | static int destroy_sibling_or_exp(const struct ip_conntrack_tuple *t) | 165 | static int destroy_sibling_or_exp(const struct ip_conntrack_tuple *t) |
@@ -176,7 +181,7 @@ static int destroy_sibling_or_exp(const struct ip_conntrack_tuple *t) | |||
176 | ip_conntrack_put(sibling); | 181 | ip_conntrack_put(sibling); |
177 | return 1; | 182 | return 1; |
178 | } else { | 183 | } else { |
179 | exp = ip_conntrack_expect_find(t); | 184 | exp = ip_conntrack_expect_find_get(t); |
180 | if (exp) { | 185 | if (exp) { |
181 | DEBUGP("unexpect_related of expect %p\n", exp); | 186 | DEBUGP("unexpect_related of expect %p\n", exp); |
182 | ip_conntrack_unexpect_related(exp); | 187 | ip_conntrack_unexpect_related(exp); |
@@ -226,6 +231,7 @@ exp_gre(struct ip_conntrack *ct, | |||
226 | { | 231 | { |
227 | struct ip_conntrack_expect *exp_orig, *exp_reply; | 232 | struct ip_conntrack_expect *exp_orig, *exp_reply; |
228 | int ret = 1; | 233 | int ret = 1; |
234 | typeof(ip_nat_pptp_hook_exp_gre) ip_nat_pptp_exp_gre; | ||
229 | 235 | ||
230 | exp_orig = ip_conntrack_expect_alloc(ct); | 236 | exp_orig = ip_conntrack_expect_alloc(ct); |
231 | if (exp_orig == NULL) | 237 | if (exp_orig == NULL) |
@@ -262,8 +268,9 @@ exp_gre(struct ip_conntrack *ct, | |||
262 | exp_reply->tuple.dst.u.gre.key = peer_callid; | 268 | exp_reply->tuple.dst.u.gre.key = peer_callid; |
263 | exp_reply->tuple.dst.protonum = IPPROTO_GRE; | 269 | exp_reply->tuple.dst.protonum = IPPROTO_GRE; |
264 | 270 | ||
265 | if (ip_nat_pptp_hook_exp_gre) | 271 | ip_nat_pptp_exp_gre = rcu_dereference(ip_nat_pptp_hook_exp_gre); |
266 | ip_nat_pptp_hook_exp_gre(exp_orig, exp_reply); | 272 | if (ip_nat_pptp_exp_gre) |
273 | ip_nat_pptp_exp_gre(exp_orig, exp_reply); | ||
267 | if (ip_conntrack_expect_related(exp_orig) != 0) | 274 | if (ip_conntrack_expect_related(exp_orig) != 0) |
268 | goto out_put_both; | 275 | goto out_put_both; |
269 | if (ip_conntrack_expect_related(exp_reply) != 0) | 276 | if (ip_conntrack_expect_related(exp_reply) != 0) |
@@ -303,6 +310,7 @@ pptp_inbound_pkt(struct sk_buff **pskb, | |||
303 | struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info; | 310 | struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info; |
304 | u_int16_t msg; | 311 | u_int16_t msg; |
305 | __be16 cid = 0, pcid = 0; | 312 | __be16 cid = 0, pcid = 0; |
313 | typeof(ip_nat_pptp_hook_inbound) ip_nat_pptp_inbound; | ||
306 | 314 | ||
307 | msg = ntohs(ctlh->messageType); | 315 | msg = ntohs(ctlh->messageType); |
308 | DEBUGP("inbound control message %s\n", pptp_msg_name[msg]); | 316 | DEBUGP("inbound control message %s\n", pptp_msg_name[msg]); |
@@ -402,9 +410,9 @@ pptp_inbound_pkt(struct sk_buff **pskb, | |||
402 | goto invalid; | 410 | goto invalid; |
403 | } | 411 | } |
404 | 412 | ||
405 | if (ip_nat_pptp_hook_inbound) | 413 | ip_nat_pptp_inbound = rcu_dereference(ip_nat_pptp_hook_inbound); |
406 | return ip_nat_pptp_hook_inbound(pskb, ct, ctinfo, ctlh, | 414 | if (ip_nat_pptp_inbound) |
407 | pptpReq); | 415 | return ip_nat_pptp_inbound(pskb, ct, ctinfo, ctlh, pptpReq); |
408 | return NF_ACCEPT; | 416 | return NF_ACCEPT; |
409 | 417 | ||
410 | invalid: | 418 | invalid: |
@@ -427,6 +435,7 @@ pptp_outbound_pkt(struct sk_buff **pskb, | |||
427 | struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info; | 435 | struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info; |
428 | u_int16_t msg; | 436 | u_int16_t msg; |
429 | __be16 cid = 0, pcid = 0; | 437 | __be16 cid = 0, pcid = 0; |
438 | typeof(ip_nat_pptp_hook_outbound) ip_nat_pptp_outbound; | ||
430 | 439 | ||
431 | msg = ntohs(ctlh->messageType); | 440 | msg = ntohs(ctlh->messageType); |
432 | DEBUGP("outbound control message %s\n", pptp_msg_name[msg]); | 441 | DEBUGP("outbound control message %s\n", pptp_msg_name[msg]); |
@@ -492,9 +501,9 @@ pptp_outbound_pkt(struct sk_buff **pskb, | |||
492 | goto invalid; | 501 | goto invalid; |
493 | } | 502 | } |
494 | 503 | ||
495 | if (ip_nat_pptp_hook_outbound) | 504 | ip_nat_pptp_outbound = rcu_dereference(ip_nat_pptp_hook_outbound); |
496 | return ip_nat_pptp_hook_outbound(pskb, ct, ctinfo, ctlh, | 505 | if (ip_nat_pptp_outbound) |
497 | pptpReq); | 506 | return ip_nat_pptp_outbound(pskb, ct, ctinfo, ctlh, pptpReq); |
498 | return NF_ACCEPT; | 507 | return NF_ACCEPT; |
499 | 508 | ||
500 | invalid: | 509 | invalid: |
diff --git a/net/ipv4/netfilter/ip_conntrack_irc.c b/net/ipv4/netfilter/ip_conntrack_irc.c index 75f7c3db1619..91832eca4106 100644 --- a/net/ipv4/netfilter/ip_conntrack_irc.c +++ b/net/ipv4/netfilter/ip_conntrack_irc.c | |||
@@ -114,6 +114,7 @@ static int help(struct sk_buff **pskb, | |||
114 | u_int16_t dcc_port; | 114 | u_int16_t dcc_port; |
115 | int i, ret = NF_ACCEPT; | 115 | int i, ret = NF_ACCEPT; |
116 | char *addr_beg_p, *addr_end_p; | 116 | char *addr_beg_p, *addr_end_p; |
117 | typeof(ip_nat_irc_hook) ip_nat_irc; | ||
117 | 118 | ||
118 | DEBUGP("entered\n"); | 119 | DEBUGP("entered\n"); |
119 | 120 | ||
@@ -222,11 +223,12 @@ static int help(struct sk_buff **pskb, | |||
222 | { .tcp = { htons(0xFFFF) } }, 0xFF }}); | 223 | { .tcp = { htons(0xFFFF) } }, 0xFF }}); |
223 | exp->expectfn = NULL; | 224 | exp->expectfn = NULL; |
224 | exp->flags = 0; | 225 | exp->flags = 0; |
225 | if (ip_nat_irc_hook) | 226 | ip_nat_irc = rcu_dereference(ip_nat_irc_hook); |
226 | ret = ip_nat_irc_hook(pskb, ctinfo, | 227 | if (ip_nat_irc) |
227 | addr_beg_p - ib_ptr, | 228 | ret = ip_nat_irc(pskb, ctinfo, |
228 | addr_end_p - addr_beg_p, | 229 | addr_beg_p - ib_ptr, |
229 | exp); | 230 | addr_end_p - addr_beg_p, |
231 | exp); | ||
230 | else if (ip_conntrack_expect_related(exp) != 0) | 232 | else if (ip_conntrack_expect_related(exp) != 0) |
231 | ret = NF_DROP; | 233 | ret = NF_DROP; |
232 | ip_conntrack_expect_put(exp); | 234 | ip_conntrack_expect_put(exp); |
diff --git a/net/ipv4/netfilter/ip_conntrack_netlink.c b/net/ipv4/netfilter/ip_conntrack_netlink.c index 262d0d44ec1b..5fcf91d617cd 100644 --- a/net/ipv4/netfilter/ip_conntrack_netlink.c +++ b/net/ipv4/netfilter/ip_conntrack_netlink.c | |||
@@ -153,6 +153,7 @@ ctnetlink_dump_protoinfo(struct sk_buff *skb, const struct ip_conntrack *ct) | |||
153 | return ret; | 153 | return ret; |
154 | 154 | ||
155 | nfattr_failure: | 155 | nfattr_failure: |
156 | ip_conntrack_proto_put(proto); | ||
156 | return -1; | 157 | return -1; |
157 | } | 158 | } |
158 | 159 | ||
@@ -319,8 +320,6 @@ static int ctnetlink_conntrack_event(struct notifier_block *this, | |||
319 | } else if (events & (IPCT_NEW | IPCT_RELATED)) { | 320 | } else if (events & (IPCT_NEW | IPCT_RELATED)) { |
320 | type = IPCTNL_MSG_CT_NEW; | 321 | type = IPCTNL_MSG_CT_NEW; |
321 | flags = NLM_F_CREATE|NLM_F_EXCL; | 322 | flags = NLM_F_CREATE|NLM_F_EXCL; |
322 | /* dump everything */ | ||
323 | events = ~0UL; | ||
324 | group = NFNLGRP_CONNTRACK_NEW; | 323 | group = NFNLGRP_CONNTRACK_NEW; |
325 | } else if (events & (IPCT_STATUS | IPCT_PROTOINFO)) { | 324 | } else if (events & (IPCT_STATUS | IPCT_PROTOINFO)) { |
326 | type = IPCTNL_MSG_CT_NEW; | 325 | type = IPCTNL_MSG_CT_NEW; |
@@ -355,28 +354,35 @@ static int ctnetlink_conntrack_event(struct notifier_block *this, | |||
355 | if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_REPLY)) < 0) | 354 | if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_REPLY)) < 0) |
356 | goto nfattr_failure; | 355 | goto nfattr_failure; |
357 | NFA_NEST_END(skb, nest_parms); | 356 | NFA_NEST_END(skb, nest_parms); |
358 | |||
359 | /* NAT stuff is now a status flag */ | ||
360 | if ((events & IPCT_STATUS || events & IPCT_NATINFO) | ||
361 | && ctnetlink_dump_status(skb, ct) < 0) | ||
362 | goto nfattr_failure; | ||
363 | if (events & IPCT_REFRESH | ||
364 | && ctnetlink_dump_timeout(skb, ct) < 0) | ||
365 | goto nfattr_failure; | ||
366 | if (events & IPCT_PROTOINFO | ||
367 | && ctnetlink_dump_protoinfo(skb, ct) < 0) | ||
368 | goto nfattr_failure; | ||
369 | if (events & IPCT_HELPINFO | ||
370 | && ctnetlink_dump_helpinfo(skb, ct) < 0) | ||
371 | goto nfattr_failure; | ||
372 | 357 | ||
373 | if (ctnetlink_dump_counters(skb, ct, IP_CT_DIR_ORIGINAL) < 0 || | 358 | if (events & IPCT_DESTROY) { |
374 | ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0) | 359 | if (ctnetlink_dump_counters(skb, ct, IP_CT_DIR_ORIGINAL) < 0 || |
375 | goto nfattr_failure; | 360 | ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0) |
361 | goto nfattr_failure; | ||
362 | } else { | ||
363 | if (ctnetlink_dump_status(skb, ct) < 0) | ||
364 | goto nfattr_failure; | ||
376 | 365 | ||
377 | if (events & IPCT_MARK | 366 | if (ctnetlink_dump_timeout(skb, ct) < 0) |
378 | && ctnetlink_dump_mark(skb, ct) < 0) | 367 | goto nfattr_failure; |
379 | goto nfattr_failure; | 368 | |
369 | if (events & IPCT_PROTOINFO | ||
370 | && ctnetlink_dump_protoinfo(skb, ct) < 0) | ||
371 | goto nfattr_failure; | ||
372 | |||
373 | if ((events & IPCT_HELPER || ct->helper) | ||
374 | && ctnetlink_dump_helpinfo(skb, ct) < 0) | ||
375 | goto nfattr_failure; | ||
376 | |||
377 | if ((events & IPCT_MARK || ct->mark) | ||
378 | && ctnetlink_dump_mark(skb, ct) < 0) | ||
379 | goto nfattr_failure; | ||
380 | |||
381 | if (events & IPCT_COUNTER_FILLING && | ||
382 | (ctnetlink_dump_counters(skb, ct, IP_CT_DIR_ORIGINAL) < 0 || | ||
383 | ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0)) | ||
384 | goto nfattr_failure; | ||
385 | } | ||
380 | 386 | ||
381 | nlh->nlmsg_len = skb->tail - b; | 387 | nlh->nlmsg_len = skb->tail - b; |
382 | nfnetlink_send(skb, 0, group, 0); | 388 | nfnetlink_send(skb, 0, group, 0); |
@@ -742,7 +748,6 @@ ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb, | |||
742 | ip_conntrack_put(ct); | 748 | ip_conntrack_put(ct); |
743 | return -ENOMEM; | 749 | return -ENOMEM; |
744 | } | 750 | } |
745 | NETLINK_CB(skb2).dst_pid = NETLINK_CB(skb).pid; | ||
746 | 751 | ||
747 | err = ctnetlink_fill_info(skb2, NETLINK_CB(skb).pid, nlh->nlmsg_seq, | 752 | err = ctnetlink_fill_info(skb2, NETLINK_CB(skb).pid, nlh->nlmsg_seq, |
748 | IPCTNL_MSG_CT_NEW, 1, ct); | 753 | IPCTNL_MSG_CT_NEW, 1, ct); |
@@ -945,9 +950,11 @@ ctnetlink_create_conntrack(struct nfattr *cda[], | |||
945 | ct->timeout.expires = jiffies + ct->timeout.expires * HZ; | 950 | ct->timeout.expires = jiffies + ct->timeout.expires * HZ; |
946 | ct->status |= IPS_CONFIRMED; | 951 | ct->status |= IPS_CONFIRMED; |
947 | 952 | ||
948 | err = ctnetlink_change_status(ct, cda); | 953 | if (cda[CTA_STATUS-1]) { |
949 | if (err < 0) | 954 | err = ctnetlink_change_status(ct, cda); |
950 | goto err; | 955 | if (err < 0) |
956 | goto err; | ||
957 | } | ||
951 | 958 | ||
952 | if (cda[CTA_PROTOINFO-1]) { | 959 | if (cda[CTA_PROTOINFO-1]) { |
953 | err = ctnetlink_change_protoinfo(ct, cda); | 960 | err = ctnetlink_change_protoinfo(ct, cda); |
@@ -1256,7 +1263,7 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb, | |||
1256 | if (err < 0) | 1263 | if (err < 0) |
1257 | return err; | 1264 | return err; |
1258 | 1265 | ||
1259 | exp = ip_conntrack_expect_find(&tuple); | 1266 | exp = ip_conntrack_expect_find_get(&tuple); |
1260 | if (!exp) | 1267 | if (!exp) |
1261 | return -ENOENT; | 1268 | return -ENOENT; |
1262 | 1269 | ||
@@ -1272,8 +1279,7 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb, | |||
1272 | skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); | 1279 | skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); |
1273 | if (!skb2) | 1280 | if (!skb2) |
1274 | goto out; | 1281 | goto out; |
1275 | NETLINK_CB(skb2).dst_pid = NETLINK_CB(skb).pid; | 1282 | |
1276 | |||
1277 | err = ctnetlink_exp_fill_info(skb2, NETLINK_CB(skb).pid, | 1283 | err = ctnetlink_exp_fill_info(skb2, NETLINK_CB(skb).pid, |
1278 | nlh->nlmsg_seq, IPCTNL_MSG_EXP_NEW, | 1284 | nlh->nlmsg_seq, IPCTNL_MSG_EXP_NEW, |
1279 | 1, exp); | 1285 | 1, exp); |
@@ -1310,7 +1316,7 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb, | |||
1310 | return err; | 1316 | return err; |
1311 | 1317 | ||
1312 | /* bump usage count to 2 */ | 1318 | /* bump usage count to 2 */ |
1313 | exp = ip_conntrack_expect_find(&tuple); | 1319 | exp = ip_conntrack_expect_find_get(&tuple); |
1314 | if (!exp) | 1320 | if (!exp) |
1315 | return -ENOENT; | 1321 | return -ENOENT; |
1316 | 1322 | ||
diff --git a/net/ipv4/netfilter/ip_conntrack_proto_gre.c b/net/ipv4/netfilter/ip_conntrack_proto_gre.c index 5fe026f467d3..ac1c49ef36a9 100644 --- a/net/ipv4/netfilter/ip_conntrack_proto_gre.c +++ b/net/ipv4/netfilter/ip_conntrack_proto_gre.c | |||
@@ -34,8 +34,6 @@ | |||
34 | #include <linux/interrupt.h> | 34 | #include <linux/interrupt.h> |
35 | 35 | ||
36 | static DEFINE_RWLOCK(ip_ct_gre_lock); | 36 | static DEFINE_RWLOCK(ip_ct_gre_lock); |
37 | #define ASSERT_READ_LOCK(x) | ||
38 | #define ASSERT_WRITE_LOCK(x) | ||
39 | 37 | ||
40 | #include <linux/netfilter_ipv4/ip_conntrack_protocol.h> | 38 | #include <linux/netfilter_ipv4/ip_conntrack_protocol.h> |
41 | #include <linux/netfilter_ipv4/ip_conntrack_helper.h> | 39 | #include <linux/netfilter_ipv4/ip_conntrack_helper.h> |
diff --git a/net/ipv4/netfilter/ip_conntrack_sip.c b/net/ipv4/netfilter/ip_conntrack_sip.c index f4f75995a9e4..3a26d63eed88 100644 --- a/net/ipv4/netfilter/ip_conntrack_sip.c +++ b/net/ipv4/netfilter/ip_conntrack_sip.c | |||
@@ -52,20 +52,56 @@ unsigned int (*ip_nat_sdp_hook)(struct sk_buff **pskb, | |||
52 | const char *dptr); | 52 | const char *dptr); |
53 | EXPORT_SYMBOL_GPL(ip_nat_sdp_hook); | 53 | EXPORT_SYMBOL_GPL(ip_nat_sdp_hook); |
54 | 54 | ||
55 | int ct_sip_get_info(const char *dptr, size_t dlen, | ||
56 | unsigned int *matchoff, | ||
57 | unsigned int *matchlen, | ||
58 | struct sip_header_nfo *hnfo); | ||
59 | EXPORT_SYMBOL_GPL(ct_sip_get_info); | ||
60 | |||
61 | |||
62 | static int digits_len(const char *dptr, const char *limit, int *shift); | 55 | static int digits_len(const char *dptr, const char *limit, int *shift); |
63 | static int epaddr_len(const char *dptr, const char *limit, int *shift); | 56 | static int epaddr_len(const char *dptr, const char *limit, int *shift); |
64 | static int skp_digits_len(const char *dptr, const char *limit, int *shift); | 57 | static int skp_digits_len(const char *dptr, const char *limit, int *shift); |
65 | static int skp_epaddr_len(const char *dptr, const char *limit, int *shift); | 58 | static int skp_epaddr_len(const char *dptr, const char *limit, int *shift); |
66 | 59 | ||
67 | struct sip_header_nfo ct_sip_hdrs[] = { | 60 | struct sip_header_nfo { |
68 | { /* Via header */ | 61 | const char *lname; |
62 | const char *sname; | ||
63 | const char *ln_str; | ||
64 | size_t lnlen; | ||
65 | size_t snlen; | ||
66 | size_t ln_strlen; | ||
67 | int case_sensitive; | ||
68 | int (*match_len)(const char *, const char *, int *); | ||
69 | }; | ||
70 | |||
71 | static struct sip_header_nfo ct_sip_hdrs[] = { | ||
72 | [POS_REG_REQ_URI] = { /* SIP REGISTER request URI */ | ||
73 | .lname = "sip:", | ||
74 | .lnlen = sizeof("sip:") - 1, | ||
75 | .ln_str = ":", | ||
76 | .ln_strlen = sizeof(":") - 1, | ||
77 | .match_len = epaddr_len | ||
78 | }, | ||
79 | [POS_REQ_URI] = { /* SIP request URI */ | ||
80 | .lname = "sip:", | ||
81 | .lnlen = sizeof("sip:") - 1, | ||
82 | .ln_str = "@", | ||
83 | .ln_strlen = sizeof("@") - 1, | ||
84 | .match_len = epaddr_len | ||
85 | }, | ||
86 | [POS_FROM] = { /* SIP From header */ | ||
87 | .lname = "From:", | ||
88 | .lnlen = sizeof("From:") - 1, | ||
89 | .sname = "\r\nf:", | ||
90 | .snlen = sizeof("\r\nf:") - 1, | ||
91 | .ln_str = "sip:", | ||
92 | .ln_strlen = sizeof("sip:") - 1, | ||
93 | .match_len = skp_epaddr_len, | ||
94 | }, | ||
95 | [POS_TO] = { /* SIP To header */ | ||
96 | .lname = "To:", | ||
97 | .lnlen = sizeof("To:") - 1, | ||
98 | .sname = "\r\nt:", | ||
99 | .snlen = sizeof("\r\nt:") - 1, | ||
100 | .ln_str = "sip:", | ||
101 | .ln_strlen = sizeof("sip:") - 1, | ||
102 | .match_len = skp_epaddr_len, | ||
103 | }, | ||
104 | [POS_VIA] = { /* SIP Via header */ | ||
69 | .lname = "Via:", | 105 | .lname = "Via:", |
70 | .lnlen = sizeof("Via:") - 1, | 106 | .lnlen = sizeof("Via:") - 1, |
71 | .sname = "\r\nv:", | 107 | .sname = "\r\nv:", |
@@ -74,7 +110,7 @@ struct sip_header_nfo ct_sip_hdrs[] = { | |||
74 | .ln_strlen = sizeof("UDP ") - 1, | 110 | .ln_strlen = sizeof("UDP ") - 1, |
75 | .match_len = epaddr_len, | 111 | .match_len = epaddr_len, |
76 | }, | 112 | }, |
77 | { /* Contact header */ | 113 | [POS_CONTACT] = { /* SIP Contact header */ |
78 | .lname = "Contact:", | 114 | .lname = "Contact:", |
79 | .lnlen = sizeof("Contact:") - 1, | 115 | .lnlen = sizeof("Contact:") - 1, |
80 | .sname = "\r\nm:", | 116 | .sname = "\r\nm:", |
@@ -83,7 +119,7 @@ struct sip_header_nfo ct_sip_hdrs[] = { | |||
83 | .ln_strlen = sizeof("sip:") - 1, | 119 | .ln_strlen = sizeof("sip:") - 1, |
84 | .match_len = skp_epaddr_len | 120 | .match_len = skp_epaddr_len |
85 | }, | 121 | }, |
86 | { /* Content length header */ | 122 | [POS_CONTENT] = { /* SIP Content length header */ |
87 | .lname = "Content-Length:", | 123 | .lname = "Content-Length:", |
88 | .lnlen = sizeof("Content-Length:") - 1, | 124 | .lnlen = sizeof("Content-Length:") - 1, |
89 | .sname = "\r\nl:", | 125 | .sname = "\r\nl:", |
@@ -92,7 +128,8 @@ struct sip_header_nfo ct_sip_hdrs[] = { | |||
92 | .ln_strlen = sizeof(":") - 1, | 128 | .ln_strlen = sizeof(":") - 1, |
93 | .match_len = skp_digits_len | 129 | .match_len = skp_digits_len |
94 | }, | 130 | }, |
95 | { /* SDP media info */ | 131 | [POS_MEDIA] = { /* SDP media info */ |
132 | .case_sensitive = 1, | ||
96 | .lname = "\nm=", | 133 | .lname = "\nm=", |
97 | .lnlen = sizeof("\nm=") - 1, | 134 | .lnlen = sizeof("\nm=") - 1, |
98 | .sname = "\rm=", | 135 | .sname = "\rm=", |
@@ -101,7 +138,8 @@ struct sip_header_nfo ct_sip_hdrs[] = { | |||
101 | .ln_strlen = sizeof("audio ") - 1, | 138 | .ln_strlen = sizeof("audio ") - 1, |
102 | .match_len = digits_len | 139 | .match_len = digits_len |
103 | }, | 140 | }, |
104 | { /* SDP owner address*/ | 141 | [POS_OWNER] = { /* SDP owner address*/ |
142 | .case_sensitive = 1, | ||
105 | .lname = "\no=", | 143 | .lname = "\no=", |
106 | .lnlen = sizeof("\no=") - 1, | 144 | .lnlen = sizeof("\no=") - 1, |
107 | .sname = "\ro=", | 145 | .sname = "\ro=", |
@@ -110,7 +148,8 @@ struct sip_header_nfo ct_sip_hdrs[] = { | |||
110 | .ln_strlen = sizeof("IN IP4 ") - 1, | 148 | .ln_strlen = sizeof("IN IP4 ") - 1, |
111 | .match_len = epaddr_len | 149 | .match_len = epaddr_len |
112 | }, | 150 | }, |
113 | { /* SDP connection info */ | 151 | [POS_CONNECTION] = { /* SDP connection info */ |
152 | .case_sensitive = 1, | ||
114 | .lname = "\nc=", | 153 | .lname = "\nc=", |
115 | .lnlen = sizeof("\nc=") - 1, | 154 | .lnlen = sizeof("\nc=") - 1, |
116 | .sname = "\rc=", | 155 | .sname = "\rc=", |
@@ -119,16 +158,8 @@ struct sip_header_nfo ct_sip_hdrs[] = { | |||
119 | .ln_strlen = sizeof("IN IP4 ") - 1, | 158 | .ln_strlen = sizeof("IN IP4 ") - 1, |
120 | .match_len = epaddr_len | 159 | .match_len = epaddr_len |
121 | }, | 160 | }, |
122 | { /* Requests headers */ | 161 | [POS_SDP_HEADER] = { /* SDP version header */ |
123 | .lname = "sip:", | 162 | .case_sensitive = 1, |
124 | .lnlen = sizeof("sip:") - 1, | ||
125 | .sname = "sip:", | ||
126 | .snlen = sizeof("sip:") - 1, /* yes, i know.. ;) */ | ||
127 | .ln_str = "@", | ||
128 | .ln_strlen = sizeof("@") - 1, | ||
129 | .match_len = epaddr_len | ||
130 | }, | ||
131 | { /* SDP version header */ | ||
132 | .lname = "\nv=", | 163 | .lname = "\nv=", |
133 | .lnlen = sizeof("\nv=") - 1, | 164 | .lnlen = sizeof("\nv=") - 1, |
134 | .sname = "\rv=", | 165 | .sname = "\rv=", |
@@ -138,7 +169,6 @@ struct sip_header_nfo ct_sip_hdrs[] = { | |||
138 | .match_len = digits_len | 169 | .match_len = digits_len |
139 | } | 170 | } |
140 | }; | 171 | }; |
141 | EXPORT_SYMBOL_GPL(ct_sip_hdrs); | ||
142 | 172 | ||
143 | /* get line lenght until first CR or LF seen. */ | 173 | /* get line lenght until first CR or LF seen. */ |
144 | int ct_sip_lnlen(const char *line, const char *limit) | 174 | int ct_sip_lnlen(const char *line, const char *limit) |
@@ -159,13 +189,19 @@ EXPORT_SYMBOL_GPL(ct_sip_lnlen); | |||
159 | 189 | ||
160 | /* Linear string search, case sensitive. */ | 190 | /* Linear string search, case sensitive. */ |
161 | const char *ct_sip_search(const char *needle, const char *haystack, | 191 | const char *ct_sip_search(const char *needle, const char *haystack, |
162 | size_t needle_len, size_t haystack_len) | 192 | size_t needle_len, size_t haystack_len, |
193 | int case_sensitive) | ||
163 | { | 194 | { |
164 | const char *limit = haystack + (haystack_len - needle_len); | 195 | const char *limit = haystack + (haystack_len - needle_len); |
165 | 196 | ||
166 | while (haystack <= limit) { | 197 | while (haystack <= limit) { |
167 | if (memcmp(haystack, needle, needle_len) == 0) | 198 | if (case_sensitive) { |
168 | return haystack; | 199 | if (strncmp(haystack, needle, needle_len) == 0) |
200 | return haystack; | ||
201 | } else { | ||
202 | if (strnicmp(haystack, needle, needle_len) == 0) | ||
203 | return haystack; | ||
204 | } | ||
169 | haystack++; | 205 | haystack++; |
170 | } | 206 | } |
171 | return NULL; | 207 | return NULL; |
@@ -263,8 +299,9 @@ static int skp_epaddr_len(const char *dptr, const char *limit, int *shift) | |||
263 | int ct_sip_get_info(const char *dptr, size_t dlen, | 299 | int ct_sip_get_info(const char *dptr, size_t dlen, |
264 | unsigned int *matchoff, | 300 | unsigned int *matchoff, |
265 | unsigned int *matchlen, | 301 | unsigned int *matchlen, |
266 | struct sip_header_nfo *hnfo) | 302 | enum sip_header_pos pos) |
267 | { | 303 | { |
304 | struct sip_header_nfo *hnfo = &ct_sip_hdrs[pos]; | ||
268 | const char *limit, *aux, *k = dptr; | 305 | const char *limit, *aux, *k = dptr; |
269 | int shift = 0; | 306 | int shift = 0; |
270 | 307 | ||
@@ -272,12 +309,14 @@ int ct_sip_get_info(const char *dptr, size_t dlen, | |||
272 | 309 | ||
273 | while (dptr <= limit) { | 310 | while (dptr <= limit) { |
274 | if ((strncmp(dptr, hnfo->lname, hnfo->lnlen) != 0) && | 311 | if ((strncmp(dptr, hnfo->lname, hnfo->lnlen) != 0) && |
275 | (strncmp(dptr, hnfo->sname, hnfo->snlen) != 0)) { | 312 | (hnfo->sname == NULL || |
313 | strncmp(dptr, hnfo->sname, hnfo->snlen) != 0)) { | ||
276 | dptr++; | 314 | dptr++; |
277 | continue; | 315 | continue; |
278 | } | 316 | } |
279 | aux = ct_sip_search(hnfo->ln_str, dptr, hnfo->ln_strlen, | 317 | aux = ct_sip_search(hnfo->ln_str, dptr, hnfo->ln_strlen, |
280 | ct_sip_lnlen(dptr, limit)); | 318 | ct_sip_lnlen(dptr, limit), |
319 | hnfo->case_sensitive); | ||
281 | if (!aux) { | 320 | if (!aux) { |
282 | DEBUGP("'%s' not found in '%s'.\n", hnfo->ln_str, | 321 | DEBUGP("'%s' not found in '%s'.\n", hnfo->ln_str, |
283 | hnfo->lname); | 322 | hnfo->lname); |
@@ -298,6 +337,7 @@ int ct_sip_get_info(const char *dptr, size_t dlen, | |||
298 | DEBUGP("%s header not found.\n", hnfo->lname); | 337 | DEBUGP("%s header not found.\n", hnfo->lname); |
299 | return 0; | 338 | return 0; |
300 | } | 339 | } |
340 | EXPORT_SYMBOL_GPL(ct_sip_get_info); | ||
301 | 341 | ||
302 | static int set_expected_rtp(struct sk_buff **pskb, | 342 | static int set_expected_rtp(struct sk_buff **pskb, |
303 | struct ip_conntrack *ct, | 343 | struct ip_conntrack *ct, |
@@ -308,6 +348,7 @@ static int set_expected_rtp(struct sk_buff **pskb, | |||
308 | struct ip_conntrack_expect *exp; | 348 | struct ip_conntrack_expect *exp; |
309 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); | 349 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); |
310 | int ret; | 350 | int ret; |
351 | typeof(ip_nat_sdp_hook) ip_nat_sdp; | ||
311 | 352 | ||
312 | exp = ip_conntrack_expect_alloc(ct); | 353 | exp = ip_conntrack_expect_alloc(ct); |
313 | if (exp == NULL) | 354 | if (exp == NULL) |
@@ -328,8 +369,9 @@ static int set_expected_rtp(struct sk_buff **pskb, | |||
328 | exp->expectfn = NULL; | 369 | exp->expectfn = NULL; |
329 | exp->flags = 0; | 370 | exp->flags = 0; |
330 | 371 | ||
331 | if (ip_nat_sdp_hook) | 372 | ip_nat_sdp = rcu_dereference(ip_nat_sdp_hook); |
332 | ret = ip_nat_sdp_hook(pskb, ctinfo, exp, dptr); | 373 | if (ip_nat_sdp) |
374 | ret = ip_nat_sdp(pskb, ctinfo, exp, dptr); | ||
333 | else { | 375 | else { |
334 | if (ip_conntrack_expect_related(exp) != 0) | 376 | if (ip_conntrack_expect_related(exp) != 0) |
335 | ret = NF_DROP; | 377 | ret = NF_DROP; |
@@ -351,6 +393,7 @@ static int sip_help(struct sk_buff **pskb, | |||
351 | int matchoff, matchlen; | 393 | int matchoff, matchlen; |
352 | __be32 ipaddr; | 394 | __be32 ipaddr; |
353 | u_int16_t port; | 395 | u_int16_t port; |
396 | typeof(ip_nat_sip_hook) ip_nat_sip; | ||
354 | 397 | ||
355 | /* No Data ? */ | 398 | /* No Data ? */ |
356 | dataoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr); | 399 | dataoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr); |
@@ -368,8 +411,9 @@ static int sip_help(struct sk_buff **pskb, | |||
368 | goto out; | 411 | goto out; |
369 | } | 412 | } |
370 | 413 | ||
371 | if (ip_nat_sip_hook) { | 414 | ip_nat_sip = rcu_dereference(ip_nat_sip_hook); |
372 | if (!ip_nat_sip_hook(pskb, ctinfo, ct, &dptr)) { | 415 | if (ip_nat_sip) { |
416 | if (!ip_nat_sip(pskb, ctinfo, ct, &dptr)) { | ||
373 | ret = NF_DROP; | 417 | ret = NF_DROP; |
374 | goto out; | 418 | goto out; |
375 | } | 419 | } |
@@ -389,7 +433,7 @@ static int sip_help(struct sk_buff **pskb, | |||
389 | } | 433 | } |
390 | /* Get ip and port address from SDP packet. */ | 434 | /* Get ip and port address from SDP packet. */ |
391 | if (ct_sip_get_info(dptr, datalen, &matchoff, &matchlen, | 435 | if (ct_sip_get_info(dptr, datalen, &matchoff, &matchlen, |
392 | &ct_sip_hdrs[POS_CONNECTION]) > 0) { | 436 | POS_CONNECTION) > 0) { |
393 | 437 | ||
394 | /* We'll drop only if there are parse problems. */ | 438 | /* We'll drop only if there are parse problems. */ |
395 | if (parse_ipaddr(dptr + matchoff, NULL, &ipaddr, | 439 | if (parse_ipaddr(dptr + matchoff, NULL, &ipaddr, |
@@ -398,7 +442,7 @@ static int sip_help(struct sk_buff **pskb, | |||
398 | goto out; | 442 | goto out; |
399 | } | 443 | } |
400 | if (ct_sip_get_info(dptr, datalen, &matchoff, &matchlen, | 444 | if (ct_sip_get_info(dptr, datalen, &matchoff, &matchlen, |
401 | &ct_sip_hdrs[POS_MEDIA]) > 0) { | 445 | POS_MEDIA) > 0) { |
402 | 446 | ||
403 | port = simple_strtoul(dptr + matchoff, NULL, 10); | 447 | port = simple_strtoul(dptr + matchoff, NULL, 10); |
404 | if (port < 1024) { | 448 | if (port < 1024) { |
diff --git a/net/ipv4/netfilter/ip_conntrack_standalone.c b/net/ipv4/netfilter/ip_conntrack_standalone.c index 02135756562e..86efb5449676 100644 --- a/net/ipv4/netfilter/ip_conntrack_standalone.c +++ b/net/ipv4/netfilter/ip_conntrack_standalone.c | |||
@@ -28,9 +28,6 @@ | |||
28 | #include <net/ip.h> | 28 | #include <net/ip.h> |
29 | #include <net/route.h> | 29 | #include <net/route.h> |
30 | 30 | ||
31 | #define ASSERT_READ_LOCK(x) | ||
32 | #define ASSERT_WRITE_LOCK(x) | ||
33 | |||
34 | #include <linux/netfilter_ipv4/ip_conntrack.h> | 31 | #include <linux/netfilter_ipv4/ip_conntrack.h> |
35 | #include <linux/netfilter_ipv4/ip_conntrack_protocol.h> | 32 | #include <linux/netfilter_ipv4/ip_conntrack_protocol.h> |
36 | #include <linux/netfilter_ipv4/ip_conntrack_core.h> | 33 | #include <linux/netfilter_ipv4/ip_conntrack_core.h> |
@@ -139,7 +136,6 @@ static int ct_seq_show(struct seq_file *s, void *v) | |||
139 | const struct ip_conntrack *conntrack = tuplehash_to_ctrack(hash); | 136 | const struct ip_conntrack *conntrack = tuplehash_to_ctrack(hash); |
140 | struct ip_conntrack_protocol *proto; | 137 | struct ip_conntrack_protocol *proto; |
141 | 138 | ||
142 | ASSERT_READ_LOCK(&ip_conntrack_lock); | ||
143 | IP_NF_ASSERT(conntrack); | 139 | IP_NF_ASSERT(conntrack); |
144 | 140 | ||
145 | /* we only want to print DIR_ORIGINAL */ | 141 | /* we only want to print DIR_ORIGINAL */ |
@@ -926,7 +922,7 @@ EXPORT_SYMBOL(__ip_ct_refresh_acct); | |||
926 | EXPORT_SYMBOL(ip_conntrack_expect_alloc); | 922 | EXPORT_SYMBOL(ip_conntrack_expect_alloc); |
927 | EXPORT_SYMBOL(ip_conntrack_expect_put); | 923 | EXPORT_SYMBOL(ip_conntrack_expect_put); |
928 | EXPORT_SYMBOL_GPL(__ip_conntrack_expect_find); | 924 | EXPORT_SYMBOL_GPL(__ip_conntrack_expect_find); |
929 | EXPORT_SYMBOL_GPL(ip_conntrack_expect_find); | 925 | EXPORT_SYMBOL_GPL(ip_conntrack_expect_find_get); |
930 | EXPORT_SYMBOL(ip_conntrack_expect_related); | 926 | EXPORT_SYMBOL(ip_conntrack_expect_related); |
931 | EXPORT_SYMBOL(ip_conntrack_unexpect_related); | 927 | EXPORT_SYMBOL(ip_conntrack_unexpect_related); |
932 | EXPORT_SYMBOL_GPL(ip_conntrack_expect_list); | 928 | EXPORT_SYMBOL_GPL(ip_conntrack_expect_list); |
diff --git a/net/ipv4/netfilter/ip_conntrack_tftp.c b/net/ipv4/netfilter/ip_conntrack_tftp.c index fe0b634dd377..ef56de2eff0c 100644 --- a/net/ipv4/netfilter/ip_conntrack_tftp.c +++ b/net/ipv4/netfilter/ip_conntrack_tftp.c | |||
@@ -50,6 +50,7 @@ static int tftp_help(struct sk_buff **pskb, | |||
50 | struct tftphdr _tftph, *tfh; | 50 | struct tftphdr _tftph, *tfh; |
51 | struct ip_conntrack_expect *exp; | 51 | struct ip_conntrack_expect *exp; |
52 | unsigned int ret = NF_ACCEPT; | 52 | unsigned int ret = NF_ACCEPT; |
53 | typeof(ip_nat_tftp_hook) ip_nat_tftp; | ||
53 | 54 | ||
54 | tfh = skb_header_pointer(*pskb, | 55 | tfh = skb_header_pointer(*pskb, |
55 | (*pskb)->nh.iph->ihl*4+sizeof(struct udphdr), | 56 | (*pskb)->nh.iph->ihl*4+sizeof(struct udphdr), |
@@ -81,8 +82,9 @@ static int tftp_help(struct sk_buff **pskb, | |||
81 | DEBUGP("expect: "); | 82 | DEBUGP("expect: "); |
82 | DUMP_TUPLE(&exp->tuple); | 83 | DUMP_TUPLE(&exp->tuple); |
83 | DUMP_TUPLE(&exp->mask); | 84 | DUMP_TUPLE(&exp->mask); |
84 | if (ip_nat_tftp_hook) | 85 | ip_nat_tftp = rcu_dereference(ip_nat_tftp_hook); |
85 | ret = ip_nat_tftp_hook(pskb, ctinfo, exp); | 86 | if (ip_nat_tftp) |
87 | ret = ip_nat_tftp(pskb, ctinfo, exp); | ||
86 | else if (ip_conntrack_expect_related(exp) != 0) | 88 | else if (ip_conntrack_expect_related(exp) != 0) |
87 | ret = NF_DROP; | 89 | ret = NF_DROP; |
88 | ip_conntrack_expect_put(exp); | 90 | ip_conntrack_expect_put(exp); |
diff --git a/net/ipv4/netfilter/ip_nat_amanda.c b/net/ipv4/netfilter/ip_nat_amanda.c index 3a888715bbf3..85df1a9aed33 100644 --- a/net/ipv4/netfilter/ip_nat_amanda.c +++ b/net/ipv4/netfilter/ip_nat_amanda.c | |||
@@ -70,15 +70,14 @@ static unsigned int help(struct sk_buff **pskb, | |||
70 | 70 | ||
71 | static void __exit ip_nat_amanda_fini(void) | 71 | static void __exit ip_nat_amanda_fini(void) |
72 | { | 72 | { |
73 | ip_nat_amanda_hook = NULL; | 73 | rcu_assign_pointer(ip_nat_amanda_hook, NULL); |
74 | /* Make sure noone calls it, meanwhile. */ | 74 | synchronize_rcu(); |
75 | synchronize_net(); | ||
76 | } | 75 | } |
77 | 76 | ||
78 | static int __init ip_nat_amanda_init(void) | 77 | static int __init ip_nat_amanda_init(void) |
79 | { | 78 | { |
80 | BUG_ON(ip_nat_amanda_hook); | 79 | BUG_ON(rcu_dereference(ip_nat_amanda_hook)); |
81 | ip_nat_amanda_hook = help; | 80 | rcu_assign_pointer(ip_nat_amanda_hook, help); |
82 | return 0; | 81 | return 0; |
83 | } | 82 | } |
84 | 83 | ||
diff --git a/net/ipv4/netfilter/ip_nat_core.c b/net/ipv4/netfilter/ip_nat_core.c index 4b6260a97408..9d1a5175dcd4 100644 --- a/net/ipv4/netfilter/ip_nat_core.c +++ b/net/ipv4/netfilter/ip_nat_core.c | |||
@@ -362,12 +362,10 @@ manip_pkt(u_int16_t proto, | |||
362 | iph = (void *)(*pskb)->data + iphdroff; | 362 | iph = (void *)(*pskb)->data + iphdroff; |
363 | 363 | ||
364 | if (maniptype == IP_NAT_MANIP_SRC) { | 364 | if (maniptype == IP_NAT_MANIP_SRC) { |
365 | iph->check = nf_csum_update(~iph->saddr, target->src.ip, | 365 | nf_csum_replace4(&iph->check, iph->saddr, target->src.ip); |
366 | iph->check); | ||
367 | iph->saddr = target->src.ip; | 366 | iph->saddr = target->src.ip; |
368 | } else { | 367 | } else { |
369 | iph->check = nf_csum_update(~iph->daddr, target->dst.ip, | 368 | nf_csum_replace4(&iph->check, iph->daddr, target->dst.ip); |
370 | iph->check); | ||
371 | iph->daddr = target->dst.ip; | 369 | iph->daddr = target->dst.ip; |
372 | } | 370 | } |
373 | return 1; | 371 | return 1; |
diff --git a/net/ipv4/netfilter/ip_nat_ftp.c b/net/ipv4/netfilter/ip_nat_ftp.c index a71c233d8112..913960e1380f 100644 --- a/net/ipv4/netfilter/ip_nat_ftp.c +++ b/net/ipv4/netfilter/ip_nat_ftp.c | |||
@@ -156,15 +156,14 @@ static unsigned int ip_nat_ftp(struct sk_buff **pskb, | |||
156 | 156 | ||
157 | static void __exit ip_nat_ftp_fini(void) | 157 | static void __exit ip_nat_ftp_fini(void) |
158 | { | 158 | { |
159 | ip_nat_ftp_hook = NULL; | 159 | rcu_assign_pointer(ip_nat_ftp_hook, NULL); |
160 | /* Make sure noone calls it, meanwhile. */ | 160 | synchronize_rcu(); |
161 | synchronize_net(); | ||
162 | } | 161 | } |
163 | 162 | ||
164 | static int __init ip_nat_ftp_init(void) | 163 | static int __init ip_nat_ftp_init(void) |
165 | { | 164 | { |
166 | BUG_ON(ip_nat_ftp_hook); | 165 | BUG_ON(rcu_dereference(ip_nat_ftp_hook)); |
167 | ip_nat_ftp_hook = ip_nat_ftp; | 166 | rcu_assign_pointer(ip_nat_ftp_hook, ip_nat_ftp); |
168 | return 0; | 167 | return 0; |
169 | } | 168 | } |
170 | 169 | ||
diff --git a/net/ipv4/netfilter/ip_nat_helper.c b/net/ipv4/netfilter/ip_nat_helper.c index 3bf858480558..ee80feb4b2a9 100644 --- a/net/ipv4/netfilter/ip_nat_helper.c +++ b/net/ipv4/netfilter/ip_nat_helper.c | |||
@@ -188,10 +188,8 @@ ip_nat_mangle_tcp_packet(struct sk_buff **pskb, | |||
188 | csum_partial((char *)tcph, | 188 | csum_partial((char *)tcph, |
189 | datalen, 0)); | 189 | datalen, 0)); |
190 | } else | 190 | } else |
191 | tcph->check = nf_proto_csum_update(*pskb, | 191 | nf_proto_csum_replace2(&tcph->check, *pskb, |
192 | htons(oldlen) ^ htons(0xFFFF), | 192 | htons(oldlen), htons(datalen), 1); |
193 | htons(datalen), | ||
194 | tcph->check, 1); | ||
195 | 193 | ||
196 | if (rep_len != match_len) { | 194 | if (rep_len != match_len) { |
197 | set_bit(IPS_SEQ_ADJUST_BIT, &ct->status); | 195 | set_bit(IPS_SEQ_ADJUST_BIT, &ct->status); |
@@ -264,12 +262,10 @@ ip_nat_mangle_udp_packet(struct sk_buff **pskb, | |||
264 | csum_partial((char *)udph, | 262 | csum_partial((char *)udph, |
265 | datalen, 0)); | 263 | datalen, 0)); |
266 | if (!udph->check) | 264 | if (!udph->check) |
267 | udph->check = -1; | 265 | udph->check = CSUM_MANGLED_0; |
268 | } else | 266 | } else |
269 | udph->check = nf_proto_csum_update(*pskb, | 267 | nf_proto_csum_replace2(&udph->check, *pskb, |
270 | htons(oldlen) ^ htons(0xFFFF), | 268 | htons(oldlen), htons(datalen), 1); |
271 | htons(datalen), | ||
272 | udph->check, 1); | ||
273 | return 1; | 269 | return 1; |
274 | } | 270 | } |
275 | EXPORT_SYMBOL(ip_nat_mangle_udp_packet); | 271 | EXPORT_SYMBOL(ip_nat_mangle_udp_packet); |
@@ -307,14 +303,10 @@ sack_adjust(struct sk_buff *skb, | |||
307 | ntohl(sack->start_seq), new_start_seq, | 303 | ntohl(sack->start_seq), new_start_seq, |
308 | ntohl(sack->end_seq), new_end_seq); | 304 | ntohl(sack->end_seq), new_end_seq); |
309 | 305 | ||
310 | tcph->check = nf_proto_csum_update(skb, | 306 | nf_proto_csum_replace4(&tcph->check, skb, |
311 | ~sack->start_seq, | 307 | sack->start_seq, new_start_seq, 0); |
312 | new_start_seq, | 308 | nf_proto_csum_replace4(&tcph->check, skb, |
313 | tcph->check, 0); | 309 | sack->end_seq, new_end_seq, 0); |
314 | tcph->check = nf_proto_csum_update(skb, | ||
315 | ~sack->end_seq, | ||
316 | new_end_seq, | ||
317 | tcph->check, 0); | ||
318 | sack->start_seq = new_start_seq; | 310 | sack->start_seq = new_start_seq; |
319 | sack->end_seq = new_end_seq; | 311 | sack->end_seq = new_end_seq; |
320 | sackoff += sizeof(*sack); | 312 | sackoff += sizeof(*sack); |
@@ -397,10 +389,8 @@ ip_nat_seq_adjust(struct sk_buff **pskb, | |||
397 | else | 389 | else |
398 | newack = htonl(ntohl(tcph->ack_seq) - other_way->offset_before); | 390 | newack = htonl(ntohl(tcph->ack_seq) - other_way->offset_before); |
399 | 391 | ||
400 | tcph->check = nf_proto_csum_update(*pskb, ~tcph->seq, newseq, | 392 | nf_proto_csum_replace4(&tcph->check, *pskb, tcph->seq, newseq, 0); |
401 | tcph->check, 0); | 393 | nf_proto_csum_replace4(&tcph->check, *pskb, tcph->ack_seq, newack, 0); |
402 | tcph->check = nf_proto_csum_update(*pskb, ~tcph->ack_seq, newack, | ||
403 | tcph->check, 0); | ||
404 | 394 | ||
405 | DEBUGP("Adjusting sequence number from %u->%u, ack from %u->%u\n", | 395 | DEBUGP("Adjusting sequence number from %u->%u, ack from %u->%u\n", |
406 | ntohl(tcph->seq), ntohl(newseq), ntohl(tcph->ack_seq), | 396 | ntohl(tcph->seq), ntohl(newseq), ntohl(tcph->ack_seq), |
diff --git a/net/ipv4/netfilter/ip_nat_helper_h323.c b/net/ipv4/netfilter/ip_nat_helper_h323.c index 4a7d34466ee2..bdc99ef6159e 100644 --- a/net/ipv4/netfilter/ip_nat_helper_h323.c +++ b/net/ipv4/netfilter/ip_nat_helper_h323.c | |||
@@ -563,25 +563,25 @@ static int nat_callforwarding(struct sk_buff **pskb, struct ip_conntrack *ct, | |||
563 | /****************************************************************************/ | 563 | /****************************************************************************/ |
564 | static int __init init(void) | 564 | static int __init init(void) |
565 | { | 565 | { |
566 | BUG_ON(set_h245_addr_hook != NULL); | 566 | BUG_ON(rcu_dereference(set_h245_addr_hook) != NULL); |
567 | BUG_ON(set_h225_addr_hook != NULL); | 567 | BUG_ON(rcu_dereference(set_h225_addr_hook) != NULL); |
568 | BUG_ON(set_sig_addr_hook != NULL); | 568 | BUG_ON(rcu_dereference(set_sig_addr_hook) != NULL); |
569 | BUG_ON(set_ras_addr_hook != NULL); | 569 | BUG_ON(rcu_dereference(set_ras_addr_hook) != NULL); |
570 | BUG_ON(nat_rtp_rtcp_hook != NULL); | 570 | BUG_ON(rcu_dereference(nat_rtp_rtcp_hook) != NULL); |
571 | BUG_ON(nat_t120_hook != NULL); | 571 | BUG_ON(rcu_dereference(nat_t120_hook) != NULL); |
572 | BUG_ON(nat_h245_hook != NULL); | 572 | BUG_ON(rcu_dereference(nat_h245_hook) != NULL); |
573 | BUG_ON(nat_callforwarding_hook != NULL); | 573 | BUG_ON(rcu_dereference(nat_callforwarding_hook) != NULL); |
574 | BUG_ON(nat_q931_hook != NULL); | 574 | BUG_ON(rcu_dereference(nat_q931_hook) != NULL); |
575 | 575 | ||
576 | set_h245_addr_hook = set_h245_addr; | 576 | rcu_assign_pointer(set_h245_addr_hook, set_h245_addr); |
577 | set_h225_addr_hook = set_h225_addr; | 577 | rcu_assign_pointer(set_h225_addr_hook, set_h225_addr); |
578 | set_sig_addr_hook = set_sig_addr; | 578 | rcu_assign_pointer(set_sig_addr_hook, set_sig_addr); |
579 | set_ras_addr_hook = set_ras_addr; | 579 | rcu_assign_pointer(set_ras_addr_hook, set_ras_addr); |
580 | nat_rtp_rtcp_hook = nat_rtp_rtcp; | 580 | rcu_assign_pointer(nat_rtp_rtcp_hook, nat_rtp_rtcp); |
581 | nat_t120_hook = nat_t120; | 581 | rcu_assign_pointer(nat_t120_hook, nat_t120); |
582 | nat_h245_hook = nat_h245; | 582 | rcu_assign_pointer(nat_h245_hook, nat_h245); |
583 | nat_callforwarding_hook = nat_callforwarding; | 583 | rcu_assign_pointer(nat_callforwarding_hook, nat_callforwarding); |
584 | nat_q931_hook = nat_q931; | 584 | rcu_assign_pointer(nat_q931_hook, nat_q931); |
585 | 585 | ||
586 | DEBUGP("ip_nat_h323: init success\n"); | 586 | DEBUGP("ip_nat_h323: init success\n"); |
587 | return 0; | 587 | return 0; |
@@ -590,16 +590,16 @@ static int __init init(void) | |||
590 | /****************************************************************************/ | 590 | /****************************************************************************/ |
591 | static void __exit fini(void) | 591 | static void __exit fini(void) |
592 | { | 592 | { |
593 | set_h245_addr_hook = NULL; | 593 | rcu_assign_pointer(set_h245_addr_hook, NULL); |
594 | set_h225_addr_hook = NULL; | 594 | rcu_assign_pointer(set_h225_addr_hook, NULL); |
595 | set_sig_addr_hook = NULL; | 595 | rcu_assign_pointer(set_sig_addr_hook, NULL); |
596 | set_ras_addr_hook = NULL; | 596 | rcu_assign_pointer(set_ras_addr_hook, NULL); |
597 | nat_rtp_rtcp_hook = NULL; | 597 | rcu_assign_pointer(nat_rtp_rtcp_hook, NULL); |
598 | nat_t120_hook = NULL; | 598 | rcu_assign_pointer(nat_t120_hook, NULL); |
599 | nat_h245_hook = NULL; | 599 | rcu_assign_pointer(nat_h245_hook, NULL); |
600 | nat_callforwarding_hook = NULL; | 600 | rcu_assign_pointer(nat_callforwarding_hook, NULL); |
601 | nat_q931_hook = NULL; | 601 | rcu_assign_pointer(nat_q931_hook, NULL); |
602 | synchronize_net(); | 602 | synchronize_rcu(); |
603 | } | 603 | } |
604 | 604 | ||
605 | /****************************************************************************/ | 605 | /****************************************************************************/ |
diff --git a/net/ipv4/netfilter/ip_nat_helper_pptp.c b/net/ipv4/netfilter/ip_nat_helper_pptp.c index 329fdcd7d702..ec957bbb5366 100644 --- a/net/ipv4/netfilter/ip_nat_helper_pptp.c +++ b/net/ipv4/netfilter/ip_nat_helper_pptp.c | |||
@@ -101,7 +101,7 @@ static void pptp_nat_expected(struct ip_conntrack *ct, | |||
101 | 101 | ||
102 | DEBUGP("trying to unexpect other dir: "); | 102 | DEBUGP("trying to unexpect other dir: "); |
103 | DUMP_TUPLE(&t); | 103 | DUMP_TUPLE(&t); |
104 | other_exp = ip_conntrack_expect_find(&t); | 104 | other_exp = ip_conntrack_expect_find_get(&t); |
105 | if (other_exp) { | 105 | if (other_exp) { |
106 | ip_conntrack_unexpect_related(other_exp); | 106 | ip_conntrack_unexpect_related(other_exp); |
107 | ip_conntrack_expect_put(other_exp); | 107 | ip_conntrack_expect_put(other_exp); |
@@ -315,17 +315,17 @@ static int __init ip_nat_helper_pptp_init(void) | |||
315 | if (ret < 0) | 315 | if (ret < 0) |
316 | return ret; | 316 | return ret; |
317 | 317 | ||
318 | BUG_ON(ip_nat_pptp_hook_outbound); | 318 | BUG_ON(rcu_dereference(ip_nat_pptp_hook_outbound)); |
319 | ip_nat_pptp_hook_outbound = &pptp_outbound_pkt; | 319 | rcu_assign_pointer(ip_nat_pptp_hook_outbound, pptp_outbound_pkt); |
320 | 320 | ||
321 | BUG_ON(ip_nat_pptp_hook_inbound); | 321 | BUG_ON(rcu_dereference(ip_nat_pptp_hook_inbound)); |
322 | ip_nat_pptp_hook_inbound = &pptp_inbound_pkt; | 322 | rcu_assign_pointer(ip_nat_pptp_hook_inbound, pptp_inbound_pkt); |
323 | 323 | ||
324 | BUG_ON(ip_nat_pptp_hook_exp_gre); | 324 | BUG_ON(rcu_dereference(ip_nat_pptp_hook_exp_gre)); |
325 | ip_nat_pptp_hook_exp_gre = &pptp_exp_gre; | 325 | rcu_assign_pointer(ip_nat_pptp_hook_exp_gre, pptp_exp_gre); |
326 | 326 | ||
327 | BUG_ON(ip_nat_pptp_hook_expectfn); | 327 | BUG_ON(rcu_dereference(ip_nat_pptp_hook_expectfn)); |
328 | ip_nat_pptp_hook_expectfn = &pptp_nat_expected; | 328 | rcu_assign_pointer(ip_nat_pptp_hook_expectfn, pptp_nat_expected); |
329 | 329 | ||
330 | printk("ip_nat_pptp version %s loaded\n", IP_NAT_PPTP_VERSION); | 330 | printk("ip_nat_pptp version %s loaded\n", IP_NAT_PPTP_VERSION); |
331 | return 0; | 331 | return 0; |
@@ -335,14 +335,13 @@ static void __exit ip_nat_helper_pptp_fini(void) | |||
335 | { | 335 | { |
336 | DEBUGP("cleanup_module\n" ); | 336 | DEBUGP("cleanup_module\n" ); |
337 | 337 | ||
338 | ip_nat_pptp_hook_expectfn = NULL; | 338 | rcu_assign_pointer(ip_nat_pptp_hook_expectfn, NULL); |
339 | ip_nat_pptp_hook_exp_gre = NULL; | 339 | rcu_assign_pointer(ip_nat_pptp_hook_exp_gre, NULL); |
340 | ip_nat_pptp_hook_inbound = NULL; | 340 | rcu_assign_pointer(ip_nat_pptp_hook_inbound, NULL); |
341 | ip_nat_pptp_hook_outbound = NULL; | 341 | rcu_assign_pointer(ip_nat_pptp_hook_outbound, NULL); |
342 | synchronize_rcu(); | ||
342 | 343 | ||
343 | ip_nat_proto_gre_fini(); | 344 | ip_nat_proto_gre_fini(); |
344 | /* Make sure noone calls it, meanwhile */ | ||
345 | synchronize_net(); | ||
346 | 345 | ||
347 | printk("ip_nat_pptp version %s unloaded\n", IP_NAT_PPTP_VERSION); | 346 | printk("ip_nat_pptp version %s unloaded\n", IP_NAT_PPTP_VERSION); |
348 | } | 347 | } |
diff --git a/net/ipv4/netfilter/ip_nat_irc.c b/net/ipv4/netfilter/ip_nat_irc.c index a767123e082c..feb26b48f1d5 100644 --- a/net/ipv4/netfilter/ip_nat_irc.c +++ b/net/ipv4/netfilter/ip_nat_irc.c | |||
@@ -98,15 +98,14 @@ static unsigned int help(struct sk_buff **pskb, | |||
98 | 98 | ||
99 | static void __exit ip_nat_irc_fini(void) | 99 | static void __exit ip_nat_irc_fini(void) |
100 | { | 100 | { |
101 | ip_nat_irc_hook = NULL; | 101 | rcu_assign_pointer(ip_nat_irc_hook, NULL); |
102 | /* Make sure noone calls it, meanwhile. */ | 102 | synchronize_rcu(); |
103 | synchronize_net(); | ||
104 | } | 103 | } |
105 | 104 | ||
106 | static int __init ip_nat_irc_init(void) | 105 | static int __init ip_nat_irc_init(void) |
107 | { | 106 | { |
108 | BUG_ON(ip_nat_irc_hook); | 107 | BUG_ON(rcu_dereference(ip_nat_irc_hook)); |
109 | ip_nat_irc_hook = help; | 108 | rcu_assign_pointer(ip_nat_irc_hook, help); |
110 | return 0; | 109 | return 0; |
111 | } | 110 | } |
112 | 111 | ||
diff --git a/net/ipv4/netfilter/ip_nat_proto_gre.c b/net/ipv4/netfilter/ip_nat_proto_gre.c index bf91f9312b3c..95810202d849 100644 --- a/net/ipv4/netfilter/ip_nat_proto_gre.c +++ b/net/ipv4/netfilter/ip_nat_proto_gre.c | |||
@@ -129,11 +129,9 @@ gre_manip_pkt(struct sk_buff **pskb, | |||
129 | } | 129 | } |
130 | if (greh->csum) { | 130 | if (greh->csum) { |
131 | /* FIXME: Never tested this code... */ | 131 | /* FIXME: Never tested this code... */ |
132 | *(gre_csum(greh)) = | 132 | nf_proto_csum_replace4(gre_csum(greh), *pskb, |
133 | nf_proto_csum_update(*pskb, | 133 | *(gre_key(greh)), |
134 | ~*(gre_key(greh)), | 134 | tuple->dst.u.gre.key, 0); |
135 | tuple->dst.u.gre.key, | ||
136 | *(gre_csum(greh)), 0); | ||
137 | } | 135 | } |
138 | *(gre_key(greh)) = tuple->dst.u.gre.key; | 136 | *(gre_key(greh)) = tuple->dst.u.gre.key; |
139 | break; | 137 | break; |
diff --git a/net/ipv4/netfilter/ip_nat_proto_icmp.c b/net/ipv4/netfilter/ip_nat_proto_icmp.c index 3f6efc13ac74..fb716edd5bc6 100644 --- a/net/ipv4/netfilter/ip_nat_proto_icmp.c +++ b/net/ipv4/netfilter/ip_nat_proto_icmp.c | |||
@@ -24,8 +24,8 @@ icmp_in_range(const struct ip_conntrack_tuple *tuple, | |||
24 | const union ip_conntrack_manip_proto *min, | 24 | const union ip_conntrack_manip_proto *min, |
25 | const union ip_conntrack_manip_proto *max) | 25 | const union ip_conntrack_manip_proto *max) |
26 | { | 26 | { |
27 | return (tuple->src.u.icmp.id >= min->icmp.id | 27 | return ntohs(tuple->src.u.icmp.id) >= ntohs(min->icmp.id) && |
28 | && tuple->src.u.icmp.id <= max->icmp.id); | 28 | ntohs(tuple->src.u.icmp.id) <= ntohs(max->icmp.id); |
29 | } | 29 | } |
30 | 30 | ||
31 | static int | 31 | static int |
@@ -66,10 +66,8 @@ icmp_manip_pkt(struct sk_buff **pskb, | |||
66 | return 0; | 66 | return 0; |
67 | 67 | ||
68 | hdr = (struct icmphdr *)((*pskb)->data + hdroff); | 68 | hdr = (struct icmphdr *)((*pskb)->data + hdroff); |
69 | hdr->checksum = nf_proto_csum_update(*pskb, | 69 | nf_proto_csum_replace2(&hdr->checksum, *pskb, |
70 | hdr->un.echo.id ^ htons(0xFFFF), | 70 | hdr->un.echo.id, tuple->src.u.icmp.id, 0); |
71 | tuple->src.u.icmp.id, | ||
72 | hdr->checksum, 0); | ||
73 | hdr->un.echo.id = tuple->src.u.icmp.id; | 71 | hdr->un.echo.id = tuple->src.u.icmp.id; |
74 | return 1; | 72 | return 1; |
75 | } | 73 | } |
diff --git a/net/ipv4/netfilter/ip_nat_proto_tcp.c b/net/ipv4/netfilter/ip_nat_proto_tcp.c index 12deb13b93b1..b586d18b3fb3 100644 --- a/net/ipv4/netfilter/ip_nat_proto_tcp.c +++ b/net/ipv4/netfilter/ip_nat_proto_tcp.c | |||
@@ -129,9 +129,8 @@ tcp_manip_pkt(struct sk_buff **pskb, | |||
129 | if (hdrsize < sizeof(*hdr)) | 129 | if (hdrsize < sizeof(*hdr)) |
130 | return 1; | 130 | return 1; |
131 | 131 | ||
132 | hdr->check = nf_proto_csum_update(*pskb, ~oldip, newip, hdr->check, 1); | 132 | nf_proto_csum_replace4(&hdr->check, *pskb, oldip, newip, 1); |
133 | hdr->check = nf_proto_csum_update(*pskb, oldport ^ htons(0xFFFF), newport, | 133 | nf_proto_csum_replace2(&hdr->check, *pskb, oldport, newport, 0); |
134 | hdr->check, 0); | ||
135 | return 1; | 134 | return 1; |
136 | } | 135 | } |
137 | 136 | ||
diff --git a/net/ipv4/netfilter/ip_nat_proto_udp.c b/net/ipv4/netfilter/ip_nat_proto_udp.c index 4bbec7730d18..5ced0877b32f 100644 --- a/net/ipv4/netfilter/ip_nat_proto_udp.c +++ b/net/ipv4/netfilter/ip_nat_proto_udp.c | |||
@@ -115,13 +115,10 @@ udp_manip_pkt(struct sk_buff **pskb, | |||
115 | } | 115 | } |
116 | 116 | ||
117 | if (hdr->check || (*pskb)->ip_summed == CHECKSUM_PARTIAL) { | 117 | if (hdr->check || (*pskb)->ip_summed == CHECKSUM_PARTIAL) { |
118 | hdr->check = nf_proto_csum_update(*pskb, ~oldip, newip, | 118 | nf_proto_csum_replace4(&hdr->check, *pskb, oldip, newip, 1); |
119 | hdr->check, 1); | 119 | nf_proto_csum_replace2(&hdr->check, *pskb, *portptr, newport, 0); |
120 | hdr->check = nf_proto_csum_update(*pskb, | ||
121 | *portptr ^ htons(0xFFFF), newport, | ||
122 | hdr->check, 0); | ||
123 | if (!hdr->check) | 120 | if (!hdr->check) |
124 | hdr->check = -1; | 121 | hdr->check = CSUM_MANGLED_0; |
125 | } | 122 | } |
126 | *portptr = newport; | 123 | *portptr = newport; |
127 | return 1; | 124 | return 1; |
diff --git a/net/ipv4/netfilter/ip_nat_sip.c b/net/ipv4/netfilter/ip_nat_sip.c index 71fc2730a007..6223abc924ff 100644 --- a/net/ipv4/netfilter/ip_nat_sip.c +++ b/net/ipv4/netfilter/ip_nat_sip.c | |||
@@ -29,27 +29,70 @@ MODULE_DESCRIPTION("SIP NAT helper"); | |||
29 | #define DEBUGP(format, args...) | 29 | #define DEBUGP(format, args...) |
30 | #endif | 30 | #endif |
31 | 31 | ||
32 | extern struct sip_header_nfo ct_sip_hdrs[]; | 32 | struct addr_map { |
33 | struct { | ||
34 | char src[sizeof("nnn.nnn.nnn.nnn:nnnnn")]; | ||
35 | char dst[sizeof("nnn.nnn.nnn.nnn:nnnnn")]; | ||
36 | unsigned int srclen, srciplen; | ||
37 | unsigned int dstlen, dstiplen; | ||
38 | } addr[IP_CT_DIR_MAX]; | ||
39 | }; | ||
40 | |||
41 | static void addr_map_init(struct ip_conntrack *ct, struct addr_map *map) | ||
42 | { | ||
43 | struct ip_conntrack_tuple *t; | ||
44 | enum ip_conntrack_dir dir; | ||
45 | unsigned int n; | ||
46 | |||
47 | for (dir = 0; dir < IP_CT_DIR_MAX; dir++) { | ||
48 | t = &ct->tuplehash[dir].tuple; | ||
49 | |||
50 | n = sprintf(map->addr[dir].src, "%u.%u.%u.%u", | ||
51 | NIPQUAD(t->src.ip)); | ||
52 | map->addr[dir].srciplen = n; | ||
53 | n += sprintf(map->addr[dir].src + n, ":%u", | ||
54 | ntohs(t->src.u.udp.port)); | ||
55 | map->addr[dir].srclen = n; | ||
56 | |||
57 | n = sprintf(map->addr[dir].dst, "%u.%u.%u.%u", | ||
58 | NIPQUAD(t->dst.ip)); | ||
59 | map->addr[dir].dstiplen = n; | ||
60 | n += sprintf(map->addr[dir].dst + n, ":%u", | ||
61 | ntohs(t->dst.u.udp.port)); | ||
62 | map->addr[dir].dstlen = n; | ||
63 | } | ||
64 | } | ||
33 | 65 | ||
34 | static unsigned int mangle_sip_packet(struct sk_buff **pskb, | 66 | static int map_sip_addr(struct sk_buff **pskb, enum ip_conntrack_info ctinfo, |
35 | enum ip_conntrack_info ctinfo, | 67 | struct ip_conntrack *ct, const char **dptr, size_t dlen, |
36 | struct ip_conntrack *ct, | 68 | enum sip_header_pos pos, struct addr_map *map) |
37 | const char **dptr, size_t dlen, | ||
38 | char *buffer, int bufflen, | ||
39 | struct sip_header_nfo *hnfo) | ||
40 | { | 69 | { |
41 | unsigned int matchlen, matchoff; | 70 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); |
71 | unsigned int matchlen, matchoff, addrlen; | ||
72 | char *addr; | ||
42 | 73 | ||
43 | if (ct_sip_get_info(*dptr, dlen, &matchoff, &matchlen, hnfo) <= 0) | 74 | if (ct_sip_get_info(*dptr, dlen, &matchoff, &matchlen, pos) <= 0) |
44 | return 0; | 75 | return 1; |
76 | |||
77 | if ((matchlen == map->addr[dir].srciplen || | ||
78 | matchlen == map->addr[dir].srclen) && | ||
79 | memcmp(*dptr + matchoff, map->addr[dir].src, matchlen) == 0) { | ||
80 | addr = map->addr[!dir].dst; | ||
81 | addrlen = map->addr[!dir].dstlen; | ||
82 | } else if ((matchlen == map->addr[dir].dstiplen || | ||
83 | matchlen == map->addr[dir].dstlen) && | ||
84 | memcmp(*dptr + matchoff, map->addr[dir].dst, matchlen) == 0) { | ||
85 | addr = map->addr[!dir].src; | ||
86 | addrlen = map->addr[!dir].srclen; | ||
87 | } else | ||
88 | return 1; | ||
45 | 89 | ||
46 | if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo, | 90 | if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo, |
47 | matchoff, matchlen, buffer, bufflen)) | 91 | matchoff, matchlen, addr, addrlen)) |
48 | return 0; | 92 | return 0; |
49 | |||
50 | /* We need to reload this. Thanks Patrick. */ | ||
51 | *dptr = (*pskb)->data + (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr); | 93 | *dptr = (*pskb)->data + (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr); |
52 | return 1; | 94 | return 1; |
95 | |||
53 | } | 96 | } |
54 | 97 | ||
55 | static unsigned int ip_nat_sip(struct sk_buff **pskb, | 98 | static unsigned int ip_nat_sip(struct sk_buff **pskb, |
@@ -57,70 +100,61 @@ static unsigned int ip_nat_sip(struct sk_buff **pskb, | |||
57 | struct ip_conntrack *ct, | 100 | struct ip_conntrack *ct, |
58 | const char **dptr) | 101 | const char **dptr) |
59 | { | 102 | { |
60 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); | 103 | enum sip_header_pos pos; |
61 | char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")]; | 104 | struct addr_map map; |
62 | unsigned int bufflen, dataoff; | 105 | int dataoff, datalen; |
63 | __be32 ip; | ||
64 | __be16 port; | ||
65 | 106 | ||
66 | dataoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr); | 107 | dataoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr); |
108 | datalen = (*pskb)->len - dataoff; | ||
109 | if (datalen < sizeof("SIP/2.0") - 1) | ||
110 | return NF_DROP; | ||
111 | |||
112 | addr_map_init(ct, &map); | ||
113 | |||
114 | /* Basic rules: requests and responses. */ | ||
115 | if (strncmp(*dptr, "SIP/2.0", sizeof("SIP/2.0") - 1) != 0) { | ||
116 | /* 10.2: Constructing the REGISTER Request: | ||
117 | * | ||
118 | * The "userinfo" and "@" components of the SIP URI MUST NOT | ||
119 | * be present. | ||
120 | */ | ||
121 | if (datalen >= sizeof("REGISTER") - 1 && | ||
122 | strncmp(*dptr, "REGISTER", sizeof("REGISTER") - 1) == 0) | ||
123 | pos = POS_REG_REQ_URI; | ||
124 | else | ||
125 | pos = POS_REQ_URI; | ||
126 | |||
127 | if (!map_sip_addr(pskb, ctinfo, ct, dptr, datalen, pos, &map)) | ||
128 | return NF_DROP; | ||
129 | } | ||
130 | |||
131 | if (!map_sip_addr(pskb, ctinfo, ct, dptr, datalen, POS_FROM, &map) || | ||
132 | !map_sip_addr(pskb, ctinfo, ct, dptr, datalen, POS_TO, &map) || | ||
133 | !map_sip_addr(pskb, ctinfo, ct, dptr, datalen, POS_VIA, &map) || | ||
134 | !map_sip_addr(pskb, ctinfo, ct, dptr, datalen, POS_CONTACT, &map)) | ||
135 | return NF_DROP; | ||
136 | return NF_ACCEPT; | ||
137 | } | ||
67 | 138 | ||
68 | ip = ct->tuplehash[!dir].tuple.dst.ip; | 139 | static unsigned int mangle_sip_packet(struct sk_buff **pskb, |
69 | port = ct->tuplehash[!dir].tuple.dst.u.udp.port; | 140 | enum ip_conntrack_info ctinfo, |
70 | bufflen = sprintf(buffer, "%u.%u.%u.%u:%u", NIPQUAD(ip), ntohs(port)); | 141 | struct ip_conntrack *ct, |
142 | const char **dptr, size_t dlen, | ||
143 | char *buffer, int bufflen, | ||
144 | enum sip_header_pos pos) | ||
145 | { | ||
146 | unsigned int matchlen, matchoff; | ||
71 | 147 | ||
72 | /* short packet ? */ | 148 | if (ct_sip_get_info(*dptr, dlen, &matchoff, &matchlen, pos) <= 0) |
73 | if (((*pskb)->len - dataoff) < (sizeof("SIP/2.0") - 1)) | ||
74 | return 0; | 149 | return 0; |
75 | 150 | ||
76 | /* Basic rules: requests and responses. */ | 151 | if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo, |
77 | if (memcmp(*dptr, "SIP/2.0", sizeof("SIP/2.0") - 1) == 0) { | 152 | matchoff, matchlen, buffer, bufflen)) |
78 | const char *aux; | 153 | return 0; |
79 | |||
80 | if ((ctinfo) < IP_CT_IS_REPLY) { | ||
81 | mangle_sip_packet(pskb, ctinfo, ct, dptr, | ||
82 | (*pskb)->len - dataoff, | ||
83 | buffer, bufflen, | ||
84 | &ct_sip_hdrs[POS_CONTACT]); | ||
85 | return 1; | ||
86 | } | ||
87 | 154 | ||
88 | if (!mangle_sip_packet(pskb, ctinfo, ct, dptr, | 155 | /* We need to reload this. Thanks Patrick. */ |
89 | (*pskb)->len - dataoff, | 156 | *dptr = (*pskb)->data + (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr); |
90 | buffer, bufflen, &ct_sip_hdrs[POS_VIA])) | 157 | return 1; |
91 | return 0; | ||
92 | |||
93 | /* This search should ignore case, but later.. */ | ||
94 | aux = ct_sip_search("CSeq:", *dptr, sizeof("CSeq:") - 1, | ||
95 | (*pskb)->len - dataoff); | ||
96 | if (!aux) | ||
97 | return 0; | ||
98 | |||
99 | if (!ct_sip_search("REGISTER", aux, sizeof("REGISTER"), | ||
100 | ct_sip_lnlen(aux, *dptr + (*pskb)->len - dataoff))) | ||
101 | return 1; | ||
102 | |||
103 | return mangle_sip_packet(pskb, ctinfo, ct, dptr, | ||
104 | (*pskb)->len - dataoff, | ||
105 | buffer, bufflen, | ||
106 | &ct_sip_hdrs[POS_CONTACT]); | ||
107 | } | ||
108 | if ((ctinfo) < IP_CT_IS_REPLY) { | ||
109 | if (!mangle_sip_packet(pskb, ctinfo, ct, dptr, | ||
110 | (*pskb)->len - dataoff, | ||
111 | buffer, bufflen, &ct_sip_hdrs[POS_VIA])) | ||
112 | return 0; | ||
113 | |||
114 | /* Mangle Contact if exists only. - watch udp_nat_mangle()! */ | ||
115 | mangle_sip_packet(pskb, ctinfo, ct, dptr, (*pskb)->len - dataoff, | ||
116 | buffer, bufflen, &ct_sip_hdrs[POS_CONTACT]); | ||
117 | return 1; | ||
118 | } | ||
119 | /* This mangle requests headers. */ | ||
120 | return mangle_sip_packet(pskb, ctinfo, ct, dptr, | ||
121 | ct_sip_lnlen(*dptr, | ||
122 | *dptr + (*pskb)->len - dataoff), | ||
123 | buffer, bufflen, &ct_sip_hdrs[POS_REQ_HEADER]); | ||
124 | } | 158 | } |
125 | 159 | ||
126 | static int mangle_content_len(struct sk_buff **pskb, | 160 | static int mangle_content_len(struct sk_buff **pskb, |
@@ -136,7 +170,7 @@ static int mangle_content_len(struct sk_buff **pskb, | |||
136 | 170 | ||
137 | /* Get actual SDP lenght */ | 171 | /* Get actual SDP lenght */ |
138 | if (ct_sip_get_info(dptr, (*pskb)->len - dataoff, &matchoff, | 172 | if (ct_sip_get_info(dptr, (*pskb)->len - dataoff, &matchoff, |
139 | &matchlen, &ct_sip_hdrs[POS_SDP_HEADER]) > 0) { | 173 | &matchlen, POS_SDP_HEADER) > 0) { |
140 | 174 | ||
141 | /* since ct_sip_get_info() give us a pointer passing 'v=' | 175 | /* since ct_sip_get_info() give us a pointer passing 'v=' |
142 | we need to add 2 bytes in this count. */ | 176 | we need to add 2 bytes in this count. */ |
@@ -144,7 +178,7 @@ static int mangle_content_len(struct sk_buff **pskb, | |||
144 | 178 | ||
145 | /* Now, update SDP lenght */ | 179 | /* Now, update SDP lenght */ |
146 | if (ct_sip_get_info(dptr, (*pskb)->len - dataoff, &matchoff, | 180 | if (ct_sip_get_info(dptr, (*pskb)->len - dataoff, &matchoff, |
147 | &matchlen, &ct_sip_hdrs[POS_CONTENT]) > 0) { | 181 | &matchlen, POS_CONTENT) > 0) { |
148 | 182 | ||
149 | bufflen = sprintf(buffer, "%u", c_len); | 183 | bufflen = sprintf(buffer, "%u", c_len); |
150 | 184 | ||
@@ -170,17 +204,17 @@ static unsigned int mangle_sdp(struct sk_buff **pskb, | |||
170 | /* Mangle owner and contact info. */ | 204 | /* Mangle owner and contact info. */ |
171 | bufflen = sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(newip)); | 205 | bufflen = sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(newip)); |
172 | if (!mangle_sip_packet(pskb, ctinfo, ct, &dptr, (*pskb)->len - dataoff, | 206 | if (!mangle_sip_packet(pskb, ctinfo, ct, &dptr, (*pskb)->len - dataoff, |
173 | buffer, bufflen, &ct_sip_hdrs[POS_OWNER])) | 207 | buffer, bufflen, POS_OWNER)) |
174 | return 0; | 208 | return 0; |
175 | 209 | ||
176 | if (!mangle_sip_packet(pskb, ctinfo, ct, &dptr, (*pskb)->len - dataoff, | 210 | if (!mangle_sip_packet(pskb, ctinfo, ct, &dptr, (*pskb)->len - dataoff, |
177 | buffer, bufflen, &ct_sip_hdrs[POS_CONNECTION])) | 211 | buffer, bufflen, POS_CONNECTION)) |
178 | return 0; | 212 | return 0; |
179 | 213 | ||
180 | /* Mangle media port. */ | 214 | /* Mangle media port. */ |
181 | bufflen = sprintf(buffer, "%u", port); | 215 | bufflen = sprintf(buffer, "%u", port); |
182 | if (!mangle_sip_packet(pskb, ctinfo, ct, &dptr, (*pskb)->len - dataoff, | 216 | if (!mangle_sip_packet(pskb, ctinfo, ct, &dptr, (*pskb)->len - dataoff, |
183 | buffer, bufflen, &ct_sip_hdrs[POS_MEDIA])) | 217 | buffer, bufflen, POS_MEDIA)) |
184 | return 0; | 218 | return 0; |
185 | 219 | ||
186 | return mangle_content_len(pskb, ctinfo, ct, dptr); | 220 | return mangle_content_len(pskb, ctinfo, ct, dptr); |
@@ -230,18 +264,17 @@ static unsigned int ip_nat_sdp(struct sk_buff **pskb, | |||
230 | 264 | ||
231 | static void __exit fini(void) | 265 | static void __exit fini(void) |
232 | { | 266 | { |
233 | ip_nat_sip_hook = NULL; | 267 | rcu_assign_pointer(ip_nat_sip_hook, NULL); |
234 | ip_nat_sdp_hook = NULL; | 268 | rcu_assign_pointer(ip_nat_sdp_hook, NULL); |
235 | /* Make sure noone calls it, meanwhile. */ | 269 | synchronize_rcu(); |
236 | synchronize_net(); | ||
237 | } | 270 | } |
238 | 271 | ||
239 | static int __init init(void) | 272 | static int __init init(void) |
240 | { | 273 | { |
241 | BUG_ON(ip_nat_sip_hook); | 274 | BUG_ON(rcu_dereference(ip_nat_sip_hook)); |
242 | BUG_ON(ip_nat_sdp_hook); | 275 | BUG_ON(rcu_dereference(ip_nat_sdp_hook)); |
243 | ip_nat_sip_hook = ip_nat_sip; | 276 | rcu_assign_pointer(ip_nat_sip_hook, ip_nat_sip); |
244 | ip_nat_sdp_hook = ip_nat_sdp; | 277 | rcu_assign_pointer(ip_nat_sdp_hook, ip_nat_sdp); |
245 | return 0; | 278 | return 0; |
246 | } | 279 | } |
247 | 280 | ||
diff --git a/net/ipv4/netfilter/ip_nat_snmp_basic.c b/net/ipv4/netfilter/ip_nat_snmp_basic.c index 168f45fa1898..c3d9f3b090c4 100644 --- a/net/ipv4/netfilter/ip_nat_snmp_basic.c +++ b/net/ipv4/netfilter/ip_nat_snmp_basic.c | |||
@@ -64,7 +64,7 @@ MODULE_DESCRIPTION("Basic SNMP Application Layer Gateway"); | |||
64 | 64 | ||
65 | #define SNMP_PORT 161 | 65 | #define SNMP_PORT 161 |
66 | #define SNMP_TRAP_PORT 162 | 66 | #define SNMP_TRAP_PORT 162 |
67 | #define NOCT1(n) (u_int8_t )((n) & 0xff) | 67 | #define NOCT1(n) (*(u8 *)n) |
68 | 68 | ||
69 | static int debug; | 69 | static int debug; |
70 | static DEFINE_SPINLOCK(snmp_lock); | 70 | static DEFINE_SPINLOCK(snmp_lock); |
@@ -613,7 +613,7 @@ struct snmp_v1_trap | |||
613 | static inline void mangle_address(unsigned char *begin, | 613 | static inline void mangle_address(unsigned char *begin, |
614 | unsigned char *addr, | 614 | unsigned char *addr, |
615 | const struct oct1_map *map, | 615 | const struct oct1_map *map, |
616 | u_int16_t *check); | 616 | __sum16 *check); |
617 | struct snmp_cnv | 617 | struct snmp_cnv |
618 | { | 618 | { |
619 | unsigned int class; | 619 | unsigned int class; |
@@ -873,38 +873,24 @@ static unsigned char snmp_request_decode(struct asn1_ctx *ctx, | |||
873 | * Fast checksum update for possibly oddly-aligned UDP byte, from the | 873 | * Fast checksum update for possibly oddly-aligned UDP byte, from the |
874 | * code example in the draft. | 874 | * code example in the draft. |
875 | */ | 875 | */ |
876 | static void fast_csum(unsigned char *csum, | 876 | static void fast_csum(__sum16 *csum, |
877 | const unsigned char *optr, | 877 | const unsigned char *optr, |
878 | const unsigned char *nptr, | 878 | const unsigned char *nptr, |
879 | int odd) | 879 | int offset) |
880 | { | 880 | { |
881 | long x, old, new; | 881 | unsigned char s[4]; |
882 | 882 | ||
883 | x = csum[0] * 256 + csum[1]; | 883 | if (offset & 1) { |
884 | 884 | s[0] = s[2] = 0; | |
885 | x =~ x & 0xFFFF; | 885 | s[1] = ~*optr; |
886 | 886 | s[3] = *nptr; | |
887 | if (odd) old = optr[0] * 256; | 887 | } else { |
888 | else old = optr[0]; | 888 | s[1] = s[3] = 0; |
889 | 889 | s[0] = ~*optr; | |
890 | x -= old & 0xFFFF; | 890 | s[2] = *nptr; |
891 | if (x <= 0) { | ||
892 | x--; | ||
893 | x &= 0xFFFF; | ||
894 | } | ||
895 | |||
896 | if (odd) new = nptr[0] * 256; | ||
897 | else new = nptr[0]; | ||
898 | |||
899 | x += new & 0xFFFF; | ||
900 | if (x & 0x10000) { | ||
901 | x++; | ||
902 | x &= 0xFFFF; | ||
903 | } | 891 | } |
904 | 892 | ||
905 | x =~ x & 0xFFFF; | 893 | *csum = csum_fold(csum_partial(s, 4, ~csum_unfold(*csum))); |
906 | csum[0] = x / 256; | ||
907 | csum[1] = x & 0xFF; | ||
908 | } | 894 | } |
909 | 895 | ||
910 | /* | 896 | /* |
@@ -915,9 +901,9 @@ static void fast_csum(unsigned char *csum, | |||
915 | static inline void mangle_address(unsigned char *begin, | 901 | static inline void mangle_address(unsigned char *begin, |
916 | unsigned char *addr, | 902 | unsigned char *addr, |
917 | const struct oct1_map *map, | 903 | const struct oct1_map *map, |
918 | u_int16_t *check) | 904 | __sum16 *check) |
919 | { | 905 | { |
920 | if (map->from == NOCT1(*addr)) { | 906 | if (map->from == NOCT1(addr)) { |
921 | u_int32_t old; | 907 | u_int32_t old; |
922 | 908 | ||
923 | if (debug) | 909 | if (debug) |
@@ -927,11 +913,8 @@ static inline void mangle_address(unsigned char *begin, | |||
927 | 913 | ||
928 | /* Update UDP checksum if being used */ | 914 | /* Update UDP checksum if being used */ |
929 | if (*check) { | 915 | if (*check) { |
930 | unsigned char odd = !((addr - begin) % 2); | 916 | fast_csum(check, |
931 | 917 | &map->from, &map->to, addr - begin); | |
932 | fast_csum((unsigned char *)check, | ||
933 | &map->from, &map->to, odd); | ||
934 | |||
935 | } | 918 | } |
936 | 919 | ||
937 | if (debug) | 920 | if (debug) |
@@ -943,7 +926,7 @@ static inline void mangle_address(unsigned char *begin, | |||
943 | static unsigned char snmp_trap_decode(struct asn1_ctx *ctx, | 926 | static unsigned char snmp_trap_decode(struct asn1_ctx *ctx, |
944 | struct snmp_v1_trap *trap, | 927 | struct snmp_v1_trap *trap, |
945 | const struct oct1_map *map, | 928 | const struct oct1_map *map, |
946 | u_int16_t *check) | 929 | __sum16 *check) |
947 | { | 930 | { |
948 | unsigned int cls, con, tag, len; | 931 | unsigned int cls, con, tag, len; |
949 | unsigned char *end; | 932 | unsigned char *end; |
@@ -1037,7 +1020,7 @@ static void hex_dump(unsigned char *buf, size_t len) | |||
1037 | static int snmp_parse_mangle(unsigned char *msg, | 1020 | static int snmp_parse_mangle(unsigned char *msg, |
1038 | u_int16_t len, | 1021 | u_int16_t len, |
1039 | const struct oct1_map *map, | 1022 | const struct oct1_map *map, |
1040 | u_int16_t *check) | 1023 | __sum16 *check) |
1041 | { | 1024 | { |
1042 | unsigned char *eoc, *end; | 1025 | unsigned char *eoc, *end; |
1043 | unsigned int cls, con, tag, vers, pdutype; | 1026 | unsigned int cls, con, tag, vers, pdutype; |
@@ -1223,12 +1206,12 @@ static int snmp_translate(struct ip_conntrack *ct, | |||
1223 | */ | 1206 | */ |
1224 | if (dir == IP_CT_DIR_ORIGINAL) { | 1207 | if (dir == IP_CT_DIR_ORIGINAL) { |
1225 | /* SNAT traps */ | 1208 | /* SNAT traps */ |
1226 | map.from = NOCT1(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip); | 1209 | map.from = NOCT1(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip); |
1227 | map.to = NOCT1(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip); | 1210 | map.to = NOCT1(&ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip); |
1228 | } else { | 1211 | } else { |
1229 | /* DNAT replies */ | 1212 | /* DNAT replies */ |
1230 | map.from = NOCT1(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip); | 1213 | map.from = NOCT1(&ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip); |
1231 | map.to = NOCT1(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip); | 1214 | map.to = NOCT1(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip); |
1232 | } | 1215 | } |
1233 | 1216 | ||
1234 | if (map.from == map.to) | 1217 | if (map.from == map.to) |
@@ -1294,11 +1277,11 @@ static struct ip_conntrack_helper snmp_helper = { | |||
1294 | .help = help, | 1277 | .help = help, |
1295 | .name = "snmp", | 1278 | .name = "snmp", |
1296 | 1279 | ||
1297 | .tuple = { .src = { .u = { __constant_htons(SNMP_PORT) } }, | 1280 | .tuple = {.src = {.u = {.udp = {.port = __constant_htons(SNMP_PORT)}}}, |
1298 | .dst = { .protonum = IPPROTO_UDP }, | 1281 | .dst = {.protonum = IPPROTO_UDP}, |
1299 | }, | 1282 | }, |
1300 | .mask = { .src = { .u = { 0xFFFF } }, | 1283 | .mask = {.src = {.u = {0xFFFF}}, |
1301 | .dst = { .protonum = 0xFF }, | 1284 | .dst = {.protonum = 0xFF}, |
1302 | }, | 1285 | }, |
1303 | }; | 1286 | }; |
1304 | 1287 | ||
@@ -1309,11 +1292,11 @@ static struct ip_conntrack_helper snmp_trap_helper = { | |||
1309 | .help = help, | 1292 | .help = help, |
1310 | .name = "snmp_trap", | 1293 | .name = "snmp_trap", |
1311 | 1294 | ||
1312 | .tuple = { .src = { .u = { __constant_htons(SNMP_TRAP_PORT) } }, | 1295 | .tuple = {.src = {.u = {.udp = {.port = __constant_htons(SNMP_TRAP_PORT)}}}, |
1313 | .dst = { .protonum = IPPROTO_UDP }, | 1296 | .dst = {.protonum = IPPROTO_UDP}, |
1314 | }, | 1297 | }, |
1315 | .mask = { .src = { .u = { 0xFFFF } }, | 1298 | .mask = {.src = {.u = {0xFFFF}}, |
1316 | .dst = { .protonum = 0xFF }, | 1299 | .dst = {.protonum = 0xFF}, |
1317 | }, | 1300 | }, |
1318 | }; | 1301 | }; |
1319 | 1302 | ||
diff --git a/net/ipv4/netfilter/ip_nat_standalone.c b/net/ipv4/netfilter/ip_nat_standalone.c index d85d2de50449..ad66328baa5d 100644 --- a/net/ipv4/netfilter/ip_nat_standalone.c +++ b/net/ipv4/netfilter/ip_nat_standalone.c | |||
@@ -44,12 +44,6 @@ | |||
44 | #define DEBUGP(format, args...) | 44 | #define DEBUGP(format, args...) |
45 | #endif | 45 | #endif |
46 | 46 | ||
47 | #define HOOKNAME(hooknum) ((hooknum) == NF_IP_POST_ROUTING ? "POST_ROUTING" \ | ||
48 | : ((hooknum) == NF_IP_PRE_ROUTING ? "PRE_ROUTING" \ | ||
49 | : ((hooknum) == NF_IP_LOCAL_OUT ? "LOCAL_OUT" \ | ||
50 | : ((hooknum) == NF_IP_LOCAL_IN ? "LOCAL_IN" \ | ||
51 | : "*ERROR*"))) | ||
52 | |||
53 | #ifdef CONFIG_XFRM | 47 | #ifdef CONFIG_XFRM |
54 | static void nat_decode_session(struct sk_buff *skb, struct flowi *fl) | 48 | static void nat_decode_session(struct sk_buff *skb, struct flowi *fl) |
55 | { | 49 | { |
diff --git a/net/ipv4/netfilter/ip_nat_tftp.c b/net/ipv4/netfilter/ip_nat_tftp.c index 94a78015451c..604793536fc1 100644 --- a/net/ipv4/netfilter/ip_nat_tftp.c +++ b/net/ipv4/netfilter/ip_nat_tftp.c | |||
@@ -55,15 +55,14 @@ static unsigned int help(struct sk_buff **pskb, | |||
55 | 55 | ||
56 | static void __exit ip_nat_tftp_fini(void) | 56 | static void __exit ip_nat_tftp_fini(void) |
57 | { | 57 | { |
58 | ip_nat_tftp_hook = NULL; | 58 | rcu_assign_pointer(ip_nat_tftp_hook, NULL); |
59 | /* Make sure noone calls it, meanwhile. */ | 59 | synchronize_rcu(); |
60 | synchronize_net(); | ||
61 | } | 60 | } |
62 | 61 | ||
63 | static int __init ip_nat_tftp_init(void) | 62 | static int __init ip_nat_tftp_init(void) |
64 | { | 63 | { |
65 | BUG_ON(ip_nat_tftp_hook); | 64 | BUG_ON(rcu_dereference(ip_nat_tftp_hook)); |
66 | ip_nat_tftp_hook = help; | 65 | rcu_assign_pointer(ip_nat_tftp_hook, help); |
67 | return 0; | 66 | return 0; |
68 | } | 67 | } |
69 | 68 | ||
diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c index 97556cc2e4e0..cd520df4dcf4 100644 --- a/net/ipv4/netfilter/ip_queue.c +++ b/net/ipv4/netfilter/ip_queue.c | |||
@@ -243,7 +243,7 @@ ipq_build_packet_message(struct ipq_queue_entry *entry, int *errp) | |||
243 | pmsg->data_len = data_len; | 243 | pmsg->data_len = data_len; |
244 | pmsg->timestamp_sec = entry->skb->tstamp.off_sec; | 244 | pmsg->timestamp_sec = entry->skb->tstamp.off_sec; |
245 | pmsg->timestamp_usec = entry->skb->tstamp.off_usec; | 245 | pmsg->timestamp_usec = entry->skb->tstamp.off_usec; |
246 | pmsg->mark = entry->skb->nfmark; | 246 | pmsg->mark = entry->skb->mark; |
247 | pmsg->hook = entry->info->hook; | 247 | pmsg->hook = entry->info->hook; |
248 | pmsg->hw_protocol = entry->skb->protocol; | 248 | pmsg->hw_protocol = entry->skb->protocol; |
249 | 249 | ||
diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c index 7a29d6e7baa7..098365062234 100644 --- a/net/ipv4/netfilter/ipt_CLUSTERIP.c +++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c | |||
@@ -40,8 +40,6 @@ | |||
40 | #define DEBUGP | 40 | #define DEBUGP |
41 | #endif | 41 | #endif |
42 | 42 | ||
43 | #define ASSERT_READ_LOCK(x) | ||
44 | |||
45 | MODULE_LICENSE("GPL"); | 43 | MODULE_LICENSE("GPL"); |
46 | MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>"); | 44 | MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>"); |
47 | MODULE_DESCRIPTION("iptables target for CLUSTERIP"); | 45 | MODULE_DESCRIPTION("iptables target for CLUSTERIP"); |
@@ -123,7 +121,6 @@ __clusterip_config_find(__be32 clusterip) | |||
123 | { | 121 | { |
124 | struct list_head *pos; | 122 | struct list_head *pos; |
125 | 123 | ||
126 | ASSERT_READ_LOCK(&clusterip_lock); | ||
127 | list_for_each(pos, &clusterip_configs) { | 124 | list_for_each(pos, &clusterip_configs) { |
128 | struct clusterip_config *c = list_entry(pos, | 125 | struct clusterip_config *c = list_entry(pos, |
129 | struct clusterip_config, list); | 126 | struct clusterip_config, list); |
@@ -170,7 +167,6 @@ clusterip_config_init(struct ipt_clusterip_tgt_info *i, __be32 ip, | |||
170 | struct net_device *dev) | 167 | struct net_device *dev) |
171 | { | 168 | { |
172 | struct clusterip_config *c; | 169 | struct clusterip_config *c; |
173 | char buffer[16]; | ||
174 | 170 | ||
175 | c = kzalloc(sizeof(*c), GFP_ATOMIC); | 171 | c = kzalloc(sizeof(*c), GFP_ATOMIC); |
176 | if (!c) | 172 | if (!c) |
@@ -187,12 +183,17 @@ clusterip_config_init(struct ipt_clusterip_tgt_info *i, __be32 ip, | |||
187 | atomic_set(&c->entries, 1); | 183 | atomic_set(&c->entries, 1); |
188 | 184 | ||
189 | #ifdef CONFIG_PROC_FS | 185 | #ifdef CONFIG_PROC_FS |
190 | /* create proc dir entry */ | 186 | { |
191 | sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(ip)); | 187 | char buffer[16]; |
192 | c->pde = create_proc_entry(buffer, S_IWUSR|S_IRUSR, clusterip_procdir); | 188 | |
193 | if (!c->pde) { | 189 | /* create proc dir entry */ |
194 | kfree(c); | 190 | sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(ip)); |
195 | return NULL; | 191 | c->pde = create_proc_entry(buffer, S_IWUSR|S_IRUSR, |
192 | clusterip_procdir); | ||
193 | if (!c->pde) { | ||
194 | kfree(c); | ||
195 | return NULL; | ||
196 | } | ||
196 | } | 197 | } |
197 | c->pde->proc_fops = &clusterip_proc_fops; | 198 | c->pde->proc_fops = &clusterip_proc_fops; |
198 | c->pde->data = c; | 199 | c->pde->data = c; |
@@ -205,6 +206,7 @@ clusterip_config_init(struct ipt_clusterip_tgt_info *i, __be32 ip, | |||
205 | return c; | 206 | return c; |
206 | } | 207 | } |
207 | 208 | ||
209 | #ifdef CONFIG_PROC_FS | ||
208 | static int | 210 | static int |
209 | clusterip_add_node(struct clusterip_config *c, u_int16_t nodenum) | 211 | clusterip_add_node(struct clusterip_config *c, u_int16_t nodenum) |
210 | { | 212 | { |
@@ -232,6 +234,7 @@ clusterip_del_node(struct clusterip_config *c, u_int16_t nodenum) | |||
232 | 234 | ||
233 | return 1; | 235 | return 1; |
234 | } | 236 | } |
237 | #endif | ||
235 | 238 | ||
236 | static inline u_int32_t | 239 | static inline u_int32_t |
237 | clusterip_hashfn(struct sk_buff *skb, struct clusterip_config *config) | 240 | clusterip_hashfn(struct sk_buff *skb, struct clusterip_config *config) |
@@ -737,8 +740,10 @@ static int __init ipt_clusterip_init(void) | |||
737 | CLUSTERIP_VERSION); | 740 | CLUSTERIP_VERSION); |
738 | return 0; | 741 | return 0; |
739 | 742 | ||
743 | #ifdef CONFIG_PROC_FS | ||
740 | cleanup_hook: | 744 | cleanup_hook: |
741 | nf_unregister_hook(&cip_arp_ops); | 745 | nf_unregister_hook(&cip_arp_ops); |
746 | #endif /* CONFIG_PROC_FS */ | ||
742 | cleanup_target: | 747 | cleanup_target: |
743 | ipt_unregister_target(&clusterip_tgt); | 748 | ipt_unregister_target(&clusterip_tgt); |
744 | return ret; | 749 | return ret; |
diff --git a/net/ipv4/netfilter/ipt_ECN.c b/net/ipv4/netfilter/ipt_ECN.c index 1aa4517fbcdb..b55d670a24df 100644 --- a/net/ipv4/netfilter/ipt_ECN.c +++ b/net/ipv4/netfilter/ipt_ECN.c | |||
@@ -28,17 +28,16 @@ static inline int | |||
28 | set_ect_ip(struct sk_buff **pskb, const struct ipt_ECN_info *einfo) | 28 | set_ect_ip(struct sk_buff **pskb, const struct ipt_ECN_info *einfo) |
29 | { | 29 | { |
30 | struct iphdr *iph = (*pskb)->nh.iph; | 30 | struct iphdr *iph = (*pskb)->nh.iph; |
31 | u_int16_t oldtos; | ||
32 | 31 | ||
33 | if ((iph->tos & IPT_ECN_IP_MASK) != (einfo->ip_ect & IPT_ECN_IP_MASK)) { | 32 | if ((iph->tos & IPT_ECN_IP_MASK) != (einfo->ip_ect & IPT_ECN_IP_MASK)) { |
33 | __u8 oldtos; | ||
34 | if (!skb_make_writable(pskb, sizeof(struct iphdr))) | 34 | if (!skb_make_writable(pskb, sizeof(struct iphdr))) |
35 | return 0; | 35 | return 0; |
36 | iph = (*pskb)->nh.iph; | 36 | iph = (*pskb)->nh.iph; |
37 | oldtos = iph->tos; | 37 | oldtos = iph->tos; |
38 | iph->tos &= ~IPT_ECN_IP_MASK; | 38 | iph->tos &= ~IPT_ECN_IP_MASK; |
39 | iph->tos |= (einfo->ip_ect & IPT_ECN_IP_MASK); | 39 | iph->tos |= (einfo->ip_ect & IPT_ECN_IP_MASK); |
40 | iph->check = nf_csum_update(htons(oldtos) ^ htons(0xFFFF), | 40 | nf_csum_replace2(&iph->check, htons(oldtos), htons(iph->tos)); |
41 | htons(iph->tos), iph->check); | ||
42 | } | 41 | } |
43 | return 1; | 42 | return 1; |
44 | } | 43 | } |
@@ -72,10 +71,8 @@ set_ect_tcp(struct sk_buff **pskb, const struct ipt_ECN_info *einfo) | |||
72 | if (einfo->operation & IPT_ECN_OP_SET_CWR) | 71 | if (einfo->operation & IPT_ECN_OP_SET_CWR) |
73 | tcph->cwr = einfo->proto.tcp.cwr; | 72 | tcph->cwr = einfo->proto.tcp.cwr; |
74 | 73 | ||
75 | tcph->check = nf_proto_csum_update((*pskb), | 74 | nf_proto_csum_replace2(&tcph->check, *pskb, |
76 | oldval ^ htons(0xFFFF), | 75 | oldval, ((__be16 *)tcph)[6], 0); |
77 | ((__be16 *)tcph)[6], | ||
78 | tcph->check, 0); | ||
79 | return 1; | 76 | return 1; |
80 | } | 77 | } |
81 | 78 | ||
diff --git a/net/ipv4/netfilter/ipt_LOG.c b/net/ipv4/netfilter/ipt_LOG.c index 7dc820df8bc5..c96de16fefae 100644 --- a/net/ipv4/netfilter/ipt_LOG.c +++ b/net/ipv4/netfilter/ipt_LOG.c | |||
@@ -171,11 +171,15 @@ static void dump_packet(const struct nf_loginfo *info, | |||
171 | } | 171 | } |
172 | break; | 172 | break; |
173 | } | 173 | } |
174 | case IPPROTO_UDP: { | 174 | case IPPROTO_UDP: |
175 | case IPPROTO_UDPLITE: { | ||
175 | struct udphdr _udph, *uh; | 176 | struct udphdr _udph, *uh; |
176 | 177 | ||
177 | /* Max length: 10 "PROTO=UDP " */ | 178 | if (ih->protocol == IPPROTO_UDP) |
178 | printk("PROTO=UDP "); | 179 | /* Max length: 10 "PROTO=UDP " */ |
180 | printk("PROTO=UDP " ); | ||
181 | else /* Max length: 14 "PROTO=UDPLITE " */ | ||
182 | printk("PROTO=UDPLITE "); | ||
179 | 183 | ||
180 | if (ntohs(ih->frag_off) & IP_OFFSET) | 184 | if (ntohs(ih->frag_off) & IP_OFFSET) |
181 | break; | 185 | break; |
@@ -341,6 +345,7 @@ static void dump_packet(const struct nf_loginfo *info, | |||
341 | /* IP: 40+46+6+11+127 = 230 */ | 345 | /* IP: 40+46+6+11+127 = 230 */ |
342 | /* TCP: 10+max(25,20+30+13+9+32+11+127) = 252 */ | 346 | /* TCP: 10+max(25,20+30+13+9+32+11+127) = 252 */ |
343 | /* UDP: 10+max(25,20) = 35 */ | 347 | /* UDP: 10+max(25,20) = 35 */ |
348 | /* UDPLITE: 14+max(25,20) = 39 */ | ||
344 | /* ICMP: 11+max(25, 18+25+max(19,14,24+3+n+10,3+n+10)) = 91+n */ | 349 | /* ICMP: 11+max(25, 18+25+max(19,14,24+3+n+10,3+n+10)) = 91+n */ |
345 | /* ESP: 10+max(25)+15 = 50 */ | 350 | /* ESP: 10+max(25)+15 = 50 */ |
346 | /* AH: 9+max(25)+15 = 49 */ | 351 | /* AH: 9+max(25)+15 = 49 */ |
@@ -425,13 +430,8 @@ ipt_log_target(struct sk_buff **pskb, | |||
425 | li.u.log.level = loginfo->level; | 430 | li.u.log.level = loginfo->level; |
426 | li.u.log.logflags = loginfo->logflags; | 431 | li.u.log.logflags = loginfo->logflags; |
427 | 432 | ||
428 | if (loginfo->logflags & IPT_LOG_NFLOG) | 433 | ipt_log_packet(PF_INET, hooknum, *pskb, in, out, &li, |
429 | nf_log_packet(PF_INET, hooknum, *pskb, in, out, &li, | 434 | loginfo->prefix); |
430 | "%s", loginfo->prefix); | ||
431 | else | ||
432 | ipt_log_packet(PF_INET, hooknum, *pskb, in, out, &li, | ||
433 | loginfo->prefix); | ||
434 | |||
435 | return IPT_CONTINUE; | 435 | return IPT_CONTINUE; |
436 | } | 436 | } |
437 | 437 | ||
diff --git a/net/ipv4/netfilter/ipt_MASQUERADE.c b/net/ipv4/netfilter/ipt_MASQUERADE.c index 3dbfcfac8a84..28b9233956b5 100644 --- a/net/ipv4/netfilter/ipt_MASQUERADE.c +++ b/net/ipv4/netfilter/ipt_MASQUERADE.c | |||
@@ -2,7 +2,7 @@ | |||
2 | (depending on route). */ | 2 | (depending on route). */ |
3 | 3 | ||
4 | /* (C) 1999-2001 Paul `Rusty' Russell | 4 | /* (C) 1999-2001 Paul `Rusty' Russell |
5 | * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> | 5 | * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License version 2 as | 8 | * it under the terms of the GNU General Public License version 2 as |
@@ -20,7 +20,11 @@ | |||
20 | #include <net/checksum.h> | 20 | #include <net/checksum.h> |
21 | #include <net/route.h> | 21 | #include <net/route.h> |
22 | #include <linux/netfilter_ipv4.h> | 22 | #include <linux/netfilter_ipv4.h> |
23 | #ifdef CONFIG_NF_NAT_NEEDED | ||
24 | #include <net/netfilter/nf_nat_rule.h> | ||
25 | #else | ||
23 | #include <linux/netfilter_ipv4/ip_nat_rule.h> | 26 | #include <linux/netfilter_ipv4/ip_nat_rule.h> |
27 | #endif | ||
24 | #include <linux/netfilter_ipv4/ip_tables.h> | 28 | #include <linux/netfilter_ipv4/ip_tables.h> |
25 | 29 | ||
26 | MODULE_LICENSE("GPL"); | 30 | MODULE_LICENSE("GPL"); |
@@ -65,23 +69,33 @@ masquerade_target(struct sk_buff **pskb, | |||
65 | const struct xt_target *target, | 69 | const struct xt_target *target, |
66 | const void *targinfo) | 70 | const void *targinfo) |
67 | { | 71 | { |
72 | #ifdef CONFIG_NF_NAT_NEEDED | ||
73 | struct nf_conn_nat *nat; | ||
74 | #endif | ||
68 | struct ip_conntrack *ct; | 75 | struct ip_conntrack *ct; |
69 | enum ip_conntrack_info ctinfo; | 76 | enum ip_conntrack_info ctinfo; |
70 | const struct ip_nat_multi_range_compat *mr; | ||
71 | struct ip_nat_range newrange; | 77 | struct ip_nat_range newrange; |
78 | const struct ip_nat_multi_range_compat *mr; | ||
72 | struct rtable *rt; | 79 | struct rtable *rt; |
73 | __be32 newsrc; | 80 | __be32 newsrc; |
74 | 81 | ||
75 | IP_NF_ASSERT(hooknum == NF_IP_POST_ROUTING); | 82 | IP_NF_ASSERT(hooknum == NF_IP_POST_ROUTING); |
76 | 83 | ||
77 | ct = ip_conntrack_get(*pskb, &ctinfo); | 84 | ct = ip_conntrack_get(*pskb, &ctinfo); |
85 | #ifdef CONFIG_NF_NAT_NEEDED | ||
86 | nat = nfct_nat(ct); | ||
87 | #endif | ||
78 | IP_NF_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED | 88 | IP_NF_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED |
79 | || ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY)); | 89 | || ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY)); |
80 | 90 | ||
81 | /* Source address is 0.0.0.0 - locally generated packet that is | 91 | /* Source address is 0.0.0.0 - locally generated packet that is |
82 | * probably not supposed to be masqueraded. | 92 | * probably not supposed to be masqueraded. |
83 | */ | 93 | */ |
94 | #ifdef CONFIG_NF_NAT_NEEDED | ||
95 | if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip == 0) | ||
96 | #else | ||
84 | if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip == 0) | 97 | if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip == 0) |
98 | #endif | ||
85 | return NF_ACCEPT; | 99 | return NF_ACCEPT; |
86 | 100 | ||
87 | mr = targinfo; | 101 | mr = targinfo; |
@@ -93,7 +107,11 @@ masquerade_target(struct sk_buff **pskb, | |||
93 | } | 107 | } |
94 | 108 | ||
95 | write_lock_bh(&masq_lock); | 109 | write_lock_bh(&masq_lock); |
110 | #ifdef CONFIG_NF_NAT_NEEDED | ||
111 | nat->masq_index = out->ifindex; | ||
112 | #else | ||
96 | ct->nat.masq_index = out->ifindex; | 113 | ct->nat.masq_index = out->ifindex; |
114 | #endif | ||
97 | write_unlock_bh(&masq_lock); | 115 | write_unlock_bh(&masq_lock); |
98 | 116 | ||
99 | /* Transfer from original range. */ | 117 | /* Transfer from original range. */ |
@@ -109,10 +127,17 @@ masquerade_target(struct sk_buff **pskb, | |||
109 | static inline int | 127 | static inline int |
110 | device_cmp(struct ip_conntrack *i, void *ifindex) | 128 | device_cmp(struct ip_conntrack *i, void *ifindex) |
111 | { | 129 | { |
130 | #ifdef CONFIG_NF_NAT_NEEDED | ||
131 | struct nf_conn_nat *nat = nfct_nat(i); | ||
132 | #endif | ||
112 | int ret; | 133 | int ret; |
113 | 134 | ||
114 | read_lock_bh(&masq_lock); | 135 | read_lock_bh(&masq_lock); |
136 | #ifdef CONFIG_NF_NAT_NEEDED | ||
137 | ret = (nat->masq_index == (int)(long)ifindex); | ||
138 | #else | ||
115 | ret = (i->nat.masq_index == (int)(long)ifindex); | 139 | ret = (i->nat.masq_index == (int)(long)ifindex); |
140 | #endif | ||
116 | read_unlock_bh(&masq_lock); | 141 | read_unlock_bh(&masq_lock); |
117 | 142 | ||
118 | return ret; | 143 | return ret; |
diff --git a/net/ipv4/netfilter/ipt_NETMAP.c b/net/ipv4/netfilter/ipt_NETMAP.c index 58a88f227108..9390e90f2b25 100644 --- a/net/ipv4/netfilter/ipt_NETMAP.c +++ b/net/ipv4/netfilter/ipt_NETMAP.c | |||
@@ -15,7 +15,11 @@ | |||
15 | #include <linux/netdevice.h> | 15 | #include <linux/netdevice.h> |
16 | #include <linux/netfilter.h> | 16 | #include <linux/netfilter.h> |
17 | #include <linux/netfilter_ipv4.h> | 17 | #include <linux/netfilter_ipv4.h> |
18 | #ifdef CONFIG_NF_NAT_NEEDED | ||
19 | #include <net/netfilter/nf_nat_rule.h> | ||
20 | #else | ||
18 | #include <linux/netfilter_ipv4/ip_nat_rule.h> | 21 | #include <linux/netfilter_ipv4/ip_nat_rule.h> |
22 | #endif | ||
19 | 23 | ||
20 | #define MODULENAME "NETMAP" | 24 | #define MODULENAME "NETMAP" |
21 | MODULE_LICENSE("GPL"); | 25 | MODULE_LICENSE("GPL"); |
diff --git a/net/ipv4/netfilter/ipt_REDIRECT.c b/net/ipv4/netfilter/ipt_REDIRECT.c index c0dcfe9d610c..462eceb3a1b1 100644 --- a/net/ipv4/netfilter/ipt_REDIRECT.c +++ b/net/ipv4/netfilter/ipt_REDIRECT.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* Redirect. Simple mapping which alters dst to a local IP address. */ | 1 | /* Redirect. Simple mapping which alters dst to a local IP address. */ |
2 | /* (C) 1999-2001 Paul `Rusty' Russell | 2 | /* (C) 1999-2001 Paul `Rusty' Russell |
3 | * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> | 3 | * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org> |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify | 5 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License version 2 as | 6 | * it under the terms of the GNU General Public License version 2 as |
@@ -18,7 +18,11 @@ | |||
18 | #include <net/protocol.h> | 18 | #include <net/protocol.h> |
19 | #include <net/checksum.h> | 19 | #include <net/checksum.h> |
20 | #include <linux/netfilter_ipv4.h> | 20 | #include <linux/netfilter_ipv4.h> |
21 | #ifdef CONFIG_NF_NAT_NEEDED | ||
22 | #include <net/netfilter/nf_nat_rule.h> | ||
23 | #else | ||
21 | #include <linux/netfilter_ipv4/ip_nat_rule.h> | 24 | #include <linux/netfilter_ipv4/ip_nat_rule.h> |
25 | #endif | ||
22 | 26 | ||
23 | MODULE_LICENSE("GPL"); | 27 | MODULE_LICENSE("GPL"); |
24 | MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>"); | 28 | MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>"); |
diff --git a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c index ad0312d0e4fd..f0319e5ee437 100644 --- a/net/ipv4/netfilter/ipt_REJECT.c +++ b/net/ipv4/netfilter/ipt_REJECT.c | |||
@@ -76,7 +76,7 @@ static void send_reset(struct sk_buff *oldskb, int hook) | |||
76 | 76 | ||
77 | /* This packet will not be the same as the other: clear nf fields */ | 77 | /* This packet will not be the same as the other: clear nf fields */ |
78 | nf_reset(nskb); | 78 | nf_reset(nskb); |
79 | nskb->nfmark = 0; | 79 | nskb->mark = 0; |
80 | skb_init_secmark(nskb); | 80 | skb_init_secmark(nskb); |
81 | 81 | ||
82 | tcph = (struct tcphdr *)((u_int32_t*)nskb->nh.iph + nskb->nh.iph->ihl); | 82 | tcph = (struct tcphdr *)((u_int32_t*)nskb->nh.iph + nskb->nh.iph->ihl); |
@@ -114,6 +114,14 @@ static void send_reset(struct sk_buff *oldskb, int hook) | |||
114 | tcph->window = 0; | 114 | tcph->window = 0; |
115 | tcph->urg_ptr = 0; | 115 | tcph->urg_ptr = 0; |
116 | 116 | ||
117 | /* Adjust TCP checksum */ | ||
118 | tcph->check = 0; | ||
119 | tcph->check = tcp_v4_check(tcph, sizeof(struct tcphdr), | ||
120 | nskb->nh.iph->saddr, | ||
121 | nskb->nh.iph->daddr, | ||
122 | csum_partial((char *)tcph, | ||
123 | sizeof(struct tcphdr), 0)); | ||
124 | |||
117 | /* Set DF, id = 0 */ | 125 | /* Set DF, id = 0 */ |
118 | nskb->nh.iph->frag_off = htons(IP_DF); | 126 | nskb->nh.iph->frag_off = htons(IP_DF); |
119 | nskb->nh.iph->id = 0; | 127 | nskb->nh.iph->id = 0; |
@@ -129,14 +137,8 @@ static void send_reset(struct sk_buff *oldskb, int hook) | |||
129 | if (ip_route_me_harder(&nskb, addr_type)) | 137 | if (ip_route_me_harder(&nskb, addr_type)) |
130 | goto free_nskb; | 138 | goto free_nskb; |
131 | 139 | ||
132 | /* Adjust TCP checksum */ | ||
133 | nskb->ip_summed = CHECKSUM_NONE; | 140 | nskb->ip_summed = CHECKSUM_NONE; |
134 | tcph->check = 0; | 141 | |
135 | tcph->check = tcp_v4_check(tcph, sizeof(struct tcphdr), | ||
136 | nskb->nh.iph->saddr, | ||
137 | nskb->nh.iph->daddr, | ||
138 | csum_partial((char *)tcph, | ||
139 | sizeof(struct tcphdr), 0)); | ||
140 | /* Adjust IP TTL */ | 142 | /* Adjust IP TTL */ |
141 | nskb->nh.iph->ttl = dst_metric(nskb->dst, RTAX_HOPLIMIT); | 143 | nskb->nh.iph->ttl = dst_metric(nskb->dst, RTAX_HOPLIMIT); |
142 | 144 | ||
diff --git a/net/ipv4/netfilter/ipt_SAME.c b/net/ipv4/netfilter/ipt_SAME.c index b38b13328d73..3dcf29411337 100644 --- a/net/ipv4/netfilter/ipt_SAME.c +++ b/net/ipv4/netfilter/ipt_SAME.c | |||
@@ -34,7 +34,11 @@ | |||
34 | #include <net/protocol.h> | 34 | #include <net/protocol.h> |
35 | #include <net/checksum.h> | 35 | #include <net/checksum.h> |
36 | #include <linux/netfilter_ipv4.h> | 36 | #include <linux/netfilter_ipv4.h> |
37 | #ifdef CONFIG_NF_NAT_NEEDED | ||
38 | #include <net/netfilter/nf_nat_rule.h> | ||
39 | #else | ||
37 | #include <linux/netfilter_ipv4/ip_nat_rule.h> | 40 | #include <linux/netfilter_ipv4/ip_nat_rule.h> |
41 | #endif | ||
38 | #include <linux/netfilter_ipv4/ipt_SAME.h> | 42 | #include <linux/netfilter_ipv4/ipt_SAME.h> |
39 | 43 | ||
40 | MODULE_LICENSE("GPL"); | 44 | MODULE_LICENSE("GPL"); |
@@ -152,11 +156,17 @@ same_target(struct sk_buff **pskb, | |||
152 | Here we calculate the index in same->iparray which | 156 | Here we calculate the index in same->iparray which |
153 | holds the ipaddress we should use */ | 157 | holds the ipaddress we should use */ |
154 | 158 | ||
159 | #ifdef CONFIG_NF_NAT_NEEDED | ||
160 | tmpip = ntohl(t->src.u3.ip); | ||
161 | |||
162 | if (!(same->info & IPT_SAME_NODST)) | ||
163 | tmpip += ntohl(t->dst.u3.ip); | ||
164 | #else | ||
155 | tmpip = ntohl(t->src.ip); | 165 | tmpip = ntohl(t->src.ip); |
156 | 166 | ||
157 | if (!(same->info & IPT_SAME_NODST)) | 167 | if (!(same->info & IPT_SAME_NODST)) |
158 | tmpip += ntohl(t->dst.ip); | 168 | tmpip += ntohl(t->dst.ip); |
159 | 169 | #endif | |
160 | aindex = tmpip % same->ipnum; | 170 | aindex = tmpip % same->ipnum; |
161 | 171 | ||
162 | new_ip = htonl(same->iparray[aindex]); | 172 | new_ip = htonl(same->iparray[aindex]); |
diff --git a/net/ipv4/netfilter/ipt_TCPMSS.c b/net/ipv4/netfilter/ipt_TCPMSS.c index 108b6b76311f..93eb5c3c1884 100644 --- a/net/ipv4/netfilter/ipt_TCPMSS.c +++ b/net/ipv4/netfilter/ipt_TCPMSS.c | |||
@@ -97,10 +97,8 @@ ipt_tcpmss_target(struct sk_buff **pskb, | |||
97 | opt[i+2] = (newmss & 0xff00) >> 8; | 97 | opt[i+2] = (newmss & 0xff00) >> 8; |
98 | opt[i+3] = (newmss & 0x00ff); | 98 | opt[i+3] = (newmss & 0x00ff); |
99 | 99 | ||
100 | tcph->check = nf_proto_csum_update(*pskb, | 100 | nf_proto_csum_replace2(&tcph->check, *pskb, |
101 | htons(oldmss)^htons(0xFFFF), | 101 | htons(oldmss), htons(newmss), 0); |
102 | htons(newmss), | ||
103 | tcph->check, 0); | ||
104 | return IPT_CONTINUE; | 102 | return IPT_CONTINUE; |
105 | } | 103 | } |
106 | } | 104 | } |
@@ -126,28 +124,22 @@ ipt_tcpmss_target(struct sk_buff **pskb, | |||
126 | opt = (u_int8_t *)tcph + sizeof(struct tcphdr); | 124 | opt = (u_int8_t *)tcph + sizeof(struct tcphdr); |
127 | memmove(opt + TCPOLEN_MSS, opt, tcplen - sizeof(struct tcphdr)); | 125 | memmove(opt + TCPOLEN_MSS, opt, tcplen - sizeof(struct tcphdr)); |
128 | 126 | ||
129 | tcph->check = nf_proto_csum_update(*pskb, | 127 | nf_proto_csum_replace2(&tcph->check, *pskb, |
130 | htons(tcplen) ^ htons(0xFFFF), | 128 | htons(tcplen), htons(tcplen + TCPOLEN_MSS), 1); |
131 | htons(tcplen + TCPOLEN_MSS), | ||
132 | tcph->check, 1); | ||
133 | opt[0] = TCPOPT_MSS; | 129 | opt[0] = TCPOPT_MSS; |
134 | opt[1] = TCPOLEN_MSS; | 130 | opt[1] = TCPOLEN_MSS; |
135 | opt[2] = (newmss & 0xff00) >> 8; | 131 | opt[2] = (newmss & 0xff00) >> 8; |
136 | opt[3] = (newmss & 0x00ff); | 132 | opt[3] = (newmss & 0x00ff); |
137 | 133 | ||
138 | tcph->check = nf_proto_csum_update(*pskb, htonl(~0), *((__be32 *)opt), | 134 | nf_proto_csum_replace4(&tcph->check, *pskb, 0, *((__be32 *)opt), 0); |
139 | tcph->check, 0); | ||
140 | 135 | ||
141 | oldval = ((__be16 *)tcph)[6]; | 136 | oldval = ((__be16 *)tcph)[6]; |
142 | tcph->doff += TCPOLEN_MSS/4; | 137 | tcph->doff += TCPOLEN_MSS/4; |
143 | tcph->check = nf_proto_csum_update(*pskb, | 138 | nf_proto_csum_replace2(&tcph->check, *pskb, |
144 | oldval ^ htons(0xFFFF), | 139 | oldval, ((__be16 *)tcph)[6], 0); |
145 | ((__be16 *)tcph)[6], | ||
146 | tcph->check, 0); | ||
147 | 140 | ||
148 | newtotlen = htons(ntohs(iph->tot_len) + TCPOLEN_MSS); | 141 | newtotlen = htons(ntohs(iph->tot_len) + TCPOLEN_MSS); |
149 | iph->check = nf_csum_update(iph->tot_len ^ htons(0xFFFF), | 142 | nf_csum_replace2(&iph->check, iph->tot_len, newtotlen); |
150 | newtotlen, iph->check); | ||
151 | iph->tot_len = newtotlen; | 143 | iph->tot_len = newtotlen; |
152 | return IPT_CONTINUE; | 144 | return IPT_CONTINUE; |
153 | } | 145 | } |
diff --git a/net/ipv4/netfilter/ipt_TOS.c b/net/ipv4/netfilter/ipt_TOS.c index 83b80b3a5d2f..18e74ac4d425 100644 --- a/net/ipv4/netfilter/ipt_TOS.c +++ b/net/ipv4/netfilter/ipt_TOS.c | |||
@@ -30,16 +30,15 @@ target(struct sk_buff **pskb, | |||
30 | { | 30 | { |
31 | const struct ipt_tos_target_info *tosinfo = targinfo; | 31 | const struct ipt_tos_target_info *tosinfo = targinfo; |
32 | struct iphdr *iph = (*pskb)->nh.iph; | 32 | struct iphdr *iph = (*pskb)->nh.iph; |
33 | u_int16_t oldtos; | ||
34 | 33 | ||
35 | if ((iph->tos & IPTOS_TOS_MASK) != tosinfo->tos) { | 34 | if ((iph->tos & IPTOS_TOS_MASK) != tosinfo->tos) { |
35 | __u8 oldtos; | ||
36 | if (!skb_make_writable(pskb, sizeof(struct iphdr))) | 36 | if (!skb_make_writable(pskb, sizeof(struct iphdr))) |
37 | return NF_DROP; | 37 | return NF_DROP; |
38 | iph = (*pskb)->nh.iph; | 38 | iph = (*pskb)->nh.iph; |
39 | oldtos = iph->tos; | 39 | oldtos = iph->tos; |
40 | iph->tos = (iph->tos & IPTOS_PREC_MASK) | tosinfo->tos; | 40 | iph->tos = (iph->tos & IPTOS_PREC_MASK) | tosinfo->tos; |
41 | iph->check = nf_csum_update(htons(oldtos) ^ htons(0xFFFF), | 41 | nf_csum_replace2(&iph->check, htons(oldtos), htons(iph->tos)); |
42 | htons(iph->tos), iph->check); | ||
43 | } | 42 | } |
44 | return IPT_CONTINUE; | 43 | return IPT_CONTINUE; |
45 | } | 44 | } |
diff --git a/net/ipv4/netfilter/ipt_TTL.c b/net/ipv4/netfilter/ipt_TTL.c index ac9517d62af0..fffe5ca82e91 100644 --- a/net/ipv4/netfilter/ipt_TTL.c +++ b/net/ipv4/netfilter/ipt_TTL.c | |||
@@ -54,9 +54,8 @@ ipt_ttl_target(struct sk_buff **pskb, | |||
54 | } | 54 | } |
55 | 55 | ||
56 | if (new_ttl != iph->ttl) { | 56 | if (new_ttl != iph->ttl) { |
57 | iph->check = nf_csum_update(htons((iph->ttl << 8)) ^ htons(0xFFFF), | 57 | nf_csum_replace2(&iph->check, htons(iph->ttl << 8), |
58 | htons(new_ttl << 8), | 58 | htons(new_ttl << 8)); |
59 | iph->check); | ||
60 | iph->ttl = new_ttl; | 59 | iph->ttl = new_ttl; |
61 | } | 60 | } |
62 | 61 | ||
diff --git a/net/ipv4/netfilter/ipt_ULOG.c b/net/ipv4/netfilter/ipt_ULOG.c index 2b104ea54f48..dbd34783a64d 100644 --- a/net/ipv4/netfilter/ipt_ULOG.c +++ b/net/ipv4/netfilter/ipt_ULOG.c | |||
@@ -239,7 +239,7 @@ static void ipt_ulog_packet(unsigned int hooknum, | |||
239 | pm->data_len = copy_len; | 239 | pm->data_len = copy_len; |
240 | pm->timestamp_sec = skb->tstamp.off_sec; | 240 | pm->timestamp_sec = skb->tstamp.off_sec; |
241 | pm->timestamp_usec = skb->tstamp.off_usec; | 241 | pm->timestamp_usec = skb->tstamp.off_usec; |
242 | pm->mark = skb->nfmark; | 242 | pm->mark = skb->mark; |
243 | pm->hook = hooknum; | 243 | pm->hook = hooknum; |
244 | if (prefix != NULL) | 244 | if (prefix != NULL) |
245 | strncpy(pm->prefix, prefix, sizeof(pm->prefix)); | 245 | strncpy(pm->prefix, prefix, sizeof(pm->prefix)); |
diff --git a/net/ipv4/netfilter/ipt_hashlimit.c b/net/ipv4/netfilter/ipt_hashlimit.c deleted file mode 100644 index 33ccdbf8e794..000000000000 --- a/net/ipv4/netfilter/ipt_hashlimit.c +++ /dev/null | |||
@@ -1,733 +0,0 @@ | |||
1 | /* iptables match extension to limit the number of packets per second | ||
2 | * seperately for each hashbucket (sourceip/sourceport/dstip/dstport) | ||
3 | * | ||
4 | * (C) 2003-2004 by Harald Welte <laforge@netfilter.org> | ||
5 | * | ||
6 | * $Id: ipt_hashlimit.c 3244 2004-10-20 16:24:29Z laforge@netfilter.org $ | ||
7 | * | ||
8 | * Development of this code was funded by Astaro AG, http://www.astaro.com/ | ||
9 | * | ||
10 | * based on ipt_limit.c by: | ||
11 | * Jérôme de Vivie <devivie@info.enserb.u-bordeaux.fr> | ||
12 | * Hervé Eychenne <eychenne@info.enserb.u-bordeaux.fr> | ||
13 | * Rusty Russell <rusty@rustcorp.com.au> | ||
14 | * | ||
15 | * The general idea is to create a hash table for every dstip and have a | ||
16 | * seperate limit counter per tuple. This way you can do something like 'limit | ||
17 | * the number of syn packets for each of my internal addresses. | ||
18 | * | ||
19 | * Ideally this would just be implemented as a general 'hash' match, which would | ||
20 | * allow us to attach any iptables target to it's hash buckets. But this is | ||
21 | * not possible in the current iptables architecture. As always, pkttables for | ||
22 | * 2.7.x will help ;) | ||
23 | */ | ||
24 | #include <linux/module.h> | ||
25 | #include <linux/skbuff.h> | ||
26 | #include <linux/spinlock.h> | ||
27 | #include <linux/random.h> | ||
28 | #include <linux/jhash.h> | ||
29 | #include <linux/slab.h> | ||
30 | #include <linux/vmalloc.h> | ||
31 | #include <linux/proc_fs.h> | ||
32 | #include <linux/seq_file.h> | ||
33 | #include <linux/list.h> | ||
34 | |||
35 | #include <linux/netfilter_ipv4/ip_tables.h> | ||
36 | #include <linux/netfilter_ipv4/ipt_hashlimit.h> | ||
37 | |||
38 | /* FIXME: this is just for IP_NF_ASSERRT */ | ||
39 | #include <linux/netfilter_ipv4/ip_conntrack.h> | ||
40 | #include <linux/mutex.h> | ||
41 | |||
42 | MODULE_LICENSE("GPL"); | ||
43 | MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>"); | ||
44 | MODULE_DESCRIPTION("iptables match for limiting per hash-bucket"); | ||
45 | |||
46 | /* need to declare this at the top */ | ||
47 | static struct proc_dir_entry *hashlimit_procdir; | ||
48 | static struct file_operations dl_file_ops; | ||
49 | |||
50 | /* hash table crap */ | ||
51 | |||
52 | struct dsthash_dst { | ||
53 | __be32 src_ip; | ||
54 | __be32 dst_ip; | ||
55 | /* ports have to be consecutive !!! */ | ||
56 | __be16 src_port; | ||
57 | __be16 dst_port; | ||
58 | }; | ||
59 | |||
60 | struct dsthash_ent { | ||
61 | /* static / read-only parts in the beginning */ | ||
62 | struct hlist_node node; | ||
63 | struct dsthash_dst dst; | ||
64 | |||
65 | /* modified structure members in the end */ | ||
66 | unsigned long expires; /* precalculated expiry time */ | ||
67 | struct { | ||
68 | unsigned long prev; /* last modification */ | ||
69 | u_int32_t credit; | ||
70 | u_int32_t credit_cap, cost; | ||
71 | } rateinfo; | ||
72 | }; | ||
73 | |||
74 | struct ipt_hashlimit_htable { | ||
75 | struct hlist_node node; /* global list of all htables */ | ||
76 | atomic_t use; | ||
77 | |||
78 | struct hashlimit_cfg cfg; /* config */ | ||
79 | |||
80 | /* used internally */ | ||
81 | spinlock_t lock; /* lock for list_head */ | ||
82 | u_int32_t rnd; /* random seed for hash */ | ||
83 | int rnd_initialized; | ||
84 | struct timer_list timer; /* timer for gc */ | ||
85 | atomic_t count; /* number entries in table */ | ||
86 | |||
87 | /* seq_file stuff */ | ||
88 | struct proc_dir_entry *pde; | ||
89 | |||
90 | struct hlist_head hash[0]; /* hashtable itself */ | ||
91 | }; | ||
92 | |||
93 | static DEFINE_SPINLOCK(hashlimit_lock); /* protects htables list */ | ||
94 | static DEFINE_MUTEX(hlimit_mutex); /* additional checkentry protection */ | ||
95 | static HLIST_HEAD(hashlimit_htables); | ||
96 | static kmem_cache_t *hashlimit_cachep __read_mostly; | ||
97 | |||
98 | static inline int dst_cmp(const struct dsthash_ent *ent, struct dsthash_dst *b) | ||
99 | { | ||
100 | return (ent->dst.dst_ip == b->dst_ip | ||
101 | && ent->dst.dst_port == b->dst_port | ||
102 | && ent->dst.src_port == b->src_port | ||
103 | && ent->dst.src_ip == b->src_ip); | ||
104 | } | ||
105 | |||
106 | static inline u_int32_t | ||
107 | hash_dst(const struct ipt_hashlimit_htable *ht, const struct dsthash_dst *dst) | ||
108 | { | ||
109 | return (jhash_3words((__force u32)dst->dst_ip, | ||
110 | ((__force u32)dst->dst_port<<16 | | ||
111 | (__force u32)dst->src_port), | ||
112 | (__force u32)dst->src_ip, ht->rnd) % ht->cfg.size); | ||
113 | } | ||
114 | |||
115 | static inline struct dsthash_ent * | ||
116 | __dsthash_find(const struct ipt_hashlimit_htable *ht, struct dsthash_dst *dst) | ||
117 | { | ||
118 | struct dsthash_ent *ent; | ||
119 | struct hlist_node *pos; | ||
120 | u_int32_t hash = hash_dst(ht, dst); | ||
121 | |||
122 | if (!hlist_empty(&ht->hash[hash])) | ||
123 | hlist_for_each_entry(ent, pos, &ht->hash[hash], node) { | ||
124 | if (dst_cmp(ent, dst)) { | ||
125 | return ent; | ||
126 | } | ||
127 | } | ||
128 | |||
129 | return NULL; | ||
130 | } | ||
131 | |||
132 | /* allocate dsthash_ent, initialize dst, put in htable and lock it */ | ||
133 | static struct dsthash_ent * | ||
134 | __dsthash_alloc_init(struct ipt_hashlimit_htable *ht, struct dsthash_dst *dst) | ||
135 | { | ||
136 | struct dsthash_ent *ent; | ||
137 | |||
138 | /* initialize hash with random val at the time we allocate | ||
139 | * the first hashtable entry */ | ||
140 | if (!ht->rnd_initialized) { | ||
141 | get_random_bytes(&ht->rnd, 4); | ||
142 | ht->rnd_initialized = 1; | ||
143 | } | ||
144 | |||
145 | if (ht->cfg.max && | ||
146 | atomic_read(&ht->count) >= ht->cfg.max) { | ||
147 | /* FIXME: do something. question is what.. */ | ||
148 | if (net_ratelimit()) | ||
149 | printk(KERN_WARNING | ||
150 | "ipt_hashlimit: max count of %u reached\n", | ||
151 | ht->cfg.max); | ||
152 | return NULL; | ||
153 | } | ||
154 | |||
155 | ent = kmem_cache_alloc(hashlimit_cachep, GFP_ATOMIC); | ||
156 | if (!ent) { | ||
157 | if (net_ratelimit()) | ||
158 | printk(KERN_ERR | ||
159 | "ipt_hashlimit: can't allocate dsthash_ent\n"); | ||
160 | return NULL; | ||
161 | } | ||
162 | |||
163 | atomic_inc(&ht->count); | ||
164 | |||
165 | ent->dst.dst_ip = dst->dst_ip; | ||
166 | ent->dst.dst_port = dst->dst_port; | ||
167 | ent->dst.src_ip = dst->src_ip; | ||
168 | ent->dst.src_port = dst->src_port; | ||
169 | |||
170 | hlist_add_head(&ent->node, &ht->hash[hash_dst(ht, dst)]); | ||
171 | |||
172 | return ent; | ||
173 | } | ||
174 | |||
175 | static inline void | ||
176 | __dsthash_free(struct ipt_hashlimit_htable *ht, struct dsthash_ent *ent) | ||
177 | { | ||
178 | hlist_del(&ent->node); | ||
179 | kmem_cache_free(hashlimit_cachep, ent); | ||
180 | atomic_dec(&ht->count); | ||
181 | } | ||
182 | static void htable_gc(unsigned long htlong); | ||
183 | |||
184 | static int htable_create(struct ipt_hashlimit_info *minfo) | ||
185 | { | ||
186 | int i; | ||
187 | unsigned int size; | ||
188 | struct ipt_hashlimit_htable *hinfo; | ||
189 | |||
190 | if (minfo->cfg.size) | ||
191 | size = minfo->cfg.size; | ||
192 | else { | ||
193 | size = (((num_physpages << PAGE_SHIFT) / 16384) | ||
194 | / sizeof(struct list_head)); | ||
195 | if (num_physpages > (1024 * 1024 * 1024 / PAGE_SIZE)) | ||
196 | size = 8192; | ||
197 | if (size < 16) | ||
198 | size = 16; | ||
199 | } | ||
200 | /* FIXME: don't use vmalloc() here or anywhere else -HW */ | ||
201 | hinfo = vmalloc(sizeof(struct ipt_hashlimit_htable) | ||
202 | + (sizeof(struct list_head) * size)); | ||
203 | if (!hinfo) { | ||
204 | printk(KERN_ERR "ipt_hashlimit: Unable to create hashtable\n"); | ||
205 | return -1; | ||
206 | } | ||
207 | minfo->hinfo = hinfo; | ||
208 | |||
209 | /* copy match config into hashtable config */ | ||
210 | memcpy(&hinfo->cfg, &minfo->cfg, sizeof(hinfo->cfg)); | ||
211 | hinfo->cfg.size = size; | ||
212 | if (!hinfo->cfg.max) | ||
213 | hinfo->cfg.max = 8 * hinfo->cfg.size; | ||
214 | else if (hinfo->cfg.max < hinfo->cfg.size) | ||
215 | hinfo->cfg.max = hinfo->cfg.size; | ||
216 | |||
217 | for (i = 0; i < hinfo->cfg.size; i++) | ||
218 | INIT_HLIST_HEAD(&hinfo->hash[i]); | ||
219 | |||
220 | atomic_set(&hinfo->count, 0); | ||
221 | atomic_set(&hinfo->use, 1); | ||
222 | hinfo->rnd_initialized = 0; | ||
223 | spin_lock_init(&hinfo->lock); | ||
224 | hinfo->pde = create_proc_entry(minfo->name, 0, hashlimit_procdir); | ||
225 | if (!hinfo->pde) { | ||
226 | vfree(hinfo); | ||
227 | return -1; | ||
228 | } | ||
229 | hinfo->pde->proc_fops = &dl_file_ops; | ||
230 | hinfo->pde->data = hinfo; | ||
231 | |||
232 | init_timer(&hinfo->timer); | ||
233 | hinfo->timer.expires = jiffies + msecs_to_jiffies(hinfo->cfg.gc_interval); | ||
234 | hinfo->timer.data = (unsigned long )hinfo; | ||
235 | hinfo->timer.function = htable_gc; | ||
236 | add_timer(&hinfo->timer); | ||
237 | |||
238 | spin_lock_bh(&hashlimit_lock); | ||
239 | hlist_add_head(&hinfo->node, &hashlimit_htables); | ||
240 | spin_unlock_bh(&hashlimit_lock); | ||
241 | |||
242 | return 0; | ||
243 | } | ||
244 | |||
245 | static int select_all(struct ipt_hashlimit_htable *ht, struct dsthash_ent *he) | ||
246 | { | ||
247 | return 1; | ||
248 | } | ||
249 | |||
250 | static int select_gc(struct ipt_hashlimit_htable *ht, struct dsthash_ent *he) | ||
251 | { | ||
252 | return (jiffies >= he->expires); | ||
253 | } | ||
254 | |||
255 | static void htable_selective_cleanup(struct ipt_hashlimit_htable *ht, | ||
256 | int (*select)(struct ipt_hashlimit_htable *ht, | ||
257 | struct dsthash_ent *he)) | ||
258 | { | ||
259 | int i; | ||
260 | |||
261 | IP_NF_ASSERT(ht->cfg.size && ht->cfg.max); | ||
262 | |||
263 | /* lock hash table and iterate over it */ | ||
264 | spin_lock_bh(&ht->lock); | ||
265 | for (i = 0; i < ht->cfg.size; i++) { | ||
266 | struct dsthash_ent *dh; | ||
267 | struct hlist_node *pos, *n; | ||
268 | hlist_for_each_entry_safe(dh, pos, n, &ht->hash[i], node) { | ||
269 | if ((*select)(ht, dh)) | ||
270 | __dsthash_free(ht, dh); | ||
271 | } | ||
272 | } | ||
273 | spin_unlock_bh(&ht->lock); | ||
274 | } | ||
275 | |||
276 | /* hash table garbage collector, run by timer */ | ||
277 | static void htable_gc(unsigned long htlong) | ||
278 | { | ||
279 | struct ipt_hashlimit_htable *ht = (struct ipt_hashlimit_htable *)htlong; | ||
280 | |||
281 | htable_selective_cleanup(ht, select_gc); | ||
282 | |||
283 | /* re-add the timer accordingly */ | ||
284 | ht->timer.expires = jiffies + msecs_to_jiffies(ht->cfg.gc_interval); | ||
285 | add_timer(&ht->timer); | ||
286 | } | ||
287 | |||
288 | static void htable_destroy(struct ipt_hashlimit_htable *hinfo) | ||
289 | { | ||
290 | /* remove timer, if it is pending */ | ||
291 | if (timer_pending(&hinfo->timer)) | ||
292 | del_timer(&hinfo->timer); | ||
293 | |||
294 | /* remove proc entry */ | ||
295 | remove_proc_entry(hinfo->pde->name, hashlimit_procdir); | ||
296 | |||
297 | htable_selective_cleanup(hinfo, select_all); | ||
298 | vfree(hinfo); | ||
299 | } | ||
300 | |||
301 | static struct ipt_hashlimit_htable *htable_find_get(char *name) | ||
302 | { | ||
303 | struct ipt_hashlimit_htable *hinfo; | ||
304 | struct hlist_node *pos; | ||
305 | |||
306 | spin_lock_bh(&hashlimit_lock); | ||
307 | hlist_for_each_entry(hinfo, pos, &hashlimit_htables, node) { | ||
308 | if (!strcmp(name, hinfo->pde->name)) { | ||
309 | atomic_inc(&hinfo->use); | ||
310 | spin_unlock_bh(&hashlimit_lock); | ||
311 | return hinfo; | ||
312 | } | ||
313 | } | ||
314 | spin_unlock_bh(&hashlimit_lock); | ||
315 | |||
316 | return NULL; | ||
317 | } | ||
318 | |||
319 | static void htable_put(struct ipt_hashlimit_htable *hinfo) | ||
320 | { | ||
321 | if (atomic_dec_and_test(&hinfo->use)) { | ||
322 | spin_lock_bh(&hashlimit_lock); | ||
323 | hlist_del(&hinfo->node); | ||
324 | spin_unlock_bh(&hashlimit_lock); | ||
325 | htable_destroy(hinfo); | ||
326 | } | ||
327 | } | ||
328 | |||
329 | |||
330 | /* The algorithm used is the Simple Token Bucket Filter (TBF) | ||
331 | * see net/sched/sch_tbf.c in the linux source tree | ||
332 | */ | ||
333 | |||
334 | /* Rusty: This is my (non-mathematically-inclined) understanding of | ||
335 | this algorithm. The `average rate' in jiffies becomes your initial | ||
336 | amount of credit `credit' and the most credit you can ever have | ||
337 | `credit_cap'. The `peak rate' becomes the cost of passing the | ||
338 | test, `cost'. | ||
339 | |||
340 | `prev' tracks the last packet hit: you gain one credit per jiffy. | ||
341 | If you get credit balance more than this, the extra credit is | ||
342 | discarded. Every time the match passes, you lose `cost' credits; | ||
343 | if you don't have that many, the test fails. | ||
344 | |||
345 | See Alexey's formal explanation in net/sched/sch_tbf.c. | ||
346 | |||
347 | To get the maximum range, we multiply by this factor (ie. you get N | ||
348 | credits per jiffy). We want to allow a rate as low as 1 per day | ||
349 | (slowest userspace tool allows), which means | ||
350 | CREDITS_PER_JIFFY*HZ*60*60*24 < 2^32 ie. | ||
351 | */ | ||
352 | #define MAX_CPJ (0xFFFFFFFF / (HZ*60*60*24)) | ||
353 | |||
354 | /* Repeated shift and or gives us all 1s, final shift and add 1 gives | ||
355 | * us the power of 2 below the theoretical max, so GCC simply does a | ||
356 | * shift. */ | ||
357 | #define _POW2_BELOW2(x) ((x)|((x)>>1)) | ||
358 | #define _POW2_BELOW4(x) (_POW2_BELOW2(x)|_POW2_BELOW2((x)>>2)) | ||
359 | #define _POW2_BELOW8(x) (_POW2_BELOW4(x)|_POW2_BELOW4((x)>>4)) | ||
360 | #define _POW2_BELOW16(x) (_POW2_BELOW8(x)|_POW2_BELOW8((x)>>8)) | ||
361 | #define _POW2_BELOW32(x) (_POW2_BELOW16(x)|_POW2_BELOW16((x)>>16)) | ||
362 | #define POW2_BELOW32(x) ((_POW2_BELOW32(x)>>1) + 1) | ||
363 | |||
364 | #define CREDITS_PER_JIFFY POW2_BELOW32(MAX_CPJ) | ||
365 | |||
366 | /* Precision saver. */ | ||
367 | static inline u_int32_t | ||
368 | user2credits(u_int32_t user) | ||
369 | { | ||
370 | /* If multiplying would overflow... */ | ||
371 | if (user > 0xFFFFFFFF / (HZ*CREDITS_PER_JIFFY)) | ||
372 | /* Divide first. */ | ||
373 | return (user / IPT_HASHLIMIT_SCALE) * HZ * CREDITS_PER_JIFFY; | ||
374 | |||
375 | return (user * HZ * CREDITS_PER_JIFFY) / IPT_HASHLIMIT_SCALE; | ||
376 | } | ||
377 | |||
378 | static inline void rateinfo_recalc(struct dsthash_ent *dh, unsigned long now) | ||
379 | { | ||
380 | dh->rateinfo.credit += (now - xchg(&dh->rateinfo.prev, now)) | ||
381 | * CREDITS_PER_JIFFY; | ||
382 | if (dh->rateinfo.credit > dh->rateinfo.credit_cap) | ||
383 | dh->rateinfo.credit = dh->rateinfo.credit_cap; | ||
384 | } | ||
385 | |||
386 | static int | ||
387 | hashlimit_match(const struct sk_buff *skb, | ||
388 | const struct net_device *in, | ||
389 | const struct net_device *out, | ||
390 | const struct xt_match *match, | ||
391 | const void *matchinfo, | ||
392 | int offset, | ||
393 | unsigned int protoff, | ||
394 | int *hotdrop) | ||
395 | { | ||
396 | struct ipt_hashlimit_info *r = | ||
397 | ((struct ipt_hashlimit_info *)matchinfo)->u.master; | ||
398 | struct ipt_hashlimit_htable *hinfo = r->hinfo; | ||
399 | unsigned long now = jiffies; | ||
400 | struct dsthash_ent *dh; | ||
401 | struct dsthash_dst dst; | ||
402 | |||
403 | /* build 'dst' according to hinfo->cfg and current packet */ | ||
404 | memset(&dst, 0, sizeof(dst)); | ||
405 | if (hinfo->cfg.mode & IPT_HASHLIMIT_HASH_DIP) | ||
406 | dst.dst_ip = skb->nh.iph->daddr; | ||
407 | if (hinfo->cfg.mode & IPT_HASHLIMIT_HASH_SIP) | ||
408 | dst.src_ip = skb->nh.iph->saddr; | ||
409 | if (hinfo->cfg.mode & IPT_HASHLIMIT_HASH_DPT | ||
410 | ||hinfo->cfg.mode & IPT_HASHLIMIT_HASH_SPT) { | ||
411 | __be16 _ports[2], *ports; | ||
412 | |||
413 | switch (skb->nh.iph->protocol) { | ||
414 | case IPPROTO_TCP: | ||
415 | case IPPROTO_UDP: | ||
416 | case IPPROTO_SCTP: | ||
417 | case IPPROTO_DCCP: | ||
418 | ports = skb_header_pointer(skb, skb->nh.iph->ihl*4, | ||
419 | sizeof(_ports), &_ports); | ||
420 | break; | ||
421 | default: | ||
422 | _ports[0] = _ports[1] = 0; | ||
423 | ports = _ports; | ||
424 | break; | ||
425 | } | ||
426 | if (!ports) { | ||
427 | /* We've been asked to examine this packet, and we | ||
428 | can't. Hence, no choice but to drop. */ | ||
429 | *hotdrop = 1; | ||
430 | return 0; | ||
431 | } | ||
432 | if (hinfo->cfg.mode & IPT_HASHLIMIT_HASH_SPT) | ||
433 | dst.src_port = ports[0]; | ||
434 | if (hinfo->cfg.mode & IPT_HASHLIMIT_HASH_DPT) | ||
435 | dst.dst_port = ports[1]; | ||
436 | } | ||
437 | |||
438 | spin_lock_bh(&hinfo->lock); | ||
439 | dh = __dsthash_find(hinfo, &dst); | ||
440 | if (!dh) { | ||
441 | dh = __dsthash_alloc_init(hinfo, &dst); | ||
442 | |||
443 | if (!dh) { | ||
444 | /* enomem... don't match == DROP */ | ||
445 | if (net_ratelimit()) | ||
446 | printk(KERN_ERR "%s: ENOMEM\n", __FUNCTION__); | ||
447 | spin_unlock_bh(&hinfo->lock); | ||
448 | return 0; | ||
449 | } | ||
450 | |||
451 | dh->expires = jiffies + msecs_to_jiffies(hinfo->cfg.expire); | ||
452 | |||
453 | dh->rateinfo.prev = jiffies; | ||
454 | dh->rateinfo.credit = user2credits(hinfo->cfg.avg * | ||
455 | hinfo->cfg.burst); | ||
456 | dh->rateinfo.credit_cap = user2credits(hinfo->cfg.avg * | ||
457 | hinfo->cfg.burst); | ||
458 | dh->rateinfo.cost = user2credits(hinfo->cfg.avg); | ||
459 | } else { | ||
460 | /* update expiration timeout */ | ||
461 | dh->expires = now + msecs_to_jiffies(hinfo->cfg.expire); | ||
462 | rateinfo_recalc(dh, now); | ||
463 | } | ||
464 | |||
465 | if (dh->rateinfo.credit >= dh->rateinfo.cost) { | ||
466 | /* We're underlimit. */ | ||
467 | dh->rateinfo.credit -= dh->rateinfo.cost; | ||
468 | spin_unlock_bh(&hinfo->lock); | ||
469 | return 1; | ||
470 | } | ||
471 | |||
472 | spin_unlock_bh(&hinfo->lock); | ||
473 | |||
474 | /* default case: we're overlimit, thus don't match */ | ||
475 | return 0; | ||
476 | } | ||
477 | |||
478 | static int | ||
479 | hashlimit_checkentry(const char *tablename, | ||
480 | const void *inf, | ||
481 | const struct xt_match *match, | ||
482 | void *matchinfo, | ||
483 | unsigned int hook_mask) | ||
484 | { | ||
485 | struct ipt_hashlimit_info *r = matchinfo; | ||
486 | |||
487 | /* Check for overflow. */ | ||
488 | if (r->cfg.burst == 0 | ||
489 | || user2credits(r->cfg.avg * r->cfg.burst) < | ||
490 | user2credits(r->cfg.avg)) { | ||
491 | printk(KERN_ERR "ipt_hashlimit: Overflow, try lower: %u/%u\n", | ||
492 | r->cfg.avg, r->cfg.burst); | ||
493 | return 0; | ||
494 | } | ||
495 | |||
496 | if (r->cfg.mode == 0 | ||
497 | || r->cfg.mode > (IPT_HASHLIMIT_HASH_DPT | ||
498 | |IPT_HASHLIMIT_HASH_DIP | ||
499 | |IPT_HASHLIMIT_HASH_SIP | ||
500 | |IPT_HASHLIMIT_HASH_SPT)) | ||
501 | return 0; | ||
502 | |||
503 | if (!r->cfg.gc_interval) | ||
504 | return 0; | ||
505 | |||
506 | if (!r->cfg.expire) | ||
507 | return 0; | ||
508 | |||
509 | if (r->name[sizeof(r->name) - 1] != '\0') | ||
510 | return 0; | ||
511 | |||
512 | /* This is the best we've got: We cannot release and re-grab lock, | ||
513 | * since checkentry() is called before ip_tables.c grabs ipt_mutex. | ||
514 | * We also cannot grab the hashtable spinlock, since htable_create will | ||
515 | * call vmalloc, and that can sleep. And we cannot just re-search | ||
516 | * the list of htable's in htable_create(), since then we would | ||
517 | * create duplicate proc files. -HW */ | ||
518 | mutex_lock(&hlimit_mutex); | ||
519 | r->hinfo = htable_find_get(r->name); | ||
520 | if (!r->hinfo && (htable_create(r) != 0)) { | ||
521 | mutex_unlock(&hlimit_mutex); | ||
522 | return 0; | ||
523 | } | ||
524 | mutex_unlock(&hlimit_mutex); | ||
525 | |||
526 | /* Ugly hack: For SMP, we only want to use one set */ | ||
527 | r->u.master = r; | ||
528 | |||
529 | return 1; | ||
530 | } | ||
531 | |||
532 | static void | ||
533 | hashlimit_destroy(const struct xt_match *match, void *matchinfo) | ||
534 | { | ||
535 | struct ipt_hashlimit_info *r = matchinfo; | ||
536 | |||
537 | htable_put(r->hinfo); | ||
538 | } | ||
539 | |||
540 | #ifdef CONFIG_COMPAT | ||
541 | struct compat_ipt_hashlimit_info { | ||
542 | char name[IFNAMSIZ]; | ||
543 | struct hashlimit_cfg cfg; | ||
544 | compat_uptr_t hinfo; | ||
545 | compat_uptr_t master; | ||
546 | }; | ||
547 | |||
548 | static void compat_from_user(void *dst, void *src) | ||
549 | { | ||
550 | int off = offsetof(struct compat_ipt_hashlimit_info, hinfo); | ||
551 | |||
552 | memcpy(dst, src, off); | ||
553 | memset(dst + off, 0, sizeof(struct compat_ipt_hashlimit_info) - off); | ||
554 | } | ||
555 | |||
556 | static int compat_to_user(void __user *dst, void *src) | ||
557 | { | ||
558 | int off = offsetof(struct compat_ipt_hashlimit_info, hinfo); | ||
559 | |||
560 | return copy_to_user(dst, src, off) ? -EFAULT : 0; | ||
561 | } | ||
562 | #endif | ||
563 | |||
564 | static struct ipt_match ipt_hashlimit = { | ||
565 | .name = "hashlimit", | ||
566 | .match = hashlimit_match, | ||
567 | .matchsize = sizeof(struct ipt_hashlimit_info), | ||
568 | #ifdef CONFIG_COMPAT | ||
569 | .compatsize = sizeof(struct compat_ipt_hashlimit_info), | ||
570 | .compat_from_user = compat_from_user, | ||
571 | .compat_to_user = compat_to_user, | ||
572 | #endif | ||
573 | .checkentry = hashlimit_checkentry, | ||
574 | .destroy = hashlimit_destroy, | ||
575 | .me = THIS_MODULE | ||
576 | }; | ||
577 | |||
578 | /* PROC stuff */ | ||
579 | |||
580 | static void *dl_seq_start(struct seq_file *s, loff_t *pos) | ||
581 | { | ||
582 | struct proc_dir_entry *pde = s->private; | ||
583 | struct ipt_hashlimit_htable *htable = pde->data; | ||
584 | unsigned int *bucket; | ||
585 | |||
586 | spin_lock_bh(&htable->lock); | ||
587 | if (*pos >= htable->cfg.size) | ||
588 | return NULL; | ||
589 | |||
590 | bucket = kmalloc(sizeof(unsigned int), GFP_ATOMIC); | ||
591 | if (!bucket) | ||
592 | return ERR_PTR(-ENOMEM); | ||
593 | |||
594 | *bucket = *pos; | ||
595 | return bucket; | ||
596 | } | ||
597 | |||
598 | static void *dl_seq_next(struct seq_file *s, void *v, loff_t *pos) | ||
599 | { | ||
600 | struct proc_dir_entry *pde = s->private; | ||
601 | struct ipt_hashlimit_htable *htable = pde->data; | ||
602 | unsigned int *bucket = (unsigned int *)v; | ||
603 | |||
604 | *pos = ++(*bucket); | ||
605 | if (*pos >= htable->cfg.size) { | ||
606 | kfree(v); | ||
607 | return NULL; | ||
608 | } | ||
609 | return bucket; | ||
610 | } | ||
611 | |||
612 | static void dl_seq_stop(struct seq_file *s, void *v) | ||
613 | { | ||
614 | struct proc_dir_entry *pde = s->private; | ||
615 | struct ipt_hashlimit_htable *htable = pde->data; | ||
616 | unsigned int *bucket = (unsigned int *)v; | ||
617 | |||
618 | kfree(bucket); | ||
619 | |||
620 | spin_unlock_bh(&htable->lock); | ||
621 | } | ||
622 | |||
623 | static inline int dl_seq_real_show(struct dsthash_ent *ent, struct seq_file *s) | ||
624 | { | ||
625 | /* recalculate to show accurate numbers */ | ||
626 | rateinfo_recalc(ent, jiffies); | ||
627 | |||
628 | return seq_printf(s, "%ld %u.%u.%u.%u:%u->%u.%u.%u.%u:%u %u %u %u\n", | ||
629 | (long)(ent->expires - jiffies)/HZ, | ||
630 | NIPQUAD(ent->dst.src_ip), ntohs(ent->dst.src_port), | ||
631 | NIPQUAD(ent->dst.dst_ip), ntohs(ent->dst.dst_port), | ||
632 | ent->rateinfo.credit, ent->rateinfo.credit_cap, | ||
633 | ent->rateinfo.cost); | ||
634 | } | ||
635 | |||
636 | static int dl_seq_show(struct seq_file *s, void *v) | ||
637 | { | ||
638 | struct proc_dir_entry *pde = s->private; | ||
639 | struct ipt_hashlimit_htable *htable = pde->data; | ||
640 | unsigned int *bucket = (unsigned int *)v; | ||
641 | struct dsthash_ent *ent; | ||
642 | struct hlist_node *pos; | ||
643 | |||
644 | if (!hlist_empty(&htable->hash[*bucket])) | ||
645 | hlist_for_each_entry(ent, pos, &htable->hash[*bucket], node) { | ||
646 | if (dl_seq_real_show(ent, s)) { | ||
647 | /* buffer was filled and unable to print that tuple */ | ||
648 | return 1; | ||
649 | } | ||
650 | } | ||
651 | |||
652 | return 0; | ||
653 | } | ||
654 | |||
655 | static struct seq_operations dl_seq_ops = { | ||
656 | .start = dl_seq_start, | ||
657 | .next = dl_seq_next, | ||
658 | .stop = dl_seq_stop, | ||
659 | .show = dl_seq_show | ||
660 | }; | ||
661 | |||
662 | static int dl_proc_open(struct inode *inode, struct file *file) | ||
663 | { | ||
664 | int ret = seq_open(file, &dl_seq_ops); | ||
665 | |||
666 | if (!ret) { | ||
667 | struct seq_file *sf = file->private_data; | ||
668 | sf->private = PDE(inode); | ||
669 | } | ||
670 | return ret; | ||
671 | } | ||
672 | |||
673 | static struct file_operations dl_file_ops = { | ||
674 | .owner = THIS_MODULE, | ||
675 | .open = dl_proc_open, | ||
676 | .read = seq_read, | ||
677 | .llseek = seq_lseek, | ||
678 | .release = seq_release | ||
679 | }; | ||
680 | |||
681 | static int init_or_fini(int fini) | ||
682 | { | ||
683 | int ret = 0; | ||
684 | |||
685 | if (fini) | ||
686 | goto cleanup; | ||
687 | |||
688 | if (ipt_register_match(&ipt_hashlimit)) { | ||
689 | ret = -EINVAL; | ||
690 | goto cleanup_nothing; | ||
691 | } | ||
692 | |||
693 | hashlimit_cachep = kmem_cache_create("ipt_hashlimit", | ||
694 | sizeof(struct dsthash_ent), 0, | ||
695 | 0, NULL, NULL); | ||
696 | if (!hashlimit_cachep) { | ||
697 | printk(KERN_ERR "Unable to create ipt_hashlimit slab cache\n"); | ||
698 | ret = -ENOMEM; | ||
699 | goto cleanup_unreg_match; | ||
700 | } | ||
701 | |||
702 | hashlimit_procdir = proc_mkdir("ipt_hashlimit", proc_net); | ||
703 | if (!hashlimit_procdir) { | ||
704 | printk(KERN_ERR "Unable to create proc dir entry\n"); | ||
705 | ret = -ENOMEM; | ||
706 | goto cleanup_free_slab; | ||
707 | } | ||
708 | |||
709 | return ret; | ||
710 | |||
711 | cleanup: | ||
712 | remove_proc_entry("ipt_hashlimit", proc_net); | ||
713 | cleanup_free_slab: | ||
714 | kmem_cache_destroy(hashlimit_cachep); | ||
715 | cleanup_unreg_match: | ||
716 | ipt_unregister_match(&ipt_hashlimit); | ||
717 | cleanup_nothing: | ||
718 | return ret; | ||
719 | |||
720 | } | ||
721 | |||
722 | static int __init ipt_hashlimit_init(void) | ||
723 | { | ||
724 | return init_or_fini(0); | ||
725 | } | ||
726 | |||
727 | static void __exit ipt_hashlimit_fini(void) | ||
728 | { | ||
729 | init_or_fini(1); | ||
730 | } | ||
731 | |||
732 | module_init(ipt_hashlimit_init); | ||
733 | module_exit(ipt_hashlimit_fini); | ||
diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c index b91f3582359b..af2939889444 100644 --- a/net/ipv4/netfilter/iptable_mangle.c +++ b/net/ipv4/netfilter/iptable_mangle.c | |||
@@ -132,7 +132,7 @@ ipt_local_hook(unsigned int hook, | |||
132 | unsigned int ret; | 132 | unsigned int ret; |
133 | u_int8_t tos; | 133 | u_int8_t tos; |
134 | __be32 saddr, daddr; | 134 | __be32 saddr, daddr; |
135 | unsigned long nfmark; | 135 | u_int32_t mark; |
136 | 136 | ||
137 | /* root is playing with raw sockets. */ | 137 | /* root is playing with raw sockets. */ |
138 | if ((*pskb)->len < sizeof(struct iphdr) | 138 | if ((*pskb)->len < sizeof(struct iphdr) |
@@ -143,7 +143,7 @@ ipt_local_hook(unsigned int hook, | |||
143 | } | 143 | } |
144 | 144 | ||
145 | /* Save things which could affect route */ | 145 | /* Save things which could affect route */ |
146 | nfmark = (*pskb)->nfmark; | 146 | mark = (*pskb)->mark; |
147 | saddr = (*pskb)->nh.iph->saddr; | 147 | saddr = (*pskb)->nh.iph->saddr; |
148 | daddr = (*pskb)->nh.iph->daddr; | 148 | daddr = (*pskb)->nh.iph->daddr; |
149 | tos = (*pskb)->nh.iph->tos; | 149 | tos = (*pskb)->nh.iph->tos; |
@@ -153,9 +153,7 @@ ipt_local_hook(unsigned int hook, | |||
153 | if (ret != NF_DROP && ret != NF_STOLEN && ret != NF_QUEUE | 153 | if (ret != NF_DROP && ret != NF_STOLEN && ret != NF_QUEUE |
154 | && ((*pskb)->nh.iph->saddr != saddr | 154 | && ((*pskb)->nh.iph->saddr != saddr |
155 | || (*pskb)->nh.iph->daddr != daddr | 155 | || (*pskb)->nh.iph->daddr != daddr |
156 | #ifdef CONFIG_IP_ROUTE_FWMARK | 156 | || (*pskb)->mark != mark |
157 | || (*pskb)->nfmark != nfmark | ||
158 | #endif | ||
159 | || (*pskb)->nh.iph->tos != tos)) | 157 | || (*pskb)->nh.iph->tos != tos)) |
160 | if (ip_route_me_harder(pskb, RTN_UNSPEC)) | 158 | if (ip_route_me_harder(pskb, RTN_UNSPEC)) |
161 | ret = NF_DROP; | 159 | ret = NF_DROP; |
diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c index 0af803df82b0..471b638cedec 100644 --- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c +++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c | |||
@@ -27,7 +27,7 @@ | |||
27 | #include <linux/netfilter_ipv4.h> | 27 | #include <linux/netfilter_ipv4.h> |
28 | #include <net/netfilter/nf_conntrack.h> | 28 | #include <net/netfilter/nf_conntrack.h> |
29 | #include <net/netfilter/nf_conntrack_helper.h> | 29 | #include <net/netfilter/nf_conntrack_helper.h> |
30 | #include <net/netfilter/nf_conntrack_protocol.h> | 30 | #include <net/netfilter/nf_conntrack_l4proto.h> |
31 | #include <net/netfilter/nf_conntrack_l3proto.h> | 31 | #include <net/netfilter/nf_conntrack_l3proto.h> |
32 | #include <net/netfilter/nf_conntrack_core.h> | 32 | #include <net/netfilter/nf_conntrack_core.h> |
33 | #include <net/netfilter/ipv4/nf_conntrack_ipv4.h> | 33 | #include <net/netfilter/ipv4/nf_conntrack_ipv4.h> |
@@ -38,12 +38,10 @@ | |||
38 | #define DEBUGP(format, args...) | 38 | #define DEBUGP(format, args...) |
39 | #endif | 39 | #endif |
40 | 40 | ||
41 | DECLARE_PER_CPU(struct nf_conntrack_stat, nf_conntrack_stat); | ||
42 | |||
43 | static int ipv4_pkt_to_tuple(const struct sk_buff *skb, unsigned int nhoff, | 41 | static int ipv4_pkt_to_tuple(const struct sk_buff *skb, unsigned int nhoff, |
44 | struct nf_conntrack_tuple *tuple) | 42 | struct nf_conntrack_tuple *tuple) |
45 | { | 43 | { |
46 | u_int32_t _addrs[2], *ap; | 44 | __be32 _addrs[2], *ap; |
47 | ap = skb_header_pointer(skb, nhoff + offsetof(struct iphdr, saddr), | 45 | ap = skb_header_pointer(skb, nhoff + offsetof(struct iphdr, saddr), |
48 | sizeof(u_int32_t) * 2, _addrs); | 46 | sizeof(u_int32_t) * 2, _addrs); |
49 | if (ap == NULL) | 47 | if (ap == NULL) |
@@ -113,10 +111,12 @@ ipv4_prepare(struct sk_buff **pskb, unsigned int hooknum, unsigned int *dataoff, | |||
113 | return NF_ACCEPT; | 111 | return NF_ACCEPT; |
114 | } | 112 | } |
115 | 113 | ||
116 | int nat_module_is_loaded = 0; | 114 | int nf_nat_module_is_loaded = 0; |
115 | EXPORT_SYMBOL_GPL(nf_nat_module_is_loaded); | ||
116 | |||
117 | static u_int32_t ipv4_get_features(const struct nf_conntrack_tuple *tuple) | 117 | static u_int32_t ipv4_get_features(const struct nf_conntrack_tuple *tuple) |
118 | { | 118 | { |
119 | if (nat_module_is_loaded) | 119 | if (nf_nat_module_is_loaded) |
120 | return NF_CT_F_NAT; | 120 | return NF_CT_F_NAT; |
121 | 121 | ||
122 | return NF_CT_F_BASIC; | 122 | return NF_CT_F_BASIC; |
@@ -268,43 +268,59 @@ static struct nf_hook_ops ipv4_conntrack_ops[] = { | |||
268 | }, | 268 | }, |
269 | }; | 269 | }; |
270 | 270 | ||
271 | #ifdef CONFIG_SYSCTL | 271 | #if defined(CONFIG_SYSCTL) && defined(CONFIG_NF_CONNTRACK_PROC_COMPAT) |
272 | /* From nf_conntrack_proto_icmp.c */ | 272 | static int log_invalid_proto_min = 0; |
273 | extern unsigned int nf_ct_icmp_timeout; | 273 | static int log_invalid_proto_max = 255; |
274 | static struct ctl_table_header *nf_ct_ipv4_sysctl_header; | ||
275 | 274 | ||
276 | static ctl_table nf_ct_sysctl_table[] = { | 275 | static ctl_table ip_ct_sysctl_table[] = { |
277 | { | 276 | { |
278 | .ctl_name = NET_NF_CONNTRACK_ICMP_TIMEOUT, | 277 | .ctl_name = NET_IPV4_NF_CONNTRACK_MAX, |
279 | .procname = "nf_conntrack_icmp_timeout", | 278 | .procname = "ip_conntrack_max", |
280 | .data = &nf_ct_icmp_timeout, | 279 | .data = &nf_conntrack_max, |
281 | .maxlen = sizeof(unsigned int), | 280 | .maxlen = sizeof(int), |
282 | .mode = 0644, | 281 | .mode = 0644, |
283 | .proc_handler = &proc_dointvec_jiffies, | 282 | .proc_handler = &proc_dointvec, |
284 | }, | 283 | }, |
285 | { .ctl_name = 0 } | ||
286 | }; | ||
287 | |||
288 | static ctl_table nf_ct_netfilter_table[] = { | ||
289 | { | 284 | { |
290 | .ctl_name = NET_NETFILTER, | 285 | .ctl_name = NET_IPV4_NF_CONNTRACK_COUNT, |
291 | .procname = "netfilter", | 286 | .procname = "ip_conntrack_count", |
292 | .mode = 0555, | 287 | .data = &nf_conntrack_count, |
293 | .child = nf_ct_sysctl_table, | 288 | .maxlen = sizeof(int), |
289 | .mode = 0444, | ||
290 | .proc_handler = &proc_dointvec, | ||
291 | }, | ||
292 | { | ||
293 | .ctl_name = NET_IPV4_NF_CONNTRACK_BUCKETS, | ||
294 | .procname = "ip_conntrack_buckets", | ||
295 | .data = &nf_conntrack_htable_size, | ||
296 | .maxlen = sizeof(unsigned int), | ||
297 | .mode = 0444, | ||
298 | .proc_handler = &proc_dointvec, | ||
299 | }, | ||
300 | { | ||
301 | .ctl_name = NET_IPV4_NF_CONNTRACK_CHECKSUM, | ||
302 | .procname = "ip_conntrack_checksum", | ||
303 | .data = &nf_conntrack_checksum, | ||
304 | .maxlen = sizeof(int), | ||
305 | .mode = 0644, | ||
306 | .proc_handler = &proc_dointvec, | ||
294 | }, | 307 | }, |
295 | { .ctl_name = 0 } | ||
296 | }; | ||
297 | |||
298 | static ctl_table nf_ct_net_table[] = { | ||
299 | { | 308 | { |
300 | .ctl_name = CTL_NET, | 309 | .ctl_name = NET_IPV4_NF_CONNTRACK_LOG_INVALID, |
301 | .procname = "net", | 310 | .procname = "ip_conntrack_log_invalid", |
302 | .mode = 0555, | 311 | .data = &nf_ct_log_invalid, |
303 | .child = nf_ct_netfilter_table, | 312 | .maxlen = sizeof(unsigned int), |
313 | .mode = 0644, | ||
314 | .proc_handler = &proc_dointvec_minmax, | ||
315 | .strategy = &sysctl_intvec, | ||
316 | .extra1 = &log_invalid_proto_min, | ||
317 | .extra2 = &log_invalid_proto_max, | ||
304 | }, | 318 | }, |
305 | { .ctl_name = 0 } | 319 | { |
320 | .ctl_name = 0 | ||
321 | } | ||
306 | }; | 322 | }; |
307 | #endif | 323 | #endif /* CONFIG_SYSCTL && CONFIG_NF_CONNTRACK_PROC_COMPAT */ |
308 | 324 | ||
309 | /* Fast function for those who don't want to parse /proc (and I don't | 325 | /* Fast function for those who don't want to parse /proc (and I don't |
310 | blame them). */ | 326 | blame them). */ |
@@ -396,10 +412,8 @@ static int ipv4_nfattr_to_tuple(struct nfattr *tb[], | |||
396 | if (nfattr_bad_size(tb, CTA_IP_MAX, cta_min_ip)) | 412 | if (nfattr_bad_size(tb, CTA_IP_MAX, cta_min_ip)) |
397 | return -EINVAL; | 413 | return -EINVAL; |
398 | 414 | ||
399 | t->src.u3.ip = | 415 | t->src.u3.ip = *(__be32 *)NFA_DATA(tb[CTA_IP_V4_SRC-1]); |
400 | *(u_int32_t *)NFA_DATA(tb[CTA_IP_V4_SRC-1]); | 416 | t->dst.u3.ip = *(__be32 *)NFA_DATA(tb[CTA_IP_V4_DST-1]); |
401 | t->dst.u3.ip = | ||
402 | *(u_int32_t *)NFA_DATA(tb[CTA_IP_V4_DST-1]); | ||
403 | 417 | ||
404 | return 0; | 418 | return 0; |
405 | } | 419 | } |
@@ -426,14 +440,15 @@ struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv4 = { | |||
426 | .tuple_to_nfattr = ipv4_tuple_to_nfattr, | 440 | .tuple_to_nfattr = ipv4_tuple_to_nfattr, |
427 | .nfattr_to_tuple = ipv4_nfattr_to_tuple, | 441 | .nfattr_to_tuple = ipv4_nfattr_to_tuple, |
428 | #endif | 442 | #endif |
443 | #if defined(CONFIG_SYSCTL) && defined(CONFIG_NF_CONNTRACK_PROC_COMPAT) | ||
444 | .ctl_table_path = nf_net_ipv4_netfilter_sysctl_path, | ||
445 | .ctl_table = ip_ct_sysctl_table, | ||
446 | #endif | ||
429 | .me = THIS_MODULE, | 447 | .me = THIS_MODULE, |
430 | }; | 448 | }; |
431 | 449 | ||
432 | extern struct nf_conntrack_protocol nf_conntrack_protocol_tcp4; | ||
433 | extern struct nf_conntrack_protocol nf_conntrack_protocol_udp4; | ||
434 | extern struct nf_conntrack_protocol nf_conntrack_protocol_icmp; | ||
435 | |||
436 | MODULE_ALIAS("nf_conntrack-" __stringify(AF_INET)); | 450 | MODULE_ALIAS("nf_conntrack-" __stringify(AF_INET)); |
451 | MODULE_ALIAS("ip_conntrack"); | ||
437 | MODULE_LICENSE("GPL"); | 452 | MODULE_LICENSE("GPL"); |
438 | 453 | ||
439 | static int __init nf_conntrack_l3proto_ipv4_init(void) | 454 | static int __init nf_conntrack_l3proto_ipv4_init(void) |
@@ -448,19 +463,19 @@ static int __init nf_conntrack_l3proto_ipv4_init(void) | |||
448 | return ret; | 463 | return ret; |
449 | } | 464 | } |
450 | 465 | ||
451 | ret = nf_conntrack_protocol_register(&nf_conntrack_protocol_tcp4); | 466 | ret = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_tcp4); |
452 | if (ret < 0) { | 467 | if (ret < 0) { |
453 | printk("nf_conntrack_ipv4: can't register tcp.\n"); | 468 | printk("nf_conntrack_ipv4: can't register tcp.\n"); |
454 | goto cleanup_sockopt; | 469 | goto cleanup_sockopt; |
455 | } | 470 | } |
456 | 471 | ||
457 | ret = nf_conntrack_protocol_register(&nf_conntrack_protocol_udp4); | 472 | ret = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_udp4); |
458 | if (ret < 0) { | 473 | if (ret < 0) { |
459 | printk("nf_conntrack_ipv4: can't register udp.\n"); | 474 | printk("nf_conntrack_ipv4: can't register udp.\n"); |
460 | goto cleanup_tcp; | 475 | goto cleanup_tcp; |
461 | } | 476 | } |
462 | 477 | ||
463 | ret = nf_conntrack_protocol_register(&nf_conntrack_protocol_icmp); | 478 | ret = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_icmp); |
464 | if (ret < 0) { | 479 | if (ret < 0) { |
465 | printk("nf_conntrack_ipv4: can't register icmp.\n"); | 480 | printk("nf_conntrack_ipv4: can't register icmp.\n"); |
466 | goto cleanup_udp; | 481 | goto cleanup_udp; |
@@ -478,28 +493,24 @@ static int __init nf_conntrack_l3proto_ipv4_init(void) | |||
478 | printk("nf_conntrack_ipv4: can't register hooks.\n"); | 493 | printk("nf_conntrack_ipv4: can't register hooks.\n"); |
479 | goto cleanup_ipv4; | 494 | goto cleanup_ipv4; |
480 | } | 495 | } |
481 | #ifdef CONFIG_SYSCTL | 496 | #if defined(CONFIG_PROC_FS) && defined(CONFIG_NF_CONNTRACK_PROC_COMPAT) |
482 | nf_ct_ipv4_sysctl_header = register_sysctl_table(nf_ct_net_table, 0); | 497 | ret = nf_conntrack_ipv4_compat_init(); |
483 | if (nf_ct_ipv4_sysctl_header == NULL) { | 498 | if (ret < 0) |
484 | printk("nf_conntrack: can't register to sysctl.\n"); | ||
485 | ret = -ENOMEM; | ||
486 | goto cleanup_hooks; | 499 | goto cleanup_hooks; |
487 | } | ||
488 | #endif | 500 | #endif |
489 | return ret; | 501 | return ret; |
490 | 502 | #if defined(CONFIG_PROC_FS) && defined(CONFIG_NF_CONNTRACK_PROC_COMPAT) | |
491 | #ifdef CONFIG_SYSCTL | ||
492 | cleanup_hooks: | 503 | cleanup_hooks: |
493 | nf_unregister_hooks(ipv4_conntrack_ops, ARRAY_SIZE(ipv4_conntrack_ops)); | 504 | nf_unregister_hooks(ipv4_conntrack_ops, ARRAY_SIZE(ipv4_conntrack_ops)); |
494 | #endif | 505 | #endif |
495 | cleanup_ipv4: | 506 | cleanup_ipv4: |
496 | nf_conntrack_l3proto_unregister(&nf_conntrack_l3proto_ipv4); | 507 | nf_conntrack_l3proto_unregister(&nf_conntrack_l3proto_ipv4); |
497 | cleanup_icmp: | 508 | cleanup_icmp: |
498 | nf_conntrack_protocol_unregister(&nf_conntrack_protocol_icmp); | 509 | nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_icmp); |
499 | cleanup_udp: | 510 | cleanup_udp: |
500 | nf_conntrack_protocol_unregister(&nf_conntrack_protocol_udp4); | 511 | nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_udp4); |
501 | cleanup_tcp: | 512 | cleanup_tcp: |
502 | nf_conntrack_protocol_unregister(&nf_conntrack_protocol_tcp4); | 513 | nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_tcp4); |
503 | cleanup_sockopt: | 514 | cleanup_sockopt: |
504 | nf_unregister_sockopt(&so_getorigdst); | 515 | nf_unregister_sockopt(&so_getorigdst); |
505 | return ret; | 516 | return ret; |
@@ -508,18 +519,16 @@ static int __init nf_conntrack_l3proto_ipv4_init(void) | |||
508 | static void __exit nf_conntrack_l3proto_ipv4_fini(void) | 519 | static void __exit nf_conntrack_l3proto_ipv4_fini(void) |
509 | { | 520 | { |
510 | synchronize_net(); | 521 | synchronize_net(); |
511 | #ifdef CONFIG_SYSCTL | 522 | #if defined(CONFIG_PROC_FS) && defined(CONFIG_NF_CONNTRACK_PROC_COMPAT) |
512 | unregister_sysctl_table(nf_ct_ipv4_sysctl_header); | 523 | nf_conntrack_ipv4_compat_fini(); |
513 | #endif | 524 | #endif |
514 | nf_unregister_hooks(ipv4_conntrack_ops, ARRAY_SIZE(ipv4_conntrack_ops)); | 525 | nf_unregister_hooks(ipv4_conntrack_ops, ARRAY_SIZE(ipv4_conntrack_ops)); |
515 | nf_conntrack_l3proto_unregister(&nf_conntrack_l3proto_ipv4); | 526 | nf_conntrack_l3proto_unregister(&nf_conntrack_l3proto_ipv4); |
516 | nf_conntrack_protocol_unregister(&nf_conntrack_protocol_icmp); | 527 | nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_icmp); |
517 | nf_conntrack_protocol_unregister(&nf_conntrack_protocol_udp4); | 528 | nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_udp4); |
518 | nf_conntrack_protocol_unregister(&nf_conntrack_protocol_tcp4); | 529 | nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_tcp4); |
519 | nf_unregister_sockopt(&so_getorigdst); | 530 | nf_unregister_sockopt(&so_getorigdst); |
520 | } | 531 | } |
521 | 532 | ||
522 | module_init(nf_conntrack_l3proto_ipv4_init); | 533 | module_init(nf_conntrack_l3proto_ipv4_init); |
523 | module_exit(nf_conntrack_l3proto_ipv4_fini); | 534 | module_exit(nf_conntrack_l3proto_ipv4_fini); |
524 | |||
525 | EXPORT_SYMBOL(nf_ct_ipv4_gather_frags); | ||
diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c new file mode 100644 index 000000000000..3b31bc649608 --- /dev/null +++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c | |||
@@ -0,0 +1,412 @@ | |||
1 | /* ip_conntrack proc compat - based on ip_conntrack_standalone.c | ||
2 | * | ||
3 | * (C) 1999-2001 Paul `Rusty' Russell | ||
4 | * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | #include <linux/types.h> | ||
11 | #include <linux/proc_fs.h> | ||
12 | #include <linux/seq_file.h> | ||
13 | #include <linux/percpu.h> | ||
14 | |||
15 | #include <linux/netfilter.h> | ||
16 | #include <net/netfilter/nf_conntrack_core.h> | ||
17 | #include <net/netfilter/nf_conntrack_l3proto.h> | ||
18 | #include <net/netfilter/nf_conntrack_l4proto.h> | ||
19 | #include <net/netfilter/nf_conntrack_expect.h> | ||
20 | |||
21 | #if 0 | ||
22 | #define DEBUGP printk | ||
23 | #else | ||
24 | #define DEBUGP(format, args...) | ||
25 | #endif | ||
26 | |||
27 | #ifdef CONFIG_NF_CT_ACCT | ||
28 | static unsigned int | ||
29 | seq_print_counters(struct seq_file *s, | ||
30 | const struct ip_conntrack_counter *counter) | ||
31 | { | ||
32 | return seq_printf(s, "packets=%llu bytes=%llu ", | ||
33 | (unsigned long long)counter->packets, | ||
34 | (unsigned long long)counter->bytes); | ||
35 | } | ||
36 | #else | ||
37 | #define seq_print_counters(x, y) 0 | ||
38 | #endif | ||
39 | |||
40 | struct ct_iter_state { | ||
41 | unsigned int bucket; | ||
42 | }; | ||
43 | |||
44 | static struct list_head *ct_get_first(struct seq_file *seq) | ||
45 | { | ||
46 | struct ct_iter_state *st = seq->private; | ||
47 | |||
48 | for (st->bucket = 0; | ||
49 | st->bucket < nf_conntrack_htable_size; | ||
50 | st->bucket++) { | ||
51 | if (!list_empty(&nf_conntrack_hash[st->bucket])) | ||
52 | return nf_conntrack_hash[st->bucket].next; | ||
53 | } | ||
54 | return NULL; | ||
55 | } | ||
56 | |||
57 | static struct list_head *ct_get_next(struct seq_file *seq, struct list_head *head) | ||
58 | { | ||
59 | struct ct_iter_state *st = seq->private; | ||
60 | |||
61 | head = head->next; | ||
62 | while (head == &nf_conntrack_hash[st->bucket]) { | ||
63 | if (++st->bucket >= nf_conntrack_htable_size) | ||
64 | return NULL; | ||
65 | head = nf_conntrack_hash[st->bucket].next; | ||
66 | } | ||
67 | return head; | ||
68 | } | ||
69 | |||
70 | static struct list_head *ct_get_idx(struct seq_file *seq, loff_t pos) | ||
71 | { | ||
72 | struct list_head *head = ct_get_first(seq); | ||
73 | |||
74 | if (head) | ||
75 | while (pos && (head = ct_get_next(seq, head))) | ||
76 | pos--; | ||
77 | return pos ? NULL : head; | ||
78 | } | ||
79 | |||
80 | static void *ct_seq_start(struct seq_file *seq, loff_t *pos) | ||
81 | { | ||
82 | read_lock_bh(&nf_conntrack_lock); | ||
83 | return ct_get_idx(seq, *pos); | ||
84 | } | ||
85 | |||
86 | static void *ct_seq_next(struct seq_file *s, void *v, loff_t *pos) | ||
87 | { | ||
88 | (*pos)++; | ||
89 | return ct_get_next(s, v); | ||
90 | } | ||
91 | |||
92 | static void ct_seq_stop(struct seq_file *s, void *v) | ||
93 | { | ||
94 | read_unlock_bh(&nf_conntrack_lock); | ||
95 | } | ||
96 | |||
97 | static int ct_seq_show(struct seq_file *s, void *v) | ||
98 | { | ||
99 | const struct nf_conntrack_tuple_hash *hash = v; | ||
100 | const struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(hash); | ||
101 | struct nf_conntrack_l3proto *l3proto; | ||
102 | struct nf_conntrack_l4proto *l4proto; | ||
103 | |||
104 | NF_CT_ASSERT(ct); | ||
105 | |||
106 | /* we only want to print DIR_ORIGINAL */ | ||
107 | if (NF_CT_DIRECTION(hash)) | ||
108 | return 0; | ||
109 | if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num != AF_INET) | ||
110 | return 0; | ||
111 | |||
112 | l3proto = __nf_ct_l3proto_find(ct->tuplehash[IP_CT_DIR_ORIGINAL] | ||
113 | .tuple.src.l3num); | ||
114 | NF_CT_ASSERT(l3proto); | ||
115 | l4proto = __nf_ct_l4proto_find(ct->tuplehash[IP_CT_DIR_ORIGINAL] | ||
116 | .tuple.src.l3num, | ||
117 | ct->tuplehash[IP_CT_DIR_ORIGINAL] | ||
118 | .tuple.dst.protonum); | ||
119 | NF_CT_ASSERT(l4proto); | ||
120 | |||
121 | if (seq_printf(s, "%-8s %u %ld ", | ||
122 | l4proto->name, | ||
123 | ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum, | ||
124 | timer_pending(&ct->timeout) | ||
125 | ? (long)(ct->timeout.expires - jiffies)/HZ : 0) != 0) | ||
126 | return -ENOSPC; | ||
127 | |||
128 | if (l3proto->print_conntrack(s, ct)) | ||
129 | return -ENOSPC; | ||
130 | |||
131 | if (l4proto->print_conntrack(s, ct)) | ||
132 | return -ENOSPC; | ||
133 | |||
134 | if (print_tuple(s, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, | ||
135 | l3proto, l4proto)) | ||
136 | return -ENOSPC; | ||
137 | |||
138 | if (seq_print_counters(s, &ct->counters[IP_CT_DIR_ORIGINAL])) | ||
139 | return -ENOSPC; | ||
140 | |||
141 | if (!(test_bit(IPS_SEEN_REPLY_BIT, &ct->status))) | ||
142 | if (seq_printf(s, "[UNREPLIED] ")) | ||
143 | return -ENOSPC; | ||
144 | |||
145 | if (print_tuple(s, &ct->tuplehash[IP_CT_DIR_REPLY].tuple, | ||
146 | l3proto, l4proto)) | ||
147 | return -ENOSPC; | ||
148 | |||
149 | if (seq_print_counters(s, &ct->counters[IP_CT_DIR_REPLY])) | ||
150 | return -ENOSPC; | ||
151 | |||
152 | if (test_bit(IPS_ASSURED_BIT, &ct->status)) | ||
153 | if (seq_printf(s, "[ASSURED] ")) | ||
154 | return -ENOSPC; | ||
155 | |||
156 | #ifdef CONFIG_NF_CONNTRACK_MARK | ||
157 | if (seq_printf(s, "mark=%u ", ct->mark)) | ||
158 | return -ENOSPC; | ||
159 | #endif | ||
160 | |||
161 | #ifdef CONFIG_NF_CONNTRACK_SECMARK | ||
162 | if (seq_printf(s, "secmark=%u ", ct->secmark)) | ||
163 | return -ENOSPC; | ||
164 | #endif | ||
165 | |||
166 | if (seq_printf(s, "use=%u\n", atomic_read(&ct->ct_general.use))) | ||
167 | return -ENOSPC; | ||
168 | |||
169 | return 0; | ||
170 | } | ||
171 | |||
172 | static struct seq_operations ct_seq_ops = { | ||
173 | .start = ct_seq_start, | ||
174 | .next = ct_seq_next, | ||
175 | .stop = ct_seq_stop, | ||
176 | .show = ct_seq_show | ||
177 | }; | ||
178 | |||
179 | static int ct_open(struct inode *inode, struct file *file) | ||
180 | { | ||
181 | struct seq_file *seq; | ||
182 | struct ct_iter_state *st; | ||
183 | int ret; | ||
184 | |||
185 | st = kmalloc(sizeof(struct ct_iter_state), GFP_KERNEL); | ||
186 | if (st == NULL) | ||
187 | return -ENOMEM; | ||
188 | ret = seq_open(file, &ct_seq_ops); | ||
189 | if (ret) | ||
190 | goto out_free; | ||
191 | seq = file->private_data; | ||
192 | seq->private = st; | ||
193 | memset(st, 0, sizeof(struct ct_iter_state)); | ||
194 | return ret; | ||
195 | out_free: | ||
196 | kfree(st); | ||
197 | return ret; | ||
198 | } | ||
199 | |||
200 | static struct file_operations ct_file_ops = { | ||
201 | .owner = THIS_MODULE, | ||
202 | .open = ct_open, | ||
203 | .read = seq_read, | ||
204 | .llseek = seq_lseek, | ||
205 | .release = seq_release_private, | ||
206 | }; | ||
207 | |||
208 | /* expects */ | ||
209 | static void *exp_seq_start(struct seq_file *s, loff_t *pos) | ||
210 | { | ||
211 | struct list_head *e = &nf_conntrack_expect_list; | ||
212 | loff_t i; | ||
213 | |||
214 | /* strange seq_file api calls stop even if we fail, | ||
215 | * thus we need to grab lock since stop unlocks */ | ||
216 | read_lock_bh(&nf_conntrack_lock); | ||
217 | |||
218 | if (list_empty(e)) | ||
219 | return NULL; | ||
220 | |||
221 | for (i = 0; i <= *pos; i++) { | ||
222 | e = e->next; | ||
223 | if (e == &nf_conntrack_expect_list) | ||
224 | return NULL; | ||
225 | } | ||
226 | return e; | ||
227 | } | ||
228 | |||
229 | static void *exp_seq_next(struct seq_file *s, void *v, loff_t *pos) | ||
230 | { | ||
231 | struct list_head *e = v; | ||
232 | |||
233 | ++*pos; | ||
234 | e = e->next; | ||
235 | |||
236 | if (e == &nf_conntrack_expect_list) | ||
237 | return NULL; | ||
238 | |||
239 | return e; | ||
240 | } | ||
241 | |||
242 | static void exp_seq_stop(struct seq_file *s, void *v) | ||
243 | { | ||
244 | read_unlock_bh(&nf_conntrack_lock); | ||
245 | } | ||
246 | |||
247 | static int exp_seq_show(struct seq_file *s, void *v) | ||
248 | { | ||
249 | struct nf_conntrack_expect *exp = v; | ||
250 | |||
251 | if (exp->tuple.src.l3num != AF_INET) | ||
252 | return 0; | ||
253 | |||
254 | if (exp->timeout.function) | ||
255 | seq_printf(s, "%ld ", timer_pending(&exp->timeout) | ||
256 | ? (long)(exp->timeout.expires - jiffies)/HZ : 0); | ||
257 | else | ||
258 | seq_printf(s, "- "); | ||
259 | |||
260 | seq_printf(s, "proto=%u ", exp->tuple.dst.protonum); | ||
261 | |||
262 | print_tuple(s, &exp->tuple, | ||
263 | __nf_ct_l3proto_find(exp->tuple.src.l3num), | ||
264 | __nf_ct_l4proto_find(exp->tuple.src.l3num, | ||
265 | exp->tuple.dst.protonum)); | ||
266 | return seq_putc(s, '\n'); | ||
267 | } | ||
268 | |||
269 | static struct seq_operations exp_seq_ops = { | ||
270 | .start = exp_seq_start, | ||
271 | .next = exp_seq_next, | ||
272 | .stop = exp_seq_stop, | ||
273 | .show = exp_seq_show | ||
274 | }; | ||
275 | |||
276 | static int exp_open(struct inode *inode, struct file *file) | ||
277 | { | ||
278 | return seq_open(file, &exp_seq_ops); | ||
279 | } | ||
280 | |||
281 | static struct file_operations ip_exp_file_ops = { | ||
282 | .owner = THIS_MODULE, | ||
283 | .open = exp_open, | ||
284 | .read = seq_read, | ||
285 | .llseek = seq_lseek, | ||
286 | .release = seq_release | ||
287 | }; | ||
288 | |||
289 | static void *ct_cpu_seq_start(struct seq_file *seq, loff_t *pos) | ||
290 | { | ||
291 | int cpu; | ||
292 | |||
293 | if (*pos == 0) | ||
294 | return SEQ_START_TOKEN; | ||
295 | |||
296 | for (cpu = *pos-1; cpu < NR_CPUS; ++cpu) { | ||
297 | if (!cpu_possible(cpu)) | ||
298 | continue; | ||
299 | *pos = cpu+1; | ||
300 | return &per_cpu(nf_conntrack_stat, cpu); | ||
301 | } | ||
302 | |||
303 | return NULL; | ||
304 | } | ||
305 | |||
306 | static void *ct_cpu_seq_next(struct seq_file *seq, void *v, loff_t *pos) | ||
307 | { | ||
308 | int cpu; | ||
309 | |||
310 | for (cpu = *pos; cpu < NR_CPUS; ++cpu) { | ||
311 | if (!cpu_possible(cpu)) | ||
312 | continue; | ||
313 | *pos = cpu+1; | ||
314 | return &per_cpu(nf_conntrack_stat, cpu); | ||
315 | } | ||
316 | |||
317 | return NULL; | ||
318 | } | ||
319 | |||
320 | static void ct_cpu_seq_stop(struct seq_file *seq, void *v) | ||
321 | { | ||
322 | } | ||
323 | |||
324 | static int ct_cpu_seq_show(struct seq_file *seq, void *v) | ||
325 | { | ||
326 | unsigned int nr_conntracks = atomic_read(&nf_conntrack_count); | ||
327 | struct ip_conntrack_stat *st = v; | ||
328 | |||
329 | if (v == SEQ_START_TOKEN) { | ||
330 | seq_printf(seq, "entries searched found new invalid ignore delete delete_list insert insert_failed drop early_drop icmp_error expect_new expect_create expect_delete\n"); | ||
331 | return 0; | ||
332 | } | ||
333 | |||
334 | seq_printf(seq, "%08x %08x %08x %08x %08x %08x %08x %08x " | ||
335 | "%08x %08x %08x %08x %08x %08x %08x %08x \n", | ||
336 | nr_conntracks, | ||
337 | st->searched, | ||
338 | st->found, | ||
339 | st->new, | ||
340 | st->invalid, | ||
341 | st->ignore, | ||
342 | st->delete, | ||
343 | st->delete_list, | ||
344 | st->insert, | ||
345 | st->insert_failed, | ||
346 | st->drop, | ||
347 | st->early_drop, | ||
348 | st->error, | ||
349 | |||
350 | st->expect_new, | ||
351 | st->expect_create, | ||
352 | st->expect_delete | ||
353 | ); | ||
354 | return 0; | ||
355 | } | ||
356 | |||
357 | static struct seq_operations ct_cpu_seq_ops = { | ||
358 | .start = ct_cpu_seq_start, | ||
359 | .next = ct_cpu_seq_next, | ||
360 | .stop = ct_cpu_seq_stop, | ||
361 | .show = ct_cpu_seq_show, | ||
362 | }; | ||
363 | |||
364 | static int ct_cpu_seq_open(struct inode *inode, struct file *file) | ||
365 | { | ||
366 | return seq_open(file, &ct_cpu_seq_ops); | ||
367 | } | ||
368 | |||
369 | static struct file_operations ct_cpu_seq_fops = { | ||
370 | .owner = THIS_MODULE, | ||
371 | .open = ct_cpu_seq_open, | ||
372 | .read = seq_read, | ||
373 | .llseek = seq_lseek, | ||
374 | .release = seq_release_private, | ||
375 | }; | ||
376 | |||
377 | int __init nf_conntrack_ipv4_compat_init(void) | ||
378 | { | ||
379 | struct proc_dir_entry *proc, *proc_exp, *proc_stat; | ||
380 | |||
381 | proc = proc_net_fops_create("ip_conntrack", 0440, &ct_file_ops); | ||
382 | if (!proc) | ||
383 | goto err1; | ||
384 | |||
385 | proc_exp = proc_net_fops_create("ip_conntrack_expect", 0440, | ||
386 | &ip_exp_file_ops); | ||
387 | if (!proc_exp) | ||
388 | goto err2; | ||
389 | |||
390 | proc_stat = create_proc_entry("ip_conntrack", S_IRUGO, proc_net_stat); | ||
391 | if (!proc_stat) | ||
392 | goto err3; | ||
393 | |||
394 | proc_stat->proc_fops = &ct_cpu_seq_fops; | ||
395 | proc_stat->owner = THIS_MODULE; | ||
396 | |||
397 | return 0; | ||
398 | |||
399 | err3: | ||
400 | proc_net_remove("ip_conntrack_expect"); | ||
401 | err2: | ||
402 | proc_net_remove("ip_conntrack"); | ||
403 | err1: | ||
404 | return -ENOMEM; | ||
405 | } | ||
406 | |||
407 | void __exit nf_conntrack_ipv4_compat_fini(void) | ||
408 | { | ||
409 | remove_proc_entry("ip_conntrack", proc_net_stat); | ||
410 | proc_net_remove("ip_conntrack_expect"); | ||
411 | proc_net_remove("ip_conntrack"); | ||
412 | } | ||
diff --git a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c index 790f00d500c3..db9e7c45d3b4 100644 --- a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c +++ b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c | |||
@@ -22,10 +22,10 @@ | |||
22 | #include <net/checksum.h> | 22 | #include <net/checksum.h> |
23 | #include <linux/netfilter_ipv4.h> | 23 | #include <linux/netfilter_ipv4.h> |
24 | #include <net/netfilter/nf_conntrack_tuple.h> | 24 | #include <net/netfilter/nf_conntrack_tuple.h> |
25 | #include <net/netfilter/nf_conntrack_protocol.h> | 25 | #include <net/netfilter/nf_conntrack_l4proto.h> |
26 | #include <net/netfilter/nf_conntrack_core.h> | 26 | #include <net/netfilter/nf_conntrack_core.h> |
27 | 27 | ||
28 | unsigned long nf_ct_icmp_timeout __read_mostly = 30*HZ; | 28 | static unsigned long nf_ct_icmp_timeout __read_mostly = 30*HZ; |
29 | 29 | ||
30 | #if 0 | 30 | #if 0 |
31 | #define DEBUGP printk | 31 | #define DEBUGP printk |
@@ -152,7 +152,7 @@ icmp_error_message(struct sk_buff *skb, | |||
152 | struct icmphdr icmp; | 152 | struct icmphdr icmp; |
153 | struct iphdr ip; | 153 | struct iphdr ip; |
154 | } _in, *inside; | 154 | } _in, *inside; |
155 | struct nf_conntrack_protocol *innerproto; | 155 | struct nf_conntrack_l4proto *innerproto; |
156 | struct nf_conntrack_tuple_hash *h; | 156 | struct nf_conntrack_tuple_hash *h; |
157 | int dataoff; | 157 | int dataoff; |
158 | 158 | ||
@@ -170,7 +170,7 @@ icmp_error_message(struct sk_buff *skb, | |||
170 | return -NF_ACCEPT; | 170 | return -NF_ACCEPT; |
171 | } | 171 | } |
172 | 172 | ||
173 | innerproto = __nf_ct_proto_find(PF_INET, inside->ip.protocol); | 173 | innerproto = __nf_ct_l4proto_find(PF_INET, inside->ip.protocol); |
174 | dataoff = skb->nh.iph->ihl*4 + sizeof(inside->icmp); | 174 | dataoff = skb->nh.iph->ihl*4 + sizeof(inside->icmp); |
175 | /* Are they talking about one of our connections? */ | 175 | /* Are they talking about one of our connections? */ |
176 | if (!nf_ct_get_tuple(skb, dataoff, dataoff + inside->ip.ihl*4, PF_INET, | 176 | if (!nf_ct_get_tuple(skb, dataoff, dataoff + inside->ip.ihl*4, PF_INET, |
@@ -311,7 +311,7 @@ static int icmp_nfattr_to_tuple(struct nfattr *tb[], | |||
311 | tuple->dst.u.icmp.code = | 311 | tuple->dst.u.icmp.code = |
312 | *(u_int8_t *)NFA_DATA(tb[CTA_PROTO_ICMP_CODE-1]); | 312 | *(u_int8_t *)NFA_DATA(tb[CTA_PROTO_ICMP_CODE-1]); |
313 | tuple->src.u.icmp.id = | 313 | tuple->src.u.icmp.id = |
314 | *(u_int16_t *)NFA_DATA(tb[CTA_PROTO_ICMP_ID-1]); | 314 | *(__be16 *)NFA_DATA(tb[CTA_PROTO_ICMP_ID-1]); |
315 | 315 | ||
316 | if (tuple->dst.u.icmp.type >= sizeof(invmap) | 316 | if (tuple->dst.u.icmp.type >= sizeof(invmap) |
317 | || !invmap[tuple->dst.u.icmp.type]) | 317 | || !invmap[tuple->dst.u.icmp.type]) |
@@ -321,11 +321,42 @@ static int icmp_nfattr_to_tuple(struct nfattr *tb[], | |||
321 | } | 321 | } |
322 | #endif | 322 | #endif |
323 | 323 | ||
324 | struct nf_conntrack_protocol nf_conntrack_protocol_icmp = | 324 | #ifdef CONFIG_SYSCTL |
325 | static struct ctl_table_header *icmp_sysctl_header; | ||
326 | static struct ctl_table icmp_sysctl_table[] = { | ||
327 | { | ||
328 | .ctl_name = NET_NF_CONNTRACK_ICMP_TIMEOUT, | ||
329 | .procname = "nf_conntrack_icmp_timeout", | ||
330 | .data = &nf_ct_icmp_timeout, | ||
331 | .maxlen = sizeof(unsigned int), | ||
332 | .mode = 0644, | ||
333 | .proc_handler = &proc_dointvec_jiffies, | ||
334 | }, | ||
335 | { | ||
336 | .ctl_name = 0 | ||
337 | } | ||
338 | }; | ||
339 | #ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT | ||
340 | static struct ctl_table icmp_compat_sysctl_table[] = { | ||
341 | { | ||
342 | .ctl_name = NET_IPV4_NF_CONNTRACK_ICMP_TIMEOUT, | ||
343 | .procname = "ip_conntrack_icmp_timeout", | ||
344 | .data = &nf_ct_icmp_timeout, | ||
345 | .maxlen = sizeof(unsigned int), | ||
346 | .mode = 0644, | ||
347 | .proc_handler = &proc_dointvec_jiffies, | ||
348 | }, | ||
349 | { | ||
350 | .ctl_name = 0 | ||
351 | } | ||
352 | }; | ||
353 | #endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */ | ||
354 | #endif /* CONFIG_SYSCTL */ | ||
355 | |||
356 | struct nf_conntrack_l4proto nf_conntrack_l4proto_icmp = | ||
325 | { | 357 | { |
326 | .list = { NULL, NULL }, | ||
327 | .l3proto = PF_INET, | 358 | .l3proto = PF_INET, |
328 | .proto = IPPROTO_ICMP, | 359 | .l4proto = IPPROTO_ICMP, |
329 | .name = "icmp", | 360 | .name = "icmp", |
330 | .pkt_to_tuple = icmp_pkt_to_tuple, | 361 | .pkt_to_tuple = icmp_pkt_to_tuple, |
331 | .invert_tuple = icmp_invert_tuple, | 362 | .invert_tuple = icmp_invert_tuple, |
@@ -341,6 +372,12 @@ struct nf_conntrack_protocol nf_conntrack_protocol_icmp = | |||
341 | .tuple_to_nfattr = icmp_tuple_to_nfattr, | 372 | .tuple_to_nfattr = icmp_tuple_to_nfattr, |
342 | .nfattr_to_tuple = icmp_nfattr_to_tuple, | 373 | .nfattr_to_tuple = icmp_nfattr_to_tuple, |
343 | #endif | 374 | #endif |
375 | #ifdef CONFIG_SYSCTL | ||
376 | .ctl_table_header = &icmp_sysctl_header, | ||
377 | .ctl_table = icmp_sysctl_table, | ||
378 | #ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT | ||
379 | .ctl_compat_table = icmp_compat_sysctl_table, | ||
380 | #endif | ||
381 | #endif | ||
344 | }; | 382 | }; |
345 | 383 | EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_icmp); | |
346 | EXPORT_SYMBOL(nf_conntrack_protocol_icmp); | ||
diff --git a/net/ipv4/netfilter/nf_nat_amanda.c b/net/ipv4/netfilter/nf_nat_amanda.c new file mode 100644 index 000000000000..0f17098917bc --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_amanda.c | |||
@@ -0,0 +1,78 @@ | |||
1 | /* Amanda extension for TCP NAT alteration. | ||
2 | * (C) 2002 by Brian J. Murrell <netfilter@interlinx.bc.ca> | ||
3 | * based on a copy of HW's ip_nat_irc.c as well as other modules | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU General Public License | ||
7 | * as published by the Free Software Foundation; either version | ||
8 | * 2 of the License, or (at your option) any later version. | ||
9 | */ | ||
10 | |||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/skbuff.h> | ||
14 | #include <linux/udp.h> | ||
15 | |||
16 | #include <net/netfilter/nf_nat_helper.h> | ||
17 | #include <net/netfilter/nf_nat_rule.h> | ||
18 | #include <net/netfilter/nf_conntrack_helper.h> | ||
19 | #include <net/netfilter/nf_conntrack_expect.h> | ||
20 | #include <linux/netfilter/nf_conntrack_amanda.h> | ||
21 | |||
22 | MODULE_AUTHOR("Brian J. Murrell <netfilter@interlinx.bc.ca>"); | ||
23 | MODULE_DESCRIPTION("Amanda NAT helper"); | ||
24 | MODULE_LICENSE("GPL"); | ||
25 | MODULE_ALIAS("ip_nat_amanda"); | ||
26 | |||
27 | static unsigned int help(struct sk_buff **pskb, | ||
28 | enum ip_conntrack_info ctinfo, | ||
29 | unsigned int matchoff, | ||
30 | unsigned int matchlen, | ||
31 | struct nf_conntrack_expect *exp) | ||
32 | { | ||
33 | char buffer[sizeof("65535")]; | ||
34 | u_int16_t port; | ||
35 | unsigned int ret; | ||
36 | |||
37 | /* Connection comes from client. */ | ||
38 | exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port; | ||
39 | exp->dir = IP_CT_DIR_ORIGINAL; | ||
40 | |||
41 | /* When you see the packet, we need to NAT it the same as the | ||
42 | * this one (ie. same IP: it will be TCP and master is UDP). */ | ||
43 | exp->expectfn = nf_nat_follow_master; | ||
44 | |||
45 | /* Try to get same port: if not, try to change it. */ | ||
46 | for (port = ntohs(exp->saved_proto.tcp.port); port != 0; port++) { | ||
47 | exp->tuple.dst.u.tcp.port = htons(port); | ||
48 | if (nf_conntrack_expect_related(exp) == 0) | ||
49 | break; | ||
50 | } | ||
51 | |||
52 | if (port == 0) | ||
53 | return NF_DROP; | ||
54 | |||
55 | sprintf(buffer, "%u", port); | ||
56 | ret = nf_nat_mangle_udp_packet(pskb, exp->master, ctinfo, | ||
57 | matchoff, matchlen, | ||
58 | buffer, strlen(buffer)); | ||
59 | if (ret != NF_ACCEPT) | ||
60 | nf_conntrack_unexpect_related(exp); | ||
61 | return ret; | ||
62 | } | ||
63 | |||
64 | static void __exit nf_nat_amanda_fini(void) | ||
65 | { | ||
66 | rcu_assign_pointer(nf_nat_amanda_hook, NULL); | ||
67 | synchronize_rcu(); | ||
68 | } | ||
69 | |||
70 | static int __init nf_nat_amanda_init(void) | ||
71 | { | ||
72 | BUG_ON(rcu_dereference(nf_nat_amanda_hook)); | ||
73 | rcu_assign_pointer(nf_nat_amanda_hook, help); | ||
74 | return 0; | ||
75 | } | ||
76 | |||
77 | module_init(nf_nat_amanda_init); | ||
78 | module_exit(nf_nat_amanda_fini); | ||
diff --git a/net/ipv4/netfilter/nf_nat_core.c b/net/ipv4/netfilter/nf_nat_core.c new file mode 100644 index 000000000000..86a92272b053 --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_core.c | |||
@@ -0,0 +1,647 @@ | |||
1 | /* NAT for netfilter; shared with compatibility layer. */ | ||
2 | |||
3 | /* (C) 1999-2001 Paul `Rusty' Russell | ||
4 | * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #include <linux/module.h> | ||
12 | #include <linux/types.h> | ||
13 | #include <linux/timer.h> | ||
14 | #include <linux/skbuff.h> | ||
15 | #include <linux/vmalloc.h> | ||
16 | #include <net/checksum.h> | ||
17 | #include <net/icmp.h> | ||
18 | #include <net/ip.h> | ||
19 | #include <net/tcp.h> /* For tcp_prot in getorigdst */ | ||
20 | #include <linux/icmp.h> | ||
21 | #include <linux/udp.h> | ||
22 | #include <linux/jhash.h> | ||
23 | |||
24 | #include <linux/netfilter_ipv4.h> | ||
25 | #include <net/netfilter/nf_conntrack.h> | ||
26 | #include <net/netfilter/nf_conntrack_core.h> | ||
27 | #include <net/netfilter/nf_nat.h> | ||
28 | #include <net/netfilter/nf_nat_protocol.h> | ||
29 | #include <net/netfilter/nf_nat_core.h> | ||
30 | #include <net/netfilter/nf_nat_helper.h> | ||
31 | #include <net/netfilter/nf_conntrack_helper.h> | ||
32 | #include <net/netfilter/nf_conntrack_l3proto.h> | ||
33 | #include <net/netfilter/nf_conntrack_l4proto.h> | ||
34 | |||
35 | #if 0 | ||
36 | #define DEBUGP printk | ||
37 | #else | ||
38 | #define DEBUGP(format, args...) | ||
39 | #endif | ||
40 | |||
41 | static DEFINE_RWLOCK(nf_nat_lock); | ||
42 | |||
43 | static struct nf_conntrack_l3proto *l3proto = NULL; | ||
44 | |||
45 | /* Calculated at init based on memory size */ | ||
46 | static unsigned int nf_nat_htable_size; | ||
47 | |||
48 | static struct list_head *bysource; | ||
49 | |||
50 | #define MAX_IP_NAT_PROTO 256 | ||
51 | static struct nf_nat_protocol *nf_nat_protos[MAX_IP_NAT_PROTO]; | ||
52 | |||
53 | static inline struct nf_nat_protocol * | ||
54 | __nf_nat_proto_find(u_int8_t protonum) | ||
55 | { | ||
56 | return nf_nat_protos[protonum]; | ||
57 | } | ||
58 | |||
59 | struct nf_nat_protocol * | ||
60 | nf_nat_proto_find_get(u_int8_t protonum) | ||
61 | { | ||
62 | struct nf_nat_protocol *p; | ||
63 | |||
64 | /* we need to disable preemption to make sure 'p' doesn't get | ||
65 | * removed until we've grabbed the reference */ | ||
66 | preempt_disable(); | ||
67 | p = __nf_nat_proto_find(protonum); | ||
68 | if (!try_module_get(p->me)) | ||
69 | p = &nf_nat_unknown_protocol; | ||
70 | preempt_enable(); | ||
71 | |||
72 | return p; | ||
73 | } | ||
74 | EXPORT_SYMBOL_GPL(nf_nat_proto_find_get); | ||
75 | |||
76 | void | ||
77 | nf_nat_proto_put(struct nf_nat_protocol *p) | ||
78 | { | ||
79 | module_put(p->me); | ||
80 | } | ||
81 | EXPORT_SYMBOL_GPL(nf_nat_proto_put); | ||
82 | |||
83 | /* We keep an extra hash for each conntrack, for fast searching. */ | ||
84 | static inline unsigned int | ||
85 | hash_by_src(const struct nf_conntrack_tuple *tuple) | ||
86 | { | ||
87 | /* Original src, to ensure we map it consistently if poss. */ | ||
88 | return jhash_3words((__force u32)tuple->src.u3.ip, tuple->src.u.all, | ||
89 | tuple->dst.protonum, 0) % nf_nat_htable_size; | ||
90 | } | ||
91 | |||
92 | /* Noone using conntrack by the time this called. */ | ||
93 | static void nf_nat_cleanup_conntrack(struct nf_conn *conn) | ||
94 | { | ||
95 | struct nf_conn_nat *nat; | ||
96 | if (!(conn->status & IPS_NAT_DONE_MASK)) | ||
97 | return; | ||
98 | |||
99 | nat = nfct_nat(conn); | ||
100 | write_lock_bh(&nf_nat_lock); | ||
101 | list_del(&nat->info.bysource); | ||
102 | write_unlock_bh(&nf_nat_lock); | ||
103 | } | ||
104 | |||
105 | /* Is this tuple already taken? (not by us) */ | ||
106 | int | ||
107 | nf_nat_used_tuple(const struct nf_conntrack_tuple *tuple, | ||
108 | const struct nf_conn *ignored_conntrack) | ||
109 | { | ||
110 | /* Conntrack tracking doesn't keep track of outgoing tuples; only | ||
111 | incoming ones. NAT means they don't have a fixed mapping, | ||
112 | so we invert the tuple and look for the incoming reply. | ||
113 | |||
114 | We could keep a separate hash if this proves too slow. */ | ||
115 | struct nf_conntrack_tuple reply; | ||
116 | |||
117 | nf_ct_invert_tuplepr(&reply, tuple); | ||
118 | return nf_conntrack_tuple_taken(&reply, ignored_conntrack); | ||
119 | } | ||
120 | EXPORT_SYMBOL(nf_nat_used_tuple); | ||
121 | |||
122 | /* If we source map this tuple so reply looks like reply_tuple, will | ||
123 | * that meet the constraints of range. */ | ||
124 | static int | ||
125 | in_range(const struct nf_conntrack_tuple *tuple, | ||
126 | const struct nf_nat_range *range) | ||
127 | { | ||
128 | struct nf_nat_protocol *proto; | ||
129 | |||
130 | proto = __nf_nat_proto_find(tuple->dst.protonum); | ||
131 | /* If we are supposed to map IPs, then we must be in the | ||
132 | range specified, otherwise let this drag us onto a new src IP. */ | ||
133 | if (range->flags & IP_NAT_RANGE_MAP_IPS) { | ||
134 | if (ntohl(tuple->src.u3.ip) < ntohl(range->min_ip) || | ||
135 | ntohl(tuple->src.u3.ip) > ntohl(range->max_ip)) | ||
136 | return 0; | ||
137 | } | ||
138 | |||
139 | if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED) || | ||
140 | proto->in_range(tuple, IP_NAT_MANIP_SRC, | ||
141 | &range->min, &range->max)) | ||
142 | return 1; | ||
143 | |||
144 | return 0; | ||
145 | } | ||
146 | |||
147 | static inline int | ||
148 | same_src(const struct nf_conn *ct, | ||
149 | const struct nf_conntrack_tuple *tuple) | ||
150 | { | ||
151 | const struct nf_conntrack_tuple *t; | ||
152 | |||
153 | t = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; | ||
154 | return (t->dst.protonum == tuple->dst.protonum && | ||
155 | t->src.u3.ip == tuple->src.u3.ip && | ||
156 | t->src.u.all == tuple->src.u.all); | ||
157 | } | ||
158 | |||
159 | /* Only called for SRC manip */ | ||
160 | static int | ||
161 | find_appropriate_src(const struct nf_conntrack_tuple *tuple, | ||
162 | struct nf_conntrack_tuple *result, | ||
163 | const struct nf_nat_range *range) | ||
164 | { | ||
165 | unsigned int h = hash_by_src(tuple); | ||
166 | struct nf_conn_nat *nat; | ||
167 | struct nf_conn *ct; | ||
168 | |||
169 | read_lock_bh(&nf_nat_lock); | ||
170 | list_for_each_entry(nat, &bysource[h], info.bysource) { | ||
171 | ct = (struct nf_conn *)((char *)nat - offsetof(struct nf_conn, data)); | ||
172 | if (same_src(ct, tuple)) { | ||
173 | /* Copy source part from reply tuple. */ | ||
174 | nf_ct_invert_tuplepr(result, | ||
175 | &ct->tuplehash[IP_CT_DIR_REPLY].tuple); | ||
176 | result->dst = tuple->dst; | ||
177 | |||
178 | if (in_range(result, range)) { | ||
179 | read_unlock_bh(&nf_nat_lock); | ||
180 | return 1; | ||
181 | } | ||
182 | } | ||
183 | } | ||
184 | read_unlock_bh(&nf_nat_lock); | ||
185 | return 0; | ||
186 | } | ||
187 | |||
188 | /* For [FUTURE] fragmentation handling, we want the least-used | ||
189 | src-ip/dst-ip/proto triple. Fairness doesn't come into it. Thus | ||
190 | if the range specifies 1.2.3.4 ports 10000-10005 and 1.2.3.5 ports | ||
191 | 1-65535, we don't do pro-rata allocation based on ports; we choose | ||
192 | the ip with the lowest src-ip/dst-ip/proto usage. | ||
193 | */ | ||
194 | static void | ||
195 | find_best_ips_proto(struct nf_conntrack_tuple *tuple, | ||
196 | const struct nf_nat_range *range, | ||
197 | const struct nf_conn *ct, | ||
198 | enum nf_nat_manip_type maniptype) | ||
199 | { | ||
200 | __be32 *var_ipp; | ||
201 | /* Host order */ | ||
202 | u_int32_t minip, maxip, j; | ||
203 | |||
204 | /* No IP mapping? Do nothing. */ | ||
205 | if (!(range->flags & IP_NAT_RANGE_MAP_IPS)) | ||
206 | return; | ||
207 | |||
208 | if (maniptype == IP_NAT_MANIP_SRC) | ||
209 | var_ipp = &tuple->src.u3.ip; | ||
210 | else | ||
211 | var_ipp = &tuple->dst.u3.ip; | ||
212 | |||
213 | /* Fast path: only one choice. */ | ||
214 | if (range->min_ip == range->max_ip) { | ||
215 | *var_ipp = range->min_ip; | ||
216 | return; | ||
217 | } | ||
218 | |||
219 | /* Hashing source and destination IPs gives a fairly even | ||
220 | * spread in practice (if there are a small number of IPs | ||
221 | * involved, there usually aren't that many connections | ||
222 | * anyway). The consistency means that servers see the same | ||
223 | * client coming from the same IP (some Internet Banking sites | ||
224 | * like this), even across reboots. */ | ||
225 | minip = ntohl(range->min_ip); | ||
226 | maxip = ntohl(range->max_ip); | ||
227 | j = jhash_2words((__force u32)tuple->src.u3.ip, | ||
228 | (__force u32)tuple->dst.u3.ip, 0); | ||
229 | *var_ipp = htonl(minip + j % (maxip - minip + 1)); | ||
230 | } | ||
231 | |||
232 | /* Manipulate the tuple into the range given. For NF_IP_POST_ROUTING, | ||
233 | * we change the source to map into the range. For NF_IP_PRE_ROUTING | ||
234 | * and NF_IP_LOCAL_OUT, we change the destination to map into the | ||
235 | * range. It might not be possible to get a unique tuple, but we try. | ||
236 | * At worst (or if we race), we will end up with a final duplicate in | ||
237 | * __ip_conntrack_confirm and drop the packet. */ | ||
238 | static void | ||
239 | get_unique_tuple(struct nf_conntrack_tuple *tuple, | ||
240 | const struct nf_conntrack_tuple *orig_tuple, | ||
241 | const struct nf_nat_range *range, | ||
242 | struct nf_conn *ct, | ||
243 | enum nf_nat_manip_type maniptype) | ||
244 | { | ||
245 | struct nf_nat_protocol *proto; | ||
246 | |||
247 | /* 1) If this srcip/proto/src-proto-part is currently mapped, | ||
248 | and that same mapping gives a unique tuple within the given | ||
249 | range, use that. | ||
250 | |||
251 | This is only required for source (ie. NAT/masq) mappings. | ||
252 | So far, we don't do local source mappings, so multiple | ||
253 | manips not an issue. */ | ||
254 | if (maniptype == IP_NAT_MANIP_SRC) { | ||
255 | if (find_appropriate_src(orig_tuple, tuple, range)) { | ||
256 | DEBUGP("get_unique_tuple: Found current src map\n"); | ||
257 | if (!nf_nat_used_tuple(tuple, ct)) | ||
258 | return; | ||
259 | } | ||
260 | } | ||
261 | |||
262 | /* 2) Select the least-used IP/proto combination in the given | ||
263 | range. */ | ||
264 | *tuple = *orig_tuple; | ||
265 | find_best_ips_proto(tuple, range, ct, maniptype); | ||
266 | |||
267 | /* 3) The per-protocol part of the manip is made to map into | ||
268 | the range to make a unique tuple. */ | ||
269 | |||
270 | proto = nf_nat_proto_find_get(orig_tuple->dst.protonum); | ||
271 | |||
272 | /* Only bother mapping if it's not already in range and unique */ | ||
273 | if ((!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED) || | ||
274 | proto->in_range(tuple, maniptype, &range->min, &range->max)) && | ||
275 | !nf_nat_used_tuple(tuple, ct)) { | ||
276 | nf_nat_proto_put(proto); | ||
277 | return; | ||
278 | } | ||
279 | |||
280 | /* Last change: get protocol to try to obtain unique tuple. */ | ||
281 | proto->unique_tuple(tuple, range, maniptype, ct); | ||
282 | |||
283 | nf_nat_proto_put(proto); | ||
284 | } | ||
285 | |||
286 | unsigned int | ||
287 | nf_nat_setup_info(struct nf_conn *ct, | ||
288 | const struct nf_nat_range *range, | ||
289 | unsigned int hooknum) | ||
290 | { | ||
291 | struct nf_conntrack_tuple curr_tuple, new_tuple; | ||
292 | struct nf_conn_nat *nat = nfct_nat(ct); | ||
293 | struct nf_nat_info *info = &nat->info; | ||
294 | int have_to_hash = !(ct->status & IPS_NAT_DONE_MASK); | ||
295 | enum nf_nat_manip_type maniptype = HOOK2MANIP(hooknum); | ||
296 | |||
297 | NF_CT_ASSERT(hooknum == NF_IP_PRE_ROUTING || | ||
298 | hooknum == NF_IP_POST_ROUTING || | ||
299 | hooknum == NF_IP_LOCAL_IN || | ||
300 | hooknum == NF_IP_LOCAL_OUT); | ||
301 | BUG_ON(nf_nat_initialized(ct, maniptype)); | ||
302 | |||
303 | /* What we've got will look like inverse of reply. Normally | ||
304 | this is what is in the conntrack, except for prior | ||
305 | manipulations (future optimization: if num_manips == 0, | ||
306 | orig_tp = | ||
307 | conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple) */ | ||
308 | nf_ct_invert_tuplepr(&curr_tuple, | ||
309 | &ct->tuplehash[IP_CT_DIR_REPLY].tuple); | ||
310 | |||
311 | get_unique_tuple(&new_tuple, &curr_tuple, range, ct, maniptype); | ||
312 | |||
313 | if (!nf_ct_tuple_equal(&new_tuple, &curr_tuple)) { | ||
314 | struct nf_conntrack_tuple reply; | ||
315 | |||
316 | /* Alter conntrack table so will recognize replies. */ | ||
317 | nf_ct_invert_tuplepr(&reply, &new_tuple); | ||
318 | nf_conntrack_alter_reply(ct, &reply); | ||
319 | |||
320 | /* Non-atomic: we own this at the moment. */ | ||
321 | if (maniptype == IP_NAT_MANIP_SRC) | ||
322 | ct->status |= IPS_SRC_NAT; | ||
323 | else | ||
324 | ct->status |= IPS_DST_NAT; | ||
325 | } | ||
326 | |||
327 | /* Place in source hash if this is the first time. */ | ||
328 | if (have_to_hash) { | ||
329 | unsigned int srchash; | ||
330 | |||
331 | srchash = hash_by_src(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); | ||
332 | write_lock_bh(&nf_nat_lock); | ||
333 | list_add(&info->bysource, &bysource[srchash]); | ||
334 | write_unlock_bh(&nf_nat_lock); | ||
335 | } | ||
336 | |||
337 | /* It's done. */ | ||
338 | if (maniptype == IP_NAT_MANIP_DST) | ||
339 | set_bit(IPS_DST_NAT_DONE_BIT, &ct->status); | ||
340 | else | ||
341 | set_bit(IPS_SRC_NAT_DONE_BIT, &ct->status); | ||
342 | |||
343 | return NF_ACCEPT; | ||
344 | } | ||
345 | EXPORT_SYMBOL(nf_nat_setup_info); | ||
346 | |||
347 | /* Returns true if succeeded. */ | ||
348 | static int | ||
349 | manip_pkt(u_int16_t proto, | ||
350 | struct sk_buff **pskb, | ||
351 | unsigned int iphdroff, | ||
352 | const struct nf_conntrack_tuple *target, | ||
353 | enum nf_nat_manip_type maniptype) | ||
354 | { | ||
355 | struct iphdr *iph; | ||
356 | struct nf_nat_protocol *p; | ||
357 | |||
358 | if (!skb_make_writable(pskb, iphdroff + sizeof(*iph))) | ||
359 | return 0; | ||
360 | |||
361 | iph = (void *)(*pskb)->data + iphdroff; | ||
362 | |||
363 | /* Manipulate protcol part. */ | ||
364 | p = nf_nat_proto_find_get(proto); | ||
365 | if (!p->manip_pkt(pskb, iphdroff, target, maniptype)) { | ||
366 | nf_nat_proto_put(p); | ||
367 | return 0; | ||
368 | } | ||
369 | nf_nat_proto_put(p); | ||
370 | |||
371 | iph = (void *)(*pskb)->data + iphdroff; | ||
372 | |||
373 | if (maniptype == IP_NAT_MANIP_SRC) { | ||
374 | nf_csum_replace4(&iph->check, iph->saddr, target->src.u3.ip); | ||
375 | iph->saddr = target->src.u3.ip; | ||
376 | } else { | ||
377 | nf_csum_replace4(&iph->check, iph->daddr, target->dst.u3.ip); | ||
378 | iph->daddr = target->dst.u3.ip; | ||
379 | } | ||
380 | return 1; | ||
381 | } | ||
382 | |||
383 | /* Do packet manipulations according to nf_nat_setup_info. */ | ||
384 | unsigned int nf_nat_packet(struct nf_conn *ct, | ||
385 | enum ip_conntrack_info ctinfo, | ||
386 | unsigned int hooknum, | ||
387 | struct sk_buff **pskb) | ||
388 | { | ||
389 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); | ||
390 | unsigned long statusbit; | ||
391 | enum nf_nat_manip_type mtype = HOOK2MANIP(hooknum); | ||
392 | |||
393 | if (mtype == IP_NAT_MANIP_SRC) | ||
394 | statusbit = IPS_SRC_NAT; | ||
395 | else | ||
396 | statusbit = IPS_DST_NAT; | ||
397 | |||
398 | /* Invert if this is reply dir. */ | ||
399 | if (dir == IP_CT_DIR_REPLY) | ||
400 | statusbit ^= IPS_NAT_MASK; | ||
401 | |||
402 | /* Non-atomic: these bits don't change. */ | ||
403 | if (ct->status & statusbit) { | ||
404 | struct nf_conntrack_tuple target; | ||
405 | |||
406 | /* We are aiming to look like inverse of other direction. */ | ||
407 | nf_ct_invert_tuplepr(&target, &ct->tuplehash[!dir].tuple); | ||
408 | |||
409 | if (!manip_pkt(target.dst.protonum, pskb, 0, &target, mtype)) | ||
410 | return NF_DROP; | ||
411 | } | ||
412 | return NF_ACCEPT; | ||
413 | } | ||
414 | EXPORT_SYMBOL_GPL(nf_nat_packet); | ||
415 | |||
416 | /* Dir is direction ICMP is coming from (opposite to packet it contains) */ | ||
417 | int nf_nat_icmp_reply_translation(struct nf_conn *ct, | ||
418 | enum ip_conntrack_info ctinfo, | ||
419 | unsigned int hooknum, | ||
420 | struct sk_buff **pskb) | ||
421 | { | ||
422 | struct { | ||
423 | struct icmphdr icmp; | ||
424 | struct iphdr ip; | ||
425 | } *inside; | ||
426 | struct nf_conntrack_tuple inner, target; | ||
427 | int hdrlen = (*pskb)->nh.iph->ihl * 4; | ||
428 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); | ||
429 | unsigned long statusbit; | ||
430 | enum nf_nat_manip_type manip = HOOK2MANIP(hooknum); | ||
431 | |||
432 | if (!skb_make_writable(pskb, hdrlen + sizeof(*inside))) | ||
433 | return 0; | ||
434 | |||
435 | inside = (void *)(*pskb)->data + (*pskb)->nh.iph->ihl*4; | ||
436 | |||
437 | /* We're actually going to mangle it beyond trivial checksum | ||
438 | adjustment, so make sure the current checksum is correct. */ | ||
439 | if (nf_ip_checksum(*pskb, hooknum, hdrlen, 0)) | ||
440 | return 0; | ||
441 | |||
442 | /* Must be RELATED */ | ||
443 | NF_CT_ASSERT((*pskb)->nfctinfo == IP_CT_RELATED || | ||
444 | (*pskb)->nfctinfo == IP_CT_RELATED+IP_CT_IS_REPLY); | ||
445 | |||
446 | /* Redirects on non-null nats must be dropped, else they'll | ||
447 | start talking to each other without our translation, and be | ||
448 | confused... --RR */ | ||
449 | if (inside->icmp.type == ICMP_REDIRECT) { | ||
450 | /* If NAT isn't finished, assume it and drop. */ | ||
451 | if ((ct->status & IPS_NAT_DONE_MASK) != IPS_NAT_DONE_MASK) | ||
452 | return 0; | ||
453 | |||
454 | if (ct->status & IPS_NAT_MASK) | ||
455 | return 0; | ||
456 | } | ||
457 | |||
458 | DEBUGP("icmp_reply_translation: translating error %p manp %u dir %s\n", | ||
459 | *pskb, manip, dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY"); | ||
460 | |||
461 | if (!nf_ct_get_tuple(*pskb, | ||
462 | (*pskb)->nh.iph->ihl*4 + sizeof(struct icmphdr), | ||
463 | (*pskb)->nh.iph->ihl*4 + | ||
464 | sizeof(struct icmphdr) + inside->ip.ihl*4, | ||
465 | (u_int16_t)AF_INET, | ||
466 | inside->ip.protocol, | ||
467 | &inner, | ||
468 | l3proto, | ||
469 | __nf_ct_l4proto_find((u_int16_t)PF_INET, | ||
470 | inside->ip.protocol))) | ||
471 | return 0; | ||
472 | |||
473 | /* Change inner back to look like incoming packet. We do the | ||
474 | opposite manip on this hook to normal, because it might not | ||
475 | pass all hooks (locally-generated ICMP). Consider incoming | ||
476 | packet: PREROUTING (DST manip), routing produces ICMP, goes | ||
477 | through POSTROUTING (which must correct the DST manip). */ | ||
478 | if (!manip_pkt(inside->ip.protocol, pskb, | ||
479 | (*pskb)->nh.iph->ihl*4 + sizeof(inside->icmp), | ||
480 | &ct->tuplehash[!dir].tuple, | ||
481 | !manip)) | ||
482 | return 0; | ||
483 | |||
484 | if ((*pskb)->ip_summed != CHECKSUM_PARTIAL) { | ||
485 | /* Reloading "inside" here since manip_pkt inner. */ | ||
486 | inside = (void *)(*pskb)->data + (*pskb)->nh.iph->ihl*4; | ||
487 | inside->icmp.checksum = 0; | ||
488 | inside->icmp.checksum = | ||
489 | csum_fold(skb_checksum(*pskb, hdrlen, | ||
490 | (*pskb)->len - hdrlen, 0)); | ||
491 | } | ||
492 | |||
493 | /* Change outer to look the reply to an incoming packet | ||
494 | * (proto 0 means don't invert per-proto part). */ | ||
495 | if (manip == IP_NAT_MANIP_SRC) | ||
496 | statusbit = IPS_SRC_NAT; | ||
497 | else | ||
498 | statusbit = IPS_DST_NAT; | ||
499 | |||
500 | /* Invert if this is reply dir. */ | ||
501 | if (dir == IP_CT_DIR_REPLY) | ||
502 | statusbit ^= IPS_NAT_MASK; | ||
503 | |||
504 | if (ct->status & statusbit) { | ||
505 | nf_ct_invert_tuplepr(&target, &ct->tuplehash[!dir].tuple); | ||
506 | if (!manip_pkt(0, pskb, 0, &target, manip)) | ||
507 | return 0; | ||
508 | } | ||
509 | |||
510 | return 1; | ||
511 | } | ||
512 | EXPORT_SYMBOL_GPL(nf_nat_icmp_reply_translation); | ||
513 | |||
514 | /* Protocol registration. */ | ||
515 | int nf_nat_protocol_register(struct nf_nat_protocol *proto) | ||
516 | { | ||
517 | int ret = 0; | ||
518 | |||
519 | write_lock_bh(&nf_nat_lock); | ||
520 | if (nf_nat_protos[proto->protonum] != &nf_nat_unknown_protocol) { | ||
521 | ret = -EBUSY; | ||
522 | goto out; | ||
523 | } | ||
524 | nf_nat_protos[proto->protonum] = proto; | ||
525 | out: | ||
526 | write_unlock_bh(&nf_nat_lock); | ||
527 | return ret; | ||
528 | } | ||
529 | EXPORT_SYMBOL(nf_nat_protocol_register); | ||
530 | |||
531 | /* Noone stores the protocol anywhere; simply delete it. */ | ||
532 | void nf_nat_protocol_unregister(struct nf_nat_protocol *proto) | ||
533 | { | ||
534 | write_lock_bh(&nf_nat_lock); | ||
535 | nf_nat_protos[proto->protonum] = &nf_nat_unknown_protocol; | ||
536 | write_unlock_bh(&nf_nat_lock); | ||
537 | |||
538 | /* Someone could be still looking at the proto in a bh. */ | ||
539 | synchronize_net(); | ||
540 | } | ||
541 | EXPORT_SYMBOL(nf_nat_protocol_unregister); | ||
542 | |||
543 | #if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \ | ||
544 | defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE) | ||
545 | int | ||
546 | nf_nat_port_range_to_nfattr(struct sk_buff *skb, | ||
547 | const struct nf_nat_range *range) | ||
548 | { | ||
549 | NFA_PUT(skb, CTA_PROTONAT_PORT_MIN, sizeof(__be16), | ||
550 | &range->min.tcp.port); | ||
551 | NFA_PUT(skb, CTA_PROTONAT_PORT_MAX, sizeof(__be16), | ||
552 | &range->max.tcp.port); | ||
553 | |||
554 | return 0; | ||
555 | |||
556 | nfattr_failure: | ||
557 | return -1; | ||
558 | } | ||
559 | EXPORT_SYMBOL_GPL(nf_nat_port_nfattr_to_range); | ||
560 | |||
561 | int | ||
562 | nf_nat_port_nfattr_to_range(struct nfattr *tb[], struct nf_nat_range *range) | ||
563 | { | ||
564 | int ret = 0; | ||
565 | |||
566 | /* we have to return whether we actually parsed something or not */ | ||
567 | |||
568 | if (tb[CTA_PROTONAT_PORT_MIN-1]) { | ||
569 | ret = 1; | ||
570 | range->min.tcp.port = | ||
571 | *(__be16 *)NFA_DATA(tb[CTA_PROTONAT_PORT_MIN-1]); | ||
572 | } | ||
573 | |||
574 | if (!tb[CTA_PROTONAT_PORT_MAX-1]) { | ||
575 | if (ret) | ||
576 | range->max.tcp.port = range->min.tcp.port; | ||
577 | } else { | ||
578 | ret = 1; | ||
579 | range->max.tcp.port = | ||
580 | *(__be16 *)NFA_DATA(tb[CTA_PROTONAT_PORT_MAX-1]); | ||
581 | } | ||
582 | |||
583 | return ret; | ||
584 | } | ||
585 | EXPORT_SYMBOL_GPL(nf_nat_port_range_to_nfattr); | ||
586 | #endif | ||
587 | |||
588 | static int __init nf_nat_init(void) | ||
589 | { | ||
590 | size_t i; | ||
591 | |||
592 | /* Leave them the same for the moment. */ | ||
593 | nf_nat_htable_size = nf_conntrack_htable_size; | ||
594 | |||
595 | /* One vmalloc for both hash tables */ | ||
596 | bysource = vmalloc(sizeof(struct list_head) * nf_nat_htable_size); | ||
597 | if (!bysource) | ||
598 | return -ENOMEM; | ||
599 | |||
600 | /* Sew in builtin protocols. */ | ||
601 | write_lock_bh(&nf_nat_lock); | ||
602 | for (i = 0; i < MAX_IP_NAT_PROTO; i++) | ||
603 | nf_nat_protos[i] = &nf_nat_unknown_protocol; | ||
604 | nf_nat_protos[IPPROTO_TCP] = &nf_nat_protocol_tcp; | ||
605 | nf_nat_protos[IPPROTO_UDP] = &nf_nat_protocol_udp; | ||
606 | nf_nat_protos[IPPROTO_ICMP] = &nf_nat_protocol_icmp; | ||
607 | write_unlock_bh(&nf_nat_lock); | ||
608 | |||
609 | for (i = 0; i < nf_nat_htable_size; i++) { | ||
610 | INIT_LIST_HEAD(&bysource[i]); | ||
611 | } | ||
612 | |||
613 | /* FIXME: Man, this is a hack. <SIGH> */ | ||
614 | NF_CT_ASSERT(nf_conntrack_destroyed == NULL); | ||
615 | nf_conntrack_destroyed = &nf_nat_cleanup_conntrack; | ||
616 | |||
617 | /* Initialize fake conntrack so that NAT will skip it */ | ||
618 | nf_conntrack_untracked.status |= IPS_NAT_DONE_MASK; | ||
619 | |||
620 | l3proto = nf_ct_l3proto_find_get((u_int16_t)AF_INET); | ||
621 | return 0; | ||
622 | } | ||
623 | |||
624 | /* Clear NAT section of all conntracks, in case we're loaded again. */ | ||
625 | static int clean_nat(struct nf_conn *i, void *data) | ||
626 | { | ||
627 | struct nf_conn_nat *nat = nfct_nat(i); | ||
628 | |||
629 | if (!nat) | ||
630 | return 0; | ||
631 | memset(nat, 0, sizeof(nat)); | ||
632 | i->status &= ~(IPS_NAT_MASK | IPS_NAT_DONE_MASK | IPS_SEQ_ADJUST); | ||
633 | return 0; | ||
634 | } | ||
635 | |||
636 | static void __exit nf_nat_cleanup(void) | ||
637 | { | ||
638 | nf_ct_iterate_cleanup(&clean_nat, NULL); | ||
639 | nf_conntrack_destroyed = NULL; | ||
640 | vfree(bysource); | ||
641 | nf_ct_l3proto_put(l3proto); | ||
642 | } | ||
643 | |||
644 | MODULE_LICENSE("GPL"); | ||
645 | |||
646 | module_init(nf_nat_init); | ||
647 | module_exit(nf_nat_cleanup); | ||
diff --git a/net/ipv4/netfilter/nf_nat_ftp.c b/net/ipv4/netfilter/nf_nat_ftp.c new file mode 100644 index 000000000000..751b59801755 --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_ftp.c | |||
@@ -0,0 +1,179 @@ | |||
1 | /* FTP extension for TCP NAT alteration. */ | ||
2 | |||
3 | /* (C) 1999-2001 Paul `Rusty' Russell | ||
4 | * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #include <linux/module.h> | ||
12 | #include <linux/moduleparam.h> | ||
13 | #include <linux/ip.h> | ||
14 | #include <linux/tcp.h> | ||
15 | #include <linux/netfilter_ipv4.h> | ||
16 | #include <net/netfilter/nf_nat.h> | ||
17 | #include <net/netfilter/nf_nat_helper.h> | ||
18 | #include <net/netfilter/nf_nat_rule.h> | ||
19 | #include <net/netfilter/nf_conntrack_helper.h> | ||
20 | #include <net/netfilter/nf_conntrack_expect.h> | ||
21 | #include <linux/netfilter/nf_conntrack_ftp.h> | ||
22 | |||
23 | MODULE_LICENSE("GPL"); | ||
24 | MODULE_AUTHOR("Rusty Russell <rusty@rustcorp.com.au>"); | ||
25 | MODULE_DESCRIPTION("ftp NAT helper"); | ||
26 | MODULE_ALIAS("ip_nat_ftp"); | ||
27 | |||
28 | #if 0 | ||
29 | #define DEBUGP printk | ||
30 | #else | ||
31 | #define DEBUGP(format, args...) | ||
32 | #endif | ||
33 | |||
34 | /* FIXME: Time out? --RR */ | ||
35 | |||
36 | static int | ||
37 | mangle_rfc959_packet(struct sk_buff **pskb, | ||
38 | __be32 newip, | ||
39 | u_int16_t port, | ||
40 | unsigned int matchoff, | ||
41 | unsigned int matchlen, | ||
42 | struct nf_conn *ct, | ||
43 | enum ip_conntrack_info ctinfo, | ||
44 | u32 *seq) | ||
45 | { | ||
46 | char buffer[sizeof("nnn,nnn,nnn,nnn,nnn,nnn")]; | ||
47 | |||
48 | sprintf(buffer, "%u,%u,%u,%u,%u,%u", | ||
49 | NIPQUAD(newip), port>>8, port&0xFF); | ||
50 | |||
51 | DEBUGP("calling nf_nat_mangle_tcp_packet\n"); | ||
52 | |||
53 | *seq += strlen(buffer) - matchlen; | ||
54 | return nf_nat_mangle_tcp_packet(pskb, ct, ctinfo, matchoff, | ||
55 | matchlen, buffer, strlen(buffer)); | ||
56 | } | ||
57 | |||
58 | /* |1|132.235.1.2|6275| */ | ||
59 | static int | ||
60 | mangle_eprt_packet(struct sk_buff **pskb, | ||
61 | __be32 newip, | ||
62 | u_int16_t port, | ||
63 | unsigned int matchoff, | ||
64 | unsigned int matchlen, | ||
65 | struct nf_conn *ct, | ||
66 | enum ip_conntrack_info ctinfo, | ||
67 | u32 *seq) | ||
68 | { | ||
69 | char buffer[sizeof("|1|255.255.255.255|65535|")]; | ||
70 | |||
71 | sprintf(buffer, "|1|%u.%u.%u.%u|%u|", NIPQUAD(newip), port); | ||
72 | |||
73 | DEBUGP("calling nf_nat_mangle_tcp_packet\n"); | ||
74 | |||
75 | *seq += strlen(buffer) - matchlen; | ||
76 | return nf_nat_mangle_tcp_packet(pskb, ct, ctinfo, matchoff, | ||
77 | matchlen, buffer, strlen(buffer)); | ||
78 | } | ||
79 | |||
80 | /* |1|132.235.1.2|6275| */ | ||
81 | static int | ||
82 | mangle_epsv_packet(struct sk_buff **pskb, | ||
83 | __be32 newip, | ||
84 | u_int16_t port, | ||
85 | unsigned int matchoff, | ||
86 | unsigned int matchlen, | ||
87 | struct nf_conn *ct, | ||
88 | enum ip_conntrack_info ctinfo, | ||
89 | u32 *seq) | ||
90 | { | ||
91 | char buffer[sizeof("|||65535|")]; | ||
92 | |||
93 | sprintf(buffer, "|||%u|", port); | ||
94 | |||
95 | DEBUGP("calling nf_nat_mangle_tcp_packet\n"); | ||
96 | |||
97 | *seq += strlen(buffer) - matchlen; | ||
98 | return nf_nat_mangle_tcp_packet(pskb, ct, ctinfo, matchoff, | ||
99 | matchlen, buffer, strlen(buffer)); | ||
100 | } | ||
101 | |||
102 | static int (*mangle[])(struct sk_buff **, __be32, u_int16_t, | ||
103 | unsigned int, unsigned int, struct nf_conn *, | ||
104 | enum ip_conntrack_info, u32 *seq) | ||
105 | = { | ||
106 | [NF_CT_FTP_PORT] = mangle_rfc959_packet, | ||
107 | [NF_CT_FTP_PASV] = mangle_rfc959_packet, | ||
108 | [NF_CT_FTP_EPRT] = mangle_eprt_packet, | ||
109 | [NF_CT_FTP_EPSV] = mangle_epsv_packet | ||
110 | }; | ||
111 | |||
112 | /* So, this packet has hit the connection tracking matching code. | ||
113 | Mangle it, and change the expectation to match the new version. */ | ||
114 | static unsigned int nf_nat_ftp(struct sk_buff **pskb, | ||
115 | enum ip_conntrack_info ctinfo, | ||
116 | enum nf_ct_ftp_type type, | ||
117 | unsigned int matchoff, | ||
118 | unsigned int matchlen, | ||
119 | struct nf_conntrack_expect *exp, | ||
120 | u32 *seq) | ||
121 | { | ||
122 | __be32 newip; | ||
123 | u_int16_t port; | ||
124 | int dir = CTINFO2DIR(ctinfo); | ||
125 | struct nf_conn *ct = exp->master; | ||
126 | |||
127 | DEBUGP("FTP_NAT: type %i, off %u len %u\n", type, matchoff, matchlen); | ||
128 | |||
129 | /* Connection will come from wherever this packet goes, hence !dir */ | ||
130 | newip = ct->tuplehash[!dir].tuple.dst.u3.ip; | ||
131 | exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port; | ||
132 | exp->dir = !dir; | ||
133 | |||
134 | /* When you see the packet, we need to NAT it the same as the | ||
135 | * this one. */ | ||
136 | exp->expectfn = nf_nat_follow_master; | ||
137 | |||
138 | /* Try to get same port: if not, try to change it. */ | ||
139 | for (port = ntohs(exp->saved_proto.tcp.port); port != 0; port++) { | ||
140 | exp->tuple.dst.u.tcp.port = htons(port); | ||
141 | if (nf_conntrack_expect_related(exp) == 0) | ||
142 | break; | ||
143 | } | ||
144 | |||
145 | if (port == 0) | ||
146 | return NF_DROP; | ||
147 | |||
148 | if (!mangle[type](pskb, newip, port, matchoff, matchlen, ct, ctinfo, | ||
149 | seq)) { | ||
150 | nf_conntrack_unexpect_related(exp); | ||
151 | return NF_DROP; | ||
152 | } | ||
153 | return NF_ACCEPT; | ||
154 | } | ||
155 | |||
156 | static void __exit nf_nat_ftp_fini(void) | ||
157 | { | ||
158 | rcu_assign_pointer(nf_nat_ftp_hook, NULL); | ||
159 | synchronize_rcu(); | ||
160 | } | ||
161 | |||
162 | static int __init nf_nat_ftp_init(void) | ||
163 | { | ||
164 | BUG_ON(rcu_dereference(nf_nat_ftp_hook)); | ||
165 | rcu_assign_pointer(nf_nat_ftp_hook, nf_nat_ftp); | ||
166 | return 0; | ||
167 | } | ||
168 | |||
169 | /* Prior to 2.6.11, we had a ports param. No longer, but don't break users. */ | ||
170 | static int warn_set(const char *val, struct kernel_param *kp) | ||
171 | { | ||
172 | printk(KERN_INFO KBUILD_MODNAME | ||
173 | ": kernel >= 2.6.10 only uses 'ports' for conntrack modules\n"); | ||
174 | return 0; | ||
175 | } | ||
176 | module_param_call(ports, warn_set, NULL, NULL, 0); | ||
177 | |||
178 | module_init(nf_nat_ftp_init); | ||
179 | module_exit(nf_nat_ftp_fini); | ||
diff --git a/net/ipv4/netfilter/nf_nat_h323.c b/net/ipv4/netfilter/nf_nat_h323.c new file mode 100644 index 000000000000..fb9ab0114c23 --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_h323.c | |||
@@ -0,0 +1,596 @@ | |||
1 | /* | ||
2 | * H.323 extension for NAT alteration. | ||
3 | * | ||
4 | * Copyright (c) 2006 Jing Min Zhao <zhaojingmin@users.sourceforge.net> | ||
5 | * | ||
6 | * This source code is licensed under General Public License version 2. | ||
7 | * | ||
8 | * Based on the 'brute force' H.323 NAT module by | ||
9 | * Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> | ||
10 | */ | ||
11 | |||
12 | #include <linux/module.h> | ||
13 | #include <linux/moduleparam.h> | ||
14 | #include <linux/tcp.h> | ||
15 | #include <net/tcp.h> | ||
16 | |||
17 | #include <net/netfilter/nf_nat.h> | ||
18 | #include <net/netfilter/nf_nat_helper.h> | ||
19 | #include <net/netfilter/nf_nat_rule.h> | ||
20 | #include <net/netfilter/nf_conntrack_helper.h> | ||
21 | #include <net/netfilter/nf_conntrack_expect.h> | ||
22 | #include <linux/netfilter/nf_conntrack_h323.h> | ||
23 | |||
24 | #if 0 | ||
25 | #define DEBUGP printk | ||
26 | #else | ||
27 | #define DEBUGP(format, args...) | ||
28 | #endif | ||
29 | |||
30 | /****************************************************************************/ | ||
31 | static int set_addr(struct sk_buff **pskb, | ||
32 | unsigned char **data, int dataoff, | ||
33 | unsigned int addroff, __be32 ip, __be16 port) | ||
34 | { | ||
35 | enum ip_conntrack_info ctinfo; | ||
36 | struct nf_conn *ct = ip_conntrack_get(*pskb, &ctinfo); | ||
37 | struct { | ||
38 | __be32 ip; | ||
39 | __be16 port; | ||
40 | } __attribute__ ((__packed__)) buf; | ||
41 | struct tcphdr _tcph, *th; | ||
42 | |||
43 | buf.ip = ip; | ||
44 | buf.port = port; | ||
45 | addroff += dataoff; | ||
46 | |||
47 | if ((*pskb)->nh.iph->protocol == IPPROTO_TCP) { | ||
48 | if (!nf_nat_mangle_tcp_packet(pskb, ct, ctinfo, | ||
49 | addroff, sizeof(buf), | ||
50 | (char *) &buf, sizeof(buf))) { | ||
51 | if (net_ratelimit()) | ||
52 | printk("nf_nat_h323: nf_nat_mangle_tcp_packet" | ||
53 | " error\n"); | ||
54 | return -1; | ||
55 | } | ||
56 | |||
57 | /* Relocate data pointer */ | ||
58 | th = skb_header_pointer(*pskb, (*pskb)->nh.iph->ihl * 4, | ||
59 | sizeof(_tcph), &_tcph); | ||
60 | if (th == NULL) | ||
61 | return -1; | ||
62 | *data = (*pskb)->data + (*pskb)->nh.iph->ihl * 4 + | ||
63 | th->doff * 4 + dataoff; | ||
64 | } else { | ||
65 | if (!nf_nat_mangle_udp_packet(pskb, ct, ctinfo, | ||
66 | addroff, sizeof(buf), | ||
67 | (char *) &buf, sizeof(buf))) { | ||
68 | if (net_ratelimit()) | ||
69 | printk("nf_nat_h323: nf_nat_mangle_udp_packet" | ||
70 | " error\n"); | ||
71 | return -1; | ||
72 | } | ||
73 | /* nf_nat_mangle_udp_packet uses skb_make_writable() to copy | ||
74 | * or pull everything in a linear buffer, so we can safely | ||
75 | * use the skb pointers now */ | ||
76 | *data = (*pskb)->data + (*pskb)->nh.iph->ihl * 4 + | ||
77 | sizeof(struct udphdr); | ||
78 | } | ||
79 | |||
80 | return 0; | ||
81 | } | ||
82 | |||
83 | /****************************************************************************/ | ||
84 | static int set_h225_addr(struct sk_buff **pskb, | ||
85 | unsigned char **data, int dataoff, | ||
86 | TransportAddress *taddr, | ||
87 | union nf_conntrack_address *addr, __be16 port) | ||
88 | { | ||
89 | return set_addr(pskb, data, dataoff, taddr->ipAddress.ip, | ||
90 | addr->ip, port); | ||
91 | } | ||
92 | |||
93 | /****************************************************************************/ | ||
94 | static int set_h245_addr(struct sk_buff **pskb, | ||
95 | unsigned char **data, int dataoff, | ||
96 | H245_TransportAddress *taddr, | ||
97 | union nf_conntrack_address *addr, __be16 port) | ||
98 | { | ||
99 | return set_addr(pskb, data, dataoff, | ||
100 | taddr->unicastAddress.iPAddress.network, | ||
101 | addr->ip, port); | ||
102 | } | ||
103 | |||
104 | /****************************************************************************/ | ||
105 | static int set_sig_addr(struct sk_buff **pskb, struct nf_conn *ct, | ||
106 | enum ip_conntrack_info ctinfo, | ||
107 | unsigned char **data, | ||
108 | TransportAddress *taddr, int count) | ||
109 | { | ||
110 | struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info; | ||
111 | int dir = CTINFO2DIR(ctinfo); | ||
112 | int i; | ||
113 | __be16 port; | ||
114 | union nf_conntrack_address addr; | ||
115 | |||
116 | for (i = 0; i < count; i++) { | ||
117 | if (get_h225_addr(ct, *data, &taddr[i], &addr, &port)) { | ||
118 | if (addr.ip == ct->tuplehash[dir].tuple.src.u3.ip && | ||
119 | port == info->sig_port[dir]) { | ||
120 | /* GW->GK */ | ||
121 | |||
122 | /* Fix for Gnomemeeting */ | ||
123 | if (i > 0 && | ||
124 | get_h225_addr(ct, *data, &taddr[0], | ||
125 | &addr, &port) && | ||
126 | (ntohl(addr.ip) & 0xff000000) == 0x7f000000) | ||
127 | i = 0; | ||
128 | |||
129 | DEBUGP | ||
130 | ("nf_nat_ras: set signal address " | ||
131 | "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", | ||
132 | NIPQUAD(ip), port, | ||
133 | NIPQUAD(ct->tuplehash[!dir].tuple.dst. | ||
134 | ip), info->sig_port[!dir]); | ||
135 | return set_h225_addr(pskb, data, 0, &taddr[i], | ||
136 | &ct->tuplehash[!dir]. | ||
137 | tuple.dst.u3, | ||
138 | info->sig_port[!dir]); | ||
139 | } else if (addr.ip == ct->tuplehash[dir].tuple.dst.u3.ip && | ||
140 | port == info->sig_port[dir]) { | ||
141 | /* GK->GW */ | ||
142 | DEBUGP | ||
143 | ("nf_nat_ras: set signal address " | ||
144 | "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", | ||
145 | NIPQUAD(ip), port, | ||
146 | NIPQUAD(ct->tuplehash[!dir].tuple.src. | ||
147 | ip), info->sig_port[!dir]); | ||
148 | return set_h225_addr(pskb, data, 0, &taddr[i], | ||
149 | &ct->tuplehash[!dir]. | ||
150 | tuple.src.u3, | ||
151 | info->sig_port[!dir]); | ||
152 | } | ||
153 | } | ||
154 | } | ||
155 | |||
156 | return 0; | ||
157 | } | ||
158 | |||
159 | /****************************************************************************/ | ||
160 | static int set_ras_addr(struct sk_buff **pskb, struct nf_conn *ct, | ||
161 | enum ip_conntrack_info ctinfo, | ||
162 | unsigned char **data, | ||
163 | TransportAddress *taddr, int count) | ||
164 | { | ||
165 | int dir = CTINFO2DIR(ctinfo); | ||
166 | int i; | ||
167 | __be16 port; | ||
168 | union nf_conntrack_address addr; | ||
169 | |||
170 | for (i = 0; i < count; i++) { | ||
171 | if (get_h225_addr(ct, *data, &taddr[i], &addr, &port) && | ||
172 | addr.ip == ct->tuplehash[dir].tuple.src.u3.ip && | ||
173 | port == ct->tuplehash[dir].tuple.src.u.udp.port) { | ||
174 | DEBUGP("nf_nat_ras: set rasAddress " | ||
175 | "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", | ||
176 | NIPQUAD(ip), ntohs(port), | ||
177 | NIPQUAD(ct->tuplehash[!dir].tuple.dst.u3.ip), | ||
178 | ntohs(ct->tuplehash[!dir].tuple.dst.u.udp. | ||
179 | port)); | ||
180 | return set_h225_addr(pskb, data, 0, &taddr[i], | ||
181 | &ct->tuplehash[!dir].tuple.dst.u3, | ||
182 | ct->tuplehash[!dir].tuple. | ||
183 | dst.u.udp.port); | ||
184 | } | ||
185 | } | ||
186 | |||
187 | return 0; | ||
188 | } | ||
189 | |||
190 | /****************************************************************************/ | ||
191 | static int nat_rtp_rtcp(struct sk_buff **pskb, struct nf_conn *ct, | ||
192 | enum ip_conntrack_info ctinfo, | ||
193 | unsigned char **data, int dataoff, | ||
194 | H245_TransportAddress *taddr, | ||
195 | __be16 port, __be16 rtp_port, | ||
196 | struct nf_conntrack_expect *rtp_exp, | ||
197 | struct nf_conntrack_expect *rtcp_exp) | ||
198 | { | ||
199 | struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info; | ||
200 | int dir = CTINFO2DIR(ctinfo); | ||
201 | int i; | ||
202 | u_int16_t nated_port; | ||
203 | |||
204 | /* Set expectations for NAT */ | ||
205 | rtp_exp->saved_proto.udp.port = rtp_exp->tuple.dst.u.udp.port; | ||
206 | rtp_exp->expectfn = nf_nat_follow_master; | ||
207 | rtp_exp->dir = !dir; | ||
208 | rtcp_exp->saved_proto.udp.port = rtcp_exp->tuple.dst.u.udp.port; | ||
209 | rtcp_exp->expectfn = nf_nat_follow_master; | ||
210 | rtcp_exp->dir = !dir; | ||
211 | |||
212 | /* Lookup existing expects */ | ||
213 | for (i = 0; i < H323_RTP_CHANNEL_MAX; i++) { | ||
214 | if (info->rtp_port[i][dir] == rtp_port) { | ||
215 | /* Expected */ | ||
216 | |||
217 | /* Use allocated ports first. This will refresh | ||
218 | * the expects */ | ||
219 | rtp_exp->tuple.dst.u.udp.port = info->rtp_port[i][dir]; | ||
220 | rtcp_exp->tuple.dst.u.udp.port = | ||
221 | htons(ntohs(info->rtp_port[i][dir]) + 1); | ||
222 | break; | ||
223 | } else if (info->rtp_port[i][dir] == 0) { | ||
224 | /* Not expected */ | ||
225 | break; | ||
226 | } | ||
227 | } | ||
228 | |||
229 | /* Run out of expectations */ | ||
230 | if (i >= H323_RTP_CHANNEL_MAX) { | ||
231 | if (net_ratelimit()) | ||
232 | printk("nf_nat_h323: out of expectations\n"); | ||
233 | return 0; | ||
234 | } | ||
235 | |||
236 | /* Try to get a pair of ports. */ | ||
237 | for (nated_port = ntohs(rtp_exp->tuple.dst.u.udp.port); | ||
238 | nated_port != 0; nated_port += 2) { | ||
239 | rtp_exp->tuple.dst.u.udp.port = htons(nated_port); | ||
240 | if (nf_conntrack_expect_related(rtp_exp) == 0) { | ||
241 | rtcp_exp->tuple.dst.u.udp.port = | ||
242 | htons(nated_port + 1); | ||
243 | if (nf_conntrack_expect_related(rtcp_exp) == 0) | ||
244 | break; | ||
245 | nf_conntrack_unexpect_related(rtp_exp); | ||
246 | } | ||
247 | } | ||
248 | |||
249 | if (nated_port == 0) { /* No port available */ | ||
250 | if (net_ratelimit()) | ||
251 | printk("nf_nat_h323: out of RTP ports\n"); | ||
252 | return 0; | ||
253 | } | ||
254 | |||
255 | /* Modify signal */ | ||
256 | if (set_h245_addr(pskb, data, dataoff, taddr, | ||
257 | &ct->tuplehash[!dir].tuple.dst.u3, | ||
258 | htons((port & htons(1)) ? nated_port + 1 : | ||
259 | nated_port)) == 0) { | ||
260 | /* Save ports */ | ||
261 | info->rtp_port[i][dir] = rtp_port; | ||
262 | info->rtp_port[i][!dir] = htons(nated_port); | ||
263 | } else { | ||
264 | nf_conntrack_unexpect_related(rtp_exp); | ||
265 | nf_conntrack_unexpect_related(rtcp_exp); | ||
266 | return -1; | ||
267 | } | ||
268 | |||
269 | /* Success */ | ||
270 | DEBUGP("nf_nat_h323: expect RTP %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", | ||
271 | NIPQUAD(rtp_exp->tuple.src.ip), | ||
272 | ntohs(rtp_exp->tuple.src.u.udp.port), | ||
273 | NIPQUAD(rtp_exp->tuple.dst.ip), | ||
274 | ntohs(rtp_exp->tuple.dst.u.udp.port)); | ||
275 | DEBUGP("nf_nat_h323: expect RTCP %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", | ||
276 | NIPQUAD(rtcp_exp->tuple.src.ip), | ||
277 | ntohs(rtcp_exp->tuple.src.u.udp.port), | ||
278 | NIPQUAD(rtcp_exp->tuple.dst.ip), | ||
279 | ntohs(rtcp_exp->tuple.dst.u.udp.port)); | ||
280 | |||
281 | return 0; | ||
282 | } | ||
283 | |||
284 | /****************************************************************************/ | ||
285 | static int nat_t120(struct sk_buff **pskb, struct nf_conn *ct, | ||
286 | enum ip_conntrack_info ctinfo, | ||
287 | unsigned char **data, int dataoff, | ||
288 | H245_TransportAddress *taddr, __be16 port, | ||
289 | struct nf_conntrack_expect *exp) | ||
290 | { | ||
291 | int dir = CTINFO2DIR(ctinfo); | ||
292 | u_int16_t nated_port = ntohs(port); | ||
293 | |||
294 | /* Set expectations for NAT */ | ||
295 | exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port; | ||
296 | exp->expectfn = nf_nat_follow_master; | ||
297 | exp->dir = !dir; | ||
298 | |||
299 | /* Try to get same port: if not, try to change it. */ | ||
300 | for (; nated_port != 0; nated_port++) { | ||
301 | exp->tuple.dst.u.tcp.port = htons(nated_port); | ||
302 | if (nf_conntrack_expect_related(exp) == 0) | ||
303 | break; | ||
304 | } | ||
305 | |||
306 | if (nated_port == 0) { /* No port available */ | ||
307 | if (net_ratelimit()) | ||
308 | printk("nf_nat_h323: out of TCP ports\n"); | ||
309 | return 0; | ||
310 | } | ||
311 | |||
312 | /* Modify signal */ | ||
313 | if (set_h245_addr(pskb, data, dataoff, taddr, | ||
314 | &ct->tuplehash[!dir].tuple.dst.u3, | ||
315 | htons(nated_port)) < 0) { | ||
316 | nf_conntrack_unexpect_related(exp); | ||
317 | return -1; | ||
318 | } | ||
319 | |||
320 | DEBUGP("nf_nat_h323: expect T.120 %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", | ||
321 | NIPQUAD(exp->tuple.src.ip), ntohs(exp->tuple.src.u.tcp.port), | ||
322 | NIPQUAD(exp->tuple.dst.ip), ntohs(exp->tuple.dst.u.tcp.port)); | ||
323 | |||
324 | return 0; | ||
325 | } | ||
326 | |||
327 | /****************************************************************************/ | ||
328 | static int nat_h245(struct sk_buff **pskb, struct nf_conn *ct, | ||
329 | enum ip_conntrack_info ctinfo, | ||
330 | unsigned char **data, int dataoff, | ||
331 | TransportAddress *taddr, __be16 port, | ||
332 | struct nf_conntrack_expect *exp) | ||
333 | { | ||
334 | struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info; | ||
335 | int dir = CTINFO2DIR(ctinfo); | ||
336 | u_int16_t nated_port = ntohs(port); | ||
337 | |||
338 | /* Set expectations for NAT */ | ||
339 | exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port; | ||
340 | exp->expectfn = nf_nat_follow_master; | ||
341 | exp->dir = !dir; | ||
342 | |||
343 | /* Check existing expects */ | ||
344 | if (info->sig_port[dir] == port) | ||
345 | nated_port = ntohs(info->sig_port[!dir]); | ||
346 | |||
347 | /* Try to get same port: if not, try to change it. */ | ||
348 | for (; nated_port != 0; nated_port++) { | ||
349 | exp->tuple.dst.u.tcp.port = htons(nated_port); | ||
350 | if (nf_conntrack_expect_related(exp) == 0) | ||
351 | break; | ||
352 | } | ||
353 | |||
354 | if (nated_port == 0) { /* No port available */ | ||
355 | if (net_ratelimit()) | ||
356 | printk("nf_nat_q931: out of TCP ports\n"); | ||
357 | return 0; | ||
358 | } | ||
359 | |||
360 | /* Modify signal */ | ||
361 | if (set_h225_addr(pskb, data, dataoff, taddr, | ||
362 | &ct->tuplehash[!dir].tuple.dst.u3, | ||
363 | htons(nated_port)) == 0) { | ||
364 | /* Save ports */ | ||
365 | info->sig_port[dir] = port; | ||
366 | info->sig_port[!dir] = htons(nated_port); | ||
367 | } else { | ||
368 | nf_conntrack_unexpect_related(exp); | ||
369 | return -1; | ||
370 | } | ||
371 | |||
372 | DEBUGP("nf_nat_q931: expect H.245 %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", | ||
373 | NIPQUAD(exp->tuple.src.ip), ntohs(exp->tuple.src.u.tcp.port), | ||
374 | NIPQUAD(exp->tuple.dst.ip), ntohs(exp->tuple.dst.u.tcp.port)); | ||
375 | |||
376 | return 0; | ||
377 | } | ||
378 | |||
379 | /**************************************************************************** | ||
380 | * This conntrack expect function replaces nf_conntrack_q931_expect() | ||
381 | * which was set by nf_conntrack_h323.c. | ||
382 | ****************************************************************************/ | ||
383 | static void ip_nat_q931_expect(struct nf_conn *new, | ||
384 | struct nf_conntrack_expect *this) | ||
385 | { | ||
386 | struct ip_nat_range range; | ||
387 | |||
388 | if (this->tuple.src.u3.ip != 0) { /* Only accept calls from GK */ | ||
389 | nf_nat_follow_master(new, this); | ||
390 | return; | ||
391 | } | ||
392 | |||
393 | /* This must be a fresh one. */ | ||
394 | BUG_ON(new->status & IPS_NAT_DONE_MASK); | ||
395 | |||
396 | /* Change src to where master sends to */ | ||
397 | range.flags = IP_NAT_RANGE_MAP_IPS; | ||
398 | range.min_ip = range.max_ip = new->tuplehash[!this->dir].tuple.src.u3.ip; | ||
399 | |||
400 | /* hook doesn't matter, but it has to do source manip */ | ||
401 | nf_nat_setup_info(new, &range, NF_IP_POST_ROUTING); | ||
402 | |||
403 | /* For DST manip, map port here to where it's expected. */ | ||
404 | range.flags = (IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED); | ||
405 | range.min = range.max = this->saved_proto; | ||
406 | range.min_ip = range.max_ip = | ||
407 | new->master->tuplehash[!this->dir].tuple.src.u3.ip; | ||
408 | |||
409 | /* hook doesn't matter, but it has to do destination manip */ | ||
410 | nf_nat_setup_info(new, &range, NF_IP_PRE_ROUTING); | ||
411 | } | ||
412 | |||
413 | /****************************************************************************/ | ||
414 | static int nat_q931(struct sk_buff **pskb, struct nf_conn *ct, | ||
415 | enum ip_conntrack_info ctinfo, | ||
416 | unsigned char **data, TransportAddress *taddr, int idx, | ||
417 | __be16 port, struct nf_conntrack_expect *exp) | ||
418 | { | ||
419 | struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info; | ||
420 | int dir = CTINFO2DIR(ctinfo); | ||
421 | u_int16_t nated_port = ntohs(port); | ||
422 | union nf_conntrack_address addr; | ||
423 | |||
424 | /* Set expectations for NAT */ | ||
425 | exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port; | ||
426 | exp->expectfn = ip_nat_q931_expect; | ||
427 | exp->dir = !dir; | ||
428 | |||
429 | /* Check existing expects */ | ||
430 | if (info->sig_port[dir] == port) | ||
431 | nated_port = ntohs(info->sig_port[!dir]); | ||
432 | |||
433 | /* Try to get same port: if not, try to change it. */ | ||
434 | for (; nated_port != 0; nated_port++) { | ||
435 | exp->tuple.dst.u.tcp.port = htons(nated_port); | ||
436 | if (nf_conntrack_expect_related(exp) == 0) | ||
437 | break; | ||
438 | } | ||
439 | |||
440 | if (nated_port == 0) { /* No port available */ | ||
441 | if (net_ratelimit()) | ||
442 | printk("nf_nat_ras: out of TCP ports\n"); | ||
443 | return 0; | ||
444 | } | ||
445 | |||
446 | /* Modify signal */ | ||
447 | if (set_h225_addr(pskb, data, 0, &taddr[idx], | ||
448 | &ct->tuplehash[!dir].tuple.dst.u3, | ||
449 | htons(nated_port)) == 0) { | ||
450 | /* Save ports */ | ||
451 | info->sig_port[dir] = port; | ||
452 | info->sig_port[!dir] = htons(nated_port); | ||
453 | |||
454 | /* Fix for Gnomemeeting */ | ||
455 | if (idx > 0 && | ||
456 | get_h225_addr(ct, *data, &taddr[0], &addr, &port) && | ||
457 | (ntohl(addr.ip) & 0xff000000) == 0x7f000000) { | ||
458 | set_h225_addr_hook(pskb, data, 0, &taddr[0], | ||
459 | &ct->tuplehash[!dir].tuple.dst.u3, | ||
460 | info->sig_port[!dir]); | ||
461 | } | ||
462 | } else { | ||
463 | nf_conntrack_unexpect_related(exp); | ||
464 | return -1; | ||
465 | } | ||
466 | |||
467 | /* Success */ | ||
468 | DEBUGP("nf_nat_ras: expect Q.931 %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", | ||
469 | NIPQUAD(exp->tuple.src.ip), ntohs(exp->tuple.src.u.tcp.port), | ||
470 | NIPQUAD(exp->tuple.dst.ip), ntohs(exp->tuple.dst.u.tcp.port)); | ||
471 | |||
472 | return 0; | ||
473 | } | ||
474 | |||
475 | /****************************************************************************/ | ||
476 | static void ip_nat_callforwarding_expect(struct nf_conn *new, | ||
477 | struct nf_conntrack_expect *this) | ||
478 | { | ||
479 | struct nf_nat_range range; | ||
480 | |||
481 | /* This must be a fresh one. */ | ||
482 | BUG_ON(new->status & IPS_NAT_DONE_MASK); | ||
483 | |||
484 | /* Change src to where master sends to */ | ||
485 | range.flags = IP_NAT_RANGE_MAP_IPS; | ||
486 | range.min_ip = range.max_ip = new->tuplehash[!this->dir].tuple.src.u3.ip; | ||
487 | |||
488 | /* hook doesn't matter, but it has to do source manip */ | ||
489 | nf_nat_setup_info(new, &range, NF_IP_POST_ROUTING); | ||
490 | |||
491 | /* For DST manip, map port here to where it's expected. */ | ||
492 | range.flags = (IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED); | ||
493 | range.min = range.max = this->saved_proto; | ||
494 | range.min_ip = range.max_ip = this->saved_ip; | ||
495 | |||
496 | /* hook doesn't matter, but it has to do destination manip */ | ||
497 | nf_nat_setup_info(new, &range, NF_IP_PRE_ROUTING); | ||
498 | } | ||
499 | |||
500 | /****************************************************************************/ | ||
501 | static int nat_callforwarding(struct sk_buff **pskb, struct nf_conn *ct, | ||
502 | enum ip_conntrack_info ctinfo, | ||
503 | unsigned char **data, int dataoff, | ||
504 | TransportAddress *taddr, __be16 port, | ||
505 | struct nf_conntrack_expect *exp) | ||
506 | { | ||
507 | int dir = CTINFO2DIR(ctinfo); | ||
508 | u_int16_t nated_port; | ||
509 | |||
510 | /* Set expectations for NAT */ | ||
511 | exp->saved_ip = exp->tuple.dst.u3.ip; | ||
512 | exp->tuple.dst.u3.ip = ct->tuplehash[!dir].tuple.dst.u3.ip; | ||
513 | exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port; | ||
514 | exp->expectfn = ip_nat_callforwarding_expect; | ||
515 | exp->dir = !dir; | ||
516 | |||
517 | /* Try to get same port: if not, try to change it. */ | ||
518 | for (nated_port = ntohs(port); nated_port != 0; nated_port++) { | ||
519 | exp->tuple.dst.u.tcp.port = htons(nated_port); | ||
520 | if (nf_conntrack_expect_related(exp) == 0) | ||
521 | break; | ||
522 | } | ||
523 | |||
524 | if (nated_port == 0) { /* No port available */ | ||
525 | if (net_ratelimit()) | ||
526 | printk("nf_nat_q931: out of TCP ports\n"); | ||
527 | return 0; | ||
528 | } | ||
529 | |||
530 | /* Modify signal */ | ||
531 | if (!set_h225_addr(pskb, data, dataoff, taddr, | ||
532 | &ct->tuplehash[!dir].tuple.dst.u3, | ||
533 | htons(nated_port)) == 0) { | ||
534 | nf_conntrack_unexpect_related(exp); | ||
535 | return -1; | ||
536 | } | ||
537 | |||
538 | /* Success */ | ||
539 | DEBUGP("nf_nat_q931: expect Call Forwarding " | ||
540 | "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", | ||
541 | NIPQUAD(exp->tuple.src.ip), ntohs(exp->tuple.src.u.tcp.port), | ||
542 | NIPQUAD(exp->tuple.dst.ip), ntohs(exp->tuple.dst.u.tcp.port)); | ||
543 | |||
544 | return 0; | ||
545 | } | ||
546 | |||
547 | /****************************************************************************/ | ||
548 | static int __init init(void) | ||
549 | { | ||
550 | BUG_ON(rcu_dereference(set_h245_addr_hook) != NULL); | ||
551 | BUG_ON(rcu_dereference(set_h225_addr_hook) != NULL); | ||
552 | BUG_ON(rcu_dereference(set_sig_addr_hook) != NULL); | ||
553 | BUG_ON(rcu_dereference(set_ras_addr_hook) != NULL); | ||
554 | BUG_ON(rcu_dereference(nat_rtp_rtcp_hook) != NULL); | ||
555 | BUG_ON(rcu_dereference(nat_t120_hook) != NULL); | ||
556 | BUG_ON(rcu_dereference(nat_h245_hook) != NULL); | ||
557 | BUG_ON(rcu_dereference(nat_callforwarding_hook) != NULL); | ||
558 | BUG_ON(rcu_dereference(nat_q931_hook) != NULL); | ||
559 | |||
560 | rcu_assign_pointer(set_h245_addr_hook, set_h245_addr); | ||
561 | rcu_assign_pointer(set_h225_addr_hook, set_h225_addr); | ||
562 | rcu_assign_pointer(set_sig_addr_hook, set_sig_addr); | ||
563 | rcu_assign_pointer(set_ras_addr_hook, set_ras_addr); | ||
564 | rcu_assign_pointer(nat_rtp_rtcp_hook, nat_rtp_rtcp); | ||
565 | rcu_assign_pointer(nat_t120_hook, nat_t120); | ||
566 | rcu_assign_pointer(nat_h245_hook, nat_h245); | ||
567 | rcu_assign_pointer(nat_callforwarding_hook, nat_callforwarding); | ||
568 | rcu_assign_pointer(nat_q931_hook, nat_q931); | ||
569 | |||
570 | DEBUGP("nf_nat_h323: init success\n"); | ||
571 | return 0; | ||
572 | } | ||
573 | |||
574 | /****************************************************************************/ | ||
575 | static void __exit fini(void) | ||
576 | { | ||
577 | rcu_assign_pointer(set_h245_addr_hook, NULL); | ||
578 | rcu_assign_pointer(set_h225_addr_hook, NULL); | ||
579 | rcu_assign_pointer(set_sig_addr_hook, NULL); | ||
580 | rcu_assign_pointer(set_ras_addr_hook, NULL); | ||
581 | rcu_assign_pointer(nat_rtp_rtcp_hook, NULL); | ||
582 | rcu_assign_pointer(nat_t120_hook, NULL); | ||
583 | rcu_assign_pointer(nat_h245_hook, NULL); | ||
584 | rcu_assign_pointer(nat_callforwarding_hook, NULL); | ||
585 | rcu_assign_pointer(nat_q931_hook, NULL); | ||
586 | synchronize_rcu(); | ||
587 | } | ||
588 | |||
589 | /****************************************************************************/ | ||
590 | module_init(init); | ||
591 | module_exit(fini); | ||
592 | |||
593 | MODULE_AUTHOR("Jing Min Zhao <zhaojingmin@users.sourceforge.net>"); | ||
594 | MODULE_DESCRIPTION("H.323 NAT helper"); | ||
595 | MODULE_LICENSE("GPL"); | ||
596 | MODULE_ALIAS("ip_nat_h323"); | ||
diff --git a/net/ipv4/netfilter/nf_nat_helper.c b/net/ipv4/netfilter/nf_nat_helper.c new file mode 100644 index 000000000000..98fbfc84d183 --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_helper.c | |||
@@ -0,0 +1,433 @@ | |||
1 | /* ip_nat_helper.c - generic support functions for NAT helpers | ||
2 | * | ||
3 | * (C) 2000-2002 Harald Welte <laforge@netfilter.org> | ||
4 | * (C) 2003-2006 Netfilter Core Team <coreteam@netfilter.org> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | #include <linux/module.h> | ||
11 | #include <linux/kmod.h> | ||
12 | #include <linux/types.h> | ||
13 | #include <linux/timer.h> | ||
14 | #include <linux/skbuff.h> | ||
15 | #include <linux/tcp.h> | ||
16 | #include <linux/udp.h> | ||
17 | #include <net/checksum.h> | ||
18 | #include <net/tcp.h> | ||
19 | |||
20 | #include <linux/netfilter_ipv4.h> | ||
21 | #include <net/netfilter/nf_conntrack.h> | ||
22 | #include <net/netfilter/nf_conntrack_helper.h> | ||
23 | #include <net/netfilter/nf_conntrack_expect.h> | ||
24 | #include <net/netfilter/nf_nat.h> | ||
25 | #include <net/netfilter/nf_nat_protocol.h> | ||
26 | #include <net/netfilter/nf_nat_core.h> | ||
27 | #include <net/netfilter/nf_nat_helper.h> | ||
28 | |||
29 | #if 0 | ||
30 | #define DEBUGP printk | ||
31 | #define DUMP_OFFSET(x) printk("offset_before=%d, offset_after=%d, correction_pos=%u\n", x->offset_before, x->offset_after, x->correction_pos); | ||
32 | #else | ||
33 | #define DEBUGP(format, args...) | ||
34 | #define DUMP_OFFSET(x) | ||
35 | #endif | ||
36 | |||
37 | static DEFINE_SPINLOCK(nf_nat_seqofs_lock); | ||
38 | |||
39 | /* Setup TCP sequence correction given this change at this sequence */ | ||
40 | static inline void | ||
41 | adjust_tcp_sequence(u32 seq, | ||
42 | int sizediff, | ||
43 | struct nf_conn *ct, | ||
44 | enum ip_conntrack_info ctinfo) | ||
45 | { | ||
46 | int dir; | ||
47 | struct nf_nat_seq *this_way, *other_way; | ||
48 | struct nf_conn_nat *nat = nfct_nat(ct); | ||
49 | |||
50 | DEBUGP("nf_nat_resize_packet: old_size = %u, new_size = %u\n", | ||
51 | (*skb)->len, new_size); | ||
52 | |||
53 | dir = CTINFO2DIR(ctinfo); | ||
54 | |||
55 | this_way = &nat->info.seq[dir]; | ||
56 | other_way = &nat->info.seq[!dir]; | ||
57 | |||
58 | DEBUGP("nf_nat_resize_packet: Seq_offset before: "); | ||
59 | DUMP_OFFSET(this_way); | ||
60 | |||
61 | spin_lock_bh(&nf_nat_seqofs_lock); | ||
62 | |||
63 | /* SYN adjust. If it's uninitialized, or this is after last | ||
64 | * correction, record it: we don't handle more than one | ||
65 | * adjustment in the window, but do deal with common case of a | ||
66 | * retransmit */ | ||
67 | if (this_way->offset_before == this_way->offset_after || | ||
68 | before(this_way->correction_pos, seq)) { | ||
69 | this_way->correction_pos = seq; | ||
70 | this_way->offset_before = this_way->offset_after; | ||
71 | this_way->offset_after += sizediff; | ||
72 | } | ||
73 | spin_unlock_bh(&nf_nat_seqofs_lock); | ||
74 | |||
75 | DEBUGP("nf_nat_resize_packet: Seq_offset after: "); | ||
76 | DUMP_OFFSET(this_way); | ||
77 | } | ||
78 | |||
79 | /* Frobs data inside this packet, which is linear. */ | ||
80 | static void mangle_contents(struct sk_buff *skb, | ||
81 | unsigned int dataoff, | ||
82 | unsigned int match_offset, | ||
83 | unsigned int match_len, | ||
84 | const char *rep_buffer, | ||
85 | unsigned int rep_len) | ||
86 | { | ||
87 | unsigned char *data; | ||
88 | |||
89 | BUG_ON(skb_is_nonlinear(skb)); | ||
90 | data = (unsigned char *)skb->nh.iph + dataoff; | ||
91 | |||
92 | /* move post-replacement */ | ||
93 | memmove(data + match_offset + rep_len, | ||
94 | data + match_offset + match_len, | ||
95 | skb->tail - (data + match_offset + match_len)); | ||
96 | |||
97 | /* insert data from buffer */ | ||
98 | memcpy(data + match_offset, rep_buffer, rep_len); | ||
99 | |||
100 | /* update skb info */ | ||
101 | if (rep_len > match_len) { | ||
102 | DEBUGP("nf_nat_mangle_packet: Extending packet by " | ||
103 | "%u from %u bytes\n", rep_len - match_len, | ||
104 | skb->len); | ||
105 | skb_put(skb, rep_len - match_len); | ||
106 | } else { | ||
107 | DEBUGP("nf_nat_mangle_packet: Shrinking packet from " | ||
108 | "%u from %u bytes\n", match_len - rep_len, | ||
109 | skb->len); | ||
110 | __skb_trim(skb, skb->len + rep_len - match_len); | ||
111 | } | ||
112 | |||
113 | /* fix IP hdr checksum information */ | ||
114 | skb->nh.iph->tot_len = htons(skb->len); | ||
115 | ip_send_check(skb->nh.iph); | ||
116 | } | ||
117 | |||
118 | /* Unusual, but possible case. */ | ||
119 | static int enlarge_skb(struct sk_buff **pskb, unsigned int extra) | ||
120 | { | ||
121 | struct sk_buff *nskb; | ||
122 | |||
123 | if ((*pskb)->len + extra > 65535) | ||
124 | return 0; | ||
125 | |||
126 | nskb = skb_copy_expand(*pskb, skb_headroom(*pskb), extra, GFP_ATOMIC); | ||
127 | if (!nskb) | ||
128 | return 0; | ||
129 | |||
130 | /* Transfer socket to new skb. */ | ||
131 | if ((*pskb)->sk) | ||
132 | skb_set_owner_w(nskb, (*pskb)->sk); | ||
133 | kfree_skb(*pskb); | ||
134 | *pskb = nskb; | ||
135 | return 1; | ||
136 | } | ||
137 | |||
138 | /* Generic function for mangling variable-length address changes inside | ||
139 | * NATed TCP connections (like the PORT XXX,XXX,XXX,XXX,XXX,XXX | ||
140 | * command in FTP). | ||
141 | * | ||
142 | * Takes care about all the nasty sequence number changes, checksumming, | ||
143 | * skb enlargement, ... | ||
144 | * | ||
145 | * */ | ||
146 | int | ||
147 | nf_nat_mangle_tcp_packet(struct sk_buff **pskb, | ||
148 | struct nf_conn *ct, | ||
149 | enum ip_conntrack_info ctinfo, | ||
150 | unsigned int match_offset, | ||
151 | unsigned int match_len, | ||
152 | const char *rep_buffer, | ||
153 | unsigned int rep_len) | ||
154 | { | ||
155 | struct iphdr *iph; | ||
156 | struct tcphdr *tcph; | ||
157 | int oldlen, datalen; | ||
158 | |||
159 | if (!skb_make_writable(pskb, (*pskb)->len)) | ||
160 | return 0; | ||
161 | |||
162 | if (rep_len > match_len && | ||
163 | rep_len - match_len > skb_tailroom(*pskb) && | ||
164 | !enlarge_skb(pskb, rep_len - match_len)) | ||
165 | return 0; | ||
166 | |||
167 | SKB_LINEAR_ASSERT(*pskb); | ||
168 | |||
169 | iph = (*pskb)->nh.iph; | ||
170 | tcph = (void *)iph + iph->ihl*4; | ||
171 | |||
172 | oldlen = (*pskb)->len - iph->ihl*4; | ||
173 | mangle_contents(*pskb, iph->ihl*4 + tcph->doff*4, | ||
174 | match_offset, match_len, rep_buffer, rep_len); | ||
175 | |||
176 | datalen = (*pskb)->len - iph->ihl*4; | ||
177 | if ((*pskb)->ip_summed != CHECKSUM_PARTIAL) { | ||
178 | tcph->check = 0; | ||
179 | tcph->check = tcp_v4_check(tcph, datalen, | ||
180 | iph->saddr, iph->daddr, | ||
181 | csum_partial((char *)tcph, | ||
182 | datalen, 0)); | ||
183 | } else | ||
184 | nf_proto_csum_replace2(&tcph->check, *pskb, | ||
185 | htons(oldlen), htons(datalen), 1); | ||
186 | |||
187 | if (rep_len != match_len) { | ||
188 | set_bit(IPS_SEQ_ADJUST_BIT, &ct->status); | ||
189 | adjust_tcp_sequence(ntohl(tcph->seq), | ||
190 | (int)rep_len - (int)match_len, | ||
191 | ct, ctinfo); | ||
192 | /* Tell TCP window tracking about seq change */ | ||
193 | nf_conntrack_tcp_update(*pskb, (*pskb)->nh.iph->ihl*4, | ||
194 | ct, CTINFO2DIR(ctinfo)); | ||
195 | } | ||
196 | return 1; | ||
197 | } | ||
198 | EXPORT_SYMBOL(nf_nat_mangle_tcp_packet); | ||
199 | |||
200 | /* Generic function for mangling variable-length address changes inside | ||
201 | * NATed UDP connections (like the CONNECT DATA XXXXX MESG XXXXX INDEX XXXXX | ||
202 | * command in the Amanda protocol) | ||
203 | * | ||
204 | * Takes care about all the nasty sequence number changes, checksumming, | ||
205 | * skb enlargement, ... | ||
206 | * | ||
207 | * XXX - This function could be merged with nf_nat_mangle_tcp_packet which | ||
208 | * should be fairly easy to do. | ||
209 | */ | ||
210 | int | ||
211 | nf_nat_mangle_udp_packet(struct sk_buff **pskb, | ||
212 | struct nf_conn *ct, | ||
213 | enum ip_conntrack_info ctinfo, | ||
214 | unsigned int match_offset, | ||
215 | unsigned int match_len, | ||
216 | const char *rep_buffer, | ||
217 | unsigned int rep_len) | ||
218 | { | ||
219 | struct iphdr *iph; | ||
220 | struct udphdr *udph; | ||
221 | int datalen, oldlen; | ||
222 | |||
223 | /* UDP helpers might accidentally mangle the wrong packet */ | ||
224 | iph = (*pskb)->nh.iph; | ||
225 | if ((*pskb)->len < iph->ihl*4 + sizeof(*udph) + | ||
226 | match_offset + match_len) | ||
227 | return 0; | ||
228 | |||
229 | if (!skb_make_writable(pskb, (*pskb)->len)) | ||
230 | return 0; | ||
231 | |||
232 | if (rep_len > match_len && | ||
233 | rep_len - match_len > skb_tailroom(*pskb) && | ||
234 | !enlarge_skb(pskb, rep_len - match_len)) | ||
235 | return 0; | ||
236 | |||
237 | iph = (*pskb)->nh.iph; | ||
238 | udph = (void *)iph + iph->ihl*4; | ||
239 | |||
240 | oldlen = (*pskb)->len - iph->ihl*4; | ||
241 | mangle_contents(*pskb, iph->ihl*4 + sizeof(*udph), | ||
242 | match_offset, match_len, rep_buffer, rep_len); | ||
243 | |||
244 | /* update the length of the UDP packet */ | ||
245 | datalen = (*pskb)->len - iph->ihl*4; | ||
246 | udph->len = htons(datalen); | ||
247 | |||
248 | /* fix udp checksum if udp checksum was previously calculated */ | ||
249 | if (!udph->check && (*pskb)->ip_summed != CHECKSUM_PARTIAL) | ||
250 | return 1; | ||
251 | |||
252 | if ((*pskb)->ip_summed != CHECKSUM_PARTIAL) { | ||
253 | udph->check = 0; | ||
254 | udph->check = csum_tcpudp_magic(iph->saddr, iph->daddr, | ||
255 | datalen, IPPROTO_UDP, | ||
256 | csum_partial((char *)udph, | ||
257 | datalen, 0)); | ||
258 | if (!udph->check) | ||
259 | udph->check = CSUM_MANGLED_0; | ||
260 | } else | ||
261 | nf_proto_csum_replace2(&udph->check, *pskb, | ||
262 | htons(oldlen), htons(datalen), 1); | ||
263 | |||
264 | return 1; | ||
265 | } | ||
266 | EXPORT_SYMBOL(nf_nat_mangle_udp_packet); | ||
267 | |||
268 | /* Adjust one found SACK option including checksum correction */ | ||
269 | static void | ||
270 | sack_adjust(struct sk_buff *skb, | ||
271 | struct tcphdr *tcph, | ||
272 | unsigned int sackoff, | ||
273 | unsigned int sackend, | ||
274 | struct nf_nat_seq *natseq) | ||
275 | { | ||
276 | while (sackoff < sackend) { | ||
277 | struct tcp_sack_block_wire *sack; | ||
278 | __be32 new_start_seq, new_end_seq; | ||
279 | |||
280 | sack = (void *)skb->data + sackoff; | ||
281 | if (after(ntohl(sack->start_seq) - natseq->offset_before, | ||
282 | natseq->correction_pos)) | ||
283 | new_start_seq = htonl(ntohl(sack->start_seq) | ||
284 | - natseq->offset_after); | ||
285 | else | ||
286 | new_start_seq = htonl(ntohl(sack->start_seq) | ||
287 | - natseq->offset_before); | ||
288 | |||
289 | if (after(ntohl(sack->end_seq) - natseq->offset_before, | ||
290 | natseq->correction_pos)) | ||
291 | new_end_seq = htonl(ntohl(sack->end_seq) | ||
292 | - natseq->offset_after); | ||
293 | else | ||
294 | new_end_seq = htonl(ntohl(sack->end_seq) | ||
295 | - natseq->offset_before); | ||
296 | |||
297 | DEBUGP("sack_adjust: start_seq: %d->%d, end_seq: %d->%d\n", | ||
298 | ntohl(sack->start_seq), new_start_seq, | ||
299 | ntohl(sack->end_seq), new_end_seq); | ||
300 | |||
301 | nf_proto_csum_replace4(&tcph->check, skb, | ||
302 | sack->start_seq, new_start_seq, 0); | ||
303 | nf_proto_csum_replace4(&tcph->check, skb, | ||
304 | sack->end_seq, new_end_seq, 0); | ||
305 | sack->start_seq = new_start_seq; | ||
306 | sack->end_seq = new_end_seq; | ||
307 | sackoff += sizeof(*sack); | ||
308 | } | ||
309 | } | ||
310 | |||
311 | /* TCP SACK sequence number adjustment */ | ||
312 | static inline unsigned int | ||
313 | nf_nat_sack_adjust(struct sk_buff **pskb, | ||
314 | struct tcphdr *tcph, | ||
315 | struct nf_conn *ct, | ||
316 | enum ip_conntrack_info ctinfo) | ||
317 | { | ||
318 | unsigned int dir, optoff, optend; | ||
319 | struct nf_conn_nat *nat = nfct_nat(ct); | ||
320 | |||
321 | optoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct tcphdr); | ||
322 | optend = (*pskb)->nh.iph->ihl*4 + tcph->doff*4; | ||
323 | |||
324 | if (!skb_make_writable(pskb, optend)) | ||
325 | return 0; | ||
326 | |||
327 | dir = CTINFO2DIR(ctinfo); | ||
328 | |||
329 | while (optoff < optend) { | ||
330 | /* Usually: option, length. */ | ||
331 | unsigned char *op = (*pskb)->data + optoff; | ||
332 | |||
333 | switch (op[0]) { | ||
334 | case TCPOPT_EOL: | ||
335 | return 1; | ||
336 | case TCPOPT_NOP: | ||
337 | optoff++; | ||
338 | continue; | ||
339 | default: | ||
340 | /* no partial options */ | ||
341 | if (optoff + 1 == optend || | ||
342 | optoff + op[1] > optend || | ||
343 | op[1] < 2) | ||
344 | return 0; | ||
345 | if (op[0] == TCPOPT_SACK && | ||
346 | op[1] >= 2+TCPOLEN_SACK_PERBLOCK && | ||
347 | ((op[1] - 2) % TCPOLEN_SACK_PERBLOCK) == 0) | ||
348 | sack_adjust(*pskb, tcph, optoff+2, | ||
349 | optoff+op[1], | ||
350 | &nat->info.seq[!dir]); | ||
351 | optoff += op[1]; | ||
352 | } | ||
353 | } | ||
354 | return 1; | ||
355 | } | ||
356 | |||
357 | /* TCP sequence number adjustment. Returns 1 on success, 0 on failure */ | ||
358 | int | ||
359 | nf_nat_seq_adjust(struct sk_buff **pskb, | ||
360 | struct nf_conn *ct, | ||
361 | enum ip_conntrack_info ctinfo) | ||
362 | { | ||
363 | struct tcphdr *tcph; | ||
364 | int dir; | ||
365 | __be32 newseq, newack; | ||
366 | struct nf_conn_nat *nat = nfct_nat(ct); | ||
367 | struct nf_nat_seq *this_way, *other_way; | ||
368 | |||
369 | dir = CTINFO2DIR(ctinfo); | ||
370 | |||
371 | this_way = &nat->info.seq[dir]; | ||
372 | other_way = &nat->info.seq[!dir]; | ||
373 | |||
374 | if (!skb_make_writable(pskb, (*pskb)->nh.iph->ihl*4+sizeof(*tcph))) | ||
375 | return 0; | ||
376 | |||
377 | tcph = (void *)(*pskb)->data + (*pskb)->nh.iph->ihl*4; | ||
378 | if (after(ntohl(tcph->seq), this_way->correction_pos)) | ||
379 | newseq = htonl(ntohl(tcph->seq) + this_way->offset_after); | ||
380 | else | ||
381 | newseq = htonl(ntohl(tcph->seq) + this_way->offset_before); | ||
382 | |||
383 | if (after(ntohl(tcph->ack_seq) - other_way->offset_before, | ||
384 | other_way->correction_pos)) | ||
385 | newack = htonl(ntohl(tcph->ack_seq) - other_way->offset_after); | ||
386 | else | ||
387 | newack = htonl(ntohl(tcph->ack_seq) - other_way->offset_before); | ||
388 | |||
389 | nf_proto_csum_replace4(&tcph->check, *pskb, tcph->seq, newseq, 0); | ||
390 | nf_proto_csum_replace4(&tcph->check, *pskb, tcph->ack_seq, newack, 0); | ||
391 | |||
392 | DEBUGP("Adjusting sequence number from %u->%u, ack from %u->%u\n", | ||
393 | ntohl(tcph->seq), ntohl(newseq), ntohl(tcph->ack_seq), | ||
394 | ntohl(newack)); | ||
395 | |||
396 | tcph->seq = newseq; | ||
397 | tcph->ack_seq = newack; | ||
398 | |||
399 | if (!nf_nat_sack_adjust(pskb, tcph, ct, ctinfo)) | ||
400 | return 0; | ||
401 | |||
402 | nf_conntrack_tcp_update(*pskb, (*pskb)->nh.iph->ihl*4, ct, dir); | ||
403 | |||
404 | return 1; | ||
405 | } | ||
406 | EXPORT_SYMBOL(nf_nat_seq_adjust); | ||
407 | |||
408 | /* Setup NAT on this expected conntrack so it follows master. */ | ||
409 | /* If we fail to get a free NAT slot, we'll get dropped on confirm */ | ||
410 | void nf_nat_follow_master(struct nf_conn *ct, | ||
411 | struct nf_conntrack_expect *exp) | ||
412 | { | ||
413 | struct nf_nat_range range; | ||
414 | |||
415 | /* This must be a fresh one. */ | ||
416 | BUG_ON(ct->status & IPS_NAT_DONE_MASK); | ||
417 | |||
418 | /* Change src to where master sends to */ | ||
419 | range.flags = IP_NAT_RANGE_MAP_IPS; | ||
420 | range.min_ip = range.max_ip | ||
421 | = ct->master->tuplehash[!exp->dir].tuple.dst.u3.ip; | ||
422 | /* hook doesn't matter, but it has to do source manip */ | ||
423 | nf_nat_setup_info(ct, &range, NF_IP_POST_ROUTING); | ||
424 | |||
425 | /* For DST manip, map port here to where it's expected. */ | ||
426 | range.flags = (IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED); | ||
427 | range.min = range.max = exp->saved_proto; | ||
428 | range.min_ip = range.max_ip | ||
429 | = ct->master->tuplehash[!exp->dir].tuple.src.u3.ip; | ||
430 | /* hook doesn't matter, but it has to do destination manip */ | ||
431 | nf_nat_setup_info(ct, &range, NF_IP_PRE_ROUTING); | ||
432 | } | ||
433 | EXPORT_SYMBOL(nf_nat_follow_master); | ||
diff --git a/net/ipv4/netfilter/nf_nat_irc.c b/net/ipv4/netfilter/nf_nat_irc.c new file mode 100644 index 000000000000..9b8c0daea744 --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_irc.c | |||
@@ -0,0 +1,101 @@ | |||
1 | /* IRC extension for TCP NAT alteration. | ||
2 | * | ||
3 | * (C) 2000-2001 by Harald Welte <laforge@gnumonks.org> | ||
4 | * (C) 2004 Rusty Russell <rusty@rustcorp.com.au> IBM Corporation | ||
5 | * based on a copy of RR's ip_nat_ftp.c | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * as published by the Free Software Foundation; either version | ||
10 | * 2 of the License, or (at your option) any later version. | ||
11 | */ | ||
12 | |||
13 | #include <linux/module.h> | ||
14 | #include <linux/moduleparam.h> | ||
15 | #include <linux/tcp.h> | ||
16 | #include <linux/kernel.h> | ||
17 | |||
18 | #include <net/netfilter/nf_nat.h> | ||
19 | #include <net/netfilter/nf_nat_helper.h> | ||
20 | #include <net/netfilter/nf_nat_rule.h> | ||
21 | #include <net/netfilter/nf_conntrack_helper.h> | ||
22 | #include <net/netfilter/nf_conntrack_expect.h> | ||
23 | #include <linux/netfilter/nf_conntrack_irc.h> | ||
24 | |||
25 | #if 0 | ||
26 | #define DEBUGP printk | ||
27 | #else | ||
28 | #define DEBUGP(format, args...) | ||
29 | #endif | ||
30 | |||
31 | MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>"); | ||
32 | MODULE_DESCRIPTION("IRC (DCC) NAT helper"); | ||
33 | MODULE_LICENSE("GPL"); | ||
34 | MODULE_ALIAS("ip_nat_irc"); | ||
35 | |||
36 | static unsigned int help(struct sk_buff **pskb, | ||
37 | enum ip_conntrack_info ctinfo, | ||
38 | unsigned int matchoff, | ||
39 | unsigned int matchlen, | ||
40 | struct nf_conntrack_expect *exp) | ||
41 | { | ||
42 | char buffer[sizeof("4294967296 65635")]; | ||
43 | u_int32_t ip; | ||
44 | u_int16_t port; | ||
45 | unsigned int ret; | ||
46 | |||
47 | DEBUGP("IRC_NAT: info (seq %u + %u) in %u\n", | ||
48 | expect->seq, exp_irc_info->len, ntohl(tcph->seq)); | ||
49 | |||
50 | /* Reply comes from server. */ | ||
51 | exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port; | ||
52 | exp->dir = IP_CT_DIR_REPLY; | ||
53 | exp->expectfn = nf_nat_follow_master; | ||
54 | |||
55 | /* Try to get same port: if not, try to change it. */ | ||
56 | for (port = ntohs(exp->saved_proto.tcp.port); port != 0; port++) { | ||
57 | exp->tuple.dst.u.tcp.port = htons(port); | ||
58 | if (nf_conntrack_expect_related(exp) == 0) | ||
59 | break; | ||
60 | } | ||
61 | |||
62 | if (port == 0) | ||
63 | return NF_DROP; | ||
64 | |||
65 | ip = ntohl(exp->master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip); | ||
66 | sprintf(buffer, "%u %u", ip, port); | ||
67 | DEBUGP("nf_nat_irc: inserting '%s' == %u.%u.%u.%u, port %u\n", | ||
68 | buffer, NIPQUAD(ip), port); | ||
69 | |||
70 | ret = nf_nat_mangle_tcp_packet(pskb, exp->master, ctinfo, | ||
71 | matchoff, matchlen, buffer, | ||
72 | strlen(buffer)); | ||
73 | if (ret != NF_ACCEPT) | ||
74 | nf_conntrack_unexpect_related(exp); | ||
75 | return ret; | ||
76 | } | ||
77 | |||
78 | static void __exit nf_nat_irc_fini(void) | ||
79 | { | ||
80 | rcu_assign_pointer(nf_nat_irc_hook, NULL); | ||
81 | synchronize_rcu(); | ||
82 | } | ||
83 | |||
84 | static int __init nf_nat_irc_init(void) | ||
85 | { | ||
86 | BUG_ON(rcu_dereference(nf_nat_irc_hook)); | ||
87 | rcu_assign_pointer(nf_nat_irc_hook, help); | ||
88 | return 0; | ||
89 | } | ||
90 | |||
91 | /* Prior to 2.6.11, we had a ports param. No longer, but don't break users. */ | ||
92 | static int warn_set(const char *val, struct kernel_param *kp) | ||
93 | { | ||
94 | printk(KERN_INFO KBUILD_MODNAME | ||
95 | ": kernel >= 2.6.10 only uses 'ports' for conntrack modules\n"); | ||
96 | return 0; | ||
97 | } | ||
98 | module_param_call(ports, warn_set, NULL, NULL, 0); | ||
99 | |||
100 | module_init(nf_nat_irc_init); | ||
101 | module_exit(nf_nat_irc_fini); | ||
diff --git a/net/ipv4/netfilter/nf_nat_pptp.c b/net/ipv4/netfilter/nf_nat_pptp.c new file mode 100644 index 000000000000..0ae45b79a4eb --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_pptp.c | |||
@@ -0,0 +1,315 @@ | |||
1 | /* | ||
2 | * nf_nat_pptp.c | ||
3 | * | ||
4 | * NAT support for PPTP (Point to Point Tunneling Protocol). | ||
5 | * PPTP is a a protocol for creating virtual private networks. | ||
6 | * It is a specification defined by Microsoft and some vendors | ||
7 | * working with Microsoft. PPTP is built on top of a modified | ||
8 | * version of the Internet Generic Routing Encapsulation Protocol. | ||
9 | * GRE is defined in RFC 1701 and RFC 1702. Documentation of | ||
10 | * PPTP can be found in RFC 2637 | ||
11 | * | ||
12 | * (C) 2000-2005 by Harald Welte <laforge@gnumonks.org> | ||
13 | * | ||
14 | * Development of this code funded by Astaro AG (http://www.astaro.com/) | ||
15 | * | ||
16 | * TODO: - NAT to a unique tuple, not to TCP source port | ||
17 | * (needs netfilter tuple reservation) | ||
18 | */ | ||
19 | |||
20 | #include <linux/module.h> | ||
21 | #include <linux/tcp.h> | ||
22 | |||
23 | #include <net/netfilter/nf_nat.h> | ||
24 | #include <net/netfilter/nf_nat_helper.h> | ||
25 | #include <net/netfilter/nf_nat_rule.h> | ||
26 | #include <net/netfilter/nf_conntrack_helper.h> | ||
27 | #include <net/netfilter/nf_conntrack_expect.h> | ||
28 | #include <linux/netfilter/nf_conntrack_proto_gre.h> | ||
29 | #include <linux/netfilter/nf_conntrack_pptp.h> | ||
30 | |||
31 | #define NF_NAT_PPTP_VERSION "3.0" | ||
32 | |||
33 | #define REQ_CID(req, off) (*(__be16 *)((char *)(req) + (off))) | ||
34 | |||
35 | MODULE_LICENSE("GPL"); | ||
36 | MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>"); | ||
37 | MODULE_DESCRIPTION("Netfilter NAT helper module for PPTP"); | ||
38 | MODULE_ALIAS("ip_nat_pptp"); | ||
39 | |||
40 | #if 0 | ||
41 | extern const char *pptp_msg_name[]; | ||
42 | #define DEBUGP(format, args...) printk(KERN_DEBUG "%s:%s: " format, __FILE__, \ | ||
43 | __FUNCTION__, ## args) | ||
44 | #else | ||
45 | #define DEBUGP(format, args...) | ||
46 | #endif | ||
47 | |||
48 | static void pptp_nat_expected(struct nf_conn *ct, | ||
49 | struct nf_conntrack_expect *exp) | ||
50 | { | ||
51 | struct nf_conn *master = ct->master; | ||
52 | struct nf_conntrack_expect *other_exp; | ||
53 | struct nf_conntrack_tuple t; | ||
54 | struct nf_ct_pptp_master *ct_pptp_info; | ||
55 | struct nf_nat_pptp *nat_pptp_info; | ||
56 | struct ip_nat_range range; | ||
57 | |||
58 | ct_pptp_info = &nfct_help(master)->help.ct_pptp_info; | ||
59 | nat_pptp_info = &nfct_nat(master)->help.nat_pptp_info; | ||
60 | |||
61 | /* And here goes the grand finale of corrosion... */ | ||
62 | if (exp->dir == IP_CT_DIR_ORIGINAL) { | ||
63 | DEBUGP("we are PNS->PAC\n"); | ||
64 | /* therefore, build tuple for PAC->PNS */ | ||
65 | t.src.l3num = AF_INET; | ||
66 | t.src.u3.ip = master->tuplehash[!exp->dir].tuple.src.u3.ip; | ||
67 | t.src.u.gre.key = ct_pptp_info->pac_call_id; | ||
68 | t.dst.u3.ip = master->tuplehash[!exp->dir].tuple.dst.u3.ip; | ||
69 | t.dst.u.gre.key = ct_pptp_info->pns_call_id; | ||
70 | t.dst.protonum = IPPROTO_GRE; | ||
71 | } else { | ||
72 | DEBUGP("we are PAC->PNS\n"); | ||
73 | /* build tuple for PNS->PAC */ | ||
74 | t.src.l3num = AF_INET; | ||
75 | t.src.u3.ip = master->tuplehash[exp->dir].tuple.src.u3.ip; | ||
76 | t.src.u.gre.key = nat_pptp_info->pns_call_id; | ||
77 | t.dst.u3.ip = master->tuplehash[exp->dir].tuple.dst.u3.ip; | ||
78 | t.dst.u.gre.key = nat_pptp_info->pac_call_id; | ||
79 | t.dst.protonum = IPPROTO_GRE; | ||
80 | } | ||
81 | |||
82 | DEBUGP("trying to unexpect other dir: "); | ||
83 | NF_CT_DUMP_TUPLE(&t); | ||
84 | other_exp = nf_conntrack_expect_find_get(&t); | ||
85 | if (other_exp) { | ||
86 | nf_conntrack_unexpect_related(other_exp); | ||
87 | nf_conntrack_expect_put(other_exp); | ||
88 | DEBUGP("success\n"); | ||
89 | } else { | ||
90 | DEBUGP("not found!\n"); | ||
91 | } | ||
92 | |||
93 | /* This must be a fresh one. */ | ||
94 | BUG_ON(ct->status & IPS_NAT_DONE_MASK); | ||
95 | |||
96 | /* Change src to where master sends to */ | ||
97 | range.flags = IP_NAT_RANGE_MAP_IPS; | ||
98 | range.min_ip = range.max_ip | ||
99 | = ct->master->tuplehash[!exp->dir].tuple.dst.u3.ip; | ||
100 | if (exp->dir == IP_CT_DIR_ORIGINAL) { | ||
101 | range.flags |= IP_NAT_RANGE_PROTO_SPECIFIED; | ||
102 | range.min = range.max = exp->saved_proto; | ||
103 | } | ||
104 | /* hook doesn't matter, but it has to do source manip */ | ||
105 | nf_nat_setup_info(ct, &range, NF_IP_POST_ROUTING); | ||
106 | |||
107 | /* For DST manip, map port here to where it's expected. */ | ||
108 | range.flags = IP_NAT_RANGE_MAP_IPS; | ||
109 | range.min_ip = range.max_ip | ||
110 | = ct->master->tuplehash[!exp->dir].tuple.src.u3.ip; | ||
111 | if (exp->dir == IP_CT_DIR_REPLY) { | ||
112 | range.flags |= IP_NAT_RANGE_PROTO_SPECIFIED; | ||
113 | range.min = range.max = exp->saved_proto; | ||
114 | } | ||
115 | /* hook doesn't matter, but it has to do destination manip */ | ||
116 | nf_nat_setup_info(ct, &range, NF_IP_PRE_ROUTING); | ||
117 | } | ||
118 | |||
119 | /* outbound packets == from PNS to PAC */ | ||
120 | static int | ||
121 | pptp_outbound_pkt(struct sk_buff **pskb, | ||
122 | struct nf_conn *ct, | ||
123 | enum ip_conntrack_info ctinfo, | ||
124 | struct PptpControlHeader *ctlh, | ||
125 | union pptp_ctrl_union *pptpReq) | ||
126 | |||
127 | { | ||
128 | struct nf_ct_pptp_master *ct_pptp_info; | ||
129 | struct nf_nat_pptp *nat_pptp_info; | ||
130 | u_int16_t msg; | ||
131 | __be16 new_callid; | ||
132 | unsigned int cid_off; | ||
133 | |||
134 | ct_pptp_info = &nfct_help(ct)->help.ct_pptp_info; | ||
135 | nat_pptp_info = &nfct_nat(ct)->help.nat_pptp_info; | ||
136 | |||
137 | new_callid = ct_pptp_info->pns_call_id; | ||
138 | |||
139 | switch (msg = ntohs(ctlh->messageType)) { | ||
140 | case PPTP_OUT_CALL_REQUEST: | ||
141 | cid_off = offsetof(union pptp_ctrl_union, ocreq.callID); | ||
142 | /* FIXME: ideally we would want to reserve a call ID | ||
143 | * here. current netfilter NAT core is not able to do | ||
144 | * this :( For now we use TCP source port. This breaks | ||
145 | * multiple calls within one control session */ | ||
146 | |||
147 | /* save original call ID in nat_info */ | ||
148 | nat_pptp_info->pns_call_id = ct_pptp_info->pns_call_id; | ||
149 | |||
150 | /* don't use tcph->source since we are at a DSTmanip | ||
151 | * hook (e.g. PREROUTING) and pkt is not mangled yet */ | ||
152 | new_callid = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.tcp.port; | ||
153 | |||
154 | /* save new call ID in ct info */ | ||
155 | ct_pptp_info->pns_call_id = new_callid; | ||
156 | break; | ||
157 | case PPTP_IN_CALL_REPLY: | ||
158 | cid_off = offsetof(union pptp_ctrl_union, icack.callID); | ||
159 | break; | ||
160 | case PPTP_CALL_CLEAR_REQUEST: | ||
161 | cid_off = offsetof(union pptp_ctrl_union, clrreq.callID); | ||
162 | break; | ||
163 | default: | ||
164 | DEBUGP("unknown outbound packet 0x%04x:%s\n", msg, | ||
165 | (msg <= PPTP_MSG_MAX)? | ||
166 | pptp_msg_name[msg]:pptp_msg_name[0]); | ||
167 | /* fall through */ | ||
168 | case PPTP_SET_LINK_INFO: | ||
169 | /* only need to NAT in case PAC is behind NAT box */ | ||
170 | case PPTP_START_SESSION_REQUEST: | ||
171 | case PPTP_START_SESSION_REPLY: | ||
172 | case PPTP_STOP_SESSION_REQUEST: | ||
173 | case PPTP_STOP_SESSION_REPLY: | ||
174 | case PPTP_ECHO_REQUEST: | ||
175 | case PPTP_ECHO_REPLY: | ||
176 | /* no need to alter packet */ | ||
177 | return NF_ACCEPT; | ||
178 | } | ||
179 | |||
180 | /* only OUT_CALL_REQUEST, IN_CALL_REPLY, CALL_CLEAR_REQUEST pass | ||
181 | * down to here */ | ||
182 | DEBUGP("altering call id from 0x%04x to 0x%04x\n", | ||
183 | ntohs(REQ_CID(pptpReq, cid_off)), ntohs(new_callid)); | ||
184 | |||
185 | /* mangle packet */ | ||
186 | if (nf_nat_mangle_tcp_packet(pskb, ct, ctinfo, | ||
187 | cid_off + sizeof(struct pptp_pkt_hdr) + | ||
188 | sizeof(struct PptpControlHeader), | ||
189 | sizeof(new_callid), (char *)&new_callid, | ||
190 | sizeof(new_callid)) == 0) | ||
191 | return NF_DROP; | ||
192 | return NF_ACCEPT; | ||
193 | } | ||
194 | |||
195 | static void | ||
196 | pptp_exp_gre(struct nf_conntrack_expect *expect_orig, | ||
197 | struct nf_conntrack_expect *expect_reply) | ||
198 | { | ||
199 | struct nf_conn *ct = expect_orig->master; | ||
200 | struct nf_ct_pptp_master *ct_pptp_info; | ||
201 | struct nf_nat_pptp *nat_pptp_info; | ||
202 | |||
203 | ct_pptp_info = &nfct_help(ct)->help.ct_pptp_info; | ||
204 | nat_pptp_info = &nfct_nat(ct)->help.nat_pptp_info; | ||
205 | |||
206 | /* save original PAC call ID in nat_info */ | ||
207 | nat_pptp_info->pac_call_id = ct_pptp_info->pac_call_id; | ||
208 | |||
209 | /* alter expectation for PNS->PAC direction */ | ||
210 | expect_orig->saved_proto.gre.key = ct_pptp_info->pns_call_id; | ||
211 | expect_orig->tuple.src.u.gre.key = nat_pptp_info->pns_call_id; | ||
212 | expect_orig->tuple.dst.u.gre.key = ct_pptp_info->pac_call_id; | ||
213 | expect_orig->dir = IP_CT_DIR_ORIGINAL; | ||
214 | |||
215 | /* alter expectation for PAC->PNS direction */ | ||
216 | expect_reply->saved_proto.gre.key = nat_pptp_info->pns_call_id; | ||
217 | expect_reply->tuple.src.u.gre.key = nat_pptp_info->pac_call_id; | ||
218 | expect_reply->tuple.dst.u.gre.key = ct_pptp_info->pns_call_id; | ||
219 | expect_reply->dir = IP_CT_DIR_REPLY; | ||
220 | } | ||
221 | |||
222 | /* inbound packets == from PAC to PNS */ | ||
223 | static int | ||
224 | pptp_inbound_pkt(struct sk_buff **pskb, | ||
225 | struct nf_conn *ct, | ||
226 | enum ip_conntrack_info ctinfo, | ||
227 | struct PptpControlHeader *ctlh, | ||
228 | union pptp_ctrl_union *pptpReq) | ||
229 | { | ||
230 | struct nf_nat_pptp *nat_pptp_info; | ||
231 | u_int16_t msg; | ||
232 | __be16 new_pcid; | ||
233 | unsigned int pcid_off; | ||
234 | |||
235 | nat_pptp_info = &nfct_nat(ct)->help.nat_pptp_info; | ||
236 | new_pcid = nat_pptp_info->pns_call_id; | ||
237 | |||
238 | switch (msg = ntohs(ctlh->messageType)) { | ||
239 | case PPTP_OUT_CALL_REPLY: | ||
240 | pcid_off = offsetof(union pptp_ctrl_union, ocack.peersCallID); | ||
241 | break; | ||
242 | case PPTP_IN_CALL_CONNECT: | ||
243 | pcid_off = offsetof(union pptp_ctrl_union, iccon.peersCallID); | ||
244 | break; | ||
245 | case PPTP_IN_CALL_REQUEST: | ||
246 | /* only need to nat in case PAC is behind NAT box */ | ||
247 | return NF_ACCEPT; | ||
248 | case PPTP_WAN_ERROR_NOTIFY: | ||
249 | pcid_off = offsetof(union pptp_ctrl_union, wanerr.peersCallID); | ||
250 | break; | ||
251 | case PPTP_CALL_DISCONNECT_NOTIFY: | ||
252 | pcid_off = offsetof(union pptp_ctrl_union, disc.callID); | ||
253 | break; | ||
254 | case PPTP_SET_LINK_INFO: | ||
255 | pcid_off = offsetof(union pptp_ctrl_union, setlink.peersCallID); | ||
256 | break; | ||
257 | default: | ||
258 | DEBUGP("unknown inbound packet %s\n", (msg <= PPTP_MSG_MAX)? | ||
259 | pptp_msg_name[msg]:pptp_msg_name[0]); | ||
260 | /* fall through */ | ||
261 | case PPTP_START_SESSION_REQUEST: | ||
262 | case PPTP_START_SESSION_REPLY: | ||
263 | case PPTP_STOP_SESSION_REQUEST: | ||
264 | case PPTP_STOP_SESSION_REPLY: | ||
265 | case PPTP_ECHO_REQUEST: | ||
266 | case PPTP_ECHO_REPLY: | ||
267 | /* no need to alter packet */ | ||
268 | return NF_ACCEPT; | ||
269 | } | ||
270 | |||
271 | /* only OUT_CALL_REPLY, IN_CALL_CONNECT, IN_CALL_REQUEST, | ||
272 | * WAN_ERROR_NOTIFY, CALL_DISCONNECT_NOTIFY pass down here */ | ||
273 | |||
274 | /* mangle packet */ | ||
275 | DEBUGP("altering peer call id from 0x%04x to 0x%04x\n", | ||
276 | ntohs(REQ_CID(pptpReq, pcid_off)), ntohs(new_pcid)); | ||
277 | |||
278 | if (nf_nat_mangle_tcp_packet(pskb, ct, ctinfo, | ||
279 | pcid_off + sizeof(struct pptp_pkt_hdr) + | ||
280 | sizeof(struct PptpControlHeader), | ||
281 | sizeof(new_pcid), (char *)&new_pcid, | ||
282 | sizeof(new_pcid)) == 0) | ||
283 | return NF_DROP; | ||
284 | return NF_ACCEPT; | ||
285 | } | ||
286 | |||
287 | static int __init nf_nat_helper_pptp_init(void) | ||
288 | { | ||
289 | nf_nat_need_gre(); | ||
290 | |||
291 | BUG_ON(rcu_dereference(nf_nat_pptp_hook_outbound)); | ||
292 | rcu_assign_pointer(nf_nat_pptp_hook_outbound, pptp_outbound_pkt); | ||
293 | |||
294 | BUG_ON(rcu_dereference(nf_nat_pptp_hook_inbound)); | ||
295 | rcu_assign_pointer(nf_nat_pptp_hook_inbound, pptp_inbound_pkt); | ||
296 | |||
297 | BUG_ON(rcu_dereference(nf_nat_pptp_hook_exp_gre)); | ||
298 | rcu_assign_pointer(nf_nat_pptp_hook_exp_gre, pptp_exp_gre); | ||
299 | |||
300 | BUG_ON(rcu_dereference(nf_nat_pptp_hook_expectfn)); | ||
301 | rcu_assign_pointer(nf_nat_pptp_hook_expectfn, pptp_nat_expected); | ||
302 | return 0; | ||
303 | } | ||
304 | |||
305 | static void __exit nf_nat_helper_pptp_fini(void) | ||
306 | { | ||
307 | rcu_assign_pointer(nf_nat_pptp_hook_expectfn, NULL); | ||
308 | rcu_assign_pointer(nf_nat_pptp_hook_exp_gre, NULL); | ||
309 | rcu_assign_pointer(nf_nat_pptp_hook_inbound, NULL); | ||
310 | rcu_assign_pointer(nf_nat_pptp_hook_outbound, NULL); | ||
311 | synchronize_rcu(); | ||
312 | } | ||
313 | |||
314 | module_init(nf_nat_helper_pptp_init); | ||
315 | module_exit(nf_nat_helper_pptp_fini); | ||
diff --git a/net/ipv4/netfilter/nf_nat_proto_gre.c b/net/ipv4/netfilter/nf_nat_proto_gre.c new file mode 100644 index 000000000000..d3de579e09d2 --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_proto_gre.c | |||
@@ -0,0 +1,179 @@ | |||
1 | /* | ||
2 | * nf_nat_proto_gre.c | ||
3 | * | ||
4 | * NAT protocol helper module for GRE. | ||
5 | * | ||
6 | * GRE is a generic encapsulation protocol, which is generally not very | ||
7 | * suited for NAT, as it has no protocol-specific part as port numbers. | ||
8 | * | ||
9 | * It has an optional key field, which may help us distinguishing two | ||
10 | * connections between the same two hosts. | ||
11 | * | ||
12 | * GRE is defined in RFC 1701 and RFC 1702, as well as RFC 2784 | ||
13 | * | ||
14 | * PPTP is built on top of a modified version of GRE, and has a mandatory | ||
15 | * field called "CallID", which serves us for the same purpose as the key | ||
16 | * field in plain GRE. | ||
17 | * | ||
18 | * Documentation about PPTP can be found in RFC 2637 | ||
19 | * | ||
20 | * (C) 2000-2005 by Harald Welte <laforge@gnumonks.org> | ||
21 | * | ||
22 | * Development of this code funded by Astaro AG (http://www.astaro.com/) | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | #include <linux/module.h> | ||
27 | #include <linux/skbuff.h> | ||
28 | #include <linux/ip.h> | ||
29 | |||
30 | #include <net/netfilter/nf_nat.h> | ||
31 | #include <net/netfilter/nf_nat_rule.h> | ||
32 | #include <net/netfilter/nf_nat_protocol.h> | ||
33 | #include <linux/netfilter/nf_conntrack_proto_gre.h> | ||
34 | |||
35 | MODULE_LICENSE("GPL"); | ||
36 | MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>"); | ||
37 | MODULE_DESCRIPTION("Netfilter NAT protocol helper module for GRE"); | ||
38 | |||
39 | #if 0 | ||
40 | #define DEBUGP(format, args...) printk(KERN_DEBUG "%s:%s: " format, __FILE__, \ | ||
41 | __FUNCTION__, ## args) | ||
42 | #else | ||
43 | #define DEBUGP(x, args...) | ||
44 | #endif | ||
45 | |||
46 | /* is key in given range between min and max */ | ||
47 | static int | ||
48 | gre_in_range(const struct nf_conntrack_tuple *tuple, | ||
49 | enum nf_nat_manip_type maniptype, | ||
50 | const union nf_conntrack_man_proto *min, | ||
51 | const union nf_conntrack_man_proto *max) | ||
52 | { | ||
53 | __be16 key; | ||
54 | |||
55 | if (maniptype == IP_NAT_MANIP_SRC) | ||
56 | key = tuple->src.u.gre.key; | ||
57 | else | ||
58 | key = tuple->dst.u.gre.key; | ||
59 | |||
60 | return ntohs(key) >= ntohs(min->gre.key) && | ||
61 | ntohs(key) <= ntohs(max->gre.key); | ||
62 | } | ||
63 | |||
64 | /* generate unique tuple ... */ | ||
65 | static int | ||
66 | gre_unique_tuple(struct nf_conntrack_tuple *tuple, | ||
67 | const struct nf_nat_range *range, | ||
68 | enum nf_nat_manip_type maniptype, | ||
69 | const struct nf_conn *conntrack) | ||
70 | { | ||
71 | static u_int16_t key; | ||
72 | __be16 *keyptr; | ||
73 | unsigned int min, i, range_size; | ||
74 | |||
75 | if (maniptype == IP_NAT_MANIP_SRC) | ||
76 | keyptr = &tuple->src.u.gre.key; | ||
77 | else | ||
78 | keyptr = &tuple->dst.u.gre.key; | ||
79 | |||
80 | if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) { | ||
81 | DEBUGP("%p: NATing GRE PPTP\n", conntrack); | ||
82 | min = 1; | ||
83 | range_size = 0xffff; | ||
84 | } else { | ||
85 | min = ntohs(range->min.gre.key); | ||
86 | range_size = ntohs(range->max.gre.key) - min + 1; | ||
87 | } | ||
88 | |||
89 | DEBUGP("min = %u, range_size = %u\n", min, range_size); | ||
90 | |||
91 | for (i = 0; i < range_size; i++, key++) { | ||
92 | *keyptr = htons(min + key % range_size); | ||
93 | if (!nf_nat_used_tuple(tuple, conntrack)) | ||
94 | return 1; | ||
95 | } | ||
96 | |||
97 | DEBUGP("%p: no NAT mapping\n", conntrack); | ||
98 | return 0; | ||
99 | } | ||
100 | |||
101 | /* manipulate a GRE packet according to maniptype */ | ||
102 | static int | ||
103 | gre_manip_pkt(struct sk_buff **pskb, unsigned int iphdroff, | ||
104 | const struct nf_conntrack_tuple *tuple, | ||
105 | enum nf_nat_manip_type maniptype) | ||
106 | { | ||
107 | struct gre_hdr *greh; | ||
108 | struct gre_hdr_pptp *pgreh; | ||
109 | struct iphdr *iph = (struct iphdr *)((*pskb)->data + iphdroff); | ||
110 | unsigned int hdroff = iphdroff + iph->ihl * 4; | ||
111 | |||
112 | /* pgreh includes two optional 32bit fields which are not required | ||
113 | * to be there. That's where the magic '8' comes from */ | ||
114 | if (!skb_make_writable(pskb, hdroff + sizeof(*pgreh) - 8)) | ||
115 | return 0; | ||
116 | |||
117 | greh = (void *)(*pskb)->data + hdroff; | ||
118 | pgreh = (struct gre_hdr_pptp *)greh; | ||
119 | |||
120 | /* we only have destination manip of a packet, since 'source key' | ||
121 | * is not present in the packet itself */ | ||
122 | if (maniptype != IP_NAT_MANIP_DST) | ||
123 | return 1; | ||
124 | switch (greh->version) { | ||
125 | case 0: | ||
126 | if (!greh->key) { | ||
127 | DEBUGP("can't nat GRE w/o key\n"); | ||
128 | break; | ||
129 | } | ||
130 | if (greh->csum) { | ||
131 | /* FIXME: Never tested this code... */ | ||
132 | nf_proto_csum_replace4(gre_csum(greh), *pskb, | ||
133 | *(gre_key(greh)), | ||
134 | tuple->dst.u.gre.key, 0); | ||
135 | } | ||
136 | *(gre_key(greh)) = tuple->dst.u.gre.key; | ||
137 | break; | ||
138 | case GRE_VERSION_PPTP: | ||
139 | DEBUGP("call_id -> 0x%04x\n", ntohs(tuple->dst.u.gre.key)); | ||
140 | pgreh->call_id = tuple->dst.u.gre.key; | ||
141 | break; | ||
142 | default: | ||
143 | DEBUGP("can't nat unknown GRE version\n"); | ||
144 | return 0; | ||
145 | } | ||
146 | return 1; | ||
147 | } | ||
148 | |||
149 | static struct nf_nat_protocol gre __read_mostly = { | ||
150 | .name = "GRE", | ||
151 | .protonum = IPPROTO_GRE, | ||
152 | .manip_pkt = gre_manip_pkt, | ||
153 | .in_range = gre_in_range, | ||
154 | .unique_tuple = gre_unique_tuple, | ||
155 | #if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \ | ||
156 | defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE) | ||
157 | .range_to_nfattr = nf_nat_port_range_to_nfattr, | ||
158 | .nfattr_to_range = nf_nat_port_nfattr_to_range, | ||
159 | #endif | ||
160 | }; | ||
161 | |||
162 | int __init nf_nat_proto_gre_init(void) | ||
163 | { | ||
164 | return nf_nat_protocol_register(&gre); | ||
165 | } | ||
166 | |||
167 | void __exit nf_nat_proto_gre_fini(void) | ||
168 | { | ||
169 | nf_nat_protocol_unregister(&gre); | ||
170 | } | ||
171 | |||
172 | module_init(nf_nat_proto_gre_init); | ||
173 | module_exit(nf_nat_proto_gre_fini); | ||
174 | |||
175 | void nf_nat_need_gre(void) | ||
176 | { | ||
177 | return; | ||
178 | } | ||
179 | EXPORT_SYMBOL_GPL(nf_nat_need_gre); | ||
diff --git a/net/ipv4/netfilter/nf_nat_proto_icmp.c b/net/ipv4/netfilter/nf_nat_proto_icmp.c new file mode 100644 index 000000000000..dcfd772972d7 --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_proto_icmp.c | |||
@@ -0,0 +1,86 @@ | |||
1 | /* (C) 1999-2001 Paul `Rusty' Russell | ||
2 | * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | #include <linux/types.h> | ||
10 | #include <linux/init.h> | ||
11 | #include <linux/ip.h> | ||
12 | #include <linux/icmp.h> | ||
13 | |||
14 | #include <linux/netfilter.h> | ||
15 | #include <net/netfilter/nf_nat.h> | ||
16 | #include <net/netfilter/nf_nat_core.h> | ||
17 | #include <net/netfilter/nf_nat_rule.h> | ||
18 | #include <net/netfilter/nf_nat_protocol.h> | ||
19 | |||
20 | static int | ||
21 | icmp_in_range(const struct nf_conntrack_tuple *tuple, | ||
22 | enum nf_nat_manip_type maniptype, | ||
23 | const union nf_conntrack_man_proto *min, | ||
24 | const union nf_conntrack_man_proto *max) | ||
25 | { | ||
26 | return ntohs(tuple->src.u.icmp.id) >= ntohs(min->icmp.id) && | ||
27 | ntohs(tuple->src.u.icmp.id) <= ntohs(max->icmp.id); | ||
28 | } | ||
29 | |||
30 | static int | ||
31 | icmp_unique_tuple(struct nf_conntrack_tuple *tuple, | ||
32 | const struct nf_nat_range *range, | ||
33 | enum nf_nat_manip_type maniptype, | ||
34 | const struct nf_conn *ct) | ||
35 | { | ||
36 | static u_int16_t id; | ||
37 | unsigned int range_size; | ||
38 | unsigned int i; | ||
39 | |||
40 | range_size = ntohs(range->max.icmp.id) - ntohs(range->min.icmp.id) + 1; | ||
41 | /* If no range specified... */ | ||
42 | if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) | ||
43 | range_size = 0xFFFF; | ||
44 | |||
45 | for (i = 0; i < range_size; i++, id++) { | ||
46 | tuple->src.u.icmp.id = htons(ntohs(range->min.icmp.id) + | ||
47 | (id % range_size)); | ||
48 | if (!nf_nat_used_tuple(tuple, ct)) | ||
49 | return 1; | ||
50 | } | ||
51 | return 0; | ||
52 | } | ||
53 | |||
54 | static int | ||
55 | icmp_manip_pkt(struct sk_buff **pskb, | ||
56 | unsigned int iphdroff, | ||
57 | const struct nf_conntrack_tuple *tuple, | ||
58 | enum nf_nat_manip_type maniptype) | ||
59 | { | ||
60 | struct iphdr *iph = (struct iphdr *)((*pskb)->data + iphdroff); | ||
61 | struct icmphdr *hdr; | ||
62 | unsigned int hdroff = iphdroff + iph->ihl*4; | ||
63 | |||
64 | if (!skb_make_writable(pskb, hdroff + sizeof(*hdr))) | ||
65 | return 0; | ||
66 | |||
67 | hdr = (struct icmphdr *)((*pskb)->data + hdroff); | ||
68 | nf_proto_csum_replace2(&hdr->checksum, *pskb, | ||
69 | hdr->un.echo.id, tuple->src.u.icmp.id, 0); | ||
70 | hdr->un.echo.id = tuple->src.u.icmp.id; | ||
71 | return 1; | ||
72 | } | ||
73 | |||
74 | struct nf_nat_protocol nf_nat_protocol_icmp = { | ||
75 | .name = "ICMP", | ||
76 | .protonum = IPPROTO_ICMP, | ||
77 | .me = THIS_MODULE, | ||
78 | .manip_pkt = icmp_manip_pkt, | ||
79 | .in_range = icmp_in_range, | ||
80 | .unique_tuple = icmp_unique_tuple, | ||
81 | #if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \ | ||
82 | defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE) | ||
83 | .range_to_nfattr = nf_nat_port_range_to_nfattr, | ||
84 | .nfattr_to_range = nf_nat_port_nfattr_to_range, | ||
85 | #endif | ||
86 | }; | ||
diff --git a/net/ipv4/netfilter/nf_nat_proto_tcp.c b/net/ipv4/netfilter/nf_nat_proto_tcp.c new file mode 100644 index 000000000000..7e26a7e9bee1 --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_proto_tcp.c | |||
@@ -0,0 +1,148 @@ | |||
1 | /* (C) 1999-2001 Paul `Rusty' Russell | ||
2 | * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | #include <linux/types.h> | ||
10 | #include <linux/init.h> | ||
11 | #include <linux/ip.h> | ||
12 | #include <linux/tcp.h> | ||
13 | |||
14 | #include <linux/netfilter.h> | ||
15 | #include <linux/netfilter/nfnetlink_conntrack.h> | ||
16 | #include <net/netfilter/nf_nat.h> | ||
17 | #include <net/netfilter/nf_nat_rule.h> | ||
18 | #include <net/netfilter/nf_nat_protocol.h> | ||
19 | #include <net/netfilter/nf_nat_core.h> | ||
20 | |||
21 | static int | ||
22 | tcp_in_range(const struct nf_conntrack_tuple *tuple, | ||
23 | enum nf_nat_manip_type maniptype, | ||
24 | const union nf_conntrack_man_proto *min, | ||
25 | const union nf_conntrack_man_proto *max) | ||
26 | { | ||
27 | __be16 port; | ||
28 | |||
29 | if (maniptype == IP_NAT_MANIP_SRC) | ||
30 | port = tuple->src.u.tcp.port; | ||
31 | else | ||
32 | port = tuple->dst.u.tcp.port; | ||
33 | |||
34 | return ntohs(port) >= ntohs(min->tcp.port) && | ||
35 | ntohs(port) <= ntohs(max->tcp.port); | ||
36 | } | ||
37 | |||
38 | static int | ||
39 | tcp_unique_tuple(struct nf_conntrack_tuple *tuple, | ||
40 | const struct nf_nat_range *range, | ||
41 | enum nf_nat_manip_type maniptype, | ||
42 | const struct nf_conn *ct) | ||
43 | { | ||
44 | static u_int16_t port; | ||
45 | __be16 *portptr; | ||
46 | unsigned int range_size, min, i; | ||
47 | |||
48 | if (maniptype == IP_NAT_MANIP_SRC) | ||
49 | portptr = &tuple->src.u.tcp.port; | ||
50 | else | ||
51 | portptr = &tuple->dst.u.tcp.port; | ||
52 | |||
53 | /* If no range specified... */ | ||
54 | if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) { | ||
55 | /* If it's dst rewrite, can't change port */ | ||
56 | if (maniptype == IP_NAT_MANIP_DST) | ||
57 | return 0; | ||
58 | |||
59 | /* Map privileged onto privileged. */ | ||
60 | if (ntohs(*portptr) < 1024) { | ||
61 | /* Loose convention: >> 512 is credential passing */ | ||
62 | if (ntohs(*portptr)<512) { | ||
63 | min = 1; | ||
64 | range_size = 511 - min + 1; | ||
65 | } else { | ||
66 | min = 600; | ||
67 | range_size = 1023 - min + 1; | ||
68 | } | ||
69 | } else { | ||
70 | min = 1024; | ||
71 | range_size = 65535 - 1024 + 1; | ||
72 | } | ||
73 | } else { | ||
74 | min = ntohs(range->min.tcp.port); | ||
75 | range_size = ntohs(range->max.tcp.port) - min + 1; | ||
76 | } | ||
77 | |||
78 | for (i = 0; i < range_size; i++, port++) { | ||
79 | *portptr = htons(min + port % range_size); | ||
80 | if (!nf_nat_used_tuple(tuple, ct)) | ||
81 | return 1; | ||
82 | } | ||
83 | return 0; | ||
84 | } | ||
85 | |||
86 | static int | ||
87 | tcp_manip_pkt(struct sk_buff **pskb, | ||
88 | unsigned int iphdroff, | ||
89 | const struct nf_conntrack_tuple *tuple, | ||
90 | enum nf_nat_manip_type maniptype) | ||
91 | { | ||
92 | struct iphdr *iph = (struct iphdr *)((*pskb)->data + iphdroff); | ||
93 | struct tcphdr *hdr; | ||
94 | unsigned int hdroff = iphdroff + iph->ihl*4; | ||
95 | __be32 oldip, newip; | ||
96 | __be16 *portptr, newport, oldport; | ||
97 | int hdrsize = 8; /* TCP connection tracking guarantees this much */ | ||
98 | |||
99 | /* this could be a inner header returned in icmp packet; in such | ||
100 | cases we cannot update the checksum field since it is outside of | ||
101 | the 8 bytes of transport layer headers we are guaranteed */ | ||
102 | if ((*pskb)->len >= hdroff + sizeof(struct tcphdr)) | ||
103 | hdrsize = sizeof(struct tcphdr); | ||
104 | |||
105 | if (!skb_make_writable(pskb, hdroff + hdrsize)) | ||
106 | return 0; | ||
107 | |||
108 | iph = (struct iphdr *)((*pskb)->data + iphdroff); | ||
109 | hdr = (struct tcphdr *)((*pskb)->data + hdroff); | ||
110 | |||
111 | if (maniptype == IP_NAT_MANIP_SRC) { | ||
112 | /* Get rid of src ip and src pt */ | ||
113 | oldip = iph->saddr; | ||
114 | newip = tuple->src.u3.ip; | ||
115 | newport = tuple->src.u.tcp.port; | ||
116 | portptr = &hdr->source; | ||
117 | } else { | ||
118 | /* Get rid of dst ip and dst pt */ | ||
119 | oldip = iph->daddr; | ||
120 | newip = tuple->dst.u3.ip; | ||
121 | newport = tuple->dst.u.tcp.port; | ||
122 | portptr = &hdr->dest; | ||
123 | } | ||
124 | |||
125 | oldport = *portptr; | ||
126 | *portptr = newport; | ||
127 | |||
128 | if (hdrsize < sizeof(*hdr)) | ||
129 | return 1; | ||
130 | |||
131 | nf_proto_csum_replace4(&hdr->check, *pskb, oldip, newip, 1); | ||
132 | nf_proto_csum_replace2(&hdr->check, *pskb, oldport, newport, 0); | ||
133 | return 1; | ||
134 | } | ||
135 | |||
136 | struct nf_nat_protocol nf_nat_protocol_tcp = { | ||
137 | .name = "TCP", | ||
138 | .protonum = IPPROTO_TCP, | ||
139 | .me = THIS_MODULE, | ||
140 | .manip_pkt = tcp_manip_pkt, | ||
141 | .in_range = tcp_in_range, | ||
142 | .unique_tuple = tcp_unique_tuple, | ||
143 | #if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \ | ||
144 | defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE) | ||
145 | .range_to_nfattr = nf_nat_port_range_to_nfattr, | ||
146 | .nfattr_to_range = nf_nat_port_nfattr_to_range, | ||
147 | #endif | ||
148 | }; | ||
diff --git a/net/ipv4/netfilter/nf_nat_proto_udp.c b/net/ipv4/netfilter/nf_nat_proto_udp.c new file mode 100644 index 000000000000..ab0ce4c8699f --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_proto_udp.c | |||
@@ -0,0 +1,138 @@ | |||
1 | /* (C) 1999-2001 Paul `Rusty' Russell | ||
2 | * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | #include <linux/types.h> | ||
10 | #include <linux/init.h> | ||
11 | #include <linux/ip.h> | ||
12 | #include <linux/udp.h> | ||
13 | |||
14 | #include <linux/netfilter.h> | ||
15 | #include <net/netfilter/nf_nat.h> | ||
16 | #include <net/netfilter/nf_nat_core.h> | ||
17 | #include <net/netfilter/nf_nat_rule.h> | ||
18 | #include <net/netfilter/nf_nat_protocol.h> | ||
19 | |||
20 | static int | ||
21 | udp_in_range(const struct nf_conntrack_tuple *tuple, | ||
22 | enum nf_nat_manip_type maniptype, | ||
23 | const union nf_conntrack_man_proto *min, | ||
24 | const union nf_conntrack_man_proto *max) | ||
25 | { | ||
26 | __be16 port; | ||
27 | |||
28 | if (maniptype == IP_NAT_MANIP_SRC) | ||
29 | port = tuple->src.u.udp.port; | ||
30 | else | ||
31 | port = tuple->dst.u.udp.port; | ||
32 | |||
33 | return ntohs(port) >= ntohs(min->udp.port) && | ||
34 | ntohs(port) <= ntohs(max->udp.port); | ||
35 | } | ||
36 | |||
37 | static int | ||
38 | udp_unique_tuple(struct nf_conntrack_tuple *tuple, | ||
39 | const struct nf_nat_range *range, | ||
40 | enum nf_nat_manip_type maniptype, | ||
41 | const struct nf_conn *ct) | ||
42 | { | ||
43 | static u_int16_t port; | ||
44 | __be16 *portptr; | ||
45 | unsigned int range_size, min, i; | ||
46 | |||
47 | if (maniptype == IP_NAT_MANIP_SRC) | ||
48 | portptr = &tuple->src.u.udp.port; | ||
49 | else | ||
50 | portptr = &tuple->dst.u.udp.port; | ||
51 | |||
52 | /* If no range specified... */ | ||
53 | if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) { | ||
54 | /* If it's dst rewrite, can't change port */ | ||
55 | if (maniptype == IP_NAT_MANIP_DST) | ||
56 | return 0; | ||
57 | |||
58 | if (ntohs(*portptr) < 1024) { | ||
59 | /* Loose convention: >> 512 is credential passing */ | ||
60 | if (ntohs(*portptr)<512) { | ||
61 | min = 1; | ||
62 | range_size = 511 - min + 1; | ||
63 | } else { | ||
64 | min = 600; | ||
65 | range_size = 1023 - min + 1; | ||
66 | } | ||
67 | } else { | ||
68 | min = 1024; | ||
69 | range_size = 65535 - 1024 + 1; | ||
70 | } | ||
71 | } else { | ||
72 | min = ntohs(range->min.udp.port); | ||
73 | range_size = ntohs(range->max.udp.port) - min + 1; | ||
74 | } | ||
75 | |||
76 | for (i = 0; i < range_size; i++, port++) { | ||
77 | *portptr = htons(min + port % range_size); | ||
78 | if (!nf_nat_used_tuple(tuple, ct)) | ||
79 | return 1; | ||
80 | } | ||
81 | return 0; | ||
82 | } | ||
83 | |||
84 | static int | ||
85 | udp_manip_pkt(struct sk_buff **pskb, | ||
86 | unsigned int iphdroff, | ||
87 | const struct nf_conntrack_tuple *tuple, | ||
88 | enum nf_nat_manip_type maniptype) | ||
89 | { | ||
90 | struct iphdr *iph = (struct iphdr *)((*pskb)->data + iphdroff); | ||
91 | struct udphdr *hdr; | ||
92 | unsigned int hdroff = iphdroff + iph->ihl*4; | ||
93 | __be32 oldip, newip; | ||
94 | __be16 *portptr, newport; | ||
95 | |||
96 | if (!skb_make_writable(pskb, hdroff + sizeof(*hdr))) | ||
97 | return 0; | ||
98 | |||
99 | iph = (struct iphdr *)((*pskb)->data + iphdroff); | ||
100 | hdr = (struct udphdr *)((*pskb)->data + hdroff); | ||
101 | |||
102 | if (maniptype == IP_NAT_MANIP_SRC) { | ||
103 | /* Get rid of src ip and src pt */ | ||
104 | oldip = iph->saddr; | ||
105 | newip = tuple->src.u3.ip; | ||
106 | newport = tuple->src.u.udp.port; | ||
107 | portptr = &hdr->source; | ||
108 | } else { | ||
109 | /* Get rid of dst ip and dst pt */ | ||
110 | oldip = iph->daddr; | ||
111 | newip = tuple->dst.u3.ip; | ||
112 | newport = tuple->dst.u.udp.port; | ||
113 | portptr = &hdr->dest; | ||
114 | } | ||
115 | if (hdr->check || (*pskb)->ip_summed == CHECKSUM_PARTIAL) { | ||
116 | nf_proto_csum_replace4(&hdr->check, *pskb, oldip, newip, 1); | ||
117 | nf_proto_csum_replace2(&hdr->check, *pskb, *portptr, newport, | ||
118 | 0); | ||
119 | if (!hdr->check) | ||
120 | hdr->check = CSUM_MANGLED_0; | ||
121 | } | ||
122 | *portptr = newport; | ||
123 | return 1; | ||
124 | } | ||
125 | |||
126 | struct nf_nat_protocol nf_nat_protocol_udp = { | ||
127 | .name = "UDP", | ||
128 | .protonum = IPPROTO_UDP, | ||
129 | .me = THIS_MODULE, | ||
130 | .manip_pkt = udp_manip_pkt, | ||
131 | .in_range = udp_in_range, | ||
132 | .unique_tuple = udp_unique_tuple, | ||
133 | #if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \ | ||
134 | defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE) | ||
135 | .range_to_nfattr = nf_nat_port_range_to_nfattr, | ||
136 | .nfattr_to_range = nf_nat_port_nfattr_to_range, | ||
137 | #endif | ||
138 | }; | ||
diff --git a/net/ipv4/netfilter/nf_nat_proto_unknown.c b/net/ipv4/netfilter/nf_nat_proto_unknown.c new file mode 100644 index 000000000000..f50d0203f9c0 --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_proto_unknown.c | |||
@@ -0,0 +1,54 @@ | |||
1 | /* The "unknown" protocol. This is what is used for protocols we | ||
2 | * don't understand. It's returned by ip_ct_find_proto(). | ||
3 | */ | ||
4 | |||
5 | /* (C) 1999-2001 Paul `Rusty' Russell | ||
6 | * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #include <linux/types.h> | ||
14 | #include <linux/init.h> | ||
15 | |||
16 | #include <linux/netfilter.h> | ||
17 | #include <net/netfilter/nf_nat.h> | ||
18 | #include <net/netfilter/nf_nat_rule.h> | ||
19 | #include <net/netfilter/nf_nat_protocol.h> | ||
20 | |||
21 | static int unknown_in_range(const struct nf_conntrack_tuple *tuple, | ||
22 | enum nf_nat_manip_type manip_type, | ||
23 | const union nf_conntrack_man_proto *min, | ||
24 | const union nf_conntrack_man_proto *max) | ||
25 | { | ||
26 | return 1; | ||
27 | } | ||
28 | |||
29 | static int unknown_unique_tuple(struct nf_conntrack_tuple *tuple, | ||
30 | const struct nf_nat_range *range, | ||
31 | enum nf_nat_manip_type maniptype, | ||
32 | const struct nf_conn *ct) | ||
33 | { | ||
34 | /* Sorry: we can't help you; if it's not unique, we can't frob | ||
35 | anything. */ | ||
36 | return 0; | ||
37 | } | ||
38 | |||
39 | static int | ||
40 | unknown_manip_pkt(struct sk_buff **pskb, | ||
41 | unsigned int iphdroff, | ||
42 | const struct nf_conntrack_tuple *tuple, | ||
43 | enum nf_nat_manip_type maniptype) | ||
44 | { | ||
45 | return 1; | ||
46 | } | ||
47 | |||
48 | struct nf_nat_protocol nf_nat_unknown_protocol = { | ||
49 | .name = "unknown", | ||
50 | /* .me isn't set: getting a ref to this cannot fail. */ | ||
51 | .manip_pkt = unknown_manip_pkt, | ||
52 | .in_range = unknown_in_range, | ||
53 | .unique_tuple = unknown_unique_tuple, | ||
54 | }; | ||
diff --git a/net/ipv4/netfilter/nf_nat_rule.c b/net/ipv4/netfilter/nf_nat_rule.c new file mode 100644 index 000000000000..b868ee0195d4 --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_rule.c | |||
@@ -0,0 +1,343 @@ | |||
1 | /* (C) 1999-2001 Paul `Rusty' Russell | ||
2 | * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | /* Everything about the rules for NAT. */ | ||
10 | #include <linux/types.h> | ||
11 | #include <linux/ip.h> | ||
12 | #include <linux/netfilter.h> | ||
13 | #include <linux/netfilter_ipv4.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/kmod.h> | ||
16 | #include <linux/skbuff.h> | ||
17 | #include <linux/proc_fs.h> | ||
18 | #include <net/checksum.h> | ||
19 | #include <net/route.h> | ||
20 | #include <linux/bitops.h> | ||
21 | |||
22 | #include <linux/netfilter_ipv4/ip_tables.h> | ||
23 | #include <net/netfilter/nf_nat.h> | ||
24 | #include <net/netfilter/nf_nat_core.h> | ||
25 | #include <net/netfilter/nf_nat_rule.h> | ||
26 | |||
27 | #if 0 | ||
28 | #define DEBUGP printk | ||
29 | #else | ||
30 | #define DEBUGP(format, args...) | ||
31 | #endif | ||
32 | |||
33 | #define NAT_VALID_HOOKS ((1<<NF_IP_PRE_ROUTING) | (1<<NF_IP_POST_ROUTING) | (1<<NF_IP_LOCAL_OUT)) | ||
34 | |||
35 | static struct | ||
36 | { | ||
37 | struct ipt_replace repl; | ||
38 | struct ipt_standard entries[3]; | ||
39 | struct ipt_error term; | ||
40 | } nat_initial_table __initdata = { | ||
41 | .repl = { | ||
42 | .name = "nat", | ||
43 | .valid_hooks = NAT_VALID_HOOKS, | ||
44 | .num_entries = 4, | ||
45 | .size = sizeof(struct ipt_standard) * 3 + sizeof(struct ipt_error), | ||
46 | .hook_entry = { | ||
47 | [NF_IP_PRE_ROUTING] = 0, | ||
48 | [NF_IP_POST_ROUTING] = sizeof(struct ipt_standard), | ||
49 | [NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 2 }, | ||
50 | .underflow = { | ||
51 | [NF_IP_PRE_ROUTING] = 0, | ||
52 | [NF_IP_POST_ROUTING] = sizeof(struct ipt_standard), | ||
53 | [NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 2 }, | ||
54 | }, | ||
55 | .entries = { | ||
56 | /* PRE_ROUTING */ | ||
57 | { | ||
58 | .entry = { | ||
59 | .target_offset = sizeof(struct ipt_entry), | ||
60 | .next_offset = sizeof(struct ipt_standard), | ||
61 | }, | ||
62 | .target = { | ||
63 | .target = { | ||
64 | .u = { | ||
65 | .target_size = IPT_ALIGN(sizeof(struct ipt_standard_target)), | ||
66 | }, | ||
67 | }, | ||
68 | .verdict = -NF_ACCEPT - 1, | ||
69 | }, | ||
70 | }, | ||
71 | /* POST_ROUTING */ | ||
72 | { | ||
73 | .entry = { | ||
74 | .target_offset = sizeof(struct ipt_entry), | ||
75 | .next_offset = sizeof(struct ipt_standard), | ||
76 | }, | ||
77 | .target = { | ||
78 | .target = { | ||
79 | .u = { | ||
80 | .target_size = IPT_ALIGN(sizeof(struct ipt_standard_target)), | ||
81 | }, | ||
82 | }, | ||
83 | .verdict = -NF_ACCEPT - 1, | ||
84 | }, | ||
85 | }, | ||
86 | /* LOCAL_OUT */ | ||
87 | { | ||
88 | .entry = { | ||
89 | .target_offset = sizeof(struct ipt_entry), | ||
90 | .next_offset = sizeof(struct ipt_standard), | ||
91 | }, | ||
92 | .target = { | ||
93 | .target = { | ||
94 | .u = { | ||
95 | .target_size = IPT_ALIGN(sizeof(struct ipt_standard_target)), | ||
96 | }, | ||
97 | }, | ||
98 | .verdict = -NF_ACCEPT - 1, | ||
99 | }, | ||
100 | }, | ||
101 | }, | ||
102 | /* ERROR */ | ||
103 | .term = { | ||
104 | .entry = { | ||
105 | .target_offset = sizeof(struct ipt_entry), | ||
106 | .next_offset = sizeof(struct ipt_error), | ||
107 | }, | ||
108 | .target = { | ||
109 | .target = { | ||
110 | .u = { | ||
111 | .user = { | ||
112 | .target_size = IPT_ALIGN(sizeof(struct ipt_error_target)), | ||
113 | .name = IPT_ERROR_TARGET, | ||
114 | }, | ||
115 | }, | ||
116 | }, | ||
117 | .errorname = "ERROR", | ||
118 | }, | ||
119 | } | ||
120 | }; | ||
121 | |||
122 | static struct ipt_table nat_table = { | ||
123 | .name = "nat", | ||
124 | .valid_hooks = NAT_VALID_HOOKS, | ||
125 | .lock = RW_LOCK_UNLOCKED, | ||
126 | .me = THIS_MODULE, | ||
127 | .af = AF_INET, | ||
128 | }; | ||
129 | |||
130 | /* Source NAT */ | ||
131 | static unsigned int ipt_snat_target(struct sk_buff **pskb, | ||
132 | const struct net_device *in, | ||
133 | const struct net_device *out, | ||
134 | unsigned int hooknum, | ||
135 | const struct xt_target *target, | ||
136 | const void *targinfo) | ||
137 | { | ||
138 | struct nf_conn *ct; | ||
139 | enum ip_conntrack_info ctinfo; | ||
140 | const struct nf_nat_multi_range_compat *mr = targinfo; | ||
141 | |||
142 | NF_CT_ASSERT(hooknum == NF_IP_POST_ROUTING); | ||
143 | |||
144 | ct = nf_ct_get(*pskb, &ctinfo); | ||
145 | |||
146 | /* Connection must be valid and new. */ | ||
147 | NF_CT_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED || | ||
148 | ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY)); | ||
149 | NF_CT_ASSERT(out); | ||
150 | |||
151 | return nf_nat_setup_info(ct, &mr->range[0], hooknum); | ||
152 | } | ||
153 | |||
154 | /* Before 2.6.11 we did implicit source NAT if required. Warn about change. */ | ||
155 | static void warn_if_extra_mangle(__be32 dstip, __be32 srcip) | ||
156 | { | ||
157 | static int warned = 0; | ||
158 | struct flowi fl = { .nl_u = { .ip4_u = { .daddr = dstip } } }; | ||
159 | struct rtable *rt; | ||
160 | |||
161 | if (ip_route_output_key(&rt, &fl) != 0) | ||
162 | return; | ||
163 | |||
164 | if (rt->rt_src != srcip && !warned) { | ||
165 | printk("NAT: no longer support implicit source local NAT\n"); | ||
166 | printk("NAT: packet src %u.%u.%u.%u -> dst %u.%u.%u.%u\n", | ||
167 | NIPQUAD(srcip), NIPQUAD(dstip)); | ||
168 | warned = 1; | ||
169 | } | ||
170 | ip_rt_put(rt); | ||
171 | } | ||
172 | |||
173 | static unsigned int ipt_dnat_target(struct sk_buff **pskb, | ||
174 | const struct net_device *in, | ||
175 | const struct net_device *out, | ||
176 | unsigned int hooknum, | ||
177 | const struct xt_target *target, | ||
178 | const void *targinfo) | ||
179 | { | ||
180 | struct nf_conn *ct; | ||
181 | enum ip_conntrack_info ctinfo; | ||
182 | const struct nf_nat_multi_range_compat *mr = targinfo; | ||
183 | |||
184 | NF_CT_ASSERT(hooknum == NF_IP_PRE_ROUTING || | ||
185 | hooknum == NF_IP_LOCAL_OUT); | ||
186 | |||
187 | ct = nf_ct_get(*pskb, &ctinfo); | ||
188 | |||
189 | /* Connection must be valid and new. */ | ||
190 | NF_CT_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED)); | ||
191 | |||
192 | if (hooknum == NF_IP_LOCAL_OUT && | ||
193 | mr->range[0].flags & IP_NAT_RANGE_MAP_IPS) | ||
194 | warn_if_extra_mangle((*pskb)->nh.iph->daddr, | ||
195 | mr->range[0].min_ip); | ||
196 | |||
197 | return nf_nat_setup_info(ct, &mr->range[0], hooknum); | ||
198 | } | ||
199 | |||
200 | static int ipt_snat_checkentry(const char *tablename, | ||
201 | const void *entry, | ||
202 | const struct xt_target *target, | ||
203 | void *targinfo, | ||
204 | unsigned int hook_mask) | ||
205 | { | ||
206 | struct nf_nat_multi_range_compat *mr = targinfo; | ||
207 | |||
208 | /* Must be a valid range */ | ||
209 | if (mr->rangesize != 1) { | ||
210 | printk("SNAT: multiple ranges no longer supported\n"); | ||
211 | return 0; | ||
212 | } | ||
213 | return 1; | ||
214 | } | ||
215 | |||
216 | static int ipt_dnat_checkentry(const char *tablename, | ||
217 | const void *entry, | ||
218 | const struct xt_target *target, | ||
219 | void *targinfo, | ||
220 | unsigned int hook_mask) | ||
221 | { | ||
222 | struct nf_nat_multi_range_compat *mr = targinfo; | ||
223 | |||
224 | /* Must be a valid range */ | ||
225 | if (mr->rangesize != 1) { | ||
226 | printk("DNAT: multiple ranges no longer supported\n"); | ||
227 | return 0; | ||
228 | } | ||
229 | return 1; | ||
230 | } | ||
231 | |||
232 | inline unsigned int | ||
233 | alloc_null_binding(struct nf_conn *ct, | ||
234 | struct nf_nat_info *info, | ||
235 | unsigned int hooknum) | ||
236 | { | ||
237 | /* Force range to this IP; let proto decide mapping for | ||
238 | per-proto parts (hence not IP_NAT_RANGE_PROTO_SPECIFIED). | ||
239 | Use reply in case it's already been mangled (eg local packet). | ||
240 | */ | ||
241 | __be32 ip | ||
242 | = (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC | ||
243 | ? ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip | ||
244 | : ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip); | ||
245 | struct nf_nat_range range | ||
246 | = { IP_NAT_RANGE_MAP_IPS, ip, ip, { 0 }, { 0 } }; | ||
247 | |||
248 | DEBUGP("Allocating NULL binding for %p (%u.%u.%u.%u)\n", | ||
249 | ct, NIPQUAD(ip)); | ||
250 | return nf_nat_setup_info(ct, &range, hooknum); | ||
251 | } | ||
252 | |||
253 | unsigned int | ||
254 | alloc_null_binding_confirmed(struct nf_conn *ct, | ||
255 | struct nf_nat_info *info, | ||
256 | unsigned int hooknum) | ||
257 | { | ||
258 | __be32 ip | ||
259 | = (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC | ||
260 | ? ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip | ||
261 | : ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip); | ||
262 | u_int16_t all | ||
263 | = (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC | ||
264 | ? ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.all | ||
265 | : ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u.all); | ||
266 | struct nf_nat_range range | ||
267 | = { IP_NAT_RANGE_MAP_IPS, ip, ip, { all }, { all } }; | ||
268 | |||
269 | DEBUGP("Allocating NULL binding for confirmed %p (%u.%u.%u.%u)\n", | ||
270 | ct, NIPQUAD(ip)); | ||
271 | return nf_nat_setup_info(ct, &range, hooknum); | ||
272 | } | ||
273 | |||
274 | int nf_nat_rule_find(struct sk_buff **pskb, | ||
275 | unsigned int hooknum, | ||
276 | const struct net_device *in, | ||
277 | const struct net_device *out, | ||
278 | struct nf_conn *ct, | ||
279 | struct nf_nat_info *info) | ||
280 | { | ||
281 | int ret; | ||
282 | |||
283 | ret = ipt_do_table(pskb, hooknum, in, out, &nat_table); | ||
284 | |||
285 | if (ret == NF_ACCEPT) { | ||
286 | if (!nf_nat_initialized(ct, HOOK2MANIP(hooknum))) | ||
287 | /* NUL mapping */ | ||
288 | ret = alloc_null_binding(ct, info, hooknum); | ||
289 | } | ||
290 | return ret; | ||
291 | } | ||
292 | |||
293 | static struct ipt_target ipt_snat_reg = { | ||
294 | .name = "SNAT", | ||
295 | .target = ipt_snat_target, | ||
296 | .targetsize = sizeof(struct nf_nat_multi_range_compat), | ||
297 | .table = "nat", | ||
298 | .hooks = 1 << NF_IP_POST_ROUTING, | ||
299 | .checkentry = ipt_snat_checkentry, | ||
300 | .family = AF_INET, | ||
301 | }; | ||
302 | |||
303 | static struct xt_target ipt_dnat_reg = { | ||
304 | .name = "DNAT", | ||
305 | .target = ipt_dnat_target, | ||
306 | .targetsize = sizeof(struct nf_nat_multi_range_compat), | ||
307 | .table = "nat", | ||
308 | .hooks = (1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_OUT), | ||
309 | .checkentry = ipt_dnat_checkentry, | ||
310 | .family = AF_INET, | ||
311 | }; | ||
312 | |||
313 | int __init nf_nat_rule_init(void) | ||
314 | { | ||
315 | int ret; | ||
316 | |||
317 | ret = ipt_register_table(&nat_table, &nat_initial_table.repl); | ||
318 | if (ret != 0) | ||
319 | return ret; | ||
320 | ret = xt_register_target(&ipt_snat_reg); | ||
321 | if (ret != 0) | ||
322 | goto unregister_table; | ||
323 | |||
324 | ret = xt_register_target(&ipt_dnat_reg); | ||
325 | if (ret != 0) | ||
326 | goto unregister_snat; | ||
327 | |||
328 | return ret; | ||
329 | |||
330 | unregister_snat: | ||
331 | xt_unregister_target(&ipt_snat_reg); | ||
332 | unregister_table: | ||
333 | ipt_unregister_table(&nat_table); | ||
334 | |||
335 | return ret; | ||
336 | } | ||
337 | |||
338 | void nf_nat_rule_cleanup(void) | ||
339 | { | ||
340 | xt_unregister_target(&ipt_dnat_reg); | ||
341 | xt_unregister_target(&ipt_snat_reg); | ||
342 | ipt_unregister_table(&nat_table); | ||
343 | } | ||
diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c new file mode 100644 index 000000000000..3d524b957310 --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_sip.c | |||
@@ -0,0 +1,283 @@ | |||
1 | /* SIP extension for UDP NAT alteration. | ||
2 | * | ||
3 | * (C) 2005 by Christian Hentschel <chentschel@arnet.com.ar> | ||
4 | * based on RR's ip_nat_ftp.c and other modules. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #include <linux/module.h> | ||
12 | #include <linux/skbuff.h> | ||
13 | #include <linux/ip.h> | ||
14 | #include <linux/udp.h> | ||
15 | |||
16 | #include <net/netfilter/nf_nat.h> | ||
17 | #include <net/netfilter/nf_nat_helper.h> | ||
18 | #include <net/netfilter/nf_nat_rule.h> | ||
19 | #include <net/netfilter/nf_conntrack_helper.h> | ||
20 | #include <net/netfilter/nf_conntrack_expect.h> | ||
21 | #include <linux/netfilter/nf_conntrack_sip.h> | ||
22 | |||
23 | MODULE_LICENSE("GPL"); | ||
24 | MODULE_AUTHOR("Christian Hentschel <chentschel@arnet.com.ar>"); | ||
25 | MODULE_DESCRIPTION("SIP NAT helper"); | ||
26 | MODULE_ALIAS("ip_nat_sip"); | ||
27 | |||
28 | #if 0 | ||
29 | #define DEBUGP printk | ||
30 | #else | ||
31 | #define DEBUGP(format, args...) | ||
32 | #endif | ||
33 | |||
34 | struct addr_map { | ||
35 | struct { | ||
36 | char src[sizeof("nnn.nnn.nnn.nnn:nnnnn")]; | ||
37 | char dst[sizeof("nnn.nnn.nnn.nnn:nnnnn")]; | ||
38 | unsigned int srclen, srciplen; | ||
39 | unsigned int dstlen, dstiplen; | ||
40 | } addr[IP_CT_DIR_MAX]; | ||
41 | }; | ||
42 | |||
43 | static void addr_map_init(struct nf_conn *ct, struct addr_map *map) | ||
44 | { | ||
45 | struct nf_conntrack_tuple *t; | ||
46 | enum ip_conntrack_dir dir; | ||
47 | unsigned int n; | ||
48 | |||
49 | for (dir = 0; dir < IP_CT_DIR_MAX; dir++) { | ||
50 | t = &ct->tuplehash[dir].tuple; | ||
51 | |||
52 | n = sprintf(map->addr[dir].src, "%u.%u.%u.%u", | ||
53 | NIPQUAD(t->src.u3.ip)); | ||
54 | map->addr[dir].srciplen = n; | ||
55 | n += sprintf(map->addr[dir].src + n, ":%u", | ||
56 | ntohs(t->src.u.udp.port)); | ||
57 | map->addr[dir].srclen = n; | ||
58 | |||
59 | n = sprintf(map->addr[dir].dst, "%u.%u.%u.%u", | ||
60 | NIPQUAD(t->dst.u3.ip)); | ||
61 | map->addr[dir].dstiplen = n; | ||
62 | n += sprintf(map->addr[dir].dst + n, ":%u", | ||
63 | ntohs(t->dst.u.udp.port)); | ||
64 | map->addr[dir].dstlen = n; | ||
65 | } | ||
66 | } | ||
67 | |||
68 | static int map_sip_addr(struct sk_buff **pskb, enum ip_conntrack_info ctinfo, | ||
69 | struct nf_conn *ct, const char **dptr, size_t dlen, | ||
70 | enum sip_header_pos pos, struct addr_map *map) | ||
71 | { | ||
72 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); | ||
73 | unsigned int matchlen, matchoff, addrlen; | ||
74 | char *addr; | ||
75 | |||
76 | if (ct_sip_get_info(ct, *dptr, dlen, &matchoff, &matchlen, pos) <= 0) | ||
77 | return 1; | ||
78 | |||
79 | if ((matchlen == map->addr[dir].srciplen || | ||
80 | matchlen == map->addr[dir].srclen) && | ||
81 | memcmp(*dptr + matchoff, map->addr[dir].src, matchlen) == 0) { | ||
82 | addr = map->addr[!dir].dst; | ||
83 | addrlen = map->addr[!dir].dstlen; | ||
84 | } else if ((matchlen == map->addr[dir].dstiplen || | ||
85 | matchlen == map->addr[dir].dstlen) && | ||
86 | memcmp(*dptr + matchoff, map->addr[dir].dst, matchlen) == 0) { | ||
87 | addr = map->addr[!dir].src; | ||
88 | addrlen = map->addr[!dir].srclen; | ||
89 | } else | ||
90 | return 1; | ||
91 | |||
92 | if (!nf_nat_mangle_udp_packet(pskb, ct, ctinfo, | ||
93 | matchoff, matchlen, addr, addrlen)) | ||
94 | return 0; | ||
95 | *dptr = (*pskb)->data + (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr); | ||
96 | return 1; | ||
97 | |||
98 | } | ||
99 | |||
100 | static unsigned int ip_nat_sip(struct sk_buff **pskb, | ||
101 | enum ip_conntrack_info ctinfo, | ||
102 | struct nf_conn *ct, | ||
103 | const char **dptr) | ||
104 | { | ||
105 | enum sip_header_pos pos; | ||
106 | struct addr_map map; | ||
107 | int dataoff, datalen; | ||
108 | |||
109 | dataoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr); | ||
110 | datalen = (*pskb)->len - dataoff; | ||
111 | if (datalen < sizeof("SIP/2.0") - 1) | ||
112 | return NF_DROP; | ||
113 | |||
114 | addr_map_init(ct, &map); | ||
115 | |||
116 | /* Basic rules: requests and responses. */ | ||
117 | if (strncmp(*dptr, "SIP/2.0", sizeof("SIP/2.0") - 1) != 0) { | ||
118 | /* 10.2: Constructing the REGISTER Request: | ||
119 | * | ||
120 | * The "userinfo" and "@" components of the SIP URI MUST NOT | ||
121 | * be present. | ||
122 | */ | ||
123 | if (datalen >= sizeof("REGISTER") - 1 && | ||
124 | strncmp(*dptr, "REGISTER", sizeof("REGISTER") - 1) == 0) | ||
125 | pos = POS_REG_REQ_URI; | ||
126 | else | ||
127 | pos = POS_REQ_URI; | ||
128 | |||
129 | if (!map_sip_addr(pskb, ctinfo, ct, dptr, datalen, pos, &map)) | ||
130 | return NF_DROP; | ||
131 | } | ||
132 | |||
133 | if (!map_sip_addr(pskb, ctinfo, ct, dptr, datalen, POS_FROM, &map) || | ||
134 | !map_sip_addr(pskb, ctinfo, ct, dptr, datalen, POS_TO, &map) || | ||
135 | !map_sip_addr(pskb, ctinfo, ct, dptr, datalen, POS_VIA, &map) || | ||
136 | !map_sip_addr(pskb, ctinfo, ct, dptr, datalen, POS_CONTACT, &map)) | ||
137 | return NF_DROP; | ||
138 | return NF_ACCEPT; | ||
139 | } | ||
140 | |||
141 | static unsigned int mangle_sip_packet(struct sk_buff **pskb, | ||
142 | enum ip_conntrack_info ctinfo, | ||
143 | struct nf_conn *ct, | ||
144 | const char **dptr, size_t dlen, | ||
145 | char *buffer, int bufflen, | ||
146 | enum sip_header_pos pos) | ||
147 | { | ||
148 | unsigned int matchlen, matchoff; | ||
149 | |||
150 | if (ct_sip_get_info(ct, *dptr, dlen, &matchoff, &matchlen, pos) <= 0) | ||
151 | return 0; | ||
152 | |||
153 | if (!nf_nat_mangle_udp_packet(pskb, ct, ctinfo, | ||
154 | matchoff, matchlen, buffer, bufflen)) | ||
155 | return 0; | ||
156 | |||
157 | /* We need to reload this. Thanks Patrick. */ | ||
158 | *dptr = (*pskb)->data + (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr); | ||
159 | return 1; | ||
160 | } | ||
161 | |||
162 | static int mangle_content_len(struct sk_buff **pskb, | ||
163 | enum ip_conntrack_info ctinfo, | ||
164 | struct nf_conn *ct, | ||
165 | const char *dptr) | ||
166 | { | ||
167 | unsigned int dataoff, matchoff, matchlen; | ||
168 | char buffer[sizeof("65536")]; | ||
169 | int bufflen; | ||
170 | |||
171 | dataoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr); | ||
172 | |||
173 | /* Get actual SDP lenght */ | ||
174 | if (ct_sip_get_info(ct, dptr, (*pskb)->len - dataoff, &matchoff, | ||
175 | &matchlen, POS_SDP_HEADER) > 0) { | ||
176 | |||
177 | /* since ct_sip_get_info() give us a pointer passing 'v=' | ||
178 | we need to add 2 bytes in this count. */ | ||
179 | int c_len = (*pskb)->len - dataoff - matchoff + 2; | ||
180 | |||
181 | /* Now, update SDP length */ | ||
182 | if (ct_sip_get_info(ct, dptr, (*pskb)->len - dataoff, &matchoff, | ||
183 | &matchlen, POS_CONTENT) > 0) { | ||
184 | |||
185 | bufflen = sprintf(buffer, "%u", c_len); | ||
186 | return nf_nat_mangle_udp_packet(pskb, ct, ctinfo, | ||
187 | matchoff, matchlen, | ||
188 | buffer, bufflen); | ||
189 | } | ||
190 | } | ||
191 | return 0; | ||
192 | } | ||
193 | |||
194 | static unsigned int mangle_sdp(struct sk_buff **pskb, | ||
195 | enum ip_conntrack_info ctinfo, | ||
196 | struct nf_conn *ct, | ||
197 | __be32 newip, u_int16_t port, | ||
198 | const char *dptr) | ||
199 | { | ||
200 | char buffer[sizeof("nnn.nnn.nnn.nnn")]; | ||
201 | unsigned int dataoff, bufflen; | ||
202 | |||
203 | dataoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr); | ||
204 | |||
205 | /* Mangle owner and contact info. */ | ||
206 | bufflen = sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(newip)); | ||
207 | if (!mangle_sip_packet(pskb, ctinfo, ct, &dptr, (*pskb)->len - dataoff, | ||
208 | buffer, bufflen, POS_OWNER_IP4)) | ||
209 | return 0; | ||
210 | |||
211 | if (!mangle_sip_packet(pskb, ctinfo, ct, &dptr, (*pskb)->len - dataoff, | ||
212 | buffer, bufflen, POS_CONNECTION_IP4)) | ||
213 | return 0; | ||
214 | |||
215 | /* Mangle media port. */ | ||
216 | bufflen = sprintf(buffer, "%u", port); | ||
217 | if (!mangle_sip_packet(pskb, ctinfo, ct, &dptr, (*pskb)->len - dataoff, | ||
218 | buffer, bufflen, POS_MEDIA)) | ||
219 | return 0; | ||
220 | |||
221 | return mangle_content_len(pskb, ctinfo, ct, dptr); | ||
222 | } | ||
223 | |||
224 | /* So, this packet has hit the connection tracking matching code. | ||
225 | Mangle it, and change the expectation to match the new version. */ | ||
226 | static unsigned int ip_nat_sdp(struct sk_buff **pskb, | ||
227 | enum ip_conntrack_info ctinfo, | ||
228 | struct nf_conntrack_expect *exp, | ||
229 | const char *dptr) | ||
230 | { | ||
231 | struct nf_conn *ct = exp->master; | ||
232 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); | ||
233 | __be32 newip; | ||
234 | u_int16_t port; | ||
235 | |||
236 | DEBUGP("ip_nat_sdp():\n"); | ||
237 | |||
238 | /* Connection will come from reply */ | ||
239 | newip = ct->tuplehash[!dir].tuple.dst.u3.ip; | ||
240 | |||
241 | exp->tuple.dst.u3.ip = newip; | ||
242 | exp->saved_proto.udp.port = exp->tuple.dst.u.udp.port; | ||
243 | exp->dir = !dir; | ||
244 | |||
245 | /* When you see the packet, we need to NAT it the same as the | ||
246 | this one. */ | ||
247 | exp->expectfn = nf_nat_follow_master; | ||
248 | |||
249 | /* Try to get same port: if not, try to change it. */ | ||
250 | for (port = ntohs(exp->saved_proto.udp.port); port != 0; port++) { | ||
251 | exp->tuple.dst.u.udp.port = htons(port); | ||
252 | if (nf_conntrack_expect_related(exp) == 0) | ||
253 | break; | ||
254 | } | ||
255 | |||
256 | if (port == 0) | ||
257 | return NF_DROP; | ||
258 | |||
259 | if (!mangle_sdp(pskb, ctinfo, ct, newip, port, dptr)) { | ||
260 | nf_conntrack_unexpect_related(exp); | ||
261 | return NF_DROP; | ||
262 | } | ||
263 | return NF_ACCEPT; | ||
264 | } | ||
265 | |||
266 | static void __exit nf_nat_sip_fini(void) | ||
267 | { | ||
268 | rcu_assign_pointer(nf_nat_sip_hook, NULL); | ||
269 | rcu_assign_pointer(nf_nat_sdp_hook, NULL); | ||
270 | synchronize_rcu(); | ||
271 | } | ||
272 | |||
273 | static int __init nf_nat_sip_init(void) | ||
274 | { | ||
275 | BUG_ON(rcu_dereference(nf_nat_sip_hook)); | ||
276 | BUG_ON(rcu_dereference(nf_nat_sdp_hook)); | ||
277 | rcu_assign_pointer(nf_nat_sip_hook, ip_nat_sip); | ||
278 | rcu_assign_pointer(nf_nat_sdp_hook, ip_nat_sdp); | ||
279 | return 0; | ||
280 | } | ||
281 | |||
282 | module_init(nf_nat_sip_init); | ||
283 | module_exit(nf_nat_sip_fini); | ||
diff --git a/net/ipv4/netfilter/nf_nat_snmp_basic.c b/net/ipv4/netfilter/nf_nat_snmp_basic.c new file mode 100644 index 000000000000..f12528fe1bf9 --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_snmp_basic.c | |||
@@ -0,0 +1,1332 @@ | |||
1 | /* | ||
2 | * nf_nat_snmp_basic.c | ||
3 | * | ||
4 | * Basic SNMP Application Layer Gateway | ||
5 | * | ||
6 | * This IP NAT module is intended for use with SNMP network | ||
7 | * discovery and monitoring applications where target networks use | ||
8 | * conflicting private address realms. | ||
9 | * | ||
10 | * Static NAT is used to remap the networks from the view of the network | ||
11 | * management system at the IP layer, and this module remaps some application | ||
12 | * layer addresses to match. | ||
13 | * | ||
14 | * The simplest form of ALG is performed, where only tagged IP addresses | ||
15 | * are modified. The module does not need to be MIB aware and only scans | ||
16 | * messages at the ASN.1/BER level. | ||
17 | * | ||
18 | * Currently, only SNMPv1 and SNMPv2 are supported. | ||
19 | * | ||
20 | * More information on ALG and associated issues can be found in | ||
21 | * RFC 2962 | ||
22 | * | ||
23 | * The ASB.1/BER parsing code is derived from the gxsnmp package by Gregory | ||
24 | * McLean & Jochen Friedrich, stripped down for use in the kernel. | ||
25 | * | ||
26 | * Copyright (c) 2000 RP Internet (www.rpi.net.au). | ||
27 | * | ||
28 | * This program is free software; you can redistribute it and/or modify | ||
29 | * it under the terms of the GNU General Public License as published by | ||
30 | * the Free Software Foundation; either version 2 of the License, or | ||
31 | * (at your option) any later version. | ||
32 | * This program is distributed in the hope that it will be useful, | ||
33 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
34 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
35 | * GNU General Public License for more details. | ||
36 | * You should have received a copy of the GNU General Public License | ||
37 | * along with this program; if not, write to the Free Software | ||
38 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
39 | * | ||
40 | * Author: James Morris <jmorris@intercode.com.au> | ||
41 | * | ||
42 | * Updates: | ||
43 | * 2000-08-06: Convert to new helper API (Harald Welte). | ||
44 | * | ||
45 | */ | ||
46 | #include <linux/module.h> | ||
47 | #include <linux/moduleparam.h> | ||
48 | #include <linux/types.h> | ||
49 | #include <linux/kernel.h> | ||
50 | #include <linux/in.h> | ||
51 | #include <linux/ip.h> | ||
52 | #include <linux/udp.h> | ||
53 | #include <net/checksum.h> | ||
54 | #include <net/udp.h> | ||
55 | |||
56 | #include <net/netfilter/nf_nat.h> | ||
57 | #include <net/netfilter/nf_conntrack_helper.h> | ||
58 | #include <net/netfilter/nf_nat_helper.h> | ||
59 | |||
60 | MODULE_LICENSE("GPL"); | ||
61 | MODULE_AUTHOR("James Morris <jmorris@intercode.com.au>"); | ||
62 | MODULE_DESCRIPTION("Basic SNMP Application Layer Gateway"); | ||
63 | MODULE_ALIAS("ip_nat_snmp_basic"); | ||
64 | |||
65 | #define SNMP_PORT 161 | ||
66 | #define SNMP_TRAP_PORT 162 | ||
67 | #define NOCT1(n) (*(u8 *)n) | ||
68 | |||
69 | static int debug; | ||
70 | static DEFINE_SPINLOCK(snmp_lock); | ||
71 | |||
72 | /* | ||
73 | * Application layer address mapping mimics the NAT mapping, but | ||
74 | * only for the first octet in this case (a more flexible system | ||
75 | * can be implemented if needed). | ||
76 | */ | ||
77 | struct oct1_map | ||
78 | { | ||
79 | u_int8_t from; | ||
80 | u_int8_t to; | ||
81 | }; | ||
82 | |||
83 | |||
84 | /***************************************************************************** | ||
85 | * | ||
86 | * Basic ASN.1 decoding routines (gxsnmp author Dirk Wisse) | ||
87 | * | ||
88 | *****************************************************************************/ | ||
89 | |||
90 | /* Class */ | ||
91 | #define ASN1_UNI 0 /* Universal */ | ||
92 | #define ASN1_APL 1 /* Application */ | ||
93 | #define ASN1_CTX 2 /* Context */ | ||
94 | #define ASN1_PRV 3 /* Private */ | ||
95 | |||
96 | /* Tag */ | ||
97 | #define ASN1_EOC 0 /* End Of Contents */ | ||
98 | #define ASN1_BOL 1 /* Boolean */ | ||
99 | #define ASN1_INT 2 /* Integer */ | ||
100 | #define ASN1_BTS 3 /* Bit String */ | ||
101 | #define ASN1_OTS 4 /* Octet String */ | ||
102 | #define ASN1_NUL 5 /* Null */ | ||
103 | #define ASN1_OJI 6 /* Object Identifier */ | ||
104 | #define ASN1_OJD 7 /* Object Description */ | ||
105 | #define ASN1_EXT 8 /* External */ | ||
106 | #define ASN1_SEQ 16 /* Sequence */ | ||
107 | #define ASN1_SET 17 /* Set */ | ||
108 | #define ASN1_NUMSTR 18 /* Numerical String */ | ||
109 | #define ASN1_PRNSTR 19 /* Printable String */ | ||
110 | #define ASN1_TEXSTR 20 /* Teletext String */ | ||
111 | #define ASN1_VIDSTR 21 /* Video String */ | ||
112 | #define ASN1_IA5STR 22 /* IA5 String */ | ||
113 | #define ASN1_UNITIM 23 /* Universal Time */ | ||
114 | #define ASN1_GENTIM 24 /* General Time */ | ||
115 | #define ASN1_GRASTR 25 /* Graphical String */ | ||
116 | #define ASN1_VISSTR 26 /* Visible String */ | ||
117 | #define ASN1_GENSTR 27 /* General String */ | ||
118 | |||
119 | /* Primitive / Constructed methods*/ | ||
120 | #define ASN1_PRI 0 /* Primitive */ | ||
121 | #define ASN1_CON 1 /* Constructed */ | ||
122 | |||
123 | /* | ||
124 | * Error codes. | ||
125 | */ | ||
126 | #define ASN1_ERR_NOERROR 0 | ||
127 | #define ASN1_ERR_DEC_EMPTY 2 | ||
128 | #define ASN1_ERR_DEC_EOC_MISMATCH 3 | ||
129 | #define ASN1_ERR_DEC_LENGTH_MISMATCH 4 | ||
130 | #define ASN1_ERR_DEC_BADVALUE 5 | ||
131 | |||
132 | /* | ||
133 | * ASN.1 context. | ||
134 | */ | ||
135 | struct asn1_ctx | ||
136 | { | ||
137 | int error; /* Error condition */ | ||
138 | unsigned char *pointer; /* Octet just to be decoded */ | ||
139 | unsigned char *begin; /* First octet */ | ||
140 | unsigned char *end; /* Octet after last octet */ | ||
141 | }; | ||
142 | |||
143 | /* | ||
144 | * Octet string (not null terminated) | ||
145 | */ | ||
146 | struct asn1_octstr | ||
147 | { | ||
148 | unsigned char *data; | ||
149 | unsigned int len; | ||
150 | }; | ||
151 | |||
152 | static void asn1_open(struct asn1_ctx *ctx, | ||
153 | unsigned char *buf, | ||
154 | unsigned int len) | ||
155 | { | ||
156 | ctx->begin = buf; | ||
157 | ctx->end = buf + len; | ||
158 | ctx->pointer = buf; | ||
159 | ctx->error = ASN1_ERR_NOERROR; | ||
160 | } | ||
161 | |||
162 | static unsigned char asn1_octet_decode(struct asn1_ctx *ctx, unsigned char *ch) | ||
163 | { | ||
164 | if (ctx->pointer >= ctx->end) { | ||
165 | ctx->error = ASN1_ERR_DEC_EMPTY; | ||
166 | return 0; | ||
167 | } | ||
168 | *ch = *(ctx->pointer)++; | ||
169 | return 1; | ||
170 | } | ||
171 | |||
172 | static unsigned char asn1_tag_decode(struct asn1_ctx *ctx, unsigned int *tag) | ||
173 | { | ||
174 | unsigned char ch; | ||
175 | |||
176 | *tag = 0; | ||
177 | |||
178 | do | ||
179 | { | ||
180 | if (!asn1_octet_decode(ctx, &ch)) | ||
181 | return 0; | ||
182 | *tag <<= 7; | ||
183 | *tag |= ch & 0x7F; | ||
184 | } while ((ch & 0x80) == 0x80); | ||
185 | return 1; | ||
186 | } | ||
187 | |||
188 | static unsigned char asn1_id_decode(struct asn1_ctx *ctx, | ||
189 | unsigned int *cls, | ||
190 | unsigned int *con, | ||
191 | unsigned int *tag) | ||
192 | { | ||
193 | unsigned char ch; | ||
194 | |||
195 | if (!asn1_octet_decode(ctx, &ch)) | ||
196 | return 0; | ||
197 | |||
198 | *cls = (ch & 0xC0) >> 6; | ||
199 | *con = (ch & 0x20) >> 5; | ||
200 | *tag = (ch & 0x1F); | ||
201 | |||
202 | if (*tag == 0x1F) { | ||
203 | if (!asn1_tag_decode(ctx, tag)) | ||
204 | return 0; | ||
205 | } | ||
206 | return 1; | ||
207 | } | ||
208 | |||
209 | static unsigned char asn1_length_decode(struct asn1_ctx *ctx, | ||
210 | unsigned int *def, | ||
211 | unsigned int *len) | ||
212 | { | ||
213 | unsigned char ch, cnt; | ||
214 | |||
215 | if (!asn1_octet_decode(ctx, &ch)) | ||
216 | return 0; | ||
217 | |||
218 | if (ch == 0x80) | ||
219 | *def = 0; | ||
220 | else { | ||
221 | *def = 1; | ||
222 | |||
223 | if (ch < 0x80) | ||
224 | *len = ch; | ||
225 | else { | ||
226 | cnt = (unsigned char) (ch & 0x7F); | ||
227 | *len = 0; | ||
228 | |||
229 | while (cnt > 0) { | ||
230 | if (!asn1_octet_decode(ctx, &ch)) | ||
231 | return 0; | ||
232 | *len <<= 8; | ||
233 | *len |= ch; | ||
234 | cnt--; | ||
235 | } | ||
236 | } | ||
237 | } | ||
238 | return 1; | ||
239 | } | ||
240 | |||
241 | static unsigned char asn1_header_decode(struct asn1_ctx *ctx, | ||
242 | unsigned char **eoc, | ||
243 | unsigned int *cls, | ||
244 | unsigned int *con, | ||
245 | unsigned int *tag) | ||
246 | { | ||
247 | unsigned int def, len; | ||
248 | |||
249 | if (!asn1_id_decode(ctx, cls, con, tag)) | ||
250 | return 0; | ||
251 | |||
252 | def = len = 0; | ||
253 | if (!asn1_length_decode(ctx, &def, &len)) | ||
254 | return 0; | ||
255 | |||
256 | if (def) | ||
257 | *eoc = ctx->pointer + len; | ||
258 | else | ||
259 | *eoc = NULL; | ||
260 | return 1; | ||
261 | } | ||
262 | |||
263 | static unsigned char asn1_eoc_decode(struct asn1_ctx *ctx, unsigned char *eoc) | ||
264 | { | ||
265 | unsigned char ch; | ||
266 | |||
267 | if (eoc == 0) { | ||
268 | if (!asn1_octet_decode(ctx, &ch)) | ||
269 | return 0; | ||
270 | |||
271 | if (ch != 0x00) { | ||
272 | ctx->error = ASN1_ERR_DEC_EOC_MISMATCH; | ||
273 | return 0; | ||
274 | } | ||
275 | |||
276 | if (!asn1_octet_decode(ctx, &ch)) | ||
277 | return 0; | ||
278 | |||
279 | if (ch != 0x00) { | ||
280 | ctx->error = ASN1_ERR_DEC_EOC_MISMATCH; | ||
281 | return 0; | ||
282 | } | ||
283 | return 1; | ||
284 | } else { | ||
285 | if (ctx->pointer != eoc) { | ||
286 | ctx->error = ASN1_ERR_DEC_LENGTH_MISMATCH; | ||
287 | return 0; | ||
288 | } | ||
289 | return 1; | ||
290 | } | ||
291 | } | ||
292 | |||
293 | static unsigned char asn1_null_decode(struct asn1_ctx *ctx, unsigned char *eoc) | ||
294 | { | ||
295 | ctx->pointer = eoc; | ||
296 | return 1; | ||
297 | } | ||
298 | |||
299 | static unsigned char asn1_long_decode(struct asn1_ctx *ctx, | ||
300 | unsigned char *eoc, | ||
301 | long *integer) | ||
302 | { | ||
303 | unsigned char ch; | ||
304 | unsigned int len; | ||
305 | |||
306 | if (!asn1_octet_decode(ctx, &ch)) | ||
307 | return 0; | ||
308 | |||
309 | *integer = (signed char) ch; | ||
310 | len = 1; | ||
311 | |||
312 | while (ctx->pointer < eoc) { | ||
313 | if (++len > sizeof (long)) { | ||
314 | ctx->error = ASN1_ERR_DEC_BADVALUE; | ||
315 | return 0; | ||
316 | } | ||
317 | |||
318 | if (!asn1_octet_decode(ctx, &ch)) | ||
319 | return 0; | ||
320 | |||
321 | *integer <<= 8; | ||
322 | *integer |= ch; | ||
323 | } | ||
324 | return 1; | ||
325 | } | ||
326 | |||
327 | static unsigned char asn1_uint_decode(struct asn1_ctx *ctx, | ||
328 | unsigned char *eoc, | ||
329 | unsigned int *integer) | ||
330 | { | ||
331 | unsigned char ch; | ||
332 | unsigned int len; | ||
333 | |||
334 | if (!asn1_octet_decode(ctx, &ch)) | ||
335 | return 0; | ||
336 | |||
337 | *integer = ch; | ||
338 | if (ch == 0) len = 0; | ||
339 | else len = 1; | ||
340 | |||
341 | while (ctx->pointer < eoc) { | ||
342 | if (++len > sizeof (unsigned int)) { | ||
343 | ctx->error = ASN1_ERR_DEC_BADVALUE; | ||
344 | return 0; | ||
345 | } | ||
346 | |||
347 | if (!asn1_octet_decode(ctx, &ch)) | ||
348 | return 0; | ||
349 | |||
350 | *integer <<= 8; | ||
351 | *integer |= ch; | ||
352 | } | ||
353 | return 1; | ||
354 | } | ||
355 | |||
356 | static unsigned char asn1_ulong_decode(struct asn1_ctx *ctx, | ||
357 | unsigned char *eoc, | ||
358 | unsigned long *integer) | ||
359 | { | ||
360 | unsigned char ch; | ||
361 | unsigned int len; | ||
362 | |||
363 | if (!asn1_octet_decode(ctx, &ch)) | ||
364 | return 0; | ||
365 | |||
366 | *integer = ch; | ||
367 | if (ch == 0) len = 0; | ||
368 | else len = 1; | ||
369 | |||
370 | while (ctx->pointer < eoc) { | ||
371 | if (++len > sizeof (unsigned long)) { | ||
372 | ctx->error = ASN1_ERR_DEC_BADVALUE; | ||
373 | return 0; | ||
374 | } | ||
375 | |||
376 | if (!asn1_octet_decode(ctx, &ch)) | ||
377 | return 0; | ||
378 | |||
379 | *integer <<= 8; | ||
380 | *integer |= ch; | ||
381 | } | ||
382 | return 1; | ||
383 | } | ||
384 | |||
385 | static unsigned char asn1_octets_decode(struct asn1_ctx *ctx, | ||
386 | unsigned char *eoc, | ||
387 | unsigned char **octets, | ||
388 | unsigned int *len) | ||
389 | { | ||
390 | unsigned char *ptr; | ||
391 | |||
392 | *len = 0; | ||
393 | |||
394 | *octets = kmalloc(eoc - ctx->pointer, GFP_ATOMIC); | ||
395 | if (*octets == NULL) { | ||
396 | if (net_ratelimit()) | ||
397 | printk("OOM in bsalg (%d)\n", __LINE__); | ||
398 | return 0; | ||
399 | } | ||
400 | |||
401 | ptr = *octets; | ||
402 | while (ctx->pointer < eoc) { | ||
403 | if (!asn1_octet_decode(ctx, (unsigned char *)ptr++)) { | ||
404 | kfree(*octets); | ||
405 | *octets = NULL; | ||
406 | return 0; | ||
407 | } | ||
408 | (*len)++; | ||
409 | } | ||
410 | return 1; | ||
411 | } | ||
412 | |||
413 | static unsigned char asn1_subid_decode(struct asn1_ctx *ctx, | ||
414 | unsigned long *subid) | ||
415 | { | ||
416 | unsigned char ch; | ||
417 | |||
418 | *subid = 0; | ||
419 | |||
420 | do { | ||
421 | if (!asn1_octet_decode(ctx, &ch)) | ||
422 | return 0; | ||
423 | |||
424 | *subid <<= 7; | ||
425 | *subid |= ch & 0x7F; | ||
426 | } while ((ch & 0x80) == 0x80); | ||
427 | return 1; | ||
428 | } | ||
429 | |||
430 | static unsigned char asn1_oid_decode(struct asn1_ctx *ctx, | ||
431 | unsigned char *eoc, | ||
432 | unsigned long **oid, | ||
433 | unsigned int *len) | ||
434 | { | ||
435 | unsigned long subid; | ||
436 | unsigned int size; | ||
437 | unsigned long *optr; | ||
438 | |||
439 | size = eoc - ctx->pointer + 1; | ||
440 | *oid = kmalloc(size * sizeof(unsigned long), GFP_ATOMIC); | ||
441 | if (*oid == NULL) { | ||
442 | if (net_ratelimit()) | ||
443 | printk("OOM in bsalg (%d)\n", __LINE__); | ||
444 | return 0; | ||
445 | } | ||
446 | |||
447 | optr = *oid; | ||
448 | |||
449 | if (!asn1_subid_decode(ctx, &subid)) { | ||
450 | kfree(*oid); | ||
451 | *oid = NULL; | ||
452 | return 0; | ||
453 | } | ||
454 | |||
455 | if (subid < 40) { | ||
456 | optr [0] = 0; | ||
457 | optr [1] = subid; | ||
458 | } else if (subid < 80) { | ||
459 | optr [0] = 1; | ||
460 | optr [1] = subid - 40; | ||
461 | } else { | ||
462 | optr [0] = 2; | ||
463 | optr [1] = subid - 80; | ||
464 | } | ||
465 | |||
466 | *len = 2; | ||
467 | optr += 2; | ||
468 | |||
469 | while (ctx->pointer < eoc) { | ||
470 | if (++(*len) > size) { | ||
471 | ctx->error = ASN1_ERR_DEC_BADVALUE; | ||
472 | kfree(*oid); | ||
473 | *oid = NULL; | ||
474 | return 0; | ||
475 | } | ||
476 | |||
477 | if (!asn1_subid_decode(ctx, optr++)) { | ||
478 | kfree(*oid); | ||
479 | *oid = NULL; | ||
480 | return 0; | ||
481 | } | ||
482 | } | ||
483 | return 1; | ||
484 | } | ||
485 | |||
486 | /***************************************************************************** | ||
487 | * | ||
488 | * SNMP decoding routines (gxsnmp author Dirk Wisse) | ||
489 | * | ||
490 | *****************************************************************************/ | ||
491 | |||
492 | /* SNMP Versions */ | ||
493 | #define SNMP_V1 0 | ||
494 | #define SNMP_V2C 1 | ||
495 | #define SNMP_V2 2 | ||
496 | #define SNMP_V3 3 | ||
497 | |||
498 | /* Default Sizes */ | ||
499 | #define SNMP_SIZE_COMM 256 | ||
500 | #define SNMP_SIZE_OBJECTID 128 | ||
501 | #define SNMP_SIZE_BUFCHR 256 | ||
502 | #define SNMP_SIZE_BUFINT 128 | ||
503 | #define SNMP_SIZE_SMALLOBJECTID 16 | ||
504 | |||
505 | /* Requests */ | ||
506 | #define SNMP_PDU_GET 0 | ||
507 | #define SNMP_PDU_NEXT 1 | ||
508 | #define SNMP_PDU_RESPONSE 2 | ||
509 | #define SNMP_PDU_SET 3 | ||
510 | #define SNMP_PDU_TRAP1 4 | ||
511 | #define SNMP_PDU_BULK 5 | ||
512 | #define SNMP_PDU_INFORM 6 | ||
513 | #define SNMP_PDU_TRAP2 7 | ||
514 | |||
515 | /* Errors */ | ||
516 | #define SNMP_NOERROR 0 | ||
517 | #define SNMP_TOOBIG 1 | ||
518 | #define SNMP_NOSUCHNAME 2 | ||
519 | #define SNMP_BADVALUE 3 | ||
520 | #define SNMP_READONLY 4 | ||
521 | #define SNMP_GENERROR 5 | ||
522 | #define SNMP_NOACCESS 6 | ||
523 | #define SNMP_WRONGTYPE 7 | ||
524 | #define SNMP_WRONGLENGTH 8 | ||
525 | #define SNMP_WRONGENCODING 9 | ||
526 | #define SNMP_WRONGVALUE 10 | ||
527 | #define SNMP_NOCREATION 11 | ||
528 | #define SNMP_INCONSISTENTVALUE 12 | ||
529 | #define SNMP_RESOURCEUNAVAILABLE 13 | ||
530 | #define SNMP_COMMITFAILED 14 | ||
531 | #define SNMP_UNDOFAILED 15 | ||
532 | #define SNMP_AUTHORIZATIONERROR 16 | ||
533 | #define SNMP_NOTWRITABLE 17 | ||
534 | #define SNMP_INCONSISTENTNAME 18 | ||
535 | |||
536 | /* General SNMP V1 Traps */ | ||
537 | #define SNMP_TRAP_COLDSTART 0 | ||
538 | #define SNMP_TRAP_WARMSTART 1 | ||
539 | #define SNMP_TRAP_LINKDOWN 2 | ||
540 | #define SNMP_TRAP_LINKUP 3 | ||
541 | #define SNMP_TRAP_AUTFAILURE 4 | ||
542 | #define SNMP_TRAP_EQPNEIGHBORLOSS 5 | ||
543 | #define SNMP_TRAP_ENTSPECIFIC 6 | ||
544 | |||
545 | /* SNMPv1 Types */ | ||
546 | #define SNMP_NULL 0 | ||
547 | #define SNMP_INTEGER 1 /* l */ | ||
548 | #define SNMP_OCTETSTR 2 /* c */ | ||
549 | #define SNMP_DISPLAYSTR 2 /* c */ | ||
550 | #define SNMP_OBJECTID 3 /* ul */ | ||
551 | #define SNMP_IPADDR 4 /* uc */ | ||
552 | #define SNMP_COUNTER 5 /* ul */ | ||
553 | #define SNMP_GAUGE 6 /* ul */ | ||
554 | #define SNMP_TIMETICKS 7 /* ul */ | ||
555 | #define SNMP_OPAQUE 8 /* c */ | ||
556 | |||
557 | /* Additional SNMPv2 Types */ | ||
558 | #define SNMP_UINTEGER 5 /* ul */ | ||
559 | #define SNMP_BITSTR 9 /* uc */ | ||
560 | #define SNMP_NSAP 10 /* uc */ | ||
561 | #define SNMP_COUNTER64 11 /* ul */ | ||
562 | #define SNMP_NOSUCHOBJECT 12 | ||
563 | #define SNMP_NOSUCHINSTANCE 13 | ||
564 | #define SNMP_ENDOFMIBVIEW 14 | ||
565 | |||
566 | union snmp_syntax | ||
567 | { | ||
568 | unsigned char uc[0]; /* 8 bit unsigned */ | ||
569 | char c[0]; /* 8 bit signed */ | ||
570 | unsigned long ul[0]; /* 32 bit unsigned */ | ||
571 | long l[0]; /* 32 bit signed */ | ||
572 | }; | ||
573 | |||
574 | struct snmp_object | ||
575 | { | ||
576 | unsigned long *id; | ||
577 | unsigned int id_len; | ||
578 | unsigned short type; | ||
579 | unsigned int syntax_len; | ||
580 | union snmp_syntax syntax; | ||
581 | }; | ||
582 | |||
583 | struct snmp_request | ||
584 | { | ||
585 | unsigned long id; | ||
586 | unsigned int error_status; | ||
587 | unsigned int error_index; | ||
588 | }; | ||
589 | |||
590 | struct snmp_v1_trap | ||
591 | { | ||
592 | unsigned long *id; | ||
593 | unsigned int id_len; | ||
594 | unsigned long ip_address; /* pointer */ | ||
595 | unsigned int general; | ||
596 | unsigned int specific; | ||
597 | unsigned long time; | ||
598 | }; | ||
599 | |||
600 | /* SNMP types */ | ||
601 | #define SNMP_IPA 0 | ||
602 | #define SNMP_CNT 1 | ||
603 | #define SNMP_GGE 2 | ||
604 | #define SNMP_TIT 3 | ||
605 | #define SNMP_OPQ 4 | ||
606 | #define SNMP_C64 6 | ||
607 | |||
608 | /* SNMP errors */ | ||
609 | #define SERR_NSO 0 | ||
610 | #define SERR_NSI 1 | ||
611 | #define SERR_EOM 2 | ||
612 | |||
613 | static inline void mangle_address(unsigned char *begin, | ||
614 | unsigned char *addr, | ||
615 | const struct oct1_map *map, | ||
616 | __sum16 *check); | ||
617 | struct snmp_cnv | ||
618 | { | ||
619 | unsigned int class; | ||
620 | unsigned int tag; | ||
621 | int syntax; | ||
622 | }; | ||
623 | |||
624 | static struct snmp_cnv snmp_conv [] = | ||
625 | { | ||
626 | {ASN1_UNI, ASN1_NUL, SNMP_NULL}, | ||
627 | {ASN1_UNI, ASN1_INT, SNMP_INTEGER}, | ||
628 | {ASN1_UNI, ASN1_OTS, SNMP_OCTETSTR}, | ||
629 | {ASN1_UNI, ASN1_OTS, SNMP_DISPLAYSTR}, | ||
630 | {ASN1_UNI, ASN1_OJI, SNMP_OBJECTID}, | ||
631 | {ASN1_APL, SNMP_IPA, SNMP_IPADDR}, | ||
632 | {ASN1_APL, SNMP_CNT, SNMP_COUNTER}, /* Counter32 */ | ||
633 | {ASN1_APL, SNMP_GGE, SNMP_GAUGE}, /* Gauge32 == Unsigned32 */ | ||
634 | {ASN1_APL, SNMP_TIT, SNMP_TIMETICKS}, | ||
635 | {ASN1_APL, SNMP_OPQ, SNMP_OPAQUE}, | ||
636 | |||
637 | /* SNMPv2 data types and errors */ | ||
638 | {ASN1_UNI, ASN1_BTS, SNMP_BITSTR}, | ||
639 | {ASN1_APL, SNMP_C64, SNMP_COUNTER64}, | ||
640 | {ASN1_CTX, SERR_NSO, SNMP_NOSUCHOBJECT}, | ||
641 | {ASN1_CTX, SERR_NSI, SNMP_NOSUCHINSTANCE}, | ||
642 | {ASN1_CTX, SERR_EOM, SNMP_ENDOFMIBVIEW}, | ||
643 | {0, 0, -1} | ||
644 | }; | ||
645 | |||
646 | static unsigned char snmp_tag_cls2syntax(unsigned int tag, | ||
647 | unsigned int cls, | ||
648 | unsigned short *syntax) | ||
649 | { | ||
650 | struct snmp_cnv *cnv; | ||
651 | |||
652 | cnv = snmp_conv; | ||
653 | |||
654 | while (cnv->syntax != -1) { | ||
655 | if (cnv->tag == tag && cnv->class == cls) { | ||
656 | *syntax = cnv->syntax; | ||
657 | return 1; | ||
658 | } | ||
659 | cnv++; | ||
660 | } | ||
661 | return 0; | ||
662 | } | ||
663 | |||
664 | static unsigned char snmp_object_decode(struct asn1_ctx *ctx, | ||
665 | struct snmp_object **obj) | ||
666 | { | ||
667 | unsigned int cls, con, tag, len, idlen; | ||
668 | unsigned short type; | ||
669 | unsigned char *eoc, *end, *p; | ||
670 | unsigned long *lp, *id; | ||
671 | unsigned long ul; | ||
672 | long l; | ||
673 | |||
674 | *obj = NULL; | ||
675 | id = NULL; | ||
676 | |||
677 | if (!asn1_header_decode(ctx, &eoc, &cls, &con, &tag)) | ||
678 | return 0; | ||
679 | |||
680 | if (cls != ASN1_UNI || con != ASN1_CON || tag != ASN1_SEQ) | ||
681 | return 0; | ||
682 | |||
683 | if (!asn1_header_decode(ctx, &end, &cls, &con, &tag)) | ||
684 | return 0; | ||
685 | |||
686 | if (cls != ASN1_UNI || con != ASN1_PRI || tag != ASN1_OJI) | ||
687 | return 0; | ||
688 | |||
689 | if (!asn1_oid_decode(ctx, end, &id, &idlen)) | ||
690 | return 0; | ||
691 | |||
692 | if (!asn1_header_decode(ctx, &end, &cls, &con, &tag)) { | ||
693 | kfree(id); | ||
694 | return 0; | ||
695 | } | ||
696 | |||
697 | if (con != ASN1_PRI) { | ||
698 | kfree(id); | ||
699 | return 0; | ||
700 | } | ||
701 | |||
702 | type = 0; | ||
703 | if (!snmp_tag_cls2syntax(tag, cls, &type)) { | ||
704 | kfree(id); | ||
705 | return 0; | ||
706 | } | ||
707 | |||
708 | l = 0; | ||
709 | switch (type) { | ||
710 | case SNMP_INTEGER: | ||
711 | len = sizeof(long); | ||
712 | if (!asn1_long_decode(ctx, end, &l)) { | ||
713 | kfree(id); | ||
714 | return 0; | ||
715 | } | ||
716 | *obj = kmalloc(sizeof(struct snmp_object) + len, | ||
717 | GFP_ATOMIC); | ||
718 | if (*obj == NULL) { | ||
719 | kfree(id); | ||
720 | if (net_ratelimit()) | ||
721 | printk("OOM in bsalg (%d)\n", __LINE__); | ||
722 | return 0; | ||
723 | } | ||
724 | (*obj)->syntax.l[0] = l; | ||
725 | break; | ||
726 | case SNMP_OCTETSTR: | ||
727 | case SNMP_OPAQUE: | ||
728 | if (!asn1_octets_decode(ctx, end, &p, &len)) { | ||
729 | kfree(id); | ||
730 | return 0; | ||
731 | } | ||
732 | *obj = kmalloc(sizeof(struct snmp_object) + len, | ||
733 | GFP_ATOMIC); | ||
734 | if (*obj == NULL) { | ||
735 | kfree(id); | ||
736 | if (net_ratelimit()) | ||
737 | printk("OOM in bsalg (%d)\n", __LINE__); | ||
738 | return 0; | ||
739 | } | ||
740 | memcpy((*obj)->syntax.c, p, len); | ||
741 | kfree(p); | ||
742 | break; | ||
743 | case SNMP_NULL: | ||
744 | case SNMP_NOSUCHOBJECT: | ||
745 | case SNMP_NOSUCHINSTANCE: | ||
746 | case SNMP_ENDOFMIBVIEW: | ||
747 | len = 0; | ||
748 | *obj = kmalloc(sizeof(struct snmp_object), GFP_ATOMIC); | ||
749 | if (*obj == NULL) { | ||
750 | kfree(id); | ||
751 | if (net_ratelimit()) | ||
752 | printk("OOM in bsalg (%d)\n", __LINE__); | ||
753 | return 0; | ||
754 | } | ||
755 | if (!asn1_null_decode(ctx, end)) { | ||
756 | kfree(id); | ||
757 | kfree(*obj); | ||
758 | *obj = NULL; | ||
759 | return 0; | ||
760 | } | ||
761 | break; | ||
762 | case SNMP_OBJECTID: | ||
763 | if (!asn1_oid_decode(ctx, end, (unsigned long **)&lp, &len)) { | ||
764 | kfree(id); | ||
765 | return 0; | ||
766 | } | ||
767 | len *= sizeof(unsigned long); | ||
768 | *obj = kmalloc(sizeof(struct snmp_object) + len, GFP_ATOMIC); | ||
769 | if (*obj == NULL) { | ||
770 | kfree(lp); | ||
771 | kfree(id); | ||
772 | if (net_ratelimit()) | ||
773 | printk("OOM in bsalg (%d)\n", __LINE__); | ||
774 | return 0; | ||
775 | } | ||
776 | memcpy((*obj)->syntax.ul, lp, len); | ||
777 | kfree(lp); | ||
778 | break; | ||
779 | case SNMP_IPADDR: | ||
780 | if (!asn1_octets_decode(ctx, end, &p, &len)) { | ||
781 | kfree(id); | ||
782 | return 0; | ||
783 | } | ||
784 | if (len != 4) { | ||
785 | kfree(p); | ||
786 | kfree(id); | ||
787 | return 0; | ||
788 | } | ||
789 | *obj = kmalloc(sizeof(struct snmp_object) + len, GFP_ATOMIC); | ||
790 | if (*obj == NULL) { | ||
791 | kfree(p); | ||
792 | kfree(id); | ||
793 | if (net_ratelimit()) | ||
794 | printk("OOM in bsalg (%d)\n", __LINE__); | ||
795 | return 0; | ||
796 | } | ||
797 | memcpy((*obj)->syntax.uc, p, len); | ||
798 | kfree(p); | ||
799 | break; | ||
800 | case SNMP_COUNTER: | ||
801 | case SNMP_GAUGE: | ||
802 | case SNMP_TIMETICKS: | ||
803 | len = sizeof(unsigned long); | ||
804 | if (!asn1_ulong_decode(ctx, end, &ul)) { | ||
805 | kfree(id); | ||
806 | return 0; | ||
807 | } | ||
808 | *obj = kmalloc(sizeof(struct snmp_object) + len, GFP_ATOMIC); | ||
809 | if (*obj == NULL) { | ||
810 | kfree(id); | ||
811 | if (net_ratelimit()) | ||
812 | printk("OOM in bsalg (%d)\n", __LINE__); | ||
813 | return 0; | ||
814 | } | ||
815 | (*obj)->syntax.ul[0] = ul; | ||
816 | break; | ||
817 | default: | ||
818 | kfree(id); | ||
819 | return 0; | ||
820 | } | ||
821 | |||
822 | (*obj)->syntax_len = len; | ||
823 | (*obj)->type = type; | ||
824 | (*obj)->id = id; | ||
825 | (*obj)->id_len = idlen; | ||
826 | |||
827 | if (!asn1_eoc_decode(ctx, eoc)) { | ||
828 | kfree(id); | ||
829 | kfree(*obj); | ||
830 | *obj = NULL; | ||
831 | return 0; | ||
832 | } | ||
833 | return 1; | ||
834 | } | ||
835 | |||
836 | static unsigned char snmp_request_decode(struct asn1_ctx *ctx, | ||
837 | struct snmp_request *request) | ||
838 | { | ||
839 | unsigned int cls, con, tag; | ||
840 | unsigned char *end; | ||
841 | |||
842 | if (!asn1_header_decode(ctx, &end, &cls, &con, &tag)) | ||
843 | return 0; | ||
844 | |||
845 | if (cls != ASN1_UNI || con != ASN1_PRI || tag != ASN1_INT) | ||
846 | return 0; | ||
847 | |||
848 | if (!asn1_ulong_decode(ctx, end, &request->id)) | ||
849 | return 0; | ||
850 | |||
851 | if (!asn1_header_decode(ctx, &end, &cls, &con, &tag)) | ||
852 | return 0; | ||
853 | |||
854 | if (cls != ASN1_UNI || con != ASN1_PRI || tag != ASN1_INT) | ||
855 | return 0; | ||
856 | |||
857 | if (!asn1_uint_decode(ctx, end, &request->error_status)) | ||
858 | return 0; | ||
859 | |||
860 | if (!asn1_header_decode(ctx, &end, &cls, &con, &tag)) | ||
861 | return 0; | ||
862 | |||
863 | if (cls != ASN1_UNI || con != ASN1_PRI || tag != ASN1_INT) | ||
864 | return 0; | ||
865 | |||
866 | if (!asn1_uint_decode(ctx, end, &request->error_index)) | ||
867 | return 0; | ||
868 | |||
869 | return 1; | ||
870 | } | ||
871 | |||
872 | /* | ||
873 | * Fast checksum update for possibly oddly-aligned UDP byte, from the | ||
874 | * code example in the draft. | ||
875 | */ | ||
876 | static void fast_csum(__sum16 *csum, | ||
877 | const unsigned char *optr, | ||
878 | const unsigned char *nptr, | ||
879 | int offset) | ||
880 | { | ||
881 | unsigned char s[4]; | ||
882 | |||
883 | if (offset & 1) { | ||
884 | s[0] = s[2] = 0; | ||
885 | s[1] = ~*optr; | ||
886 | s[3] = *nptr; | ||
887 | } else { | ||
888 | s[1] = s[3] = 0; | ||
889 | s[0] = ~*optr; | ||
890 | s[2] = *nptr; | ||
891 | } | ||
892 | |||
893 | *csum = csum_fold(csum_partial(s, 4, ~csum_unfold(*csum))); | ||
894 | } | ||
895 | |||
896 | /* | ||
897 | * Mangle IP address. | ||
898 | * - begin points to the start of the snmp messgae | ||
899 | * - addr points to the start of the address | ||
900 | */ | ||
901 | static inline void mangle_address(unsigned char *begin, | ||
902 | unsigned char *addr, | ||
903 | const struct oct1_map *map, | ||
904 | __sum16 *check) | ||
905 | { | ||
906 | if (map->from == NOCT1(addr)) { | ||
907 | u_int32_t old; | ||
908 | |||
909 | if (debug) | ||
910 | memcpy(&old, (unsigned char *)addr, sizeof(old)); | ||
911 | |||
912 | *addr = map->to; | ||
913 | |||
914 | /* Update UDP checksum if being used */ | ||
915 | if (*check) { | ||
916 | fast_csum(check, | ||
917 | &map->from, &map->to, addr - begin); | ||
918 | |||
919 | } | ||
920 | |||
921 | if (debug) | ||
922 | printk(KERN_DEBUG "bsalg: mapped %u.%u.%u.%u to " | ||
923 | "%u.%u.%u.%u\n", NIPQUAD(old), NIPQUAD(*addr)); | ||
924 | } | ||
925 | } | ||
926 | |||
927 | static unsigned char snmp_trap_decode(struct asn1_ctx *ctx, | ||
928 | struct snmp_v1_trap *trap, | ||
929 | const struct oct1_map *map, | ||
930 | __sum16 *check) | ||
931 | { | ||
932 | unsigned int cls, con, tag, len; | ||
933 | unsigned char *end; | ||
934 | |||
935 | if (!asn1_header_decode(ctx, &end, &cls, &con, &tag)) | ||
936 | return 0; | ||
937 | |||
938 | if (cls != ASN1_UNI || con != ASN1_PRI || tag != ASN1_OJI) | ||
939 | return 0; | ||
940 | |||
941 | if (!asn1_oid_decode(ctx, end, &trap->id, &trap->id_len)) | ||
942 | return 0; | ||
943 | |||
944 | if (!asn1_header_decode(ctx, &end, &cls, &con, &tag)) | ||
945 | goto err_id_free; | ||
946 | |||
947 | if (!((cls == ASN1_APL && con == ASN1_PRI && tag == SNMP_IPA) || | ||
948 | (cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_OTS))) | ||
949 | goto err_id_free; | ||
950 | |||
951 | if (!asn1_octets_decode(ctx, end, (unsigned char **)&trap->ip_address, &len)) | ||
952 | goto err_id_free; | ||
953 | |||
954 | /* IPv4 only */ | ||
955 | if (len != 4) | ||
956 | goto err_addr_free; | ||
957 | |||
958 | mangle_address(ctx->begin, ctx->pointer - 4, map, check); | ||
959 | |||
960 | if (!asn1_header_decode(ctx, &end, &cls, &con, &tag)) | ||
961 | goto err_addr_free; | ||
962 | |||
963 | if (cls != ASN1_UNI || con != ASN1_PRI || tag != ASN1_INT) | ||
964 | goto err_addr_free; | ||
965 | |||
966 | if (!asn1_uint_decode(ctx, end, &trap->general)) | ||
967 | goto err_addr_free; | ||
968 | |||
969 | if (!asn1_header_decode(ctx, &end, &cls, &con, &tag)) | ||
970 | goto err_addr_free; | ||
971 | |||
972 | if (cls != ASN1_UNI || con != ASN1_PRI || tag != ASN1_INT) | ||
973 | goto err_addr_free; | ||
974 | |||
975 | if (!asn1_uint_decode(ctx, end, &trap->specific)) | ||
976 | goto err_addr_free; | ||
977 | |||
978 | if (!asn1_header_decode(ctx, &end, &cls, &con, &tag)) | ||
979 | goto err_addr_free; | ||
980 | |||
981 | if (!((cls == ASN1_APL && con == ASN1_PRI && tag == SNMP_TIT) || | ||
982 | (cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_INT))) | ||
983 | goto err_addr_free; | ||
984 | |||
985 | if (!asn1_ulong_decode(ctx, end, &trap->time)) | ||
986 | goto err_addr_free; | ||
987 | |||
988 | return 1; | ||
989 | |||
990 | err_addr_free: | ||
991 | kfree((unsigned long *)trap->ip_address); | ||
992 | |||
993 | err_id_free: | ||
994 | kfree(trap->id); | ||
995 | |||
996 | return 0; | ||
997 | } | ||
998 | |||
999 | /***************************************************************************** | ||
1000 | * | ||
1001 | * Misc. routines | ||
1002 | * | ||
1003 | *****************************************************************************/ | ||
1004 | |||
1005 | static void hex_dump(unsigned char *buf, size_t len) | ||
1006 | { | ||
1007 | size_t i; | ||
1008 | |||
1009 | for (i = 0; i < len; i++) { | ||
1010 | if (i && !(i % 16)) | ||
1011 | printk("\n"); | ||
1012 | printk("%02x ", *(buf + i)); | ||
1013 | } | ||
1014 | printk("\n"); | ||
1015 | } | ||
1016 | |||
1017 | /* | ||
1018 | * Parse and mangle SNMP message according to mapping. | ||
1019 | * (And this is the fucking 'basic' method). | ||
1020 | */ | ||
1021 | static int snmp_parse_mangle(unsigned char *msg, | ||
1022 | u_int16_t len, | ||
1023 | const struct oct1_map *map, | ||
1024 | __sum16 *check) | ||
1025 | { | ||
1026 | unsigned char *eoc, *end; | ||
1027 | unsigned int cls, con, tag, vers, pdutype; | ||
1028 | struct asn1_ctx ctx; | ||
1029 | struct asn1_octstr comm; | ||
1030 | struct snmp_object **obj; | ||
1031 | |||
1032 | if (debug > 1) | ||
1033 | hex_dump(msg, len); | ||
1034 | |||
1035 | asn1_open(&ctx, msg, len); | ||
1036 | |||
1037 | /* | ||
1038 | * Start of SNMP message. | ||
1039 | */ | ||
1040 | if (!asn1_header_decode(&ctx, &eoc, &cls, &con, &tag)) | ||
1041 | return 0; | ||
1042 | if (cls != ASN1_UNI || con != ASN1_CON || tag != ASN1_SEQ) | ||
1043 | return 0; | ||
1044 | |||
1045 | /* | ||
1046 | * Version 1 or 2 handled. | ||
1047 | */ | ||
1048 | if (!asn1_header_decode(&ctx, &end, &cls, &con, &tag)) | ||
1049 | return 0; | ||
1050 | if (cls != ASN1_UNI || con != ASN1_PRI || tag != ASN1_INT) | ||
1051 | return 0; | ||
1052 | if (!asn1_uint_decode (&ctx, end, &vers)) | ||
1053 | return 0; | ||
1054 | if (debug > 1) | ||
1055 | printk(KERN_DEBUG "bsalg: snmp version: %u\n", vers + 1); | ||
1056 | if (vers > 1) | ||
1057 | return 1; | ||
1058 | |||
1059 | /* | ||
1060 | * Community. | ||
1061 | */ | ||
1062 | if (!asn1_header_decode (&ctx, &end, &cls, &con, &tag)) | ||
1063 | return 0; | ||
1064 | if (cls != ASN1_UNI || con != ASN1_PRI || tag != ASN1_OTS) | ||
1065 | return 0; | ||
1066 | if (!asn1_octets_decode(&ctx, end, &comm.data, &comm.len)) | ||
1067 | return 0; | ||
1068 | if (debug > 1) { | ||
1069 | unsigned int i; | ||
1070 | |||
1071 | printk(KERN_DEBUG "bsalg: community: "); | ||
1072 | for (i = 0; i < comm.len; i++) | ||
1073 | printk("%c", comm.data[i]); | ||
1074 | printk("\n"); | ||
1075 | } | ||
1076 | kfree(comm.data); | ||
1077 | |||
1078 | /* | ||
1079 | * PDU type | ||
1080 | */ | ||
1081 | if (!asn1_header_decode(&ctx, &eoc, &cls, &con, &pdutype)) | ||
1082 | return 0; | ||
1083 | if (cls != ASN1_CTX || con != ASN1_CON) | ||
1084 | return 0; | ||
1085 | if (debug > 1) { | ||
1086 | unsigned char *pdus[] = { | ||
1087 | [SNMP_PDU_GET] = "get", | ||
1088 | [SNMP_PDU_NEXT] = "get-next", | ||
1089 | [SNMP_PDU_RESPONSE] = "response", | ||
1090 | [SNMP_PDU_SET] = "set", | ||
1091 | [SNMP_PDU_TRAP1] = "trapv1", | ||
1092 | [SNMP_PDU_BULK] = "bulk", | ||
1093 | [SNMP_PDU_INFORM] = "inform", | ||
1094 | [SNMP_PDU_TRAP2] = "trapv2" | ||
1095 | }; | ||
1096 | |||
1097 | if (pdutype > SNMP_PDU_TRAP2) | ||
1098 | printk(KERN_DEBUG "bsalg: bad pdu type %u\n", pdutype); | ||
1099 | else | ||
1100 | printk(KERN_DEBUG "bsalg: pdu: %s\n", pdus[pdutype]); | ||
1101 | } | ||
1102 | if (pdutype != SNMP_PDU_RESPONSE && | ||
1103 | pdutype != SNMP_PDU_TRAP1 && pdutype != SNMP_PDU_TRAP2) | ||
1104 | return 1; | ||
1105 | |||
1106 | /* | ||
1107 | * Request header or v1 trap | ||
1108 | */ | ||
1109 | if (pdutype == SNMP_PDU_TRAP1) { | ||
1110 | struct snmp_v1_trap trap; | ||
1111 | unsigned char ret = snmp_trap_decode(&ctx, &trap, map, check); | ||
1112 | |||
1113 | if (ret) { | ||
1114 | kfree(trap.id); | ||
1115 | kfree((unsigned long *)trap.ip_address); | ||
1116 | } else | ||
1117 | return ret; | ||
1118 | |||
1119 | } else { | ||
1120 | struct snmp_request req; | ||
1121 | |||
1122 | if (!snmp_request_decode(&ctx, &req)) | ||
1123 | return 0; | ||
1124 | |||
1125 | if (debug > 1) | ||
1126 | printk(KERN_DEBUG "bsalg: request: id=0x%lx error_status=%u " | ||
1127 | "error_index=%u\n", req.id, req.error_status, | ||
1128 | req.error_index); | ||
1129 | } | ||
1130 | |||
1131 | /* | ||
1132 | * Loop through objects, look for IP addresses to mangle. | ||
1133 | */ | ||
1134 | if (!asn1_header_decode(&ctx, &eoc, &cls, &con, &tag)) | ||
1135 | return 0; | ||
1136 | |||
1137 | if (cls != ASN1_UNI || con != ASN1_CON || tag != ASN1_SEQ) | ||
1138 | return 0; | ||
1139 | |||
1140 | obj = kmalloc(sizeof(struct snmp_object), GFP_ATOMIC); | ||
1141 | if (obj == NULL) { | ||
1142 | if (net_ratelimit()) | ||
1143 | printk(KERN_WARNING "OOM in bsalg(%d)\n", __LINE__); | ||
1144 | return 0; | ||
1145 | } | ||
1146 | |||
1147 | while (!asn1_eoc_decode(&ctx, eoc)) { | ||
1148 | unsigned int i; | ||
1149 | |||
1150 | if (!snmp_object_decode(&ctx, obj)) { | ||
1151 | if (*obj) { | ||
1152 | kfree((*obj)->id); | ||
1153 | kfree(*obj); | ||
1154 | } | ||
1155 | kfree(obj); | ||
1156 | return 0; | ||
1157 | } | ||
1158 | |||
1159 | if (debug > 1) { | ||
1160 | printk(KERN_DEBUG "bsalg: object: "); | ||
1161 | for (i = 0; i < (*obj)->id_len; i++) { | ||
1162 | if (i > 0) | ||
1163 | printk("."); | ||
1164 | printk("%lu", (*obj)->id[i]); | ||
1165 | } | ||
1166 | printk(": type=%u\n", (*obj)->type); | ||
1167 | |||
1168 | } | ||
1169 | |||
1170 | if ((*obj)->type == SNMP_IPADDR) | ||
1171 | mangle_address(ctx.begin, ctx.pointer - 4 , map, check); | ||
1172 | |||
1173 | kfree((*obj)->id); | ||
1174 | kfree(*obj); | ||
1175 | } | ||
1176 | kfree(obj); | ||
1177 | |||
1178 | if (!asn1_eoc_decode(&ctx, eoc)) | ||
1179 | return 0; | ||
1180 | |||
1181 | return 1; | ||
1182 | } | ||
1183 | |||
1184 | /***************************************************************************** | ||
1185 | * | ||
1186 | * NAT routines. | ||
1187 | * | ||
1188 | *****************************************************************************/ | ||
1189 | |||
1190 | /* | ||
1191 | * SNMP translation routine. | ||
1192 | */ | ||
1193 | static int snmp_translate(struct nf_conn *ct, | ||
1194 | enum ip_conntrack_info ctinfo, | ||
1195 | struct sk_buff **pskb) | ||
1196 | { | ||
1197 | struct iphdr *iph = (*pskb)->nh.iph; | ||
1198 | struct udphdr *udph = (struct udphdr *)((__be32 *)iph + iph->ihl); | ||
1199 | u_int16_t udplen = ntohs(udph->len); | ||
1200 | u_int16_t paylen = udplen - sizeof(struct udphdr); | ||
1201 | int dir = CTINFO2DIR(ctinfo); | ||
1202 | struct oct1_map map; | ||
1203 | |||
1204 | /* | ||
1205 | * Determine mappping for application layer addresses based | ||
1206 | * on NAT manipulations for the packet. | ||
1207 | */ | ||
1208 | if (dir == IP_CT_DIR_ORIGINAL) { | ||
1209 | /* SNAT traps */ | ||
1210 | map.from = NOCT1(&ct->tuplehash[dir].tuple.src.u3.ip); | ||
1211 | map.to = NOCT1(&ct->tuplehash[!dir].tuple.dst.u3.ip); | ||
1212 | } else { | ||
1213 | /* DNAT replies */ | ||
1214 | map.from = NOCT1(&ct->tuplehash[dir].tuple.src.u3.ip); | ||
1215 | map.to = NOCT1(&ct->tuplehash[!dir].tuple.dst.u3.ip); | ||
1216 | } | ||
1217 | |||
1218 | if (map.from == map.to) | ||
1219 | return NF_ACCEPT; | ||
1220 | |||
1221 | if (!snmp_parse_mangle((unsigned char *)udph + sizeof(struct udphdr), | ||
1222 | paylen, &map, &udph->check)) { | ||
1223 | if (net_ratelimit()) | ||
1224 | printk(KERN_WARNING "bsalg: parser failed\n"); | ||
1225 | return NF_DROP; | ||
1226 | } | ||
1227 | return NF_ACCEPT; | ||
1228 | } | ||
1229 | |||
1230 | /* We don't actually set up expectations, just adjust internal IP | ||
1231 | * addresses if this is being NATted */ | ||
1232 | static int help(struct sk_buff **pskb, unsigned int protoff, | ||
1233 | struct nf_conn *ct, | ||
1234 | enum ip_conntrack_info ctinfo) | ||
1235 | { | ||
1236 | int dir = CTINFO2DIR(ctinfo); | ||
1237 | unsigned int ret; | ||
1238 | struct iphdr *iph = (*pskb)->nh.iph; | ||
1239 | struct udphdr *udph = (struct udphdr *)((u_int32_t *)iph + iph->ihl); | ||
1240 | |||
1241 | /* SNMP replies and originating SNMP traps get mangled */ | ||
1242 | if (udph->source == htons(SNMP_PORT) && dir != IP_CT_DIR_REPLY) | ||
1243 | return NF_ACCEPT; | ||
1244 | if (udph->dest == htons(SNMP_TRAP_PORT) && dir != IP_CT_DIR_ORIGINAL) | ||
1245 | return NF_ACCEPT; | ||
1246 | |||
1247 | /* No NAT? */ | ||
1248 | if (!(ct->status & IPS_NAT_MASK)) | ||
1249 | return NF_ACCEPT; | ||
1250 | |||
1251 | /* | ||
1252 | * Make sure the packet length is ok. So far, we were only guaranteed | ||
1253 | * to have a valid length IP header plus 8 bytes, which means we have | ||
1254 | * enough room for a UDP header. Just verify the UDP length field so we | ||
1255 | * can mess around with the payload. | ||
1256 | */ | ||
1257 | if (ntohs(udph->len) != (*pskb)->len - (iph->ihl << 2)) { | ||
1258 | if (net_ratelimit()) | ||
1259 | printk(KERN_WARNING "SNMP: dropping malformed packet " | ||
1260 | "src=%u.%u.%u.%u dst=%u.%u.%u.%u\n", | ||
1261 | NIPQUAD(iph->saddr), NIPQUAD(iph->daddr)); | ||
1262 | return NF_DROP; | ||
1263 | } | ||
1264 | |||
1265 | if (!skb_make_writable(pskb, (*pskb)->len)) | ||
1266 | return NF_DROP; | ||
1267 | |||
1268 | spin_lock_bh(&snmp_lock); | ||
1269 | ret = snmp_translate(ct, ctinfo, pskb); | ||
1270 | spin_unlock_bh(&snmp_lock); | ||
1271 | return ret; | ||
1272 | } | ||
1273 | |||
1274 | static struct nf_conntrack_helper snmp_helper __read_mostly = { | ||
1275 | .max_expected = 0, | ||
1276 | .timeout = 180, | ||
1277 | .me = THIS_MODULE, | ||
1278 | .help = help, | ||
1279 | .name = "snmp", | ||
1280 | .tuple.src.l3num = AF_INET, | ||
1281 | .tuple.src.u.udp.port = __constant_htons(SNMP_PORT), | ||
1282 | .tuple.dst.protonum = IPPROTO_UDP, | ||
1283 | .mask.src.l3num = 0xFFFF, | ||
1284 | .mask.src.u.udp.port = __constant_htons(0xFFFF), | ||
1285 | .mask.dst.protonum = 0xFF, | ||
1286 | }; | ||
1287 | |||
1288 | static struct nf_conntrack_helper snmp_trap_helper __read_mostly = { | ||
1289 | .max_expected = 0, | ||
1290 | .timeout = 180, | ||
1291 | .me = THIS_MODULE, | ||
1292 | .help = help, | ||
1293 | .name = "snmp_trap", | ||
1294 | .tuple.src.l3num = AF_INET, | ||
1295 | .tuple.src.u.udp.port = __constant_htons(SNMP_TRAP_PORT), | ||
1296 | .tuple.dst.protonum = IPPROTO_UDP, | ||
1297 | .mask.src.l3num = 0xFFFF, | ||
1298 | .mask.src.u.udp.port = __constant_htons(0xFFFF), | ||
1299 | .mask.dst.protonum = 0xFF, | ||
1300 | }; | ||
1301 | |||
1302 | /***************************************************************************** | ||
1303 | * | ||
1304 | * Module stuff. | ||
1305 | * | ||
1306 | *****************************************************************************/ | ||
1307 | |||
1308 | static int __init nf_nat_snmp_basic_init(void) | ||
1309 | { | ||
1310 | int ret = 0; | ||
1311 | |||
1312 | ret = nf_conntrack_helper_register(&snmp_helper); | ||
1313 | if (ret < 0) | ||
1314 | return ret; | ||
1315 | ret = nf_conntrack_helper_register(&snmp_trap_helper); | ||
1316 | if (ret < 0) { | ||
1317 | nf_conntrack_helper_unregister(&snmp_helper); | ||
1318 | return ret; | ||
1319 | } | ||
1320 | return ret; | ||
1321 | } | ||
1322 | |||
1323 | static void __exit nf_nat_snmp_basic_fini(void) | ||
1324 | { | ||
1325 | nf_conntrack_helper_unregister(&snmp_helper); | ||
1326 | nf_conntrack_helper_unregister(&snmp_trap_helper); | ||
1327 | } | ||
1328 | |||
1329 | module_init(nf_nat_snmp_basic_init); | ||
1330 | module_exit(nf_nat_snmp_basic_fini); | ||
1331 | |||
1332 | module_param(debug, int, 0600); | ||
diff --git a/net/ipv4/netfilter/nf_nat_standalone.c b/net/ipv4/netfilter/nf_nat_standalone.c new file mode 100644 index 000000000000..730a7a44c883 --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_standalone.c | |||
@@ -0,0 +1,406 @@ | |||
1 | /* (C) 1999-2001 Paul `Rusty' Russell | ||
2 | * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | #include <linux/types.h> | ||
9 | #include <linux/icmp.h> | ||
10 | #include <linux/ip.h> | ||
11 | #include <linux/netfilter.h> | ||
12 | #include <linux/netfilter_ipv4.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/skbuff.h> | ||
15 | #include <linux/proc_fs.h> | ||
16 | #include <net/ip.h> | ||
17 | #include <net/checksum.h> | ||
18 | #include <linux/spinlock.h> | ||
19 | |||
20 | #include <net/netfilter/nf_conntrack.h> | ||
21 | #include <net/netfilter/nf_conntrack_core.h> | ||
22 | #include <net/netfilter/nf_nat.h> | ||
23 | #include <net/netfilter/nf_nat_rule.h> | ||
24 | #include <net/netfilter/nf_nat_protocol.h> | ||
25 | #include <net/netfilter/nf_nat_core.h> | ||
26 | #include <net/netfilter/nf_nat_helper.h> | ||
27 | #include <linux/netfilter_ipv4/ip_tables.h> | ||
28 | |||
29 | #if 0 | ||
30 | #define DEBUGP printk | ||
31 | #else | ||
32 | #define DEBUGP(format, args...) | ||
33 | #endif | ||
34 | |||
35 | #define HOOKNAME(hooknum) ((hooknum) == NF_IP_POST_ROUTING ? "POST_ROUTING" \ | ||
36 | : ((hooknum) == NF_IP_PRE_ROUTING ? "PRE_ROUTING" \ | ||
37 | : ((hooknum) == NF_IP_LOCAL_OUT ? "LOCAL_OUT" \ | ||
38 | : ((hooknum) == NF_IP_LOCAL_IN ? "LOCAL_IN" \ | ||
39 | : "*ERROR*"))) | ||
40 | |||
41 | #ifdef CONFIG_XFRM | ||
42 | static void nat_decode_session(struct sk_buff *skb, struct flowi *fl) | ||
43 | { | ||
44 | struct nf_conn *ct; | ||
45 | struct nf_conntrack_tuple *t; | ||
46 | enum ip_conntrack_info ctinfo; | ||
47 | enum ip_conntrack_dir dir; | ||
48 | unsigned long statusbit; | ||
49 | |||
50 | ct = nf_ct_get(skb, &ctinfo); | ||
51 | if (ct == NULL) | ||
52 | return; | ||
53 | dir = CTINFO2DIR(ctinfo); | ||
54 | t = &ct->tuplehash[dir].tuple; | ||
55 | |||
56 | if (dir == IP_CT_DIR_ORIGINAL) | ||
57 | statusbit = IPS_DST_NAT; | ||
58 | else | ||
59 | statusbit = IPS_SRC_NAT; | ||
60 | |||
61 | if (ct->status & statusbit) { | ||
62 | fl->fl4_dst = t->dst.u3.ip; | ||
63 | if (t->dst.protonum == IPPROTO_TCP || | ||
64 | t->dst.protonum == IPPROTO_UDP) | ||
65 | fl->fl_ip_dport = t->dst.u.tcp.port; | ||
66 | } | ||
67 | |||
68 | statusbit ^= IPS_NAT_MASK; | ||
69 | |||
70 | if (ct->status & statusbit) { | ||
71 | fl->fl4_src = t->src.u3.ip; | ||
72 | if (t->dst.protonum == IPPROTO_TCP || | ||
73 | t->dst.protonum == IPPROTO_UDP) | ||
74 | fl->fl_ip_sport = t->src.u.tcp.port; | ||
75 | } | ||
76 | } | ||
77 | #endif | ||
78 | |||
79 | static unsigned int | ||
80 | nf_nat_fn(unsigned int hooknum, | ||
81 | struct sk_buff **pskb, | ||
82 | const struct net_device *in, | ||
83 | const struct net_device *out, | ||
84 | int (*okfn)(struct sk_buff *)) | ||
85 | { | ||
86 | struct nf_conn *ct; | ||
87 | enum ip_conntrack_info ctinfo; | ||
88 | struct nf_conn_nat *nat; | ||
89 | struct nf_nat_info *info; | ||
90 | /* maniptype == SRC for postrouting. */ | ||
91 | enum nf_nat_manip_type maniptype = HOOK2MANIP(hooknum); | ||
92 | |||
93 | /* We never see fragments: conntrack defrags on pre-routing | ||
94 | and local-out, and nf_nat_out protects post-routing. */ | ||
95 | NF_CT_ASSERT(!((*pskb)->nh.iph->frag_off | ||
96 | & htons(IP_MF|IP_OFFSET))); | ||
97 | |||
98 | ct = nf_ct_get(*pskb, &ctinfo); | ||
99 | /* Can't track? It's not due to stress, or conntrack would | ||
100 | have dropped it. Hence it's the user's responsibilty to | ||
101 | packet filter it out, or implement conntrack/NAT for that | ||
102 | protocol. 8) --RR */ | ||
103 | if (!ct) { | ||
104 | /* Exception: ICMP redirect to new connection (not in | ||
105 | hash table yet). We must not let this through, in | ||
106 | case we're doing NAT to the same network. */ | ||
107 | if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP) { | ||
108 | struct icmphdr _hdr, *hp; | ||
109 | |||
110 | hp = skb_header_pointer(*pskb, | ||
111 | (*pskb)->nh.iph->ihl*4, | ||
112 | sizeof(_hdr), &_hdr); | ||
113 | if (hp != NULL && | ||
114 | hp->type == ICMP_REDIRECT) | ||
115 | return NF_DROP; | ||
116 | } | ||
117 | return NF_ACCEPT; | ||
118 | } | ||
119 | |||
120 | /* Don't try to NAT if this packet is not conntracked */ | ||
121 | if (ct == &nf_conntrack_untracked) | ||
122 | return NF_ACCEPT; | ||
123 | |||
124 | nat = nfct_nat(ct); | ||
125 | if (!nat) | ||
126 | return NF_DROP; | ||
127 | |||
128 | switch (ctinfo) { | ||
129 | case IP_CT_RELATED: | ||
130 | case IP_CT_RELATED+IP_CT_IS_REPLY: | ||
131 | if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP) { | ||
132 | if (!nf_nat_icmp_reply_translation(ct, ctinfo, | ||
133 | hooknum, pskb)) | ||
134 | return NF_DROP; | ||
135 | else | ||
136 | return NF_ACCEPT; | ||
137 | } | ||
138 | /* Fall thru... (Only ICMPs can be IP_CT_IS_REPLY) */ | ||
139 | case IP_CT_NEW: | ||
140 | info = &nat->info; | ||
141 | |||
142 | /* Seen it before? This can happen for loopback, retrans, | ||
143 | or local packets.. */ | ||
144 | if (!nf_nat_initialized(ct, maniptype)) { | ||
145 | unsigned int ret; | ||
146 | |||
147 | if (unlikely(nf_ct_is_confirmed(ct))) | ||
148 | /* NAT module was loaded late */ | ||
149 | ret = alloc_null_binding_confirmed(ct, info, | ||
150 | hooknum); | ||
151 | else if (hooknum == NF_IP_LOCAL_IN) | ||
152 | /* LOCAL_IN hook doesn't have a chain! */ | ||
153 | ret = alloc_null_binding(ct, info, hooknum); | ||
154 | else | ||
155 | ret = nf_nat_rule_find(pskb, hooknum, in, out, | ||
156 | ct, info); | ||
157 | |||
158 | if (ret != NF_ACCEPT) { | ||
159 | return ret; | ||
160 | } | ||
161 | } else | ||
162 | DEBUGP("Already setup manip %s for ct %p\n", | ||
163 | maniptype == IP_NAT_MANIP_SRC ? "SRC" : "DST", | ||
164 | ct); | ||
165 | break; | ||
166 | |||
167 | default: | ||
168 | /* ESTABLISHED */ | ||
169 | NF_CT_ASSERT(ctinfo == IP_CT_ESTABLISHED || | ||
170 | ctinfo == (IP_CT_ESTABLISHED+IP_CT_IS_REPLY)); | ||
171 | info = &nat->info; | ||
172 | } | ||
173 | |||
174 | NF_CT_ASSERT(info); | ||
175 | return nf_nat_packet(ct, ctinfo, hooknum, pskb); | ||
176 | } | ||
177 | |||
178 | static unsigned int | ||
179 | nf_nat_in(unsigned int hooknum, | ||
180 | struct sk_buff **pskb, | ||
181 | const struct net_device *in, | ||
182 | const struct net_device *out, | ||
183 | int (*okfn)(struct sk_buff *)) | ||
184 | { | ||
185 | unsigned int ret; | ||
186 | __be32 daddr = (*pskb)->nh.iph->daddr; | ||
187 | |||
188 | ret = nf_nat_fn(hooknum, pskb, in, out, okfn); | ||
189 | if (ret != NF_DROP && ret != NF_STOLEN && | ||
190 | daddr != (*pskb)->nh.iph->daddr) { | ||
191 | dst_release((*pskb)->dst); | ||
192 | (*pskb)->dst = NULL; | ||
193 | } | ||
194 | return ret; | ||
195 | } | ||
196 | |||
197 | static unsigned int | ||
198 | nf_nat_out(unsigned int hooknum, | ||
199 | struct sk_buff **pskb, | ||
200 | const struct net_device *in, | ||
201 | const struct net_device *out, | ||
202 | int (*okfn)(struct sk_buff *)) | ||
203 | { | ||
204 | #ifdef CONFIG_XFRM | ||
205 | struct nf_conn *ct; | ||
206 | enum ip_conntrack_info ctinfo; | ||
207 | #endif | ||
208 | unsigned int ret; | ||
209 | |||
210 | /* root is playing with raw sockets. */ | ||
211 | if ((*pskb)->len < sizeof(struct iphdr) || | ||
212 | (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr)) | ||
213 | return NF_ACCEPT; | ||
214 | |||
215 | ret = nf_nat_fn(hooknum, pskb, in, out, okfn); | ||
216 | #ifdef CONFIG_XFRM | ||
217 | if (ret != NF_DROP && ret != NF_STOLEN && | ||
218 | (ct = nf_ct_get(*pskb, &ctinfo)) != NULL) { | ||
219 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); | ||
220 | |||
221 | if (ct->tuplehash[dir].tuple.src.u3.ip != | ||
222 | ct->tuplehash[!dir].tuple.dst.u3.ip | ||
223 | || ct->tuplehash[dir].tuple.src.u.all != | ||
224 | ct->tuplehash[!dir].tuple.dst.u.all | ||
225 | ) | ||
226 | return ip_xfrm_me_harder(pskb) == 0 ? ret : NF_DROP; | ||
227 | } | ||
228 | #endif | ||
229 | return ret; | ||
230 | } | ||
231 | |||
232 | static unsigned int | ||
233 | nf_nat_local_fn(unsigned int hooknum, | ||
234 | struct sk_buff **pskb, | ||
235 | const struct net_device *in, | ||
236 | const struct net_device *out, | ||
237 | int (*okfn)(struct sk_buff *)) | ||
238 | { | ||
239 | struct nf_conn *ct; | ||
240 | enum ip_conntrack_info ctinfo; | ||
241 | unsigned int ret; | ||
242 | |||
243 | /* root is playing with raw sockets. */ | ||
244 | if ((*pskb)->len < sizeof(struct iphdr) || | ||
245 | (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr)) | ||
246 | return NF_ACCEPT; | ||
247 | |||
248 | ret = nf_nat_fn(hooknum, pskb, in, out, okfn); | ||
249 | if (ret != NF_DROP && ret != NF_STOLEN && | ||
250 | (ct = nf_ct_get(*pskb, &ctinfo)) != NULL) { | ||
251 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); | ||
252 | |||
253 | if (ct->tuplehash[dir].tuple.dst.u3.ip != | ||
254 | ct->tuplehash[!dir].tuple.src.u3.ip | ||
255 | #ifdef CONFIG_XFRM | ||
256 | || ct->tuplehash[dir].tuple.dst.u.all != | ||
257 | ct->tuplehash[!dir].tuple.src.u.all | ||
258 | #endif | ||
259 | ) | ||
260 | if (ip_route_me_harder(pskb, RTN_UNSPEC)) | ||
261 | ret = NF_DROP; | ||
262 | } | ||
263 | return ret; | ||
264 | } | ||
265 | |||
266 | static unsigned int | ||
267 | nf_nat_adjust(unsigned int hooknum, | ||
268 | struct sk_buff **pskb, | ||
269 | const struct net_device *in, | ||
270 | const struct net_device *out, | ||
271 | int (*okfn)(struct sk_buff *)) | ||
272 | { | ||
273 | struct nf_conn *ct; | ||
274 | enum ip_conntrack_info ctinfo; | ||
275 | |||
276 | ct = nf_ct_get(*pskb, &ctinfo); | ||
277 | if (ct && test_bit(IPS_SEQ_ADJUST_BIT, &ct->status)) { | ||
278 | DEBUGP("nf_nat_standalone: adjusting sequence number\n"); | ||
279 | if (!nf_nat_seq_adjust(pskb, ct, ctinfo)) | ||
280 | return NF_DROP; | ||
281 | } | ||
282 | return NF_ACCEPT; | ||
283 | } | ||
284 | |||
285 | /* We must be after connection tracking and before packet filtering. */ | ||
286 | |||
287 | static struct nf_hook_ops nf_nat_ops[] = { | ||
288 | /* Before packet filtering, change destination */ | ||
289 | { | ||
290 | .hook = nf_nat_in, | ||
291 | .owner = THIS_MODULE, | ||
292 | .pf = PF_INET, | ||
293 | .hooknum = NF_IP_PRE_ROUTING, | ||
294 | .priority = NF_IP_PRI_NAT_DST, | ||
295 | }, | ||
296 | /* After packet filtering, change source */ | ||
297 | { | ||
298 | .hook = nf_nat_out, | ||
299 | .owner = THIS_MODULE, | ||
300 | .pf = PF_INET, | ||
301 | .hooknum = NF_IP_POST_ROUTING, | ||
302 | .priority = NF_IP_PRI_NAT_SRC, | ||
303 | }, | ||
304 | /* After conntrack, adjust sequence number */ | ||
305 | { | ||
306 | .hook = nf_nat_adjust, | ||
307 | .owner = THIS_MODULE, | ||
308 | .pf = PF_INET, | ||
309 | .hooknum = NF_IP_POST_ROUTING, | ||
310 | .priority = NF_IP_PRI_NAT_SEQ_ADJUST, | ||
311 | }, | ||
312 | /* Before packet filtering, change destination */ | ||
313 | { | ||
314 | .hook = nf_nat_local_fn, | ||
315 | .owner = THIS_MODULE, | ||
316 | .pf = PF_INET, | ||
317 | .hooknum = NF_IP_LOCAL_OUT, | ||
318 | .priority = NF_IP_PRI_NAT_DST, | ||
319 | }, | ||
320 | /* After packet filtering, change source */ | ||
321 | { | ||
322 | .hook = nf_nat_fn, | ||
323 | .owner = THIS_MODULE, | ||
324 | .pf = PF_INET, | ||
325 | .hooknum = NF_IP_LOCAL_IN, | ||
326 | .priority = NF_IP_PRI_NAT_SRC, | ||
327 | }, | ||
328 | /* After conntrack, adjust sequence number */ | ||
329 | { | ||
330 | .hook = nf_nat_adjust, | ||
331 | .owner = THIS_MODULE, | ||
332 | .pf = PF_INET, | ||
333 | .hooknum = NF_IP_LOCAL_IN, | ||
334 | .priority = NF_IP_PRI_NAT_SEQ_ADJUST, | ||
335 | }, | ||
336 | }; | ||
337 | |||
338 | static int __init nf_nat_standalone_init(void) | ||
339 | { | ||
340 | int size, ret = 0; | ||
341 | |||
342 | need_conntrack(); | ||
343 | |||
344 | size = ALIGN(sizeof(struct nf_conn), __alignof__(struct nf_conn_nat)) + | ||
345 | sizeof(struct nf_conn_nat); | ||
346 | ret = nf_conntrack_register_cache(NF_CT_F_NAT, "nf_nat:base", size); | ||
347 | if (ret < 0) { | ||
348 | printk(KERN_ERR "nf_nat_init: Unable to create slab cache\n"); | ||
349 | return ret; | ||
350 | } | ||
351 | |||
352 | size = ALIGN(size, __alignof__(struct nf_conn_help)) + | ||
353 | sizeof(struct nf_conn_help); | ||
354 | ret = nf_conntrack_register_cache(NF_CT_F_NAT|NF_CT_F_HELP, | ||
355 | "nf_nat:help", size); | ||
356 | if (ret < 0) { | ||
357 | printk(KERN_ERR "nf_nat_init: Unable to create slab cache\n"); | ||
358 | goto cleanup_register_cache; | ||
359 | } | ||
360 | #ifdef CONFIG_XFRM | ||
361 | BUG_ON(ip_nat_decode_session != NULL); | ||
362 | ip_nat_decode_session = nat_decode_session; | ||
363 | #endif | ||
364 | ret = nf_nat_rule_init(); | ||
365 | if (ret < 0) { | ||
366 | printk("nf_nat_init: can't setup rules.\n"); | ||
367 | goto cleanup_decode_session; | ||
368 | } | ||
369 | ret = nf_register_hooks(nf_nat_ops, ARRAY_SIZE(nf_nat_ops)); | ||
370 | if (ret < 0) { | ||
371 | printk("nf_nat_init: can't register hooks.\n"); | ||
372 | goto cleanup_rule_init; | ||
373 | } | ||
374 | nf_nat_module_is_loaded = 1; | ||
375 | return ret; | ||
376 | |||
377 | cleanup_rule_init: | ||
378 | nf_nat_rule_cleanup(); | ||
379 | cleanup_decode_session: | ||
380 | #ifdef CONFIG_XFRM | ||
381 | ip_nat_decode_session = NULL; | ||
382 | synchronize_net(); | ||
383 | #endif | ||
384 | nf_conntrack_unregister_cache(NF_CT_F_NAT|NF_CT_F_HELP); | ||
385 | cleanup_register_cache: | ||
386 | nf_conntrack_unregister_cache(NF_CT_F_NAT); | ||
387 | return ret; | ||
388 | } | ||
389 | |||
390 | static void __exit nf_nat_standalone_fini(void) | ||
391 | { | ||
392 | nf_unregister_hooks(nf_nat_ops, ARRAY_SIZE(nf_nat_ops)); | ||
393 | nf_nat_rule_cleanup(); | ||
394 | nf_nat_module_is_loaded = 0; | ||
395 | #ifdef CONFIG_XFRM | ||
396 | ip_nat_decode_session = NULL; | ||
397 | synchronize_net(); | ||
398 | #endif | ||
399 | /* Conntrack caches are unregistered in nf_conntrack_cleanup */ | ||
400 | } | ||
401 | |||
402 | module_init(nf_nat_standalone_init); | ||
403 | module_exit(nf_nat_standalone_fini); | ||
404 | |||
405 | MODULE_LICENSE("GPL"); | ||
406 | MODULE_ALIAS("ip_nat"); | ||
diff --git a/net/ipv4/netfilter/nf_nat_tftp.c b/net/ipv4/netfilter/nf_nat_tftp.c new file mode 100644 index 000000000000..2566b79de224 --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_tftp.c | |||
@@ -0,0 +1,52 @@ | |||
1 | /* (C) 2001-2002 Magnus Boden <mb@ozaba.mine.nu> | ||
2 | * | ||
3 | * This program is free software; you can redistribute it and/or modify | ||
4 | * it under the terms of the GNU General Public License version 2 as | ||
5 | * published by the Free Software Foundation. | ||
6 | */ | ||
7 | |||
8 | #include <linux/module.h> | ||
9 | #include <linux/moduleparam.h> | ||
10 | #include <linux/udp.h> | ||
11 | |||
12 | #include <net/netfilter/nf_nat_helper.h> | ||
13 | #include <net/netfilter/nf_nat_rule.h> | ||
14 | #include <net/netfilter/nf_conntrack_helper.h> | ||
15 | #include <net/netfilter/nf_conntrack_expect.h> | ||
16 | #include <linux/netfilter/nf_conntrack_tftp.h> | ||
17 | |||
18 | MODULE_AUTHOR("Magnus Boden <mb@ozaba.mine.nu>"); | ||
19 | MODULE_DESCRIPTION("TFTP NAT helper"); | ||
20 | MODULE_LICENSE("GPL"); | ||
21 | MODULE_ALIAS("ip_nat_tftp"); | ||
22 | |||
23 | static unsigned int help(struct sk_buff **pskb, | ||
24 | enum ip_conntrack_info ctinfo, | ||
25 | struct nf_conntrack_expect *exp) | ||
26 | { | ||
27 | struct nf_conn *ct = exp->master; | ||
28 | |||
29 | exp->saved_proto.udp.port | ||
30 | = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.udp.port; | ||
31 | exp->dir = IP_CT_DIR_REPLY; | ||
32 | exp->expectfn = nf_nat_follow_master; | ||
33 | if (nf_conntrack_expect_related(exp) != 0) | ||
34 | return NF_DROP; | ||
35 | return NF_ACCEPT; | ||
36 | } | ||
37 | |||
38 | static void __exit nf_nat_tftp_fini(void) | ||
39 | { | ||
40 | rcu_assign_pointer(nf_nat_tftp_hook, NULL); | ||
41 | synchronize_rcu(); | ||
42 | } | ||
43 | |||
44 | static int __init nf_nat_tftp_init(void) | ||
45 | { | ||
46 | BUG_ON(rcu_dereference(nf_nat_tftp_hook)); | ||
47 | rcu_assign_pointer(nf_nat_tftp_hook, help); | ||
48 | return 0; | ||
49 | } | ||
50 | |||
51 | module_init(nf_nat_tftp_init); | ||
52 | module_exit(nf_nat_tftp_fini); | ||
diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c index 9c6cbe3d9fb8..cd873da54cbe 100644 --- a/net/ipv4/proc.c +++ b/net/ipv4/proc.c | |||
@@ -38,6 +38,7 @@ | |||
38 | #include <net/protocol.h> | 38 | #include <net/protocol.h> |
39 | #include <net/tcp.h> | 39 | #include <net/tcp.h> |
40 | #include <net/udp.h> | 40 | #include <net/udp.h> |
41 | #include <net/udplite.h> | ||
41 | #include <linux/inetdevice.h> | 42 | #include <linux/inetdevice.h> |
42 | #include <linux/proc_fs.h> | 43 | #include <linux/proc_fs.h> |
43 | #include <linux/seq_file.h> | 44 | #include <linux/seq_file.h> |
@@ -66,6 +67,7 @@ static int sockstat_seq_show(struct seq_file *seq, void *v) | |||
66 | tcp_death_row.tw_count, atomic_read(&tcp_sockets_allocated), | 67 | tcp_death_row.tw_count, atomic_read(&tcp_sockets_allocated), |
67 | atomic_read(&tcp_memory_allocated)); | 68 | atomic_read(&tcp_memory_allocated)); |
68 | seq_printf(seq, "UDP: inuse %d\n", fold_prot_inuse(&udp_prot)); | 69 | seq_printf(seq, "UDP: inuse %d\n", fold_prot_inuse(&udp_prot)); |
70 | seq_printf(seq, "UDPLITE: inuse %d\n", fold_prot_inuse(&udplite_prot)); | ||
69 | seq_printf(seq, "RAW: inuse %d\n", fold_prot_inuse(&raw_prot)); | 71 | seq_printf(seq, "RAW: inuse %d\n", fold_prot_inuse(&raw_prot)); |
70 | seq_printf(seq, "FRAG: inuse %d memory %d\n", ip_frag_nqueues, | 72 | seq_printf(seq, "FRAG: inuse %d memory %d\n", ip_frag_nqueues, |
71 | atomic_read(&ip_frag_mem)); | 73 | atomic_read(&ip_frag_mem)); |
@@ -304,6 +306,17 @@ static int snmp_seq_show(struct seq_file *seq, void *v) | |||
304 | fold_field((void **) udp_statistics, | 306 | fold_field((void **) udp_statistics, |
305 | snmp4_udp_list[i].entry)); | 307 | snmp4_udp_list[i].entry)); |
306 | 308 | ||
309 | /* the UDP and UDP-Lite MIBs are the same */ | ||
310 | seq_puts(seq, "\nUdpLite:"); | ||
311 | for (i = 0; snmp4_udp_list[i].name != NULL; i++) | ||
312 | seq_printf(seq, " %s", snmp4_udp_list[i].name); | ||
313 | |||
314 | seq_puts(seq, "\nUdpLite:"); | ||
315 | for (i = 0; snmp4_udp_list[i].name != NULL; i++) | ||
316 | seq_printf(seq, " %lu", | ||
317 | fold_field((void **) udplite_statistics, | ||
318 | snmp4_udp_list[i].entry) ); | ||
319 | |||
307 | seq_putc(seq, '\n'); | 320 | seq_putc(seq, '\n'); |
308 | return 0; | 321 | return 0; |
309 | } | 322 | } |
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 5c31dead2bdc..a6c63bbd9ddb 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c | |||
@@ -854,8 +854,8 @@ static void raw_seq_stop(struct seq_file *seq, void *v) | |||
854 | static __inline__ char *get_raw_sock(struct sock *sp, char *tmpbuf, int i) | 854 | static __inline__ char *get_raw_sock(struct sock *sp, char *tmpbuf, int i) |
855 | { | 855 | { |
856 | struct inet_sock *inet = inet_sk(sp); | 856 | struct inet_sock *inet = inet_sk(sp); |
857 | unsigned int dest = inet->daddr, | 857 | __be32 dest = inet->daddr, |
858 | src = inet->rcv_saddr; | 858 | src = inet->rcv_saddr; |
859 | __u16 destp = 0, | 859 | __u16 destp = 0, |
860 | srcp = inet->num; | 860 | srcp = inet->num; |
861 | 861 | ||
diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 925ee4dfc32c..9f3924c4905e 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c | |||
@@ -566,11 +566,9 @@ static inline u32 rt_score(struct rtable *rt) | |||
566 | 566 | ||
567 | static inline int compare_keys(struct flowi *fl1, struct flowi *fl2) | 567 | static inline int compare_keys(struct flowi *fl1, struct flowi *fl2) |
568 | { | 568 | { |
569 | return ((fl1->nl_u.ip4_u.daddr ^ fl2->nl_u.ip4_u.daddr) | | 569 | return ((__force u32)((fl1->nl_u.ip4_u.daddr ^ fl2->nl_u.ip4_u.daddr) | |
570 | (fl1->nl_u.ip4_u.saddr ^ fl2->nl_u.ip4_u.saddr) | | 570 | (fl1->nl_u.ip4_u.saddr ^ fl2->nl_u.ip4_u.saddr)) | |
571 | #ifdef CONFIG_IP_ROUTE_FWMARK | 571 | (fl1->mark ^ fl2->mark) | |
572 | (fl1->nl_u.ip4_u.fwmark ^ fl2->nl_u.ip4_u.fwmark) | | ||
573 | #endif | ||
574 | (*(u16 *)&fl1->nl_u.ip4_u.tos ^ | 572 | (*(u16 *)&fl1->nl_u.ip4_u.tos ^ |
575 | *(u16 *)&fl2->nl_u.ip4_u.tos) | | 573 | *(u16 *)&fl2->nl_u.ip4_u.tos) | |
576 | (fl1->oif ^ fl2->oif) | | 574 | (fl1->oif ^ fl2->oif) | |
@@ -1643,9 +1641,7 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr, | |||
1643 | rth->fl.fl4_dst = daddr; | 1641 | rth->fl.fl4_dst = daddr; |
1644 | rth->rt_dst = daddr; | 1642 | rth->rt_dst = daddr; |
1645 | rth->fl.fl4_tos = tos; | 1643 | rth->fl.fl4_tos = tos; |
1646 | #ifdef CONFIG_IP_ROUTE_FWMARK | 1644 | rth->fl.mark = skb->mark; |
1647 | rth->fl.fl4_fwmark= skb->nfmark; | ||
1648 | #endif | ||
1649 | rth->fl.fl4_src = saddr; | 1645 | rth->fl.fl4_src = saddr; |
1650 | rth->rt_src = saddr; | 1646 | rth->rt_src = saddr; |
1651 | #ifdef CONFIG_NET_CLS_ROUTE | 1647 | #ifdef CONFIG_NET_CLS_ROUTE |
@@ -1789,9 +1785,7 @@ static inline int __mkroute_input(struct sk_buff *skb, | |||
1789 | rth->fl.fl4_dst = daddr; | 1785 | rth->fl.fl4_dst = daddr; |
1790 | rth->rt_dst = daddr; | 1786 | rth->rt_dst = daddr; |
1791 | rth->fl.fl4_tos = tos; | 1787 | rth->fl.fl4_tos = tos; |
1792 | #ifdef CONFIG_IP_ROUTE_FWMARK | 1788 | rth->fl.mark = skb->mark; |
1793 | rth->fl.fl4_fwmark= skb->nfmark; | ||
1794 | #endif | ||
1795 | rth->fl.fl4_src = saddr; | 1789 | rth->fl.fl4_src = saddr; |
1796 | rth->rt_src = saddr; | 1790 | rth->rt_src = saddr; |
1797 | rth->rt_gateway = daddr; | 1791 | rth->rt_gateway = daddr; |
@@ -1920,10 +1914,8 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr, | |||
1920 | .saddr = saddr, | 1914 | .saddr = saddr, |
1921 | .tos = tos, | 1915 | .tos = tos, |
1922 | .scope = RT_SCOPE_UNIVERSE, | 1916 | .scope = RT_SCOPE_UNIVERSE, |
1923 | #ifdef CONFIG_IP_ROUTE_FWMARK | ||
1924 | .fwmark = skb->nfmark | ||
1925 | #endif | ||
1926 | } }, | 1917 | } }, |
1918 | .mark = skb->mark, | ||
1927 | .iif = dev->ifindex }; | 1919 | .iif = dev->ifindex }; |
1928 | unsigned flags = 0; | 1920 | unsigned flags = 0; |
1929 | u32 itag = 0; | 1921 | u32 itag = 0; |
@@ -2034,9 +2026,7 @@ local_input: | |||
2034 | rth->fl.fl4_dst = daddr; | 2026 | rth->fl.fl4_dst = daddr; |
2035 | rth->rt_dst = daddr; | 2027 | rth->rt_dst = daddr; |
2036 | rth->fl.fl4_tos = tos; | 2028 | rth->fl.fl4_tos = tos; |
2037 | #ifdef CONFIG_IP_ROUTE_FWMARK | 2029 | rth->fl.mark = skb->mark; |
2038 | rth->fl.fl4_fwmark= skb->nfmark; | ||
2039 | #endif | ||
2040 | rth->fl.fl4_src = saddr; | 2030 | rth->fl.fl4_src = saddr; |
2041 | rth->rt_src = saddr; | 2031 | rth->rt_src = saddr; |
2042 | #ifdef CONFIG_NET_CLS_ROUTE | 2032 | #ifdef CONFIG_NET_CLS_ROUTE |
@@ -2113,9 +2103,7 @@ int ip_route_input(struct sk_buff *skb, __be32 daddr, __be32 saddr, | |||
2113 | rth->fl.fl4_src == saddr && | 2103 | rth->fl.fl4_src == saddr && |
2114 | rth->fl.iif == iif && | 2104 | rth->fl.iif == iif && |
2115 | rth->fl.oif == 0 && | 2105 | rth->fl.oif == 0 && |
2116 | #ifdef CONFIG_IP_ROUTE_FWMARK | 2106 | rth->fl.mark == skb->mark && |
2117 | rth->fl.fl4_fwmark == skb->nfmark && | ||
2118 | #endif | ||
2119 | rth->fl.fl4_tos == tos) { | 2107 | rth->fl.fl4_tos == tos) { |
2120 | rth->u.dst.lastuse = jiffies; | 2108 | rth->u.dst.lastuse = jiffies; |
2121 | dst_hold(&rth->u.dst); | 2109 | dst_hold(&rth->u.dst); |
@@ -2239,9 +2227,7 @@ static inline int __mkroute_output(struct rtable **result, | |||
2239 | rth->fl.fl4_tos = tos; | 2227 | rth->fl.fl4_tos = tos; |
2240 | rth->fl.fl4_src = oldflp->fl4_src; | 2228 | rth->fl.fl4_src = oldflp->fl4_src; |
2241 | rth->fl.oif = oldflp->oif; | 2229 | rth->fl.oif = oldflp->oif; |
2242 | #ifdef CONFIG_IP_ROUTE_FWMARK | 2230 | rth->fl.mark = oldflp->mark; |
2243 | rth->fl.fl4_fwmark= oldflp->fl4_fwmark; | ||
2244 | #endif | ||
2245 | rth->rt_dst = fl->fl4_dst; | 2231 | rth->rt_dst = fl->fl4_dst; |
2246 | rth->rt_src = fl->fl4_src; | 2232 | rth->rt_src = fl->fl4_src; |
2247 | rth->rt_iif = oldflp->oif ? : dev_out->ifindex; | 2233 | rth->rt_iif = oldflp->oif ? : dev_out->ifindex; |
@@ -2385,10 +2371,8 @@ static int ip_route_output_slow(struct rtable **rp, const struct flowi *oldflp) | |||
2385 | .scope = ((tos & RTO_ONLINK) ? | 2371 | .scope = ((tos & RTO_ONLINK) ? |
2386 | RT_SCOPE_LINK : | 2372 | RT_SCOPE_LINK : |
2387 | RT_SCOPE_UNIVERSE), | 2373 | RT_SCOPE_UNIVERSE), |
2388 | #ifdef CONFIG_IP_ROUTE_FWMARK | ||
2389 | .fwmark = oldflp->fl4_fwmark | ||
2390 | #endif | ||
2391 | } }, | 2374 | } }, |
2375 | .mark = oldflp->mark, | ||
2392 | .iif = loopback_dev.ifindex, | 2376 | .iif = loopback_dev.ifindex, |
2393 | .oif = oldflp->oif }; | 2377 | .oif = oldflp->oif }; |
2394 | struct fib_result res; | 2378 | struct fib_result res; |
@@ -2583,9 +2567,7 @@ int __ip_route_output_key(struct rtable **rp, const struct flowi *flp) | |||
2583 | rth->fl.fl4_src == flp->fl4_src && | 2567 | rth->fl.fl4_src == flp->fl4_src && |
2584 | rth->fl.iif == 0 && | 2568 | rth->fl.iif == 0 && |
2585 | rth->fl.oif == flp->oif && | 2569 | rth->fl.oif == flp->oif && |
2586 | #ifdef CONFIG_IP_ROUTE_FWMARK | 2570 | rth->fl.mark == flp->mark && |
2587 | rth->fl.fl4_fwmark == flp->fl4_fwmark && | ||
2588 | #endif | ||
2589 | !((rth->fl.fl4_tos ^ flp->fl4_tos) & | 2571 | !((rth->fl.fl4_tos ^ flp->fl4_tos) & |
2590 | (IPTOS_RT_MASK | RTO_ONLINK))) { | 2572 | (IPTOS_RT_MASK | RTO_ONLINK))) { |
2591 | 2573 | ||
@@ -2647,7 +2629,8 @@ static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event, | |||
2647 | struct rtable *rt = (struct rtable*)skb->dst; | 2629 | struct rtable *rt = (struct rtable*)skb->dst; |
2648 | struct rtmsg *r; | 2630 | struct rtmsg *r; |
2649 | struct nlmsghdr *nlh; | 2631 | struct nlmsghdr *nlh; |
2650 | struct rta_cacheinfo ci; | 2632 | long expires; |
2633 | u32 id = 0, ts = 0, tsage = 0, error; | ||
2651 | 2634 | ||
2652 | nlh = nlmsg_put(skb, pid, seq, event, sizeof(*r), flags); | 2635 | nlh = nlmsg_put(skb, pid, seq, event, sizeof(*r), flags); |
2653 | if (nlh == NULL) | 2636 | if (nlh == NULL) |
@@ -2694,20 +2677,13 @@ static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event, | |||
2694 | if (rtnetlink_put_metrics(skb, rt->u.dst.metrics) < 0) | 2677 | if (rtnetlink_put_metrics(skb, rt->u.dst.metrics) < 0) |
2695 | goto nla_put_failure; | 2678 | goto nla_put_failure; |
2696 | 2679 | ||
2697 | ci.rta_lastuse = jiffies_to_clock_t(jiffies - rt->u.dst.lastuse); | 2680 | error = rt->u.dst.error; |
2698 | ci.rta_used = rt->u.dst.__use; | 2681 | expires = rt->u.dst.expires ? rt->u.dst.expires - jiffies : 0; |
2699 | ci.rta_clntref = atomic_read(&rt->u.dst.__refcnt); | ||
2700 | if (rt->u.dst.expires) | ||
2701 | ci.rta_expires = jiffies_to_clock_t(rt->u.dst.expires - jiffies); | ||
2702 | else | ||
2703 | ci.rta_expires = 0; | ||
2704 | ci.rta_error = rt->u.dst.error; | ||
2705 | ci.rta_id = ci.rta_ts = ci.rta_tsage = 0; | ||
2706 | if (rt->peer) { | 2682 | if (rt->peer) { |
2707 | ci.rta_id = rt->peer->ip_id_count; | 2683 | id = rt->peer->ip_id_count; |
2708 | if (rt->peer->tcp_ts_stamp) { | 2684 | if (rt->peer->tcp_ts_stamp) { |
2709 | ci.rta_ts = rt->peer->tcp_ts; | 2685 | ts = rt->peer->tcp_ts; |
2710 | ci.rta_tsage = xtime.tv_sec - rt->peer->tcp_ts_stamp; | 2686 | tsage = xtime.tv_sec - rt->peer->tcp_ts_stamp; |
2711 | } | 2687 | } |
2712 | } | 2688 | } |
2713 | 2689 | ||
@@ -2726,7 +2702,7 @@ static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event, | |||
2726 | } else { | 2702 | } else { |
2727 | if (err == -EMSGSIZE) | 2703 | if (err == -EMSGSIZE) |
2728 | goto nla_put_failure; | 2704 | goto nla_put_failure; |
2729 | ci.rta_error = err; | 2705 | error = err; |
2730 | } | 2706 | } |
2731 | } | 2707 | } |
2732 | } else | 2708 | } else |
@@ -2734,7 +2710,9 @@ static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event, | |||
2734 | NLA_PUT_U32(skb, RTA_IIF, rt->fl.iif); | 2710 | NLA_PUT_U32(skb, RTA_IIF, rt->fl.iif); |
2735 | } | 2711 | } |
2736 | 2712 | ||
2737 | NLA_PUT(skb, RTA_CACHEINFO, sizeof(ci), &ci); | 2713 | if (rtnl_put_cacheinfo(skb, &rt->u.dst, id, ts, tsage, |
2714 | expires, error) < 0) | ||
2715 | goto nla_put_failure; | ||
2738 | 2716 | ||
2739 | return nlmsg_end(skb, nlh); | 2717 | return nlmsg_end(skb, nlh); |
2740 | 2718 | ||
diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c index 661e0a4bca72..6b19530905af 100644 --- a/net/ipv4/syncookies.c +++ b/net/ipv4/syncookies.c | |||
@@ -35,23 +35,23 @@ module_init(init_syncookies); | |||
35 | #define COOKIEBITS 24 /* Upper bits store count */ | 35 | #define COOKIEBITS 24 /* Upper bits store count */ |
36 | #define COOKIEMASK (((__u32)1 << COOKIEBITS) - 1) | 36 | #define COOKIEMASK (((__u32)1 << COOKIEBITS) - 1) |
37 | 37 | ||
38 | static u32 cookie_hash(u32 saddr, u32 daddr, u32 sport, u32 dport, | 38 | static u32 cookie_hash(__be32 saddr, __be32 daddr, __be16 sport, __be16 dport, |
39 | u32 count, int c) | 39 | u32 count, int c) |
40 | { | 40 | { |
41 | __u32 tmp[16 + 5 + SHA_WORKSPACE_WORDS]; | 41 | __u32 tmp[16 + 5 + SHA_WORKSPACE_WORDS]; |
42 | 42 | ||
43 | memcpy(tmp + 3, syncookie_secret[c], sizeof(syncookie_secret[c])); | 43 | memcpy(tmp + 3, syncookie_secret[c], sizeof(syncookie_secret[c])); |
44 | tmp[0] = saddr; | 44 | tmp[0] = (__force u32)saddr; |
45 | tmp[1] = daddr; | 45 | tmp[1] = (__force u32)daddr; |
46 | tmp[2] = (sport << 16) + dport; | 46 | tmp[2] = ((__force u32)sport << 16) + (__force u32)dport; |
47 | tmp[3] = count; | 47 | tmp[3] = count; |
48 | sha_transform(tmp + 16, (__u8 *)tmp, tmp + 16 + 5); | 48 | sha_transform(tmp + 16, (__u8 *)tmp, tmp + 16 + 5); |
49 | 49 | ||
50 | return tmp[17]; | 50 | return tmp[17]; |
51 | } | 51 | } |
52 | 52 | ||
53 | static __u32 secure_tcp_syn_cookie(__u32 saddr, __u32 daddr, __u16 sport, | 53 | static __u32 secure_tcp_syn_cookie(__be32 saddr, __be32 daddr, __be16 sport, |
54 | __u16 dport, __u32 sseq, __u32 count, | 54 | __be16 dport, __u32 sseq, __u32 count, |
55 | __u32 data) | 55 | __u32 data) |
56 | { | 56 | { |
57 | /* | 57 | /* |
@@ -80,8 +80,8 @@ static __u32 secure_tcp_syn_cookie(__u32 saddr, __u32 daddr, __u16 sport, | |||
80 | * "maxdiff" if the current (passed-in) "count". The return value | 80 | * "maxdiff" if the current (passed-in) "count". The return value |
81 | * is (__u32)-1 if this test fails. | 81 | * is (__u32)-1 if this test fails. |
82 | */ | 82 | */ |
83 | static __u32 check_tcp_syn_cookie(__u32 cookie, __u32 saddr, __u32 daddr, | 83 | static __u32 check_tcp_syn_cookie(__u32 cookie, __be32 saddr, __be32 daddr, |
84 | __u16 sport, __u16 dport, __u32 sseq, | 84 | __be16 sport, __be16 dport, __u32 sseq, |
85 | __u32 count, __u32 maxdiff) | 85 | __u32 count, __u32 maxdiff) |
86 | { | 86 | { |
87 | __u32 diff; | 87 | __u32 diff; |
@@ -220,7 +220,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb, | |||
220 | } | 220 | } |
221 | ireq = inet_rsk(req); | 221 | ireq = inet_rsk(req); |
222 | treq = tcp_rsk(req); | 222 | treq = tcp_rsk(req); |
223 | treq->rcv_isn = htonl(skb->h.th->seq) - 1; | 223 | treq->rcv_isn = ntohl(skb->h.th->seq) - 1; |
224 | treq->snt_isn = cookie; | 224 | treq->snt_isn = cookie; |
225 | req->mss = mss; | 225 | req->mss = mss; |
226 | ireq->rmt_port = skb->h.th->source; | 226 | ireq->rmt_port = skb->h.th->source; |
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index 15061b314411..dfcf47f10f88 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c | |||
@@ -129,6 +129,67 @@ static int sysctl_tcp_congestion_control(ctl_table *table, int __user *name, | |||
129 | return ret; | 129 | return ret; |
130 | } | 130 | } |
131 | 131 | ||
132 | static int proc_tcp_available_congestion_control(ctl_table *ctl, | ||
133 | int write, struct file * filp, | ||
134 | void __user *buffer, size_t *lenp, | ||
135 | loff_t *ppos) | ||
136 | { | ||
137 | ctl_table tbl = { .maxlen = TCP_CA_BUF_MAX, }; | ||
138 | int ret; | ||
139 | |||
140 | tbl.data = kmalloc(tbl.maxlen, GFP_USER); | ||
141 | if (!tbl.data) | ||
142 | return -ENOMEM; | ||
143 | tcp_get_available_congestion_control(tbl.data, TCP_CA_BUF_MAX); | ||
144 | ret = proc_dostring(&tbl, write, filp, buffer, lenp, ppos); | ||
145 | kfree(tbl.data); | ||
146 | return ret; | ||
147 | } | ||
148 | |||
149 | static int proc_allowed_congestion_control(ctl_table *ctl, | ||
150 | int write, struct file * filp, | ||
151 | void __user *buffer, size_t *lenp, | ||
152 | loff_t *ppos) | ||
153 | { | ||
154 | ctl_table tbl = { .maxlen = TCP_CA_BUF_MAX }; | ||
155 | int ret; | ||
156 | |||
157 | tbl.data = kmalloc(tbl.maxlen, GFP_USER); | ||
158 | if (!tbl.data) | ||
159 | return -ENOMEM; | ||
160 | |||
161 | tcp_get_allowed_congestion_control(tbl.data, tbl.maxlen); | ||
162 | ret = proc_dostring(&tbl, write, filp, buffer, lenp, ppos); | ||
163 | if (write && ret == 0) | ||
164 | ret = tcp_set_allowed_congestion_control(tbl.data); | ||
165 | kfree(tbl.data); | ||
166 | return ret; | ||
167 | } | ||
168 | |||
169 | static int strategy_allowed_congestion_control(ctl_table *table, int __user *name, | ||
170 | int nlen, void __user *oldval, | ||
171 | size_t __user *oldlenp, | ||
172 | void __user *newval, size_t newlen, | ||
173 | void **context) | ||
174 | { | ||
175 | ctl_table tbl = { .maxlen = TCP_CA_BUF_MAX }; | ||
176 | int ret; | ||
177 | |||
178 | tbl.data = kmalloc(tbl.maxlen, GFP_USER); | ||
179 | if (!tbl.data) | ||
180 | return -ENOMEM; | ||
181 | |||
182 | tcp_get_available_congestion_control(tbl.data, tbl.maxlen); | ||
183 | ret = sysctl_string(&tbl, name, nlen, oldval, oldlenp, newval, newlen, | ||
184 | context); | ||
185 | if (ret == 0 && newval && newlen) | ||
186 | ret = tcp_set_allowed_congestion_control(tbl.data); | ||
187 | kfree(tbl.data); | ||
188 | |||
189 | return ret; | ||
190 | |||
191 | } | ||
192 | |||
132 | ctl_table ipv4_table[] = { | 193 | ctl_table ipv4_table[] = { |
133 | { | 194 | { |
134 | .ctl_name = NET_IPV4_TCP_TIMESTAMPS, | 195 | .ctl_name = NET_IPV4_TCP_TIMESTAMPS, |
@@ -731,6 +792,21 @@ ctl_table ipv4_table[] = { | |||
731 | .proc_handler = &proc_dointvec, | 792 | .proc_handler = &proc_dointvec, |
732 | }, | 793 | }, |
733 | #endif /* CONFIG_NETLABEL */ | 794 | #endif /* CONFIG_NETLABEL */ |
795 | { | ||
796 | .ctl_name = NET_TCP_AVAIL_CONG_CONTROL, | ||
797 | .procname = "tcp_available_congestion_control", | ||
798 | .maxlen = TCP_CA_BUF_MAX, | ||
799 | .mode = 0444, | ||
800 | .proc_handler = &proc_tcp_available_congestion_control, | ||
801 | }, | ||
802 | { | ||
803 | .ctl_name = NET_TCP_ALLOWED_CONG_CONTROL, | ||
804 | .procname = "tcp_allowed_congestion_control", | ||
805 | .maxlen = TCP_CA_BUF_MAX, | ||
806 | .mode = 0644, | ||
807 | .proc_handler = &proc_allowed_congestion_control, | ||
808 | .strategy = &strategy_allowed_congestion_control, | ||
809 | }, | ||
734 | { .ctl_name = 0 } | 810 | { .ctl_name = 0 } |
735 | }; | 811 | }; |
736 | 812 | ||
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index c05e8edaf544..090c690627e5 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c | |||
@@ -258,6 +258,7 @@ | |||
258 | #include <linux/bootmem.h> | 258 | #include <linux/bootmem.h> |
259 | #include <linux/cache.h> | 259 | #include <linux/cache.h> |
260 | #include <linux/err.h> | 260 | #include <linux/err.h> |
261 | #include <linux/crypto.h> | ||
261 | 262 | ||
262 | #include <net/icmp.h> | 263 | #include <net/icmp.h> |
263 | #include <net/tcp.h> | 264 | #include <net/tcp.h> |
@@ -462,11 +463,12 @@ static inline int forced_push(struct tcp_sock *tp) | |||
462 | static inline void skb_entail(struct sock *sk, struct tcp_sock *tp, | 463 | static inline void skb_entail(struct sock *sk, struct tcp_sock *tp, |
463 | struct sk_buff *skb) | 464 | struct sk_buff *skb) |
464 | { | 465 | { |
465 | skb->csum = 0; | 466 | struct tcp_skb_cb *tcb = TCP_SKB_CB(skb); |
466 | TCP_SKB_CB(skb)->seq = tp->write_seq; | 467 | |
467 | TCP_SKB_CB(skb)->end_seq = tp->write_seq; | 468 | skb->csum = 0; |
468 | TCP_SKB_CB(skb)->flags = TCPCB_FLAG_ACK; | 469 | tcb->seq = tcb->end_seq = tp->write_seq; |
469 | TCP_SKB_CB(skb)->sacked = 0; | 470 | tcb->flags = TCPCB_FLAG_ACK; |
471 | tcb->sacked = 0; | ||
470 | skb_header_release(skb); | 472 | skb_header_release(skb); |
471 | __skb_queue_tail(&sk->sk_write_queue, skb); | 473 | __skb_queue_tail(&sk->sk_write_queue, skb); |
472 | sk_charge_skb(sk, skb); | 474 | sk_charge_skb(sk, skb); |
@@ -1942,6 +1944,13 @@ static int do_tcp_setsockopt(struct sock *sk, int level, | |||
1942 | } | 1944 | } |
1943 | break; | 1945 | break; |
1944 | 1946 | ||
1947 | #ifdef CONFIG_TCP_MD5SIG | ||
1948 | case TCP_MD5SIG: | ||
1949 | /* Read the IP->Key mappings from userspace */ | ||
1950 | err = tp->af_specific->md5_parse(sk, optval, optlen); | ||
1951 | break; | ||
1952 | #endif | ||
1953 | |||
1945 | default: | 1954 | default: |
1946 | err = -ENOPROTOOPT; | 1955 | err = -ENOPROTOOPT; |
1947 | break; | 1956 | break; |
@@ -2154,7 +2163,7 @@ struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int features) | |||
2154 | struct tcphdr *th; | 2163 | struct tcphdr *th; |
2155 | unsigned thlen; | 2164 | unsigned thlen; |
2156 | unsigned int seq; | 2165 | unsigned int seq; |
2157 | unsigned int delta; | 2166 | __be32 delta; |
2158 | unsigned int oldlen; | 2167 | unsigned int oldlen; |
2159 | unsigned int len; | 2168 | unsigned int len; |
2160 | 2169 | ||
@@ -2207,7 +2216,8 @@ struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int features) | |||
2207 | do { | 2216 | do { |
2208 | th->fin = th->psh = 0; | 2217 | th->fin = th->psh = 0; |
2209 | 2218 | ||
2210 | th->check = ~csum_fold(th->check + delta); | 2219 | th->check = ~csum_fold((__force __wsum)((__force u32)th->check + |
2220 | (__force u32)delta)); | ||
2211 | if (skb->ip_summed != CHECKSUM_PARTIAL) | 2221 | if (skb->ip_summed != CHECKSUM_PARTIAL) |
2212 | th->check = csum_fold(csum_partial(skb->h.raw, thlen, | 2222 | th->check = csum_fold(csum_partial(skb->h.raw, thlen, |
2213 | skb->csum)); | 2223 | skb->csum)); |
@@ -2221,7 +2231,8 @@ struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int features) | |||
2221 | } while (skb->next); | 2231 | } while (skb->next); |
2222 | 2232 | ||
2223 | delta = htonl(oldlen + (skb->tail - skb->h.raw) + skb->data_len); | 2233 | delta = htonl(oldlen + (skb->tail - skb->h.raw) + skb->data_len); |
2224 | th->check = ~csum_fold(th->check + delta); | 2234 | th->check = ~csum_fold((__force __wsum)((__force u32)th->check + |
2235 | (__force u32)delta)); | ||
2225 | if (skb->ip_summed != CHECKSUM_PARTIAL) | 2236 | if (skb->ip_summed != CHECKSUM_PARTIAL) |
2226 | th->check = csum_fold(csum_partial(skb->h.raw, thlen, | 2237 | th->check = csum_fold(csum_partial(skb->h.raw, thlen, |
2227 | skb->csum)); | 2238 | skb->csum)); |
@@ -2231,6 +2242,135 @@ out: | |||
2231 | } | 2242 | } |
2232 | EXPORT_SYMBOL(tcp_tso_segment); | 2243 | EXPORT_SYMBOL(tcp_tso_segment); |
2233 | 2244 | ||
2245 | #ifdef CONFIG_TCP_MD5SIG | ||
2246 | static unsigned long tcp_md5sig_users; | ||
2247 | static struct tcp_md5sig_pool **tcp_md5sig_pool; | ||
2248 | static DEFINE_SPINLOCK(tcp_md5sig_pool_lock); | ||
2249 | |||
2250 | static void __tcp_free_md5sig_pool(struct tcp_md5sig_pool **pool) | ||
2251 | { | ||
2252 | int cpu; | ||
2253 | for_each_possible_cpu(cpu) { | ||
2254 | struct tcp_md5sig_pool *p = *per_cpu_ptr(pool, cpu); | ||
2255 | if (p) { | ||
2256 | if (p->md5_desc.tfm) | ||
2257 | crypto_free_hash(p->md5_desc.tfm); | ||
2258 | kfree(p); | ||
2259 | p = NULL; | ||
2260 | } | ||
2261 | } | ||
2262 | free_percpu(pool); | ||
2263 | } | ||
2264 | |||
2265 | void tcp_free_md5sig_pool(void) | ||
2266 | { | ||
2267 | struct tcp_md5sig_pool **pool = NULL; | ||
2268 | |||
2269 | spin_lock(&tcp_md5sig_pool_lock); | ||
2270 | if (--tcp_md5sig_users == 0) { | ||
2271 | pool = tcp_md5sig_pool; | ||
2272 | tcp_md5sig_pool = NULL; | ||
2273 | } | ||
2274 | spin_unlock(&tcp_md5sig_pool_lock); | ||
2275 | if (pool) | ||
2276 | __tcp_free_md5sig_pool(pool); | ||
2277 | } | ||
2278 | |||
2279 | EXPORT_SYMBOL(tcp_free_md5sig_pool); | ||
2280 | |||
2281 | static struct tcp_md5sig_pool **__tcp_alloc_md5sig_pool(void) | ||
2282 | { | ||
2283 | int cpu; | ||
2284 | struct tcp_md5sig_pool **pool; | ||
2285 | |||
2286 | pool = alloc_percpu(struct tcp_md5sig_pool *); | ||
2287 | if (!pool) | ||
2288 | return NULL; | ||
2289 | |||
2290 | for_each_possible_cpu(cpu) { | ||
2291 | struct tcp_md5sig_pool *p; | ||
2292 | struct crypto_hash *hash; | ||
2293 | |||
2294 | p = kzalloc(sizeof(*p), GFP_KERNEL); | ||
2295 | if (!p) | ||
2296 | goto out_free; | ||
2297 | *per_cpu_ptr(pool, cpu) = p; | ||
2298 | |||
2299 | hash = crypto_alloc_hash("md5", 0, CRYPTO_ALG_ASYNC); | ||
2300 | if (!hash || IS_ERR(hash)) | ||
2301 | goto out_free; | ||
2302 | |||
2303 | p->md5_desc.tfm = hash; | ||
2304 | } | ||
2305 | return pool; | ||
2306 | out_free: | ||
2307 | __tcp_free_md5sig_pool(pool); | ||
2308 | return NULL; | ||
2309 | } | ||
2310 | |||
2311 | struct tcp_md5sig_pool **tcp_alloc_md5sig_pool(void) | ||
2312 | { | ||
2313 | struct tcp_md5sig_pool **pool; | ||
2314 | int alloc = 0; | ||
2315 | |||
2316 | retry: | ||
2317 | spin_lock(&tcp_md5sig_pool_lock); | ||
2318 | pool = tcp_md5sig_pool; | ||
2319 | if (tcp_md5sig_users++ == 0) { | ||
2320 | alloc = 1; | ||
2321 | spin_unlock(&tcp_md5sig_pool_lock); | ||
2322 | } else if (!pool) { | ||
2323 | tcp_md5sig_users--; | ||
2324 | spin_unlock(&tcp_md5sig_pool_lock); | ||
2325 | cpu_relax(); | ||
2326 | goto retry; | ||
2327 | } else | ||
2328 | spin_unlock(&tcp_md5sig_pool_lock); | ||
2329 | |||
2330 | if (alloc) { | ||
2331 | /* we cannot hold spinlock here because this may sleep. */ | ||
2332 | struct tcp_md5sig_pool **p = __tcp_alloc_md5sig_pool(); | ||
2333 | spin_lock(&tcp_md5sig_pool_lock); | ||
2334 | if (!p) { | ||
2335 | tcp_md5sig_users--; | ||
2336 | spin_unlock(&tcp_md5sig_pool_lock); | ||
2337 | return NULL; | ||
2338 | } | ||
2339 | pool = tcp_md5sig_pool; | ||
2340 | if (pool) { | ||
2341 | /* oops, it has already been assigned. */ | ||
2342 | spin_unlock(&tcp_md5sig_pool_lock); | ||
2343 | __tcp_free_md5sig_pool(p); | ||
2344 | } else { | ||
2345 | tcp_md5sig_pool = pool = p; | ||
2346 | spin_unlock(&tcp_md5sig_pool_lock); | ||
2347 | } | ||
2348 | } | ||
2349 | return pool; | ||
2350 | } | ||
2351 | |||
2352 | EXPORT_SYMBOL(tcp_alloc_md5sig_pool); | ||
2353 | |||
2354 | struct tcp_md5sig_pool *__tcp_get_md5sig_pool(int cpu) | ||
2355 | { | ||
2356 | struct tcp_md5sig_pool **p; | ||
2357 | spin_lock(&tcp_md5sig_pool_lock); | ||
2358 | p = tcp_md5sig_pool; | ||
2359 | if (p) | ||
2360 | tcp_md5sig_users++; | ||
2361 | spin_unlock(&tcp_md5sig_pool_lock); | ||
2362 | return (p ? *per_cpu_ptr(p, cpu) : NULL); | ||
2363 | } | ||
2364 | |||
2365 | EXPORT_SYMBOL(__tcp_get_md5sig_pool); | ||
2366 | |||
2367 | void __tcp_put_md5sig_pool(void) { | ||
2368 | __tcp_free_md5sig_pool(tcp_md5sig_pool); | ||
2369 | } | ||
2370 | |||
2371 | EXPORT_SYMBOL(__tcp_put_md5sig_pool); | ||
2372 | #endif | ||
2373 | |||
2234 | extern void __skb_cb_too_small_for_tcp(int, int); | 2374 | extern void __skb_cb_too_small_for_tcp(int, int); |
2235 | extern struct tcp_congestion_ops tcp_reno; | 2375 | extern struct tcp_congestion_ops tcp_reno; |
2236 | 2376 | ||
diff --git a/net/ipv4/tcp_cong.c b/net/ipv4/tcp_cong.c index 1e2982f4acd4..5ca7723d0798 100644 --- a/net/ipv4/tcp_cong.c +++ b/net/ipv4/tcp_cong.c | |||
@@ -113,7 +113,7 @@ int tcp_set_default_congestion_control(const char *name) | |||
113 | spin_lock(&tcp_cong_list_lock); | 113 | spin_lock(&tcp_cong_list_lock); |
114 | ca = tcp_ca_find(name); | 114 | ca = tcp_ca_find(name); |
115 | #ifdef CONFIG_KMOD | 115 | #ifdef CONFIG_KMOD |
116 | if (!ca) { | 116 | if (!ca && capable(CAP_SYS_MODULE)) { |
117 | spin_unlock(&tcp_cong_list_lock); | 117 | spin_unlock(&tcp_cong_list_lock); |
118 | 118 | ||
119 | request_module("tcp_%s", name); | 119 | request_module("tcp_%s", name); |
@@ -123,6 +123,7 @@ int tcp_set_default_congestion_control(const char *name) | |||
123 | #endif | 123 | #endif |
124 | 124 | ||
125 | if (ca) { | 125 | if (ca) { |
126 | ca->non_restricted = 1; /* default is always allowed */ | ||
126 | list_move(&ca->list, &tcp_cong_list); | 127 | list_move(&ca->list, &tcp_cong_list); |
127 | ret = 0; | 128 | ret = 0; |
128 | } | 129 | } |
@@ -139,6 +140,22 @@ static int __init tcp_congestion_default(void) | |||
139 | late_initcall(tcp_congestion_default); | 140 | late_initcall(tcp_congestion_default); |
140 | 141 | ||
141 | 142 | ||
143 | /* Build string with list of available congestion control values */ | ||
144 | void tcp_get_available_congestion_control(char *buf, size_t maxlen) | ||
145 | { | ||
146 | struct tcp_congestion_ops *ca; | ||
147 | size_t offs = 0; | ||
148 | |||
149 | rcu_read_lock(); | ||
150 | list_for_each_entry_rcu(ca, &tcp_cong_list, list) { | ||
151 | offs += snprintf(buf + offs, maxlen - offs, | ||
152 | "%s%s", | ||
153 | offs == 0 ? "" : " ", ca->name); | ||
154 | |||
155 | } | ||
156 | rcu_read_unlock(); | ||
157 | } | ||
158 | |||
142 | /* Get current default congestion control */ | 159 | /* Get current default congestion control */ |
143 | void tcp_get_default_congestion_control(char *name) | 160 | void tcp_get_default_congestion_control(char *name) |
144 | { | 161 | { |
@@ -152,6 +169,64 @@ void tcp_get_default_congestion_control(char *name) | |||
152 | rcu_read_unlock(); | 169 | rcu_read_unlock(); |
153 | } | 170 | } |
154 | 171 | ||
172 | /* Built list of non-restricted congestion control values */ | ||
173 | void tcp_get_allowed_congestion_control(char *buf, size_t maxlen) | ||
174 | { | ||
175 | struct tcp_congestion_ops *ca; | ||
176 | size_t offs = 0; | ||
177 | |||
178 | *buf = '\0'; | ||
179 | rcu_read_lock(); | ||
180 | list_for_each_entry_rcu(ca, &tcp_cong_list, list) { | ||
181 | if (!ca->non_restricted) | ||
182 | continue; | ||
183 | offs += snprintf(buf + offs, maxlen - offs, | ||
184 | "%s%s", | ||
185 | offs == 0 ? "" : " ", ca->name); | ||
186 | |||
187 | } | ||
188 | rcu_read_unlock(); | ||
189 | } | ||
190 | |||
191 | /* Change list of non-restricted congestion control */ | ||
192 | int tcp_set_allowed_congestion_control(char *val) | ||
193 | { | ||
194 | struct tcp_congestion_ops *ca; | ||
195 | char *clone, *name; | ||
196 | int ret = 0; | ||
197 | |||
198 | clone = kstrdup(val, GFP_USER); | ||
199 | if (!clone) | ||
200 | return -ENOMEM; | ||
201 | |||
202 | spin_lock(&tcp_cong_list_lock); | ||
203 | /* pass 1 check for bad entries */ | ||
204 | while ((name = strsep(&clone, " ")) && *name) { | ||
205 | ca = tcp_ca_find(name); | ||
206 | if (!ca) { | ||
207 | ret = -ENOENT; | ||
208 | goto out; | ||
209 | } | ||
210 | } | ||
211 | |||
212 | /* pass 2 clear */ | ||
213 | list_for_each_entry_rcu(ca, &tcp_cong_list, list) | ||
214 | ca->non_restricted = 0; | ||
215 | |||
216 | /* pass 3 mark as allowed */ | ||
217 | while ((name = strsep(&val, " ")) && *name) { | ||
218 | ca = tcp_ca_find(name); | ||
219 | WARN_ON(!ca); | ||
220 | if (ca) | ||
221 | ca->non_restricted = 1; | ||
222 | } | ||
223 | out: | ||
224 | spin_unlock(&tcp_cong_list_lock); | ||
225 | |||
226 | return ret; | ||
227 | } | ||
228 | |||
229 | |||
155 | /* Change congestion control for socket */ | 230 | /* Change congestion control for socket */ |
156 | int tcp_set_congestion_control(struct sock *sk, const char *name) | 231 | int tcp_set_congestion_control(struct sock *sk, const char *name) |
157 | { | 232 | { |
@@ -161,12 +236,25 @@ int tcp_set_congestion_control(struct sock *sk, const char *name) | |||
161 | 236 | ||
162 | rcu_read_lock(); | 237 | rcu_read_lock(); |
163 | ca = tcp_ca_find(name); | 238 | ca = tcp_ca_find(name); |
239 | /* no change asking for existing value */ | ||
164 | if (ca == icsk->icsk_ca_ops) | 240 | if (ca == icsk->icsk_ca_ops) |
165 | goto out; | 241 | goto out; |
166 | 242 | ||
243 | #ifdef CONFIG_KMOD | ||
244 | /* not found attempt to autoload module */ | ||
245 | if (!ca && capable(CAP_SYS_MODULE)) { | ||
246 | rcu_read_unlock(); | ||
247 | request_module("tcp_%s", name); | ||
248 | rcu_read_lock(); | ||
249 | ca = tcp_ca_find(name); | ||
250 | } | ||
251 | #endif | ||
167 | if (!ca) | 252 | if (!ca) |
168 | err = -ENOENT; | 253 | err = -ENOENT; |
169 | 254 | ||
255 | else if (!(ca->non_restricted || capable(CAP_NET_ADMIN))) | ||
256 | err = -EPERM; | ||
257 | |||
170 | else if (!try_module_get(ca->owner)) | 258 | else if (!try_module_get(ca->owner)) |
171 | err = -EBUSY; | 259 | err = -EBUSY; |
172 | 260 | ||
@@ -268,6 +356,7 @@ EXPORT_SYMBOL_GPL(tcp_reno_min_cwnd); | |||
268 | 356 | ||
269 | struct tcp_congestion_ops tcp_reno = { | 357 | struct tcp_congestion_ops tcp_reno = { |
270 | .name = "reno", | 358 | .name = "reno", |
359 | .non_restricted = 1, | ||
271 | .owner = THIS_MODULE, | 360 | .owner = THIS_MODULE, |
272 | .ssthresh = tcp_reno_ssthresh, | 361 | .ssthresh = tcp_reno_ssthresh, |
273 | .cong_avoid = tcp_reno_cong_avoid, | 362 | .cong_avoid = tcp_reno_cong_avoid, |
diff --git a/net/ipv4/tcp_htcp.c b/net/ipv4/tcp_htcp.c index 283be3cb4667..753987a1048f 100644 --- a/net/ipv4/tcp_htcp.c +++ b/net/ipv4/tcp_htcp.c | |||
@@ -26,12 +26,12 @@ struct htcp { | |||
26 | u32 alpha; /* Fixed point arith, << 7 */ | 26 | u32 alpha; /* Fixed point arith, << 7 */ |
27 | u8 beta; /* Fixed point arith, << 7 */ | 27 | u8 beta; /* Fixed point arith, << 7 */ |
28 | u8 modeswitch; /* Delay modeswitch until we had at least one congestion event */ | 28 | u8 modeswitch; /* Delay modeswitch until we had at least one congestion event */ |
29 | u32 last_cong; /* Time since last congestion event end */ | ||
30 | u32 undo_last_cong; | ||
31 | u16 pkts_acked; | 29 | u16 pkts_acked; |
32 | u32 packetcount; | 30 | u32 packetcount; |
33 | u32 minRTT; | 31 | u32 minRTT; |
34 | u32 maxRTT; | 32 | u32 maxRTT; |
33 | u32 last_cong; /* Time since last congestion event end */ | ||
34 | u32 undo_last_cong; | ||
35 | 35 | ||
36 | u32 undo_maxRTT; | 36 | u32 undo_maxRTT; |
37 | u32 undo_old_maxB; | 37 | u32 undo_old_maxB; |
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index cf06accbe687..9304034c0c47 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c | |||
@@ -2677,6 +2677,14 @@ void tcp_parse_options(struct sk_buff *skb, struct tcp_options_received *opt_rx, | |||
2677 | opt_rx->sack_ok) { | 2677 | opt_rx->sack_ok) { |
2678 | TCP_SKB_CB(skb)->sacked = (ptr - 2) - (unsigned char *)th; | 2678 | TCP_SKB_CB(skb)->sacked = (ptr - 2) - (unsigned char *)th; |
2679 | } | 2679 | } |
2680 | #ifdef CONFIG_TCP_MD5SIG | ||
2681 | case TCPOPT_MD5SIG: | ||
2682 | /* | ||
2683 | * The MD5 Hash has already been | ||
2684 | * checked (see tcp_v{4,6}_do_rcv()). | ||
2685 | */ | ||
2686 | break; | ||
2687 | #endif | ||
2680 | }; | 2688 | }; |
2681 | ptr+=opsize-2; | 2689 | ptr+=opsize-2; |
2682 | length-=opsize; | 2690 | length-=opsize; |
@@ -3782,9 +3790,9 @@ static int tcp_copy_to_iovec(struct sock *sk, struct sk_buff *skb, int hlen) | |||
3782 | return err; | 3790 | return err; |
3783 | } | 3791 | } |
3784 | 3792 | ||
3785 | static int __tcp_checksum_complete_user(struct sock *sk, struct sk_buff *skb) | 3793 | static __sum16 __tcp_checksum_complete_user(struct sock *sk, struct sk_buff *skb) |
3786 | { | 3794 | { |
3787 | int result; | 3795 | __sum16 result; |
3788 | 3796 | ||
3789 | if (sock_owned_by_user(sk)) { | 3797 | if (sock_owned_by_user(sk)) { |
3790 | local_bh_enable(); | 3798 | local_bh_enable(); |
@@ -4230,6 +4238,8 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb, | |||
4230 | mb(); | 4238 | mb(); |
4231 | tcp_set_state(sk, TCP_ESTABLISHED); | 4239 | tcp_set_state(sk, TCP_ESTABLISHED); |
4232 | 4240 | ||
4241 | security_inet_conn_established(sk, skb); | ||
4242 | |||
4233 | /* Make sure socket is routed, for correct metrics. */ | 4243 | /* Make sure socket is routed, for correct metrics. */ |
4234 | icsk->icsk_af_ops->rebuild_header(sk); | 4244 | icsk->icsk_af_ops->rebuild_header(sk); |
4235 | 4245 | ||
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 22ef8bd26620..a1222d6968c4 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c | |||
@@ -78,6 +78,9 @@ | |||
78 | #include <linux/proc_fs.h> | 78 | #include <linux/proc_fs.h> |
79 | #include <linux/seq_file.h> | 79 | #include <linux/seq_file.h> |
80 | 80 | ||
81 | #include <linux/crypto.h> | ||
82 | #include <linux/scatterlist.h> | ||
83 | |||
81 | int sysctl_tcp_tw_reuse __read_mostly; | 84 | int sysctl_tcp_tw_reuse __read_mostly; |
82 | int sysctl_tcp_low_latency __read_mostly; | 85 | int sysctl_tcp_low_latency __read_mostly; |
83 | 86 | ||
@@ -89,10 +92,19 @@ static struct socket *tcp_socket; | |||
89 | 92 | ||
90 | void tcp_v4_send_check(struct sock *sk, int len, struct sk_buff *skb); | 93 | void tcp_v4_send_check(struct sock *sk, int len, struct sk_buff *skb); |
91 | 94 | ||
95 | #ifdef CONFIG_TCP_MD5SIG | ||
96 | static struct tcp_md5sig_key *tcp_v4_md5_do_lookup(struct sock *sk, | ||
97 | __be32 addr); | ||
98 | static int tcp_v4_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, | ||
99 | __be32 saddr, __be32 daddr, | ||
100 | struct tcphdr *th, int protocol, | ||
101 | int tcplen); | ||
102 | #endif | ||
103 | |||
92 | struct inet_hashinfo __cacheline_aligned tcp_hashinfo = { | 104 | struct inet_hashinfo __cacheline_aligned tcp_hashinfo = { |
93 | .lhash_lock = __RW_LOCK_UNLOCKED(tcp_hashinfo.lhash_lock), | 105 | .lhash_lock = __RW_LOCK_UNLOCKED(tcp_hashinfo.lhash_lock), |
94 | .lhash_users = ATOMIC_INIT(0), | 106 | .lhash_users = ATOMIC_INIT(0), |
95 | .lhash_wait = __WAIT_QUEUE_HEAD_INITIALIZER(tcp_hashinfo.lhash_wait), | 107 | .lhash_wait = __WAIT_QUEUE_HEAD_INITIALIZER(tcp_hashinfo.lhash_wait), |
96 | }; | 108 | }; |
97 | 109 | ||
98 | static int tcp_v4_get_port(struct sock *sk, unsigned short snum) | 110 | static int tcp_v4_get_port(struct sock *sk, unsigned short snum) |
@@ -111,7 +123,7 @@ void tcp_unhash(struct sock *sk) | |||
111 | inet_unhash(&tcp_hashinfo, sk); | 123 | inet_unhash(&tcp_hashinfo, sk); |
112 | } | 124 | } |
113 | 125 | ||
114 | static inline __u32 tcp_v4_init_sequence(struct sock *sk, struct sk_buff *skb) | 126 | static inline __u32 tcp_v4_init_sequence(struct sk_buff *skb) |
115 | { | 127 | { |
116 | return secure_tcp_sequence_number(skb->nh.iph->daddr, | 128 | return secure_tcp_sequence_number(skb->nh.iph->daddr, |
117 | skb->nh.iph->saddr, | 129 | skb->nh.iph->saddr, |
@@ -205,13 +217,14 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) | |||
205 | if (tcp_death_row.sysctl_tw_recycle && | 217 | if (tcp_death_row.sysctl_tw_recycle && |
206 | !tp->rx_opt.ts_recent_stamp && rt->rt_dst == daddr) { | 218 | !tp->rx_opt.ts_recent_stamp && rt->rt_dst == daddr) { |
207 | struct inet_peer *peer = rt_get_peer(rt); | 219 | struct inet_peer *peer = rt_get_peer(rt); |
208 | 220 | /* | |
209 | /* VJ's idea. We save last timestamp seen from | 221 | * VJ's idea. We save last timestamp seen from |
210 | * the destination in peer table, when entering state TIME-WAIT | 222 | * the destination in peer table, when entering state |
211 | * and initialize rx_opt.ts_recent from it, when trying new connection. | 223 | * TIME-WAIT * and initialize rx_opt.ts_recent from it, |
224 | * when trying new connection. | ||
212 | */ | 225 | */ |
213 | 226 | if (peer != NULL && | |
214 | if (peer && peer->tcp_ts_stamp + TCP_PAWS_MSL >= xtime.tv_sec) { | 227 | peer->tcp_ts_stamp + TCP_PAWS_MSL >= xtime.tv_sec) { |
215 | tp->rx_opt.ts_recent_stamp = peer->tcp_ts_stamp; | 228 | tp->rx_opt.ts_recent_stamp = peer->tcp_ts_stamp; |
216 | tp->rx_opt.ts_recent = peer->tcp_ts; | 229 | tp->rx_opt.ts_recent = peer->tcp_ts; |
217 | } | 230 | } |
@@ -236,7 +249,8 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) | |||
236 | if (err) | 249 | if (err) |
237 | goto failure; | 250 | goto failure; |
238 | 251 | ||
239 | err = ip_route_newports(&rt, IPPROTO_TCP, inet->sport, inet->dport, sk); | 252 | err = ip_route_newports(&rt, IPPROTO_TCP, |
253 | inet->sport, inet->dport, sk); | ||
240 | if (err) | 254 | if (err) |
241 | goto failure; | 255 | goto failure; |
242 | 256 | ||
@@ -260,7 +274,10 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) | |||
260 | return 0; | 274 | return 0; |
261 | 275 | ||
262 | failure: | 276 | failure: |
263 | /* This unhashes the socket and releases the local port, if necessary. */ | 277 | /* |
278 | * This unhashes the socket and releases the local port, | ||
279 | * if necessary. | ||
280 | */ | ||
264 | tcp_set_state(sk, TCP_CLOSE); | 281 | tcp_set_state(sk, TCP_CLOSE); |
265 | ip_rt_put(rt); | 282 | ip_rt_put(rt); |
266 | sk->sk_route_caps = 0; | 283 | sk->sk_route_caps = 0; |
@@ -485,8 +502,9 @@ void tcp_v4_send_check(struct sock *sk, int len, struct sk_buff *skb) | |||
485 | struct tcphdr *th = skb->h.th; | 502 | struct tcphdr *th = skb->h.th; |
486 | 503 | ||
487 | if (skb->ip_summed == CHECKSUM_PARTIAL) { | 504 | if (skb->ip_summed == CHECKSUM_PARTIAL) { |
488 | th->check = ~tcp_v4_check(th, len, inet->saddr, inet->daddr, 0); | 505 | th->check = ~tcp_v4_check(th, len, |
489 | skb->csum = offsetof(struct tcphdr, check); | 506 | inet->saddr, inet->daddr, 0); |
507 | skb->csum_offset = offsetof(struct tcphdr, check); | ||
490 | } else { | 508 | } else { |
491 | th->check = tcp_v4_check(th, len, inet->saddr, inet->daddr, | 509 | th->check = tcp_v4_check(th, len, inet->saddr, inet->daddr, |
492 | csum_partial((char *)th, | 510 | csum_partial((char *)th, |
@@ -508,7 +526,7 @@ int tcp_v4_gso_send_check(struct sk_buff *skb) | |||
508 | 526 | ||
509 | th->check = 0; | 527 | th->check = 0; |
510 | th->check = ~tcp_v4_check(th, skb->len, iph->saddr, iph->daddr, 0); | 528 | th->check = ~tcp_v4_check(th, skb->len, iph->saddr, iph->daddr, 0); |
511 | skb->csum = offsetof(struct tcphdr, check); | 529 | skb->csum_offset = offsetof(struct tcphdr, check); |
512 | skb->ip_summed = CHECKSUM_PARTIAL; | 530 | skb->ip_summed = CHECKSUM_PARTIAL; |
513 | return 0; | 531 | return 0; |
514 | } | 532 | } |
@@ -526,11 +544,19 @@ int tcp_v4_gso_send_check(struct sk_buff *skb) | |||
526 | * Exception: precedence violation. We do not implement it in any case. | 544 | * Exception: precedence violation. We do not implement it in any case. |
527 | */ | 545 | */ |
528 | 546 | ||
529 | static void tcp_v4_send_reset(struct sk_buff *skb) | 547 | static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb) |
530 | { | 548 | { |
531 | struct tcphdr *th = skb->h.th; | 549 | struct tcphdr *th = skb->h.th; |
532 | struct tcphdr rth; | 550 | struct { |
551 | struct tcphdr th; | ||
552 | #ifdef CONFIG_TCP_MD5SIG | ||
553 | __be32 opt[(TCPOLEN_MD5SIG_ALIGNED >> 2)]; | ||
554 | #endif | ||
555 | } rep; | ||
533 | struct ip_reply_arg arg; | 556 | struct ip_reply_arg arg; |
557 | #ifdef CONFIG_TCP_MD5SIG | ||
558 | struct tcp_md5sig_key *key; | ||
559 | #endif | ||
534 | 560 | ||
535 | /* Never send a reset in response to a reset. */ | 561 | /* Never send a reset in response to a reset. */ |
536 | if (th->rst) | 562 | if (th->rst) |
@@ -540,29 +566,49 @@ static void tcp_v4_send_reset(struct sk_buff *skb) | |||
540 | return; | 566 | return; |
541 | 567 | ||
542 | /* Swap the send and the receive. */ | 568 | /* Swap the send and the receive. */ |
543 | memset(&rth, 0, sizeof(struct tcphdr)); | 569 | memset(&rep, 0, sizeof(rep)); |
544 | rth.dest = th->source; | 570 | rep.th.dest = th->source; |
545 | rth.source = th->dest; | 571 | rep.th.source = th->dest; |
546 | rth.doff = sizeof(struct tcphdr) / 4; | 572 | rep.th.doff = sizeof(struct tcphdr) / 4; |
547 | rth.rst = 1; | 573 | rep.th.rst = 1; |
548 | 574 | ||
549 | if (th->ack) { | 575 | if (th->ack) { |
550 | rth.seq = th->ack_seq; | 576 | rep.th.seq = th->ack_seq; |
551 | } else { | 577 | } else { |
552 | rth.ack = 1; | 578 | rep.th.ack = 1; |
553 | rth.ack_seq = htonl(ntohl(th->seq) + th->syn + th->fin + | 579 | rep.th.ack_seq = htonl(ntohl(th->seq) + th->syn + th->fin + |
554 | skb->len - (th->doff << 2)); | 580 | skb->len - (th->doff << 2)); |
555 | } | 581 | } |
556 | 582 | ||
557 | memset(&arg, 0, sizeof arg); | 583 | memset(&arg, 0, sizeof(arg)); |
558 | arg.iov[0].iov_base = (unsigned char *)&rth; | 584 | arg.iov[0].iov_base = (unsigned char *)&rep; |
559 | arg.iov[0].iov_len = sizeof rth; | 585 | arg.iov[0].iov_len = sizeof(rep.th); |
586 | |||
587 | #ifdef CONFIG_TCP_MD5SIG | ||
588 | key = sk ? tcp_v4_md5_do_lookup(sk, skb->nh.iph->daddr) : NULL; | ||
589 | if (key) { | ||
590 | rep.opt[0] = htonl((TCPOPT_NOP << 24) | | ||
591 | (TCPOPT_NOP << 16) | | ||
592 | (TCPOPT_MD5SIG << 8) | | ||
593 | TCPOLEN_MD5SIG); | ||
594 | /* Update length and the length the header thinks exists */ | ||
595 | arg.iov[0].iov_len += TCPOLEN_MD5SIG_ALIGNED; | ||
596 | rep.th.doff = arg.iov[0].iov_len / 4; | ||
597 | |||
598 | tcp_v4_do_calc_md5_hash((__u8 *)&rep.opt[1], | ||
599 | key, | ||
600 | skb->nh.iph->daddr, | ||
601 | skb->nh.iph->saddr, | ||
602 | &rep.th, IPPROTO_TCP, | ||
603 | arg.iov[0].iov_len); | ||
604 | } | ||
605 | #endif | ||
560 | arg.csum = csum_tcpudp_nofold(skb->nh.iph->daddr, | 606 | arg.csum = csum_tcpudp_nofold(skb->nh.iph->daddr, |
561 | skb->nh.iph->saddr, /*XXX*/ | 607 | skb->nh.iph->saddr, /* XXX */ |
562 | sizeof(struct tcphdr), IPPROTO_TCP, 0); | 608 | sizeof(struct tcphdr), IPPROTO_TCP, 0); |
563 | arg.csumoffset = offsetof(struct tcphdr, check) / 2; | 609 | arg.csumoffset = offsetof(struct tcphdr, check) / 2; |
564 | 610 | ||
565 | ip_send_reply(tcp_socket->sk, skb, &arg, sizeof rth); | 611 | ip_send_reply(tcp_socket->sk, skb, &arg, arg.iov[0].iov_len); |
566 | 612 | ||
567 | TCP_INC_STATS_BH(TCP_MIB_OUTSEGS); | 613 | TCP_INC_STATS_BH(TCP_MIB_OUTSEGS); |
568 | TCP_INC_STATS_BH(TCP_MIB_OUTRSTS); | 614 | TCP_INC_STATS_BH(TCP_MIB_OUTRSTS); |
@@ -572,28 +618,37 @@ static void tcp_v4_send_reset(struct sk_buff *skb) | |||
572 | outside socket context is ugly, certainly. What can I do? | 618 | outside socket context is ugly, certainly. What can I do? |
573 | */ | 619 | */ |
574 | 620 | ||
575 | static void tcp_v4_send_ack(struct sk_buff *skb, u32 seq, u32 ack, | 621 | static void tcp_v4_send_ack(struct tcp_timewait_sock *twsk, |
622 | struct sk_buff *skb, u32 seq, u32 ack, | ||
576 | u32 win, u32 ts) | 623 | u32 win, u32 ts) |
577 | { | 624 | { |
578 | struct tcphdr *th = skb->h.th; | 625 | struct tcphdr *th = skb->h.th; |
579 | struct { | 626 | struct { |
580 | struct tcphdr th; | 627 | struct tcphdr th; |
581 | u32 tsopt[TCPOLEN_TSTAMP_ALIGNED >> 2]; | 628 | __be32 opt[(TCPOLEN_TSTAMP_ALIGNED >> 2) |
629 | #ifdef CONFIG_TCP_MD5SIG | ||
630 | + (TCPOLEN_MD5SIG_ALIGNED >> 2) | ||
631 | #endif | ||
632 | ]; | ||
582 | } rep; | 633 | } rep; |
583 | struct ip_reply_arg arg; | 634 | struct ip_reply_arg arg; |
635 | #ifdef CONFIG_TCP_MD5SIG | ||
636 | struct tcp_md5sig_key *key; | ||
637 | struct tcp_md5sig_key tw_key; | ||
638 | #endif | ||
584 | 639 | ||
585 | memset(&rep.th, 0, sizeof(struct tcphdr)); | 640 | memset(&rep.th, 0, sizeof(struct tcphdr)); |
586 | memset(&arg, 0, sizeof arg); | 641 | memset(&arg, 0, sizeof(arg)); |
587 | 642 | ||
588 | arg.iov[0].iov_base = (unsigned char *)&rep; | 643 | arg.iov[0].iov_base = (unsigned char *)&rep; |
589 | arg.iov[0].iov_len = sizeof(rep.th); | 644 | arg.iov[0].iov_len = sizeof(rep.th); |
590 | if (ts) { | 645 | if (ts) { |
591 | rep.tsopt[0] = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | | 646 | rep.opt[0] = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | |
592 | (TCPOPT_TIMESTAMP << 8) | | 647 | (TCPOPT_TIMESTAMP << 8) | |
593 | TCPOLEN_TIMESTAMP); | 648 | TCPOLEN_TIMESTAMP); |
594 | rep.tsopt[1] = htonl(tcp_time_stamp); | 649 | rep.opt[1] = htonl(tcp_time_stamp); |
595 | rep.tsopt[2] = htonl(ts); | 650 | rep.opt[2] = htonl(ts); |
596 | arg.iov[0].iov_len = sizeof(rep); | 651 | arg.iov[0].iov_len = TCPOLEN_TSTAMP_ALIGNED; |
597 | } | 652 | } |
598 | 653 | ||
599 | /* Swap the send and the receive. */ | 654 | /* Swap the send and the receive. */ |
@@ -605,8 +660,44 @@ static void tcp_v4_send_ack(struct sk_buff *skb, u32 seq, u32 ack, | |||
605 | rep.th.ack = 1; | 660 | rep.th.ack = 1; |
606 | rep.th.window = htons(win); | 661 | rep.th.window = htons(win); |
607 | 662 | ||
663 | #ifdef CONFIG_TCP_MD5SIG | ||
664 | /* | ||
665 | * The SKB holds an imcoming packet, but may not have a valid ->sk | ||
666 | * pointer. This is especially the case when we're dealing with a | ||
667 | * TIME_WAIT ack, because the sk structure is long gone, and only | ||
668 | * the tcp_timewait_sock remains. So the md5 key is stashed in that | ||
669 | * structure, and we use it in preference. I believe that (twsk || | ||
670 | * skb->sk) holds true, but we program defensively. | ||
671 | */ | ||
672 | if (!twsk && skb->sk) { | ||
673 | key = tcp_v4_md5_do_lookup(skb->sk, skb->nh.iph->daddr); | ||
674 | } else if (twsk && twsk->tw_md5_keylen) { | ||
675 | tw_key.key = twsk->tw_md5_key; | ||
676 | tw_key.keylen = twsk->tw_md5_keylen; | ||
677 | key = &tw_key; | ||
678 | } else | ||
679 | key = NULL; | ||
680 | |||
681 | if (key) { | ||
682 | int offset = (ts) ? 3 : 0; | ||
683 | |||
684 | rep.opt[offset++] = htonl((TCPOPT_NOP << 24) | | ||
685 | (TCPOPT_NOP << 16) | | ||
686 | (TCPOPT_MD5SIG << 8) | | ||
687 | TCPOLEN_MD5SIG); | ||
688 | arg.iov[0].iov_len += TCPOLEN_MD5SIG_ALIGNED; | ||
689 | rep.th.doff = arg.iov[0].iov_len/4; | ||
690 | |||
691 | tcp_v4_do_calc_md5_hash((__u8 *)&rep.opt[offset], | ||
692 | key, | ||
693 | skb->nh.iph->daddr, | ||
694 | skb->nh.iph->saddr, | ||
695 | &rep.th, IPPROTO_TCP, | ||
696 | arg.iov[0].iov_len); | ||
697 | } | ||
698 | #endif | ||
608 | arg.csum = csum_tcpudp_nofold(skb->nh.iph->daddr, | 699 | arg.csum = csum_tcpudp_nofold(skb->nh.iph->daddr, |
609 | skb->nh.iph->saddr, /*XXX*/ | 700 | skb->nh.iph->saddr, /* XXX */ |
610 | arg.iov[0].iov_len, IPPROTO_TCP, 0); | 701 | arg.iov[0].iov_len, IPPROTO_TCP, 0); |
611 | arg.csumoffset = offsetof(struct tcphdr, check) / 2; | 702 | arg.csumoffset = offsetof(struct tcphdr, check) / 2; |
612 | 703 | ||
@@ -618,17 +709,20 @@ static void tcp_v4_send_ack(struct sk_buff *skb, u32 seq, u32 ack, | |||
618 | static void tcp_v4_timewait_ack(struct sock *sk, struct sk_buff *skb) | 709 | static void tcp_v4_timewait_ack(struct sock *sk, struct sk_buff *skb) |
619 | { | 710 | { |
620 | struct inet_timewait_sock *tw = inet_twsk(sk); | 711 | struct inet_timewait_sock *tw = inet_twsk(sk); |
621 | const struct tcp_timewait_sock *tcptw = tcp_twsk(sk); | 712 | struct tcp_timewait_sock *tcptw = tcp_twsk(sk); |
622 | 713 | ||
623 | tcp_v4_send_ack(skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt, | 714 | tcp_v4_send_ack(tcptw, skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt, |
624 | tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale, tcptw->tw_ts_recent); | 715 | tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale, |
716 | tcptw->tw_ts_recent); | ||
625 | 717 | ||
626 | inet_twsk_put(tw); | 718 | inet_twsk_put(tw); |
627 | } | 719 | } |
628 | 720 | ||
629 | static void tcp_v4_reqsk_send_ack(struct sk_buff *skb, struct request_sock *req) | 721 | static void tcp_v4_reqsk_send_ack(struct sk_buff *skb, |
722 | struct request_sock *req) | ||
630 | { | 723 | { |
631 | tcp_v4_send_ack(skb, tcp_rsk(req)->snt_isn + 1, tcp_rsk(req)->rcv_isn + 1, req->rcv_wnd, | 724 | tcp_v4_send_ack(NULL, skb, tcp_rsk(req)->snt_isn + 1, |
725 | tcp_rsk(req)->rcv_isn + 1, req->rcv_wnd, | ||
632 | req->ts_recent); | 726 | req->ts_recent); |
633 | } | 727 | } |
634 | 728 | ||
@@ -662,8 +756,7 @@ static int tcp_v4_send_synack(struct sock *sk, struct request_sock *req, | |||
662 | err = ip_build_and_send_pkt(skb, sk, ireq->loc_addr, | 756 | err = ip_build_and_send_pkt(skb, sk, ireq->loc_addr, |
663 | ireq->rmt_addr, | 757 | ireq->rmt_addr, |
664 | ireq->opt); | 758 | ireq->opt); |
665 | if (err == NET_XMIT_CN) | 759 | err = net_xmit_eval(err); |
666 | err = 0; | ||
667 | } | 760 | } |
668 | 761 | ||
669 | out: | 762 | out: |
@@ -715,7 +808,423 @@ static struct ip_options *tcp_v4_save_options(struct sock *sk, | |||
715 | return dopt; | 808 | return dopt; |
716 | } | 809 | } |
717 | 810 | ||
718 | struct request_sock_ops tcp_request_sock_ops = { | 811 | #ifdef CONFIG_TCP_MD5SIG |
812 | /* | ||
813 | * RFC2385 MD5 checksumming requires a mapping of | ||
814 | * IP address->MD5 Key. | ||
815 | * We need to maintain these in the sk structure. | ||
816 | */ | ||
817 | |||
818 | /* Find the Key structure for an address. */ | ||
819 | static struct tcp_md5sig_key * | ||
820 | tcp_v4_md5_do_lookup(struct sock *sk, __be32 addr) | ||
821 | { | ||
822 | struct tcp_sock *tp = tcp_sk(sk); | ||
823 | int i; | ||
824 | |||
825 | if (!tp->md5sig_info || !tp->md5sig_info->entries4) | ||
826 | return NULL; | ||
827 | for (i = 0; i < tp->md5sig_info->entries4; i++) { | ||
828 | if (tp->md5sig_info->keys4[i].addr == addr) | ||
829 | return (struct tcp_md5sig_key *) | ||
830 | &tp->md5sig_info->keys4[i]; | ||
831 | } | ||
832 | return NULL; | ||
833 | } | ||
834 | |||
835 | struct tcp_md5sig_key *tcp_v4_md5_lookup(struct sock *sk, | ||
836 | struct sock *addr_sk) | ||
837 | { | ||
838 | return tcp_v4_md5_do_lookup(sk, inet_sk(addr_sk)->daddr); | ||
839 | } | ||
840 | |||
841 | EXPORT_SYMBOL(tcp_v4_md5_lookup); | ||
842 | |||
843 | static struct tcp_md5sig_key *tcp_v4_reqsk_md5_lookup(struct sock *sk, | ||
844 | struct request_sock *req) | ||
845 | { | ||
846 | return tcp_v4_md5_do_lookup(sk, inet_rsk(req)->rmt_addr); | ||
847 | } | ||
848 | |||
849 | /* This can be called on a newly created socket, from other files */ | ||
850 | int tcp_v4_md5_do_add(struct sock *sk, __be32 addr, | ||
851 | u8 *newkey, u8 newkeylen) | ||
852 | { | ||
853 | /* Add Key to the list */ | ||
854 | struct tcp4_md5sig_key *key; | ||
855 | struct tcp_sock *tp = tcp_sk(sk); | ||
856 | struct tcp4_md5sig_key *keys; | ||
857 | |||
858 | key = (struct tcp4_md5sig_key *)tcp_v4_md5_do_lookup(sk, addr); | ||
859 | if (key) { | ||
860 | /* Pre-existing entry - just update that one. */ | ||
861 | kfree(key->key); | ||
862 | key->key = newkey; | ||
863 | key->keylen = newkeylen; | ||
864 | } else { | ||
865 | struct tcp_md5sig_info *md5sig; | ||
866 | |||
867 | if (!tp->md5sig_info) { | ||
868 | tp->md5sig_info = kzalloc(sizeof(*tp->md5sig_info), | ||
869 | GFP_ATOMIC); | ||
870 | if (!tp->md5sig_info) { | ||
871 | kfree(newkey); | ||
872 | return -ENOMEM; | ||
873 | } | ||
874 | } | ||
875 | if (tcp_alloc_md5sig_pool() == NULL) { | ||
876 | kfree(newkey); | ||
877 | return -ENOMEM; | ||
878 | } | ||
879 | md5sig = tp->md5sig_info; | ||
880 | |||
881 | if (md5sig->alloced4 == md5sig->entries4) { | ||
882 | keys = kmalloc((sizeof(*keys) * | ||
883 | (md5sig->entries4 + 1)), GFP_ATOMIC); | ||
884 | if (!keys) { | ||
885 | kfree(newkey); | ||
886 | tcp_free_md5sig_pool(); | ||
887 | return -ENOMEM; | ||
888 | } | ||
889 | |||
890 | if (md5sig->entries4) | ||
891 | memcpy(keys, md5sig->keys4, | ||
892 | sizeof(*keys) * md5sig->entries4); | ||
893 | |||
894 | /* Free old key list, and reference new one */ | ||
895 | if (md5sig->keys4) | ||
896 | kfree(md5sig->keys4); | ||
897 | md5sig->keys4 = keys; | ||
898 | md5sig->alloced4++; | ||
899 | } | ||
900 | md5sig->entries4++; | ||
901 | md5sig->keys4[md5sig->entries4 - 1].addr = addr; | ||
902 | md5sig->keys4[md5sig->entries4 - 1].key = newkey; | ||
903 | md5sig->keys4[md5sig->entries4 - 1].keylen = newkeylen; | ||
904 | } | ||
905 | return 0; | ||
906 | } | ||
907 | |||
908 | EXPORT_SYMBOL(tcp_v4_md5_do_add); | ||
909 | |||
910 | static int tcp_v4_md5_add_func(struct sock *sk, struct sock *addr_sk, | ||
911 | u8 *newkey, u8 newkeylen) | ||
912 | { | ||
913 | return tcp_v4_md5_do_add(sk, inet_sk(addr_sk)->daddr, | ||
914 | newkey, newkeylen); | ||
915 | } | ||
916 | |||
917 | int tcp_v4_md5_do_del(struct sock *sk, __be32 addr) | ||
918 | { | ||
919 | struct tcp_sock *tp = tcp_sk(sk); | ||
920 | int i; | ||
921 | |||
922 | for (i = 0; i < tp->md5sig_info->entries4; i++) { | ||
923 | if (tp->md5sig_info->keys4[i].addr == addr) { | ||
924 | /* Free the key */ | ||
925 | kfree(tp->md5sig_info->keys4[i].key); | ||
926 | tp->md5sig_info->entries4--; | ||
927 | |||
928 | if (tp->md5sig_info->entries4 == 0) { | ||
929 | kfree(tp->md5sig_info->keys4); | ||
930 | tp->md5sig_info->keys4 = NULL; | ||
931 | } else if (tp->md5sig_info->entries4 != i) { | ||
932 | /* Need to do some manipulation */ | ||
933 | memcpy(&tp->md5sig_info->keys4[i], | ||
934 | &tp->md5sig_info->keys4[i+1], | ||
935 | (tp->md5sig_info->entries4 - i) * | ||
936 | sizeof(struct tcp4_md5sig_key)); | ||
937 | } | ||
938 | tcp_free_md5sig_pool(); | ||
939 | return 0; | ||
940 | } | ||
941 | } | ||
942 | return -ENOENT; | ||
943 | } | ||
944 | |||
945 | EXPORT_SYMBOL(tcp_v4_md5_do_del); | ||
946 | |||
947 | static void tcp_v4_clear_md5_list(struct sock *sk) | ||
948 | { | ||
949 | struct tcp_sock *tp = tcp_sk(sk); | ||
950 | |||
951 | /* Free each key, then the set of key keys, | ||
952 | * the crypto element, and then decrement our | ||
953 | * hold on the last resort crypto. | ||
954 | */ | ||
955 | if (tp->md5sig_info->entries4) { | ||
956 | int i; | ||
957 | for (i = 0; i < tp->md5sig_info->entries4; i++) | ||
958 | kfree(tp->md5sig_info->keys4[i].key); | ||
959 | tp->md5sig_info->entries4 = 0; | ||
960 | tcp_free_md5sig_pool(); | ||
961 | } | ||
962 | if (tp->md5sig_info->keys4) { | ||
963 | kfree(tp->md5sig_info->keys4); | ||
964 | tp->md5sig_info->keys4 = NULL; | ||
965 | tp->md5sig_info->alloced4 = 0; | ||
966 | } | ||
967 | } | ||
968 | |||
969 | static int tcp_v4_parse_md5_keys(struct sock *sk, char __user *optval, | ||
970 | int optlen) | ||
971 | { | ||
972 | struct tcp_md5sig cmd; | ||
973 | struct sockaddr_in *sin = (struct sockaddr_in *)&cmd.tcpm_addr; | ||
974 | u8 *newkey; | ||
975 | |||
976 | if (optlen < sizeof(cmd)) | ||
977 | return -EINVAL; | ||
978 | |||
979 | if (copy_from_user(&cmd, optval, sizeof(cmd))) | ||
980 | return -EFAULT; | ||
981 | |||
982 | if (sin->sin_family != AF_INET) | ||
983 | return -EINVAL; | ||
984 | |||
985 | if (!cmd.tcpm_key || !cmd.tcpm_keylen) { | ||
986 | if (!tcp_sk(sk)->md5sig_info) | ||
987 | return -ENOENT; | ||
988 | return tcp_v4_md5_do_del(sk, sin->sin_addr.s_addr); | ||
989 | } | ||
990 | |||
991 | if (cmd.tcpm_keylen > TCP_MD5SIG_MAXKEYLEN) | ||
992 | return -EINVAL; | ||
993 | |||
994 | if (!tcp_sk(sk)->md5sig_info) { | ||
995 | struct tcp_sock *tp = tcp_sk(sk); | ||
996 | struct tcp_md5sig_info *p = kzalloc(sizeof(*p), GFP_KERNEL); | ||
997 | |||
998 | if (!p) | ||
999 | return -EINVAL; | ||
1000 | |||
1001 | tp->md5sig_info = p; | ||
1002 | |||
1003 | } | ||
1004 | |||
1005 | newkey = kmemdup(cmd.tcpm_key, cmd.tcpm_keylen, GFP_KERNEL); | ||
1006 | if (!newkey) | ||
1007 | return -ENOMEM; | ||
1008 | return tcp_v4_md5_do_add(sk, sin->sin_addr.s_addr, | ||
1009 | newkey, cmd.tcpm_keylen); | ||
1010 | } | ||
1011 | |||
1012 | static int tcp_v4_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, | ||
1013 | __be32 saddr, __be32 daddr, | ||
1014 | struct tcphdr *th, int protocol, | ||
1015 | int tcplen) | ||
1016 | { | ||
1017 | struct scatterlist sg[4]; | ||
1018 | __u16 data_len; | ||
1019 | int block = 0; | ||
1020 | __sum16 old_checksum; | ||
1021 | struct tcp_md5sig_pool *hp; | ||
1022 | struct tcp4_pseudohdr *bp; | ||
1023 | struct hash_desc *desc; | ||
1024 | int err; | ||
1025 | unsigned int nbytes = 0; | ||
1026 | |||
1027 | /* | ||
1028 | * Okay, so RFC2385 is turned on for this connection, | ||
1029 | * so we need to generate the MD5 hash for the packet now. | ||
1030 | */ | ||
1031 | |||
1032 | hp = tcp_get_md5sig_pool(); | ||
1033 | if (!hp) | ||
1034 | goto clear_hash_noput; | ||
1035 | |||
1036 | bp = &hp->md5_blk.ip4; | ||
1037 | desc = &hp->md5_desc; | ||
1038 | |||
1039 | /* | ||
1040 | * 1. the TCP pseudo-header (in the order: source IP address, | ||
1041 | * destination IP address, zero-padded protocol number, and | ||
1042 | * segment length) | ||
1043 | */ | ||
1044 | bp->saddr = saddr; | ||
1045 | bp->daddr = daddr; | ||
1046 | bp->pad = 0; | ||
1047 | bp->protocol = protocol; | ||
1048 | bp->len = htons(tcplen); | ||
1049 | sg_set_buf(&sg[block++], bp, sizeof(*bp)); | ||
1050 | nbytes += sizeof(*bp); | ||
1051 | |||
1052 | /* 2. the TCP header, excluding options, and assuming a | ||
1053 | * checksum of zero/ | ||
1054 | */ | ||
1055 | old_checksum = th->check; | ||
1056 | th->check = 0; | ||
1057 | sg_set_buf(&sg[block++], th, sizeof(struct tcphdr)); | ||
1058 | nbytes += sizeof(struct tcphdr); | ||
1059 | |||
1060 | /* 3. the TCP segment data (if any) */ | ||
1061 | data_len = tcplen - (th->doff << 2); | ||
1062 | if (data_len > 0) { | ||
1063 | unsigned char *data = (unsigned char *)th + (th->doff << 2); | ||
1064 | sg_set_buf(&sg[block++], data, data_len); | ||
1065 | nbytes += data_len; | ||
1066 | } | ||
1067 | |||
1068 | /* 4. an independently-specified key or password, known to both | ||
1069 | * TCPs and presumably connection-specific | ||
1070 | */ | ||
1071 | sg_set_buf(&sg[block++], key->key, key->keylen); | ||
1072 | nbytes += key->keylen; | ||
1073 | |||
1074 | /* Now store the Hash into the packet */ | ||
1075 | err = crypto_hash_init(desc); | ||
1076 | if (err) | ||
1077 | goto clear_hash; | ||
1078 | err = crypto_hash_update(desc, sg, nbytes); | ||
1079 | if (err) | ||
1080 | goto clear_hash; | ||
1081 | err = crypto_hash_final(desc, md5_hash); | ||
1082 | if (err) | ||
1083 | goto clear_hash; | ||
1084 | |||
1085 | /* Reset header, and free up the crypto */ | ||
1086 | tcp_put_md5sig_pool(); | ||
1087 | th->check = old_checksum; | ||
1088 | |||
1089 | out: | ||
1090 | return 0; | ||
1091 | clear_hash: | ||
1092 | tcp_put_md5sig_pool(); | ||
1093 | clear_hash_noput: | ||
1094 | memset(md5_hash, 0, 16); | ||
1095 | goto out; | ||
1096 | } | ||
1097 | |||
1098 | int tcp_v4_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, | ||
1099 | struct sock *sk, | ||
1100 | struct dst_entry *dst, | ||
1101 | struct request_sock *req, | ||
1102 | struct tcphdr *th, int protocol, | ||
1103 | int tcplen) | ||
1104 | { | ||
1105 | __be32 saddr, daddr; | ||
1106 | |||
1107 | if (sk) { | ||
1108 | saddr = inet_sk(sk)->saddr; | ||
1109 | daddr = inet_sk(sk)->daddr; | ||
1110 | } else { | ||
1111 | struct rtable *rt = (struct rtable *)dst; | ||
1112 | BUG_ON(!rt); | ||
1113 | saddr = rt->rt_src; | ||
1114 | daddr = rt->rt_dst; | ||
1115 | } | ||
1116 | return tcp_v4_do_calc_md5_hash(md5_hash, key, | ||
1117 | saddr, daddr, | ||
1118 | th, protocol, tcplen); | ||
1119 | } | ||
1120 | |||
1121 | EXPORT_SYMBOL(tcp_v4_calc_md5_hash); | ||
1122 | |||
1123 | static int tcp_v4_inbound_md5_hash(struct sock *sk, struct sk_buff *skb) | ||
1124 | { | ||
1125 | /* | ||
1126 | * This gets called for each TCP segment that arrives | ||
1127 | * so we want to be efficient. | ||
1128 | * We have 3 drop cases: | ||
1129 | * o No MD5 hash and one expected. | ||
1130 | * o MD5 hash and we're not expecting one. | ||
1131 | * o MD5 hash and its wrong. | ||
1132 | */ | ||
1133 | __u8 *hash_location = NULL; | ||
1134 | struct tcp_md5sig_key *hash_expected; | ||
1135 | struct iphdr *iph = skb->nh.iph; | ||
1136 | struct tcphdr *th = skb->h.th; | ||
1137 | int length = (th->doff << 2) - sizeof(struct tcphdr); | ||
1138 | int genhash; | ||
1139 | unsigned char *ptr; | ||
1140 | unsigned char newhash[16]; | ||
1141 | |||
1142 | hash_expected = tcp_v4_md5_do_lookup(sk, iph->saddr); | ||
1143 | |||
1144 | /* | ||
1145 | * If the TCP option length is less than the TCP_MD5SIG | ||
1146 | * option length, then we can shortcut | ||
1147 | */ | ||
1148 | if (length < TCPOLEN_MD5SIG) { | ||
1149 | if (hash_expected) | ||
1150 | return 1; | ||
1151 | else | ||
1152 | return 0; | ||
1153 | } | ||
1154 | |||
1155 | /* Okay, we can't shortcut - we have to grub through the options */ | ||
1156 | ptr = (unsigned char *)(th + 1); | ||
1157 | while (length > 0) { | ||
1158 | int opcode = *ptr++; | ||
1159 | int opsize; | ||
1160 | |||
1161 | switch (opcode) { | ||
1162 | case TCPOPT_EOL: | ||
1163 | goto done_opts; | ||
1164 | case TCPOPT_NOP: | ||
1165 | length--; | ||
1166 | continue; | ||
1167 | default: | ||
1168 | opsize = *ptr++; | ||
1169 | if (opsize < 2) | ||
1170 | goto done_opts; | ||
1171 | if (opsize > length) | ||
1172 | goto done_opts; | ||
1173 | |||
1174 | if (opcode == TCPOPT_MD5SIG) { | ||
1175 | hash_location = ptr; | ||
1176 | goto done_opts; | ||
1177 | } | ||
1178 | } | ||
1179 | ptr += opsize-2; | ||
1180 | length -= opsize; | ||
1181 | } | ||
1182 | done_opts: | ||
1183 | /* We've parsed the options - do we have a hash? */ | ||
1184 | if (!hash_expected && !hash_location) | ||
1185 | return 0; | ||
1186 | |||
1187 | if (hash_expected && !hash_location) { | ||
1188 | LIMIT_NETDEBUG(KERN_INFO "MD5 Hash NOT expected but found " | ||
1189 | "(" NIPQUAD_FMT ", %d)->(" NIPQUAD_FMT ", %d)\n", | ||
1190 | NIPQUAD(iph->saddr), ntohs(th->source), | ||
1191 | NIPQUAD(iph->daddr), ntohs(th->dest)); | ||
1192 | return 1; | ||
1193 | } | ||
1194 | |||
1195 | if (!hash_expected && hash_location) { | ||
1196 | LIMIT_NETDEBUG(KERN_INFO "MD5 Hash NOT expected but found " | ||
1197 | "(" NIPQUAD_FMT ", %d)->(" NIPQUAD_FMT ", %d)\n", | ||
1198 | NIPQUAD(iph->saddr), ntohs(th->source), | ||
1199 | NIPQUAD(iph->daddr), ntohs(th->dest)); | ||
1200 | return 1; | ||
1201 | } | ||
1202 | |||
1203 | /* Okay, so this is hash_expected and hash_location - | ||
1204 | * so we need to calculate the checksum. | ||
1205 | */ | ||
1206 | genhash = tcp_v4_do_calc_md5_hash(newhash, | ||
1207 | hash_expected, | ||
1208 | iph->saddr, iph->daddr, | ||
1209 | th, sk->sk_protocol, | ||
1210 | skb->len); | ||
1211 | |||
1212 | if (genhash || memcmp(hash_location, newhash, 16) != 0) { | ||
1213 | if (net_ratelimit()) { | ||
1214 | printk(KERN_INFO "MD5 Hash failed for " | ||
1215 | "(" NIPQUAD_FMT ", %d)->(" NIPQUAD_FMT ", %d)%s\n", | ||
1216 | NIPQUAD(iph->saddr), ntohs(th->source), | ||
1217 | NIPQUAD(iph->daddr), ntohs(th->dest), | ||
1218 | genhash ? " tcp_v4_calc_md5_hash failed" : ""); | ||
1219 | } | ||
1220 | return 1; | ||
1221 | } | ||
1222 | return 0; | ||
1223 | } | ||
1224 | |||
1225 | #endif | ||
1226 | |||
1227 | struct request_sock_ops tcp_request_sock_ops __read_mostly = { | ||
719 | .family = PF_INET, | 1228 | .family = PF_INET, |
720 | .obj_size = sizeof(struct tcp_request_sock), | 1229 | .obj_size = sizeof(struct tcp_request_sock), |
721 | .rtx_syn_ack = tcp_v4_send_synack, | 1230 | .rtx_syn_ack = tcp_v4_send_synack, |
@@ -724,9 +1233,16 @@ struct request_sock_ops tcp_request_sock_ops = { | |||
724 | .send_reset = tcp_v4_send_reset, | 1233 | .send_reset = tcp_v4_send_reset, |
725 | }; | 1234 | }; |
726 | 1235 | ||
1236 | #ifdef CONFIG_TCP_MD5SIG | ||
1237 | static struct tcp_request_sock_ops tcp_request_sock_ipv4_ops = { | ||
1238 | .md5_lookup = tcp_v4_reqsk_md5_lookup, | ||
1239 | }; | ||
1240 | #endif | ||
1241 | |||
727 | static struct timewait_sock_ops tcp_timewait_sock_ops = { | 1242 | static struct timewait_sock_ops tcp_timewait_sock_ops = { |
728 | .twsk_obj_size = sizeof(struct tcp_timewait_sock), | 1243 | .twsk_obj_size = sizeof(struct tcp_timewait_sock), |
729 | .twsk_unique = tcp_twsk_unique, | 1244 | .twsk_unique = tcp_twsk_unique, |
1245 | .twsk_destructor= tcp_twsk_destructor, | ||
730 | }; | 1246 | }; |
731 | 1247 | ||
732 | int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) | 1248 | int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) |
@@ -774,6 +1290,10 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) | |||
774 | if (!req) | 1290 | if (!req) |
775 | goto drop; | 1291 | goto drop; |
776 | 1292 | ||
1293 | #ifdef CONFIG_TCP_MD5SIG | ||
1294 | tcp_rsk(req)->af_specific = &tcp_request_sock_ipv4_ops; | ||
1295 | #endif | ||
1296 | |||
777 | tcp_clear_options(&tmp_opt); | 1297 | tcp_clear_options(&tmp_opt); |
778 | tmp_opt.mss_clamp = 536; | 1298 | tmp_opt.mss_clamp = 536; |
779 | tmp_opt.user_mss = tcp_sk(sk)->rx_opt.user_mss; | 1299 | tmp_opt.user_mss = tcp_sk(sk)->rx_opt.user_mss; |
@@ -859,7 +1379,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) | |||
859 | goto drop_and_free; | 1379 | goto drop_and_free; |
860 | } | 1380 | } |
861 | 1381 | ||
862 | isn = tcp_v4_init_sequence(sk, skb); | 1382 | isn = tcp_v4_init_sequence(skb); |
863 | } | 1383 | } |
864 | tcp_rsk(req)->snt_isn = isn; | 1384 | tcp_rsk(req)->snt_isn = isn; |
865 | 1385 | ||
@@ -892,6 +1412,9 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb, | |||
892 | struct inet_sock *newinet; | 1412 | struct inet_sock *newinet; |
893 | struct tcp_sock *newtp; | 1413 | struct tcp_sock *newtp; |
894 | struct sock *newsk; | 1414 | struct sock *newsk; |
1415 | #ifdef CONFIG_TCP_MD5SIG | ||
1416 | struct tcp_md5sig_key *key; | ||
1417 | #endif | ||
895 | 1418 | ||
896 | if (sk_acceptq_is_full(sk)) | 1419 | if (sk_acceptq_is_full(sk)) |
897 | goto exit_overflow; | 1420 | goto exit_overflow; |
@@ -926,6 +1449,22 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb, | |||
926 | newtp->advmss = dst_metric(dst, RTAX_ADVMSS); | 1449 | newtp->advmss = dst_metric(dst, RTAX_ADVMSS); |
927 | tcp_initialize_rcv_mss(newsk); | 1450 | tcp_initialize_rcv_mss(newsk); |
928 | 1451 | ||
1452 | #ifdef CONFIG_TCP_MD5SIG | ||
1453 | /* Copy over the MD5 key from the original socket */ | ||
1454 | if ((key = tcp_v4_md5_do_lookup(sk, newinet->daddr)) != NULL) { | ||
1455 | /* | ||
1456 | * We're using one, so create a matching key | ||
1457 | * on the newsk structure. If we fail to get | ||
1458 | * memory, then we end up not copying the key | ||
1459 | * across. Shucks. | ||
1460 | */ | ||
1461 | char *newkey = kmemdup(key->key, key->keylen, GFP_ATOMIC); | ||
1462 | if (newkey != NULL) | ||
1463 | tcp_v4_md5_do_add(newsk, inet_sk(sk)->daddr, | ||
1464 | newkey, key->keylen); | ||
1465 | } | ||
1466 | #endif | ||
1467 | |||
929 | __inet_hash(&tcp_hashinfo, newsk, 0); | 1468 | __inet_hash(&tcp_hashinfo, newsk, 0); |
930 | __inet_inherit_port(&tcp_hashinfo, sk, newsk); | 1469 | __inet_inherit_port(&tcp_hashinfo, sk, newsk); |
931 | 1470 | ||
@@ -971,7 +1510,7 @@ static struct sock *tcp_v4_hnd_req(struct sock *sk, struct sk_buff *skb) | |||
971 | return sk; | 1510 | return sk; |
972 | } | 1511 | } |
973 | 1512 | ||
974 | static int tcp_v4_checksum_init(struct sk_buff *skb) | 1513 | static __sum16 tcp_v4_checksum_init(struct sk_buff *skb) |
975 | { | 1514 | { |
976 | if (skb->ip_summed == CHECKSUM_COMPLETE) { | 1515 | if (skb->ip_summed == CHECKSUM_COMPLETE) { |
977 | if (!tcp_v4_check(skb->h.th, skb->len, skb->nh.iph->saddr, | 1516 | if (!tcp_v4_check(skb->h.th, skb->len, skb->nh.iph->saddr, |
@@ -1001,10 +1540,24 @@ static int tcp_v4_checksum_init(struct sk_buff *skb) | |||
1001 | */ | 1540 | */ |
1002 | int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb) | 1541 | int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb) |
1003 | { | 1542 | { |
1543 | struct sock *rsk; | ||
1544 | #ifdef CONFIG_TCP_MD5SIG | ||
1545 | /* | ||
1546 | * We really want to reject the packet as early as possible | ||
1547 | * if: | ||
1548 | * o We're expecting an MD5'd packet and this is no MD5 tcp option | ||
1549 | * o There is an MD5 option and we're not expecting one | ||
1550 | */ | ||
1551 | if (tcp_v4_inbound_md5_hash(sk, skb)) | ||
1552 | goto discard; | ||
1553 | #endif | ||
1554 | |||
1004 | if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */ | 1555 | if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */ |
1005 | TCP_CHECK_TIMER(sk); | 1556 | TCP_CHECK_TIMER(sk); |
1006 | if (tcp_rcv_established(sk, skb, skb->h.th, skb->len)) | 1557 | if (tcp_rcv_established(sk, skb, skb->h.th, skb->len)) { |
1558 | rsk = sk; | ||
1007 | goto reset; | 1559 | goto reset; |
1560 | } | ||
1008 | TCP_CHECK_TIMER(sk); | 1561 | TCP_CHECK_TIMER(sk); |
1009 | return 0; | 1562 | return 0; |
1010 | } | 1563 | } |
@@ -1018,20 +1571,24 @@ int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb) | |||
1018 | goto discard; | 1571 | goto discard; |
1019 | 1572 | ||
1020 | if (nsk != sk) { | 1573 | if (nsk != sk) { |
1021 | if (tcp_child_process(sk, nsk, skb)) | 1574 | if (tcp_child_process(sk, nsk, skb)) { |
1575 | rsk = nsk; | ||
1022 | goto reset; | 1576 | goto reset; |
1577 | } | ||
1023 | return 0; | 1578 | return 0; |
1024 | } | 1579 | } |
1025 | } | 1580 | } |
1026 | 1581 | ||
1027 | TCP_CHECK_TIMER(sk); | 1582 | TCP_CHECK_TIMER(sk); |
1028 | if (tcp_rcv_state_process(sk, skb, skb->h.th, skb->len)) | 1583 | if (tcp_rcv_state_process(sk, skb, skb->h.th, skb->len)) { |
1584 | rsk = sk; | ||
1029 | goto reset; | 1585 | goto reset; |
1586 | } | ||
1030 | TCP_CHECK_TIMER(sk); | 1587 | TCP_CHECK_TIMER(sk); |
1031 | return 0; | 1588 | return 0; |
1032 | 1589 | ||
1033 | reset: | 1590 | reset: |
1034 | tcp_v4_send_reset(skb); | 1591 | tcp_v4_send_reset(rsk, skb); |
1035 | discard: | 1592 | discard: |
1036 | kfree_skb(skb); | 1593 | kfree_skb(skb); |
1037 | /* Be careful here. If this function gets more complicated and | 1594 | /* Be careful here. If this function gets more complicated and |
@@ -1140,7 +1697,7 @@ no_tcp_socket: | |||
1140 | bad_packet: | 1697 | bad_packet: |
1141 | TCP_INC_STATS_BH(TCP_MIB_INERRS); | 1698 | TCP_INC_STATS_BH(TCP_MIB_INERRS); |
1142 | } else { | 1699 | } else { |
1143 | tcp_v4_send_reset(skb); | 1700 | tcp_v4_send_reset(NULL, skb); |
1144 | } | 1701 | } |
1145 | 1702 | ||
1146 | discard_it: | 1703 | discard_it: |
@@ -1263,6 +1820,15 @@ struct inet_connection_sock_af_ops ipv4_specific = { | |||
1263 | #endif | 1820 | #endif |
1264 | }; | 1821 | }; |
1265 | 1822 | ||
1823 | #ifdef CONFIG_TCP_MD5SIG | ||
1824 | static struct tcp_sock_af_ops tcp_sock_ipv4_specific = { | ||
1825 | .md5_lookup = tcp_v4_md5_lookup, | ||
1826 | .calc_md5_hash = tcp_v4_calc_md5_hash, | ||
1827 | .md5_add = tcp_v4_md5_add_func, | ||
1828 | .md5_parse = tcp_v4_parse_md5_keys, | ||
1829 | }; | ||
1830 | #endif | ||
1831 | |||
1266 | /* NOTE: A lot of things set to zero explicitly by call to | 1832 | /* NOTE: A lot of things set to zero explicitly by call to |
1267 | * sk_alloc() so need not be done here. | 1833 | * sk_alloc() so need not be done here. |
1268 | */ | 1834 | */ |
@@ -1302,6 +1868,9 @@ static int tcp_v4_init_sock(struct sock *sk) | |||
1302 | 1868 | ||
1303 | icsk->icsk_af_ops = &ipv4_specific; | 1869 | icsk->icsk_af_ops = &ipv4_specific; |
1304 | icsk->icsk_sync_mss = tcp_sync_mss; | 1870 | icsk->icsk_sync_mss = tcp_sync_mss; |
1871 | #ifdef CONFIG_TCP_MD5SIG | ||
1872 | tp->af_specific = &tcp_sock_ipv4_specific; | ||
1873 | #endif | ||
1305 | 1874 | ||
1306 | sk->sk_sndbuf = sysctl_tcp_wmem[1]; | 1875 | sk->sk_sndbuf = sysctl_tcp_wmem[1]; |
1307 | sk->sk_rcvbuf = sysctl_tcp_rmem[1]; | 1876 | sk->sk_rcvbuf = sysctl_tcp_rmem[1]; |
@@ -1325,6 +1894,15 @@ int tcp_v4_destroy_sock(struct sock *sk) | |||
1325 | /* Cleans up our, hopefully empty, out_of_order_queue. */ | 1894 | /* Cleans up our, hopefully empty, out_of_order_queue. */ |
1326 | __skb_queue_purge(&tp->out_of_order_queue); | 1895 | __skb_queue_purge(&tp->out_of_order_queue); |
1327 | 1896 | ||
1897 | #ifdef CONFIG_TCP_MD5SIG | ||
1898 | /* Clean up the MD5 key list, if any */ | ||
1899 | if (tp->md5sig_info) { | ||
1900 | tcp_v4_clear_md5_list(sk); | ||
1901 | kfree(tp->md5sig_info); | ||
1902 | tp->md5sig_info = NULL; | ||
1903 | } | ||
1904 | #endif | ||
1905 | |||
1328 | #ifdef CONFIG_NET_DMA | 1906 | #ifdef CONFIG_NET_DMA |
1329 | /* Cleans up our sk_async_wait_queue */ | 1907 | /* Cleans up our sk_async_wait_queue */ |
1330 | __skb_queue_purge(&sk->sk_async_wait_queue); | 1908 | __skb_queue_purge(&sk->sk_async_wait_queue); |
@@ -1385,7 +1963,7 @@ static void *listening_get_next(struct seq_file *seq, void *cur) | |||
1385 | if (st->state == TCP_SEQ_STATE_OPENREQ) { | 1963 | if (st->state == TCP_SEQ_STATE_OPENREQ) { |
1386 | struct request_sock *req = cur; | 1964 | struct request_sock *req = cur; |
1387 | 1965 | ||
1388 | icsk = inet_csk(st->syn_wait_sk); | 1966 | icsk = inet_csk(st->syn_wait_sk); |
1389 | req = req->dl_next; | 1967 | req = req->dl_next; |
1390 | while (1) { | 1968 | while (1) { |
1391 | while (req) { | 1969 | while (req) { |
@@ -1395,7 +1973,7 @@ static void *listening_get_next(struct seq_file *seq, void *cur) | |||
1395 | } | 1973 | } |
1396 | req = req->dl_next; | 1974 | req = req->dl_next; |
1397 | } | 1975 | } |
1398 | if (++st->sbucket >= TCP_SYNQ_HSIZE) | 1976 | if (++st->sbucket >= icsk->icsk_accept_queue.listen_opt->nr_table_entries) |
1399 | break; | 1977 | break; |
1400 | get_req: | 1978 | get_req: |
1401 | req = icsk->icsk_accept_queue.listen_opt->syn_table[st->sbucket]; | 1979 | req = icsk->icsk_accept_queue.listen_opt->syn_table[st->sbucket]; |
@@ -1543,7 +2121,7 @@ static void *established_get_idx(struct seq_file *seq, loff_t pos) | |||
1543 | while (rc && pos) { | 2121 | while (rc && pos) { |
1544 | rc = established_get_next(seq, rc); | 2122 | rc = established_get_next(seq, rc); |
1545 | --pos; | 2123 | --pos; |
1546 | } | 2124 | } |
1547 | return rc; | 2125 | return rc; |
1548 | } | 2126 | } |
1549 | 2127 | ||
@@ -1672,7 +2250,7 @@ int tcp_proc_register(struct tcp_seq_afinfo *afinfo) | |||
1672 | afinfo->seq_fops->read = seq_read; | 2250 | afinfo->seq_fops->read = seq_read; |
1673 | afinfo->seq_fops->llseek = seq_lseek; | 2251 | afinfo->seq_fops->llseek = seq_lseek; |
1674 | afinfo->seq_fops->release = seq_release_private; | 2252 | afinfo->seq_fops->release = seq_release_private; |
1675 | 2253 | ||
1676 | p = proc_net_fops_create(afinfo->name, S_IRUGO, afinfo->seq_fops); | 2254 | p = proc_net_fops_create(afinfo->name, S_IRUGO, afinfo->seq_fops); |
1677 | if (p) | 2255 | if (p) |
1678 | p->data = afinfo; | 2256 | p->data = afinfo; |
@@ -1686,7 +2264,7 @@ void tcp_proc_unregister(struct tcp_seq_afinfo *afinfo) | |||
1686 | if (!afinfo) | 2264 | if (!afinfo) |
1687 | return; | 2265 | return; |
1688 | proc_net_remove(afinfo->name); | 2266 | proc_net_remove(afinfo->name); |
1689 | memset(afinfo->seq_fops, 0, sizeof(*afinfo->seq_fops)); | 2267 | memset(afinfo->seq_fops, 0, sizeof(*afinfo->seq_fops)); |
1690 | } | 2268 | } |
1691 | 2269 | ||
1692 | static void get_openreq4(struct sock *sk, struct request_sock *req, | 2270 | static void get_openreq4(struct sock *sk, struct request_sock *req, |
@@ -1721,8 +2299,8 @@ static void get_tcp4_sock(struct sock *sp, char *tmpbuf, int i) | |||
1721 | struct tcp_sock *tp = tcp_sk(sp); | 2299 | struct tcp_sock *tp = tcp_sk(sp); |
1722 | const struct inet_connection_sock *icsk = inet_csk(sp); | 2300 | const struct inet_connection_sock *icsk = inet_csk(sp); |
1723 | struct inet_sock *inet = inet_sk(sp); | 2301 | struct inet_sock *inet = inet_sk(sp); |
1724 | unsigned int dest = inet->daddr; | 2302 | __be32 dest = inet->daddr; |
1725 | unsigned int src = inet->rcv_saddr; | 2303 | __be32 src = inet->rcv_saddr; |
1726 | __u16 destp = ntohs(inet->dport); | 2304 | __u16 destp = ntohs(inet->dport); |
1727 | __u16 srcp = ntohs(inet->sport); | 2305 | __u16 srcp = ntohs(inet->sport); |
1728 | 2306 | ||
@@ -1744,7 +2322,8 @@ static void get_tcp4_sock(struct sock *sp, char *tmpbuf, int i) | |||
1744 | "%08X %5d %8d %lu %d %p %u %u %u %u %d", | 2322 | "%08X %5d %8d %lu %d %p %u %u %u %u %d", |
1745 | i, src, srcp, dest, destp, sp->sk_state, | 2323 | i, src, srcp, dest, destp, sp->sk_state, |
1746 | tp->write_seq - tp->snd_una, | 2324 | tp->write_seq - tp->snd_una, |
1747 | (sp->sk_state == TCP_LISTEN) ? sp->sk_ack_backlog : (tp->rcv_nxt - tp->copied_seq), | 2325 | sp->sk_state == TCP_LISTEN ? sp->sk_ack_backlog : |
2326 | (tp->rcv_nxt - tp->copied_seq), | ||
1748 | timer_active, | 2327 | timer_active, |
1749 | jiffies_to_clock_t(timer_expires - jiffies), | 2328 | jiffies_to_clock_t(timer_expires - jiffies), |
1750 | icsk->icsk_retransmits, | 2329 | icsk->icsk_retransmits, |
@@ -1759,7 +2338,8 @@ static void get_tcp4_sock(struct sock *sp, char *tmpbuf, int i) | |||
1759 | tp->snd_ssthresh >= 0xFFFF ? -1 : tp->snd_ssthresh); | 2338 | tp->snd_ssthresh >= 0xFFFF ? -1 : tp->snd_ssthresh); |
1760 | } | 2339 | } |
1761 | 2340 | ||
1762 | static void get_timewait4_sock(struct inet_timewait_sock *tw, char *tmpbuf, int i) | 2341 | static void get_timewait4_sock(struct inet_timewait_sock *tw, |
2342 | char *tmpbuf, int i) | ||
1763 | { | 2343 | { |
1764 | __be32 dest, src; | 2344 | __be32 dest, src; |
1765 | __u16 destp, srcp; | 2345 | __u16 destp, srcp; |
@@ -1872,7 +2452,8 @@ struct proto tcp_prot = { | |||
1872 | 2452 | ||
1873 | void __init tcp_v4_init(struct net_proto_family *ops) | 2453 | void __init tcp_v4_init(struct net_proto_family *ops) |
1874 | { | 2454 | { |
1875 | if (inet_csk_ctl_sock_create(&tcp_socket, PF_INET, SOCK_RAW, IPPROTO_TCP) < 0) | 2455 | if (inet_csk_ctl_sock_create(&tcp_socket, PF_INET, SOCK_RAW, |
2456 | IPPROTO_TCP) < 0) | ||
1876 | panic("Failed to create the TCP control socket.\n"); | 2457 | panic("Failed to create the TCP control socket.\n"); |
1877 | } | 2458 | } |
1878 | 2459 | ||
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index af7b2c986b1f..4a3889dd1943 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c | |||
@@ -305,6 +305,28 @@ void tcp_time_wait(struct sock *sk, int state, int timeo) | |||
305 | tw->tw_ipv6only = np->ipv6only; | 305 | tw->tw_ipv6only = np->ipv6only; |
306 | } | 306 | } |
307 | #endif | 307 | #endif |
308 | |||
309 | #ifdef CONFIG_TCP_MD5SIG | ||
310 | /* | ||
311 | * The timewait bucket does not have the key DB from the | ||
312 | * sock structure. We just make a quick copy of the | ||
313 | * md5 key being used (if indeed we are using one) | ||
314 | * so the timewait ack generating code has the key. | ||
315 | */ | ||
316 | do { | ||
317 | struct tcp_md5sig_key *key; | ||
318 | memset(tcptw->tw_md5_key, 0, sizeof(tcptw->tw_md5_key)); | ||
319 | tcptw->tw_md5_keylen = 0; | ||
320 | key = tp->af_specific->md5_lookup(sk, sk); | ||
321 | if (key != NULL) { | ||
322 | memcpy(&tcptw->tw_md5_key, key->key, key->keylen); | ||
323 | tcptw->tw_md5_keylen = key->keylen; | ||
324 | if (tcp_alloc_md5sig_pool() == NULL) | ||
325 | BUG(); | ||
326 | } | ||
327 | } while(0); | ||
328 | #endif | ||
329 | |||
308 | /* Linkage updates. */ | 330 | /* Linkage updates. */ |
309 | __inet_twsk_hashdance(tw, sk, &tcp_hashinfo); | 331 | __inet_twsk_hashdance(tw, sk, &tcp_hashinfo); |
310 | 332 | ||
@@ -328,14 +350,24 @@ void tcp_time_wait(struct sock *sk, int state, int timeo) | |||
328 | * socket up. We've got bigger problems than | 350 | * socket up. We've got bigger problems than |
329 | * non-graceful socket closings. | 351 | * non-graceful socket closings. |
330 | */ | 352 | */ |
331 | if (net_ratelimit()) | 353 | LIMIT_NETDEBUG(KERN_INFO "TCP: time wait bucket table overflow\n"); |
332 | printk(KERN_INFO "TCP: time wait bucket table overflow\n"); | ||
333 | } | 354 | } |
334 | 355 | ||
335 | tcp_update_metrics(sk); | 356 | tcp_update_metrics(sk); |
336 | tcp_done(sk); | 357 | tcp_done(sk); |
337 | } | 358 | } |
338 | 359 | ||
360 | void tcp_twsk_destructor(struct sock *sk) | ||
361 | { | ||
362 | #ifdef CONFIG_TCP_MD5SIG | ||
363 | struct tcp_timewait_sock *twsk = tcp_twsk(sk); | ||
364 | if (twsk->tw_md5_keylen) | ||
365 | tcp_put_md5sig_pool(); | ||
366 | #endif | ||
367 | } | ||
368 | |||
369 | EXPORT_SYMBOL_GPL(tcp_twsk_destructor); | ||
370 | |||
339 | /* This is not only more efficient than what we used to do, it eliminates | 371 | /* This is not only more efficient than what we used to do, it eliminates |
340 | * a lot of code duplication between IPv4/IPv6 SYN recv processing. -DaveM | 372 | * a lot of code duplication between IPv4/IPv6 SYN recv processing. -DaveM |
341 | * | 373 | * |
@@ -434,6 +466,11 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req, | |||
434 | newtp->rx_opt.ts_recent_stamp = 0; | 466 | newtp->rx_opt.ts_recent_stamp = 0; |
435 | newtp->tcp_header_len = sizeof(struct tcphdr); | 467 | newtp->tcp_header_len = sizeof(struct tcphdr); |
436 | } | 468 | } |
469 | #ifdef CONFIG_TCP_MD5SIG | ||
470 | newtp->md5sig_info = NULL; /*XXX*/ | ||
471 | if (newtp->af_specific->md5_lookup(sk, newsk)) | ||
472 | newtp->tcp_header_len += TCPOLEN_MD5SIG_ALIGNED; | ||
473 | #endif | ||
437 | if (skb->len >= TCP_MIN_RCVMSS+newtp->tcp_header_len) | 474 | if (skb->len >= TCP_MIN_RCVMSS+newtp->tcp_header_len) |
438 | newicsk->icsk_ack.last_seg_size = skb->len - newtp->tcp_header_len; | 475 | newicsk->icsk_ack.last_seg_size = skb->len - newtp->tcp_header_len; |
439 | newtp->rx_opt.mss_clamp = req->mss; | 476 | newtp->rx_opt.mss_clamp = req->mss; |
@@ -454,7 +491,7 @@ struct sock *tcp_check_req(struct sock *sk,struct sk_buff *skb, | |||
454 | struct request_sock **prev) | 491 | struct request_sock **prev) |
455 | { | 492 | { |
456 | struct tcphdr *th = skb->h.th; | 493 | struct tcphdr *th = skb->h.th; |
457 | u32 flg = tcp_flag_word(th) & (TCP_FLAG_RST|TCP_FLAG_SYN|TCP_FLAG_ACK); | 494 | __be32 flg = tcp_flag_word(th) & (TCP_FLAG_RST|TCP_FLAG_SYN|TCP_FLAG_ACK); |
458 | int paws_reject = 0; | 495 | int paws_reject = 0; |
459 | struct tcp_options_received tmp_opt; | 496 | struct tcp_options_received tmp_opt; |
460 | struct sock *child; | 497 | struct sock *child; |
@@ -616,6 +653,30 @@ struct sock *tcp_check_req(struct sock *sk,struct sk_buff *skb, | |||
616 | req, NULL); | 653 | req, NULL); |
617 | if (child == NULL) | 654 | if (child == NULL) |
618 | goto listen_overflow; | 655 | goto listen_overflow; |
656 | #ifdef CONFIG_TCP_MD5SIG | ||
657 | else { | ||
658 | /* Copy over the MD5 key from the original socket */ | ||
659 | struct tcp_md5sig_key *key; | ||
660 | struct tcp_sock *tp = tcp_sk(sk); | ||
661 | key = tp->af_specific->md5_lookup(sk, child); | ||
662 | if (key != NULL) { | ||
663 | /* | ||
664 | * We're using one, so create a matching key on the | ||
665 | * newsk structure. If we fail to get memory then we | ||
666 | * end up not copying the key across. Shucks. | ||
667 | */ | ||
668 | char *newkey = kmemdup(key->key, key->keylen, | ||
669 | GFP_ATOMIC); | ||
670 | if (newkey) { | ||
671 | if (!tcp_alloc_md5sig_pool()) | ||
672 | BUG(); | ||
673 | tp->af_specific->md5_add(child, child, | ||
674 | newkey, | ||
675 | key->keylen); | ||
676 | } | ||
677 | } | ||
678 | } | ||
679 | #endif | ||
619 | 680 | ||
620 | inet_csk_reqsk_queue_unlink(sk, req, prev); | 681 | inet_csk_reqsk_queue_unlink(sk, req, prev); |
621 | inet_csk_reqsk_queue_removed(sk, req); | 682 | inet_csk_reqsk_queue_removed(sk, req); |
@@ -632,7 +693,7 @@ struct sock *tcp_check_req(struct sock *sk,struct sk_buff *skb, | |||
632 | embryonic_reset: | 693 | embryonic_reset: |
633 | NET_INC_STATS_BH(LINUX_MIB_EMBRYONICRSTS); | 694 | NET_INC_STATS_BH(LINUX_MIB_EMBRYONICRSTS); |
634 | if (!(flg & TCP_FLAG_RST)) | 695 | if (!(flg & TCP_FLAG_RST)) |
635 | req->rsk_ops->send_reset(skb); | 696 | req->rsk_ops->send_reset(sk, skb); |
636 | 697 | ||
637 | inet_csk_reqsk_queue_drop(sk, req, prev); | 698 | inet_csk_reqsk_queue_drop(sk, req, prev); |
638 | return NULL; | 699 | return NULL; |
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index ca406157724c..32c1a972fa31 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c | |||
@@ -270,7 +270,7 @@ static u16 tcp_select_window(struct sock *sk) | |||
270 | } | 270 | } |
271 | 271 | ||
272 | static void tcp_build_and_update_options(__be32 *ptr, struct tcp_sock *tp, | 272 | static void tcp_build_and_update_options(__be32 *ptr, struct tcp_sock *tp, |
273 | __u32 tstamp) | 273 | __u32 tstamp, __u8 **md5_hash) |
274 | { | 274 | { |
275 | if (tp->rx_opt.tstamp_ok) { | 275 | if (tp->rx_opt.tstamp_ok) { |
276 | *ptr++ = htonl((TCPOPT_NOP << 24) | | 276 | *ptr++ = htonl((TCPOPT_NOP << 24) | |
@@ -298,16 +298,29 @@ static void tcp_build_and_update_options(__be32 *ptr, struct tcp_sock *tp, | |||
298 | tp->rx_opt.eff_sacks--; | 298 | tp->rx_opt.eff_sacks--; |
299 | } | 299 | } |
300 | } | 300 | } |
301 | #ifdef CONFIG_TCP_MD5SIG | ||
302 | if (md5_hash) { | ||
303 | *ptr++ = htonl((TCPOPT_NOP << 24) | | ||
304 | (TCPOPT_NOP << 16) | | ||
305 | (TCPOPT_MD5SIG << 8) | | ||
306 | TCPOLEN_MD5SIG); | ||
307 | *md5_hash = (__u8 *)ptr; | ||
308 | } | ||
309 | #endif | ||
301 | } | 310 | } |
302 | 311 | ||
303 | /* Construct a tcp options header for a SYN or SYN_ACK packet. | 312 | /* Construct a tcp options header for a SYN or SYN_ACK packet. |
304 | * If this is every changed make sure to change the definition of | 313 | * If this is every changed make sure to change the definition of |
305 | * MAX_SYN_SIZE to match the new maximum number of options that you | 314 | * MAX_SYN_SIZE to match the new maximum number of options that you |
306 | * can generate. | 315 | * can generate. |
316 | * | ||
317 | * Note - that with the RFC2385 TCP option, we make room for the | ||
318 | * 16 byte MD5 hash. This will be filled in later, so the pointer for the | ||
319 | * location to be filled is passed back up. | ||
307 | */ | 320 | */ |
308 | static void tcp_syn_build_options(__be32 *ptr, int mss, int ts, int sack, | 321 | static void tcp_syn_build_options(__be32 *ptr, int mss, int ts, int sack, |
309 | int offer_wscale, int wscale, __u32 tstamp, | 322 | int offer_wscale, int wscale, __u32 tstamp, |
310 | __u32 ts_recent) | 323 | __u32 ts_recent, __u8 **md5_hash) |
311 | { | 324 | { |
312 | /* We always get an MSS option. | 325 | /* We always get an MSS option. |
313 | * The option bytes which will be seen in normal data | 326 | * The option bytes which will be seen in normal data |
@@ -346,6 +359,20 @@ static void tcp_syn_build_options(__be32 *ptr, int mss, int ts, int sack, | |||
346 | (TCPOPT_WINDOW << 16) | | 359 | (TCPOPT_WINDOW << 16) | |
347 | (TCPOLEN_WINDOW << 8) | | 360 | (TCPOLEN_WINDOW << 8) | |
348 | (wscale)); | 361 | (wscale)); |
362 | #ifdef CONFIG_TCP_MD5SIG | ||
363 | /* | ||
364 | * If MD5 is enabled, then we set the option, and include the size | ||
365 | * (always 18). The actual MD5 hash is added just before the | ||
366 | * packet is sent. | ||
367 | */ | ||
368 | if (md5_hash) { | ||
369 | *ptr++ = htonl((TCPOPT_NOP << 24) | | ||
370 | (TCPOPT_NOP << 16) | | ||
371 | (TCPOPT_MD5SIG << 8) | | ||
372 | TCPOLEN_MD5SIG); | ||
373 | *md5_hash = (__u8 *) ptr; | ||
374 | } | ||
375 | #endif | ||
349 | } | 376 | } |
350 | 377 | ||
351 | /* This routine actually transmits TCP packets queued in by | 378 | /* This routine actually transmits TCP packets queued in by |
@@ -366,6 +393,10 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, | |||
366 | struct tcp_sock *tp; | 393 | struct tcp_sock *tp; |
367 | struct tcp_skb_cb *tcb; | 394 | struct tcp_skb_cb *tcb; |
368 | int tcp_header_size; | 395 | int tcp_header_size; |
396 | #ifdef CONFIG_TCP_MD5SIG | ||
397 | struct tcp_md5sig_key *md5; | ||
398 | __u8 *md5_hash_location; | ||
399 | #endif | ||
369 | struct tcphdr *th; | 400 | struct tcphdr *th; |
370 | int sysctl_flags; | 401 | int sysctl_flags; |
371 | int err; | 402 | int err; |
@@ -424,9 +455,18 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, | |||
424 | if (tcp_packets_in_flight(tp) == 0) | 455 | if (tcp_packets_in_flight(tp) == 0) |
425 | tcp_ca_event(sk, CA_EVENT_TX_START); | 456 | tcp_ca_event(sk, CA_EVENT_TX_START); |
426 | 457 | ||
458 | #ifdef CONFIG_TCP_MD5SIG | ||
459 | /* | ||
460 | * Are we doing MD5 on this segment? If so - make | ||
461 | * room for it. | ||
462 | */ | ||
463 | md5 = tp->af_specific->md5_lookup(sk, sk); | ||
464 | if (md5) | ||
465 | tcp_header_size += TCPOLEN_MD5SIG_ALIGNED; | ||
466 | #endif | ||
467 | |||
427 | th = (struct tcphdr *) skb_push(skb, tcp_header_size); | 468 | th = (struct tcphdr *) skb_push(skb, tcp_header_size); |
428 | skb->h.th = th; | 469 | skb->h.th = th; |
429 | skb_set_owner_w(skb, sk); | ||
430 | 470 | ||
431 | /* Build TCP header and checksum it. */ | 471 | /* Build TCP header and checksum it. */ |
432 | th->source = inet->sport; | 472 | th->source = inet->sport; |
@@ -461,13 +501,34 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, | |||
461 | (sysctl_flags & SYSCTL_FLAG_WSCALE), | 501 | (sysctl_flags & SYSCTL_FLAG_WSCALE), |
462 | tp->rx_opt.rcv_wscale, | 502 | tp->rx_opt.rcv_wscale, |
463 | tcb->when, | 503 | tcb->when, |
464 | tp->rx_opt.ts_recent); | 504 | tp->rx_opt.ts_recent, |
505 | |||
506 | #ifdef CONFIG_TCP_MD5SIG | ||
507 | md5 ? &md5_hash_location : | ||
508 | #endif | ||
509 | NULL); | ||
465 | } else { | 510 | } else { |
466 | tcp_build_and_update_options((__be32 *)(th + 1), | 511 | tcp_build_and_update_options((__be32 *)(th + 1), |
467 | tp, tcb->when); | 512 | tp, tcb->when, |
513 | #ifdef CONFIG_TCP_MD5SIG | ||
514 | md5 ? &md5_hash_location : | ||
515 | #endif | ||
516 | NULL); | ||
468 | TCP_ECN_send(sk, tp, skb, tcp_header_size); | 517 | TCP_ECN_send(sk, tp, skb, tcp_header_size); |
469 | } | 518 | } |
470 | 519 | ||
520 | #ifdef CONFIG_TCP_MD5SIG | ||
521 | /* Calculate the MD5 hash, as we have all we need now */ | ||
522 | if (md5) { | ||
523 | tp->af_specific->calc_md5_hash(md5_hash_location, | ||
524 | md5, | ||
525 | sk, NULL, NULL, | ||
526 | skb->h.th, | ||
527 | sk->sk_protocol, | ||
528 | skb->len); | ||
529 | } | ||
530 | #endif | ||
531 | |||
471 | icsk->icsk_af_ops->send_check(sk, skb->len, skb); | 532 | icsk->icsk_af_ops->send_check(sk, skb->len, skb); |
472 | 533 | ||
473 | if (likely(tcb->flags & TCPCB_FLAG_ACK)) | 534 | if (likely(tcb->flags & TCPCB_FLAG_ACK)) |
@@ -479,19 +540,13 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, | |||
479 | if (after(tcb->end_seq, tp->snd_nxt) || tcb->seq == tcb->end_seq) | 540 | if (after(tcb->end_seq, tp->snd_nxt) || tcb->seq == tcb->end_seq) |
480 | TCP_INC_STATS(TCP_MIB_OUTSEGS); | 541 | TCP_INC_STATS(TCP_MIB_OUTSEGS); |
481 | 542 | ||
482 | err = icsk->icsk_af_ops->queue_xmit(skb, 0); | 543 | err = icsk->icsk_af_ops->queue_xmit(skb, sk, 0); |
483 | if (likely(err <= 0)) | 544 | if (likely(err <= 0)) |
484 | return err; | 545 | return err; |
485 | 546 | ||
486 | tcp_enter_cwr(sk); | 547 | tcp_enter_cwr(sk); |
487 | 548 | ||
488 | /* NET_XMIT_CN is special. It does not guarantee, | 549 | return net_xmit_eval(err); |
489 | * that this packet is lost. It tells that device | ||
490 | * is about to start to drop packets or already | ||
491 | * drops some packets of the same priority and | ||
492 | * invokes us to send less aggressively. | ||
493 | */ | ||
494 | return err == NET_XMIT_CN ? 0 : err; | ||
495 | 550 | ||
496 | #undef SYSCTL_FLAG_TSTAMPS | 551 | #undef SYSCTL_FLAG_TSTAMPS |
497 | #undef SYSCTL_FLAG_WSCALE | 552 | #undef SYSCTL_FLAG_WSCALE |
@@ -847,6 +902,11 @@ unsigned int tcp_current_mss(struct sock *sk, int large_allowed) | |||
847 | mss_now -= (TCPOLEN_SACK_BASE_ALIGNED + | 902 | mss_now -= (TCPOLEN_SACK_BASE_ALIGNED + |
848 | (tp->rx_opt.eff_sacks * TCPOLEN_SACK_PERBLOCK)); | 903 | (tp->rx_opt.eff_sacks * TCPOLEN_SACK_PERBLOCK)); |
849 | 904 | ||
905 | #ifdef CONFIG_TCP_MD5SIG | ||
906 | if (tp->af_specific->md5_lookup(sk, sk)) | ||
907 | mss_now -= TCPOLEN_MD5SIG_ALIGNED; | ||
908 | #endif | ||
909 | |||
850 | xmit_size_goal = mss_now; | 910 | xmit_size_goal = mss_now; |
851 | 911 | ||
852 | if (doing_tso) { | 912 | if (doing_tso) { |
@@ -2040,6 +2100,10 @@ struct sk_buff * tcp_make_synack(struct sock *sk, struct dst_entry *dst, | |||
2040 | struct tcphdr *th; | 2100 | struct tcphdr *th; |
2041 | int tcp_header_size; | 2101 | int tcp_header_size; |
2042 | struct sk_buff *skb; | 2102 | struct sk_buff *skb; |
2103 | #ifdef CONFIG_TCP_MD5SIG | ||
2104 | struct tcp_md5sig_key *md5; | ||
2105 | __u8 *md5_hash_location; | ||
2106 | #endif | ||
2043 | 2107 | ||
2044 | skb = sock_wmalloc(sk, MAX_TCP_HEADER + 15, 1, GFP_ATOMIC); | 2108 | skb = sock_wmalloc(sk, MAX_TCP_HEADER + 15, 1, GFP_ATOMIC); |
2045 | if (skb == NULL) | 2109 | if (skb == NULL) |
@@ -2055,6 +2119,13 @@ struct sk_buff * tcp_make_synack(struct sock *sk, struct dst_entry *dst, | |||
2055 | (ireq->wscale_ok ? TCPOLEN_WSCALE_ALIGNED : 0) + | 2119 | (ireq->wscale_ok ? TCPOLEN_WSCALE_ALIGNED : 0) + |
2056 | /* SACK_PERM is in the place of NOP NOP of TS */ | 2120 | /* SACK_PERM is in the place of NOP NOP of TS */ |
2057 | ((ireq->sack_ok && !ireq->tstamp_ok) ? TCPOLEN_SACKPERM_ALIGNED : 0)); | 2121 | ((ireq->sack_ok && !ireq->tstamp_ok) ? TCPOLEN_SACKPERM_ALIGNED : 0)); |
2122 | |||
2123 | #ifdef CONFIG_TCP_MD5SIG | ||
2124 | /* Are we doing MD5 on this segment? If so - make room for it */ | ||
2125 | md5 = tcp_rsk(req)->af_specific->md5_lookup(sk, req); | ||
2126 | if (md5) | ||
2127 | tcp_header_size += TCPOLEN_MD5SIG_ALIGNED; | ||
2128 | #endif | ||
2058 | skb->h.th = th = (struct tcphdr *) skb_push(skb, tcp_header_size); | 2129 | skb->h.th = th = (struct tcphdr *) skb_push(skb, tcp_header_size); |
2059 | 2130 | ||
2060 | memset(th, 0, sizeof(struct tcphdr)); | 2131 | memset(th, 0, sizeof(struct tcphdr)); |
@@ -2092,11 +2163,29 @@ struct sk_buff * tcp_make_synack(struct sock *sk, struct dst_entry *dst, | |||
2092 | tcp_syn_build_options((__be32 *)(th + 1), dst_metric(dst, RTAX_ADVMSS), ireq->tstamp_ok, | 2163 | tcp_syn_build_options((__be32 *)(th + 1), dst_metric(dst, RTAX_ADVMSS), ireq->tstamp_ok, |
2093 | ireq->sack_ok, ireq->wscale_ok, ireq->rcv_wscale, | 2164 | ireq->sack_ok, ireq->wscale_ok, ireq->rcv_wscale, |
2094 | TCP_SKB_CB(skb)->when, | 2165 | TCP_SKB_CB(skb)->when, |
2095 | req->ts_recent); | 2166 | req->ts_recent, |
2167 | ( | ||
2168 | #ifdef CONFIG_TCP_MD5SIG | ||
2169 | md5 ? &md5_hash_location : | ||
2170 | #endif | ||
2171 | NULL) | ||
2172 | ); | ||
2096 | 2173 | ||
2097 | skb->csum = 0; | 2174 | skb->csum = 0; |
2098 | th->doff = (tcp_header_size >> 2); | 2175 | th->doff = (tcp_header_size >> 2); |
2099 | TCP_INC_STATS(TCP_MIB_OUTSEGS); | 2176 | TCP_INC_STATS(TCP_MIB_OUTSEGS); |
2177 | |||
2178 | #ifdef CONFIG_TCP_MD5SIG | ||
2179 | /* Okay, we have all we need - do the md5 hash if needed */ | ||
2180 | if (md5) { | ||
2181 | tp->af_specific->calc_md5_hash(md5_hash_location, | ||
2182 | md5, | ||
2183 | NULL, dst, req, | ||
2184 | skb->h.th, sk->sk_protocol, | ||
2185 | skb->len); | ||
2186 | } | ||
2187 | #endif | ||
2188 | |||
2100 | return skb; | 2189 | return skb; |
2101 | } | 2190 | } |
2102 | 2191 | ||
@@ -2115,6 +2204,11 @@ static void tcp_connect_init(struct sock *sk) | |||
2115 | tp->tcp_header_len = sizeof(struct tcphdr) + | 2204 | tp->tcp_header_len = sizeof(struct tcphdr) + |
2116 | (sysctl_tcp_timestamps ? TCPOLEN_TSTAMP_ALIGNED : 0); | 2205 | (sysctl_tcp_timestamps ? TCPOLEN_TSTAMP_ALIGNED : 0); |
2117 | 2206 | ||
2207 | #ifdef CONFIG_TCP_MD5SIG | ||
2208 | if (tp->af_specific->md5_lookup(sk, sk) != NULL) | ||
2209 | tp->tcp_header_len += TCPOLEN_MD5SIG_ALIGNED; | ||
2210 | #endif | ||
2211 | |||
2118 | /* If user gave his TCP_MAXSEG, record it to clamp */ | 2212 | /* If user gave his TCP_MAXSEG, record it to clamp */ |
2119 | if (tp->rx_opt.user_mss) | 2213 | if (tp->rx_opt.user_mss) |
2120 | tp->rx_opt.mss_clamp = tp->rx_opt.user_mss; | 2214 | tp->rx_opt.mss_clamp = tp->rx_opt.user_mss; |
diff --git a/net/ipv4/tcp_probe.c b/net/ipv4/tcp_probe.c index 4be336f17883..f230eeecf092 100644 --- a/net/ipv4/tcp_probe.c +++ b/net/ipv4/tcp_probe.c | |||
@@ -156,6 +156,8 @@ static __init int tcpprobe_init(void) | |||
156 | init_waitqueue_head(&tcpw.wait); | 156 | init_waitqueue_head(&tcpw.wait); |
157 | spin_lock_init(&tcpw.lock); | 157 | spin_lock_init(&tcpw.lock); |
158 | tcpw.fifo = kfifo_alloc(bufsize, GFP_KERNEL, &tcpw.lock); | 158 | tcpw.fifo = kfifo_alloc(bufsize, GFP_KERNEL, &tcpw.lock); |
159 | if (IS_ERR(tcpw.fifo)) | ||
160 | return PTR_ERR(tcpw.fifo); | ||
159 | 161 | ||
160 | if (!proc_net_fops_create(procname, S_IRUSR, &tcpprobe_fops)) | 162 | if (!proc_net_fops_create(procname, S_IRUSR, &tcpprobe_fops)) |
161 | goto err0; | 163 | goto err0; |
diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index fb09ade5897b..3355c276b611 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c | |||
@@ -297,7 +297,7 @@ static void tcp_retransmit_timer(struct sock *sk) | |||
297 | if (net_ratelimit()) { | 297 | if (net_ratelimit()) { |
298 | struct inet_sock *inet = inet_sk(sk); | 298 | struct inet_sock *inet = inet_sk(sk); |
299 | printk(KERN_DEBUG "TCP: Treason uncloaked! Peer %u.%u.%u.%u:%u/%u shrinks window %u:%u. Repaired.\n", | 299 | printk(KERN_DEBUG "TCP: Treason uncloaked! Peer %u.%u.%u.%u:%u/%u shrinks window %u:%u. Repaired.\n", |
300 | NIPQUAD(inet->daddr), htons(inet->dport), | 300 | NIPQUAD(inet->daddr), ntohs(inet->dport), |
301 | inet->num, tp->snd_una, tp->snd_nxt); | 301 | inet->num, tp->snd_una, tp->snd_nxt); |
302 | } | 302 | } |
303 | #endif | 303 | #endif |
diff --git a/net/ipv4/tcp_vegas.c b/net/ipv4/tcp_vegas.c index a3b7aa015a2f..ddc4bcc5785e 100644 --- a/net/ipv4/tcp_vegas.c +++ b/net/ipv4/tcp_vegas.c | |||
@@ -42,8 +42,8 @@ | |||
42 | * with V_PARAM_SHIFT bits to the right of the binary point. | 42 | * with V_PARAM_SHIFT bits to the right of the binary point. |
43 | */ | 43 | */ |
44 | #define V_PARAM_SHIFT 1 | 44 | #define V_PARAM_SHIFT 1 |
45 | static int alpha = 1<<V_PARAM_SHIFT; | 45 | static int alpha = 2<<V_PARAM_SHIFT; |
46 | static int beta = 3<<V_PARAM_SHIFT; | 46 | static int beta = 4<<V_PARAM_SHIFT; |
47 | static int gamma = 1<<V_PARAM_SHIFT; | 47 | static int gamma = 1<<V_PARAM_SHIFT; |
48 | 48 | ||
49 | module_param(alpha, int, 0644); | 49 | module_param(alpha, int, 0644); |
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 865d75214a9a..035915fc9ed3 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c | |||
@@ -92,22 +92,16 @@ | |||
92 | #include <linux/timer.h> | 92 | #include <linux/timer.h> |
93 | #include <linux/mm.h> | 93 | #include <linux/mm.h> |
94 | #include <linux/inet.h> | 94 | #include <linux/inet.h> |
95 | #include <linux/ipv6.h> | ||
96 | #include <linux/netdevice.h> | 95 | #include <linux/netdevice.h> |
97 | #include <net/snmp.h> | ||
98 | #include <net/ip.h> | ||
99 | #include <net/tcp_states.h> | 96 | #include <net/tcp_states.h> |
100 | #include <net/protocol.h> | ||
101 | #include <linux/skbuff.h> | 97 | #include <linux/skbuff.h> |
102 | #include <linux/proc_fs.h> | 98 | #include <linux/proc_fs.h> |
103 | #include <linux/seq_file.h> | 99 | #include <linux/seq_file.h> |
104 | #include <net/sock.h> | ||
105 | #include <net/udp.h> | ||
106 | #include <net/icmp.h> | 100 | #include <net/icmp.h> |
107 | #include <net/route.h> | 101 | #include <net/route.h> |
108 | #include <net/inet_common.h> | ||
109 | #include <net/checksum.h> | 102 | #include <net/checksum.h> |
110 | #include <net/xfrm.h> | 103 | #include <net/xfrm.h> |
104 | #include "udp_impl.h" | ||
111 | 105 | ||
112 | /* | 106 | /* |
113 | * Snmp MIB for the UDP layer | 107 | * Snmp MIB for the UDP layer |
@@ -120,26 +114,30 @@ DEFINE_RWLOCK(udp_hash_lock); | |||
120 | 114 | ||
121 | static int udp_port_rover; | 115 | static int udp_port_rover; |
122 | 116 | ||
123 | static inline int udp_lport_inuse(u16 num) | 117 | static inline int __udp_lib_lport_inuse(__u16 num, struct hlist_head udptable[]) |
124 | { | 118 | { |
125 | struct sock *sk; | 119 | struct sock *sk; |
126 | struct hlist_node *node; | 120 | struct hlist_node *node; |
127 | 121 | ||
128 | sk_for_each(sk, node, &udp_hash[num & (UDP_HTABLE_SIZE - 1)]) | 122 | sk_for_each(sk, node, &udptable[num & (UDP_HTABLE_SIZE - 1)]) |
129 | if (inet_sk(sk)->num == num) | 123 | if (inet_sk(sk)->num == num) |
130 | return 1; | 124 | return 1; |
131 | return 0; | 125 | return 0; |
132 | } | 126 | } |
133 | 127 | ||
134 | /** | 128 | /** |
135 | * udp_get_port - common port lookup for IPv4 and IPv6 | 129 | * __udp_lib_get_port - UDP/-Lite port lookup for IPv4 and IPv6 |
136 | * | 130 | * |
137 | * @sk: socket struct in question | 131 | * @sk: socket struct in question |
138 | * @snum: port number to look up | 132 | * @snum: port number to look up |
133 | * @udptable: hash list table, must be of UDP_HTABLE_SIZE | ||
134 | * @port_rover: pointer to record of last unallocated port | ||
139 | * @saddr_comp: AF-dependent comparison of bound local IP addresses | 135 | * @saddr_comp: AF-dependent comparison of bound local IP addresses |
140 | */ | 136 | */ |
141 | int udp_get_port(struct sock *sk, unsigned short snum, | 137 | int __udp_lib_get_port(struct sock *sk, unsigned short snum, |
142 | int (*saddr_cmp)(const struct sock *sk1, const struct sock *sk2)) | 138 | struct hlist_head udptable[], int *port_rover, |
139 | int (*saddr_comp)(const struct sock *sk1, | ||
140 | const struct sock *sk2 ) ) | ||
143 | { | 141 | { |
144 | struct hlist_node *node; | 142 | struct hlist_node *node; |
145 | struct hlist_head *head; | 143 | struct hlist_head *head; |
@@ -150,15 +148,15 @@ int udp_get_port(struct sock *sk, unsigned short snum, | |||
150 | if (snum == 0) { | 148 | if (snum == 0) { |
151 | int best_size_so_far, best, result, i; | 149 | int best_size_so_far, best, result, i; |
152 | 150 | ||
153 | if (udp_port_rover > sysctl_local_port_range[1] || | 151 | if (*port_rover > sysctl_local_port_range[1] || |
154 | udp_port_rover < sysctl_local_port_range[0]) | 152 | *port_rover < sysctl_local_port_range[0]) |
155 | udp_port_rover = sysctl_local_port_range[0]; | 153 | *port_rover = sysctl_local_port_range[0]; |
156 | best_size_so_far = 32767; | 154 | best_size_so_far = 32767; |
157 | best = result = udp_port_rover; | 155 | best = result = *port_rover; |
158 | for (i = 0; i < UDP_HTABLE_SIZE; i++, result++) { | 156 | for (i = 0; i < UDP_HTABLE_SIZE; i++, result++) { |
159 | int size; | 157 | int size; |
160 | 158 | ||
161 | head = &udp_hash[result & (UDP_HTABLE_SIZE - 1)]; | 159 | head = &udptable[result & (UDP_HTABLE_SIZE - 1)]; |
162 | if (hlist_empty(head)) { | 160 | if (hlist_empty(head)) { |
163 | if (result > sysctl_local_port_range[1]) | 161 | if (result > sysctl_local_port_range[1]) |
164 | result = sysctl_local_port_range[0] + | 162 | result = sysctl_local_port_range[0] + |
@@ -179,15 +177,15 @@ int udp_get_port(struct sock *sk, unsigned short snum, | |||
179 | result = sysctl_local_port_range[0] | 177 | result = sysctl_local_port_range[0] |
180 | + ((result - sysctl_local_port_range[0]) & | 178 | + ((result - sysctl_local_port_range[0]) & |
181 | (UDP_HTABLE_SIZE - 1)); | 179 | (UDP_HTABLE_SIZE - 1)); |
182 | if (!udp_lport_inuse(result)) | 180 | if (! __udp_lib_lport_inuse(result, udptable)) |
183 | break; | 181 | break; |
184 | } | 182 | } |
185 | if (i >= (1 << 16) / UDP_HTABLE_SIZE) | 183 | if (i >= (1 << 16) / UDP_HTABLE_SIZE) |
186 | goto fail; | 184 | goto fail; |
187 | gotit: | 185 | gotit: |
188 | udp_port_rover = snum = result; | 186 | *port_rover = snum = result; |
189 | } else { | 187 | } else { |
190 | head = &udp_hash[snum & (UDP_HTABLE_SIZE - 1)]; | 188 | head = &udptable[snum & (UDP_HTABLE_SIZE - 1)]; |
191 | 189 | ||
192 | sk_for_each(sk2, node, head) | 190 | sk_for_each(sk2, node, head) |
193 | if (inet_sk(sk2)->num == snum && | 191 | if (inet_sk(sk2)->num == snum && |
@@ -195,12 +193,12 @@ gotit: | |||
195 | (!sk2->sk_reuse || !sk->sk_reuse) && | 193 | (!sk2->sk_reuse || !sk->sk_reuse) && |
196 | (!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if | 194 | (!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if |
197 | || sk2->sk_bound_dev_if == sk->sk_bound_dev_if) && | 195 | || sk2->sk_bound_dev_if == sk->sk_bound_dev_if) && |
198 | (*saddr_cmp)(sk, sk2) ) | 196 | (*saddr_comp)(sk, sk2) ) |
199 | goto fail; | 197 | goto fail; |
200 | } | 198 | } |
201 | inet_sk(sk)->num = snum; | 199 | inet_sk(sk)->num = snum; |
202 | if (sk_unhashed(sk)) { | 200 | if (sk_unhashed(sk)) { |
203 | head = &udp_hash[snum & (UDP_HTABLE_SIZE - 1)]; | 201 | head = &udptable[snum & (UDP_HTABLE_SIZE - 1)]; |
204 | sk_add_node(sk, head); | 202 | sk_add_node(sk, head); |
205 | sock_prot_inc_use(sk->sk_prot); | 203 | sock_prot_inc_use(sk->sk_prot); |
206 | } | 204 | } |
@@ -210,7 +208,13 @@ fail: | |||
210 | return error; | 208 | return error; |
211 | } | 209 | } |
212 | 210 | ||
213 | static inline int ipv4_rcv_saddr_equal(const struct sock *sk1, const struct sock *sk2) | 211 | __inline__ int udp_get_port(struct sock *sk, unsigned short snum, |
212 | int (*scmp)(const struct sock *, const struct sock *)) | ||
213 | { | ||
214 | return __udp_lib_get_port(sk, snum, udp_hash, &udp_port_rover, scmp); | ||
215 | } | ||
216 | |||
217 | inline int ipv4_rcv_saddr_equal(const struct sock *sk1, const struct sock *sk2) | ||
214 | { | 218 | { |
215 | struct inet_sock *inet1 = inet_sk(sk1), *inet2 = inet_sk(sk2); | 219 | struct inet_sock *inet1 = inet_sk(sk1), *inet2 = inet_sk(sk2); |
216 | 220 | ||
@@ -224,34 +228,20 @@ static inline int udp_v4_get_port(struct sock *sk, unsigned short snum) | |||
224 | return udp_get_port(sk, snum, ipv4_rcv_saddr_equal); | 228 | return udp_get_port(sk, snum, ipv4_rcv_saddr_equal); |
225 | } | 229 | } |
226 | 230 | ||
227 | |||
228 | static void udp_v4_hash(struct sock *sk) | ||
229 | { | ||
230 | BUG(); | ||
231 | } | ||
232 | |||
233 | static void udp_v4_unhash(struct sock *sk) | ||
234 | { | ||
235 | write_lock_bh(&udp_hash_lock); | ||
236 | if (sk_del_node_init(sk)) { | ||
237 | inet_sk(sk)->num = 0; | ||
238 | sock_prot_dec_use(sk->sk_prot); | ||
239 | } | ||
240 | write_unlock_bh(&udp_hash_lock); | ||
241 | } | ||
242 | |||
243 | /* UDP is nearly always wildcards out the wazoo, it makes no sense to try | 231 | /* UDP is nearly always wildcards out the wazoo, it makes no sense to try |
244 | * harder than this. -DaveM | 232 | * harder than this. -DaveM |
245 | */ | 233 | */ |
246 | static struct sock *udp_v4_lookup_longway(__be32 saddr, __be16 sport, | 234 | static struct sock *__udp4_lib_lookup(__be32 saddr, __be16 sport, |
247 | __be32 daddr, __be16 dport, int dif) | 235 | __be32 daddr, __be16 dport, |
236 | int dif, struct hlist_head udptable[]) | ||
248 | { | 237 | { |
249 | struct sock *sk, *result = NULL; | 238 | struct sock *sk, *result = NULL; |
250 | struct hlist_node *node; | 239 | struct hlist_node *node; |
251 | unsigned short hnum = ntohs(dport); | 240 | unsigned short hnum = ntohs(dport); |
252 | int badness = -1; | 241 | int badness = -1; |
253 | 242 | ||
254 | sk_for_each(sk, node, &udp_hash[hnum & (UDP_HTABLE_SIZE - 1)]) { | 243 | read_lock(&udp_hash_lock); |
244 | sk_for_each(sk, node, &udptable[hnum & (UDP_HTABLE_SIZE - 1)]) { | ||
255 | struct inet_sock *inet = inet_sk(sk); | 245 | struct inet_sock *inet = inet_sk(sk); |
256 | 246 | ||
257 | if (inet->num == hnum && !ipv6_only_sock(sk)) { | 247 | if (inet->num == hnum && !ipv6_only_sock(sk)) { |
@@ -285,20 +275,10 @@ static struct sock *udp_v4_lookup_longway(__be32 saddr, __be16 sport, | |||
285 | } | 275 | } |
286 | } | 276 | } |
287 | } | 277 | } |
288 | return result; | 278 | if (result) |
289 | } | 279 | sock_hold(result); |
290 | |||
291 | static __inline__ struct sock *udp_v4_lookup(__be32 saddr, __be16 sport, | ||
292 | __be32 daddr, __be16 dport, int dif) | ||
293 | { | ||
294 | struct sock *sk; | ||
295 | |||
296 | read_lock(&udp_hash_lock); | ||
297 | sk = udp_v4_lookup_longway(saddr, sport, daddr, dport, dif); | ||
298 | if (sk) | ||
299 | sock_hold(sk); | ||
300 | read_unlock(&udp_hash_lock); | 280 | read_unlock(&udp_hash_lock); |
301 | return sk; | 281 | return result; |
302 | } | 282 | } |
303 | 283 | ||
304 | static inline struct sock *udp_v4_mcast_next(struct sock *sk, | 284 | static inline struct sock *udp_v4_mcast_next(struct sock *sk, |
@@ -340,7 +320,7 @@ found: | |||
340 | * to find the appropriate port. | 320 | * to find the appropriate port. |
341 | */ | 321 | */ |
342 | 322 | ||
343 | void udp_err(struct sk_buff *skb, u32 info) | 323 | void __udp4_lib_err(struct sk_buff *skb, u32 info, struct hlist_head udptable[]) |
344 | { | 324 | { |
345 | struct inet_sock *inet; | 325 | struct inet_sock *inet; |
346 | struct iphdr *iph = (struct iphdr*)skb->data; | 326 | struct iphdr *iph = (struct iphdr*)skb->data; |
@@ -351,7 +331,8 @@ void udp_err(struct sk_buff *skb, u32 info) | |||
351 | int harderr; | 331 | int harderr; |
352 | int err; | 332 | int err; |
353 | 333 | ||
354 | sk = udp_v4_lookup(iph->daddr, uh->dest, iph->saddr, uh->source, skb->dev->ifindex); | 334 | sk = __udp4_lib_lookup(iph->daddr, uh->dest, iph->saddr, uh->source, |
335 | skb->dev->ifindex, udptable ); | ||
355 | if (sk == NULL) { | 336 | if (sk == NULL) { |
356 | ICMP_INC_STATS_BH(ICMP_MIB_INERRORS); | 337 | ICMP_INC_STATS_BH(ICMP_MIB_INERRORS); |
357 | return; /* No socket for error */ | 338 | return; /* No socket for error */ |
@@ -405,6 +386,11 @@ out: | |||
405 | sock_put(sk); | 386 | sock_put(sk); |
406 | } | 387 | } |
407 | 388 | ||
389 | __inline__ void udp_err(struct sk_buff *skb, u32 info) | ||
390 | { | ||
391 | return __udp4_lib_err(skb, info, udp_hash); | ||
392 | } | ||
393 | |||
408 | /* | 394 | /* |
409 | * Throw away all pending data and cancel the corking. Socket is locked. | 395 | * Throw away all pending data and cancel the corking. Socket is locked. |
410 | */ | 396 | */ |
@@ -419,16 +405,58 @@ static void udp_flush_pending_frames(struct sock *sk) | |||
419 | } | 405 | } |
420 | } | 406 | } |
421 | 407 | ||
408 | /** | ||
409 | * udp4_hwcsum_outgoing - handle outgoing HW checksumming | ||
410 | * @sk: socket we are sending on | ||
411 | * @skb: sk_buff containing the filled-in UDP header | ||
412 | * (checksum field must be zeroed out) | ||
413 | */ | ||
414 | static void udp4_hwcsum_outgoing(struct sock *sk, struct sk_buff *skb, | ||
415 | __be32 src, __be32 dst, int len ) | ||
416 | { | ||
417 | unsigned int offset; | ||
418 | struct udphdr *uh = skb->h.uh; | ||
419 | __wsum csum = 0; | ||
420 | |||
421 | if (skb_queue_len(&sk->sk_write_queue) == 1) { | ||
422 | /* | ||
423 | * Only one fragment on the socket. | ||
424 | */ | ||
425 | skb->csum_offset = offsetof(struct udphdr, check); | ||
426 | uh->check = ~csum_tcpudp_magic(src, dst, len, IPPROTO_UDP, 0); | ||
427 | } else { | ||
428 | /* | ||
429 | * HW-checksum won't work as there are two or more | ||
430 | * fragments on the socket so that all csums of sk_buffs | ||
431 | * should be together | ||
432 | */ | ||
433 | offset = skb->h.raw - skb->data; | ||
434 | skb->csum = skb_checksum(skb, offset, skb->len - offset, 0); | ||
435 | |||
436 | skb->ip_summed = CHECKSUM_NONE; | ||
437 | |||
438 | skb_queue_walk(&sk->sk_write_queue, skb) { | ||
439 | csum = csum_add(csum, skb->csum); | ||
440 | } | ||
441 | |||
442 | uh->check = csum_tcpudp_magic(src, dst, len, IPPROTO_UDP, csum); | ||
443 | if (uh->check == 0) | ||
444 | uh->check = CSUM_MANGLED_0; | ||
445 | } | ||
446 | } | ||
447 | |||
422 | /* | 448 | /* |
423 | * Push out all pending data as one UDP datagram. Socket is locked. | 449 | * Push out all pending data as one UDP datagram. Socket is locked. |
424 | */ | 450 | */ |
425 | static int udp_push_pending_frames(struct sock *sk, struct udp_sock *up) | 451 | static int udp_push_pending_frames(struct sock *sk) |
426 | { | 452 | { |
453 | struct udp_sock *up = udp_sk(sk); | ||
427 | struct inet_sock *inet = inet_sk(sk); | 454 | struct inet_sock *inet = inet_sk(sk); |
428 | struct flowi *fl = &inet->cork.fl; | 455 | struct flowi *fl = &inet->cork.fl; |
429 | struct sk_buff *skb; | 456 | struct sk_buff *skb; |
430 | struct udphdr *uh; | 457 | struct udphdr *uh; |
431 | int err = 0; | 458 | int err = 0; |
459 | __wsum csum = 0; | ||
432 | 460 | ||
433 | /* Grab the skbuff where UDP header space exists. */ | 461 | /* Grab the skbuff where UDP header space exists. */ |
434 | if ((skb = skb_peek(&sk->sk_write_queue)) == NULL) | 462 | if ((skb = skb_peek(&sk->sk_write_queue)) == NULL) |
@@ -443,52 +471,28 @@ static int udp_push_pending_frames(struct sock *sk, struct udp_sock *up) | |||
443 | uh->len = htons(up->len); | 471 | uh->len = htons(up->len); |
444 | uh->check = 0; | 472 | uh->check = 0; |
445 | 473 | ||
446 | if (sk->sk_no_check == UDP_CSUM_NOXMIT) { | 474 | if (up->pcflag) /* UDP-Lite */ |
475 | csum = udplite_csum_outgoing(sk, skb); | ||
476 | |||
477 | else if (sk->sk_no_check == UDP_CSUM_NOXMIT) { /* UDP csum disabled */ | ||
478 | |||
447 | skb->ip_summed = CHECKSUM_NONE; | 479 | skb->ip_summed = CHECKSUM_NONE; |
448 | goto send; | 480 | goto send; |
449 | } | ||
450 | 481 | ||
451 | if (skb_queue_len(&sk->sk_write_queue) == 1) { | 482 | } else if (skb->ip_summed == CHECKSUM_PARTIAL) { /* UDP hardware csum */ |
452 | /* | ||
453 | * Only one fragment on the socket. | ||
454 | */ | ||
455 | if (skb->ip_summed == CHECKSUM_PARTIAL) { | ||
456 | skb->csum = offsetof(struct udphdr, check); | ||
457 | uh->check = ~csum_tcpudp_magic(fl->fl4_src, fl->fl4_dst, | ||
458 | up->len, IPPROTO_UDP, 0); | ||
459 | } else { | ||
460 | skb->csum = csum_partial((char *)uh, | ||
461 | sizeof(struct udphdr), skb->csum); | ||
462 | uh->check = csum_tcpudp_magic(fl->fl4_src, fl->fl4_dst, | ||
463 | up->len, IPPROTO_UDP, skb->csum); | ||
464 | if (uh->check == 0) | ||
465 | uh->check = -1; | ||
466 | } | ||
467 | } else { | ||
468 | unsigned int csum = 0; | ||
469 | /* | ||
470 | * HW-checksum won't work as there are two or more | ||
471 | * fragments on the socket so that all csums of sk_buffs | ||
472 | * should be together. | ||
473 | */ | ||
474 | if (skb->ip_summed == CHECKSUM_PARTIAL) { | ||
475 | int offset = (unsigned char *)uh - skb->data; | ||
476 | skb->csum = skb_checksum(skb, offset, skb->len - offset, 0); | ||
477 | 483 | ||
478 | skb->ip_summed = CHECKSUM_NONE; | 484 | udp4_hwcsum_outgoing(sk, skb, fl->fl4_src,fl->fl4_dst, up->len); |
479 | } else { | 485 | goto send; |
480 | skb->csum = csum_partial((char *)uh, | 486 | |
481 | sizeof(struct udphdr), skb->csum); | 487 | } else /* `normal' UDP */ |
482 | } | 488 | csum = udp_csum_outgoing(sk, skb); |
489 | |||
490 | /* add protocol-dependent pseudo-header */ | ||
491 | uh->check = csum_tcpudp_magic(fl->fl4_src, fl->fl4_dst, up->len, | ||
492 | sk->sk_protocol, csum ); | ||
493 | if (uh->check == 0) | ||
494 | uh->check = CSUM_MANGLED_0; | ||
483 | 495 | ||
484 | skb_queue_walk(&sk->sk_write_queue, skb) { | ||
485 | csum = csum_add(csum, skb->csum); | ||
486 | } | ||
487 | uh->check = csum_tcpudp_magic(fl->fl4_src, fl->fl4_dst, | ||
488 | up->len, IPPROTO_UDP, csum); | ||
489 | if (uh->check == 0) | ||
490 | uh->check = -1; | ||
491 | } | ||
492 | send: | 496 | send: |
493 | err = ip_push_pending_frames(sk); | 497 | err = ip_push_pending_frames(sk); |
494 | out: | 498 | out: |
@@ -497,12 +501,6 @@ out: | |||
497 | return err; | 501 | return err; |
498 | } | 502 | } |
499 | 503 | ||
500 | |||
501 | static unsigned short udp_check(struct udphdr *uh, int len, __be32 saddr, __be32 daddr, unsigned long base) | ||
502 | { | ||
503 | return(csum_tcpudp_magic(saddr, daddr, len, IPPROTO_UDP, base)); | ||
504 | } | ||
505 | |||
506 | int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | 504 | int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, |
507 | size_t len) | 505 | size_t len) |
508 | { | 506 | { |
@@ -516,8 +514,9 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
516 | __be32 daddr, faddr, saddr; | 514 | __be32 daddr, faddr, saddr; |
517 | __be16 dport; | 515 | __be16 dport; |
518 | u8 tos; | 516 | u8 tos; |
519 | int err; | 517 | int err, is_udplite = up->pcflag; |
520 | int corkreq = up->corkflag || msg->msg_flags&MSG_MORE; | 518 | int corkreq = up->corkflag || msg->msg_flags&MSG_MORE; |
519 | int (*getfrag)(void *, char *, int, int, int, struct sk_buff *); | ||
521 | 520 | ||
522 | if (len > 0xFFFF) | 521 | if (len > 0xFFFF) |
523 | return -EMSGSIZE; | 522 | return -EMSGSIZE; |
@@ -622,7 +621,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
622 | { .daddr = faddr, | 621 | { .daddr = faddr, |
623 | .saddr = saddr, | 622 | .saddr = saddr, |
624 | .tos = tos } }, | 623 | .tos = tos } }, |
625 | .proto = IPPROTO_UDP, | 624 | .proto = sk->sk_protocol, |
626 | .uli_u = { .ports = | 625 | .uli_u = { .ports = |
627 | { .sport = inet->sport, | 626 | { .sport = inet->sport, |
628 | .dport = dport } } }; | 627 | .dport = dport } } }; |
@@ -668,13 +667,14 @@ back_from_confirm: | |||
668 | 667 | ||
669 | do_append_data: | 668 | do_append_data: |
670 | up->len += ulen; | 669 | up->len += ulen; |
671 | err = ip_append_data(sk, ip_generic_getfrag, msg->msg_iov, ulen, | 670 | getfrag = is_udplite ? udplite_getfrag : ip_generic_getfrag; |
672 | sizeof(struct udphdr), &ipc, rt, | 671 | err = ip_append_data(sk, getfrag, msg->msg_iov, ulen, |
672 | sizeof(struct udphdr), &ipc, rt, | ||
673 | corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags); | 673 | corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags); |
674 | if (err) | 674 | if (err) |
675 | udp_flush_pending_frames(sk); | 675 | udp_flush_pending_frames(sk); |
676 | else if (!corkreq) | 676 | else if (!corkreq) |
677 | err = udp_push_pending_frames(sk, up); | 677 | err = udp_push_pending_frames(sk); |
678 | else if (unlikely(skb_queue_empty(&sk->sk_write_queue))) | 678 | else if (unlikely(skb_queue_empty(&sk->sk_write_queue))) |
679 | up->pending = 0; | 679 | up->pending = 0; |
680 | release_sock(sk); | 680 | release_sock(sk); |
@@ -684,7 +684,7 @@ out: | |||
684 | if (free) | 684 | if (free) |
685 | kfree(ipc.opt); | 685 | kfree(ipc.opt); |
686 | if (!err) { | 686 | if (!err) { |
687 | UDP_INC_STATS_USER(UDP_MIB_OUTDATAGRAMS); | 687 | UDP_INC_STATS_USER(UDP_MIB_OUTDATAGRAMS, is_udplite); |
688 | return len; | 688 | return len; |
689 | } | 689 | } |
690 | /* | 690 | /* |
@@ -695,7 +695,7 @@ out: | |||
695 | * seems like overkill. | 695 | * seems like overkill. |
696 | */ | 696 | */ |
697 | if (err == -ENOBUFS || test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) { | 697 | if (err == -ENOBUFS || test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) { |
698 | UDP_INC_STATS_USER(UDP_MIB_SNDBUFERRORS); | 698 | UDP_INC_STATS_USER(UDP_MIB_SNDBUFERRORS, is_udplite); |
699 | } | 699 | } |
700 | return err; | 700 | return err; |
701 | 701 | ||
@@ -707,8 +707,8 @@ do_confirm: | |||
707 | goto out; | 707 | goto out; |
708 | } | 708 | } |
709 | 709 | ||
710 | static int udp_sendpage(struct sock *sk, struct page *page, int offset, | 710 | int udp_sendpage(struct sock *sk, struct page *page, int offset, |
711 | size_t size, int flags) | 711 | size_t size, int flags) |
712 | { | 712 | { |
713 | struct udp_sock *up = udp_sk(sk); | 713 | struct udp_sock *up = udp_sk(sk); |
714 | int ret; | 714 | int ret; |
@@ -747,7 +747,7 @@ static int udp_sendpage(struct sock *sk, struct page *page, int offset, | |||
747 | 747 | ||
748 | up->len += size; | 748 | up->len += size; |
749 | if (!(up->corkflag || (flags&MSG_MORE))) | 749 | if (!(up->corkflag || (flags&MSG_MORE))) |
750 | ret = udp_push_pending_frames(sk, up); | 750 | ret = udp_push_pending_frames(sk); |
751 | if (!ret) | 751 | if (!ret) |
752 | ret = size; | 752 | ret = size; |
753 | out: | 753 | out: |
@@ -795,29 +795,18 @@ int udp_ioctl(struct sock *sk, int cmd, unsigned long arg) | |||
795 | return(0); | 795 | return(0); |
796 | } | 796 | } |
797 | 797 | ||
798 | static __inline__ int __udp_checksum_complete(struct sk_buff *skb) | ||
799 | { | ||
800 | return __skb_checksum_complete(skb); | ||
801 | } | ||
802 | |||
803 | static __inline__ int udp_checksum_complete(struct sk_buff *skb) | ||
804 | { | ||
805 | return skb->ip_summed != CHECKSUM_UNNECESSARY && | ||
806 | __udp_checksum_complete(skb); | ||
807 | } | ||
808 | |||
809 | /* | 798 | /* |
810 | * This should be easy, if there is something there we | 799 | * This should be easy, if there is something there we |
811 | * return it, otherwise we block. | 800 | * return it, otherwise we block. |
812 | */ | 801 | */ |
813 | 802 | ||
814 | static int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | 803 | int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, |
815 | size_t len, int noblock, int flags, int *addr_len) | 804 | size_t len, int noblock, int flags, int *addr_len) |
816 | { | 805 | { |
817 | struct inet_sock *inet = inet_sk(sk); | 806 | struct inet_sock *inet = inet_sk(sk); |
818 | struct sockaddr_in *sin = (struct sockaddr_in *)msg->msg_name; | 807 | struct sockaddr_in *sin = (struct sockaddr_in *)msg->msg_name; |
819 | struct sk_buff *skb; | 808 | struct sk_buff *skb; |
820 | int copied, err; | 809 | int copied, err, copy_only, is_udplite = IS_UDPLITE(sk); |
821 | 810 | ||
822 | /* | 811 | /* |
823 | * Check any passed addresses | 812 | * Check any passed addresses |
@@ -839,15 +828,25 @@ try_again: | |||
839 | msg->msg_flags |= MSG_TRUNC; | 828 | msg->msg_flags |= MSG_TRUNC; |
840 | } | 829 | } |
841 | 830 | ||
842 | if (skb->ip_summed==CHECKSUM_UNNECESSARY) { | 831 | /* |
843 | err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov, | 832 | * Decide whether to checksum and/or copy data. |
844 | copied); | 833 | * |
845 | } else if (msg->msg_flags&MSG_TRUNC) { | 834 | * UDP: checksum may have been computed in HW, |
846 | if (__udp_checksum_complete(skb)) | 835 | * (re-)compute it if message is truncated. |
836 | * UDP-Lite: always needs to checksum, no HW support. | ||
837 | */ | ||
838 | copy_only = (skb->ip_summed==CHECKSUM_UNNECESSARY); | ||
839 | |||
840 | if (is_udplite || (!copy_only && msg->msg_flags&MSG_TRUNC)) { | ||
841 | if (__udp_lib_checksum_complete(skb)) | ||
847 | goto csum_copy_err; | 842 | goto csum_copy_err; |
848 | err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov, | 843 | copy_only = 1; |
849 | copied); | 844 | } |
850 | } else { | 845 | |
846 | if (copy_only) | ||
847 | err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), | ||
848 | msg->msg_iov, copied ); | ||
849 | else { | ||
851 | err = skb_copy_and_csum_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov); | 850 | err = skb_copy_and_csum_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov); |
852 | 851 | ||
853 | if (err == -EINVAL) | 852 | if (err == -EINVAL) |
@@ -880,7 +879,7 @@ out: | |||
880 | return err; | 879 | return err; |
881 | 880 | ||
882 | csum_copy_err: | 881 | csum_copy_err: |
883 | UDP_INC_STATS_BH(UDP_MIB_INERRORS); | 882 | UDP_INC_STATS_BH(UDP_MIB_INERRORS, is_udplite); |
884 | 883 | ||
885 | skb_kill_datagram(sk, skb, flags); | 884 | skb_kill_datagram(sk, skb, flags); |
886 | 885 | ||
@@ -912,11 +911,6 @@ int udp_disconnect(struct sock *sk, int flags) | |||
912 | return 0; | 911 | return 0; |
913 | } | 912 | } |
914 | 913 | ||
915 | static void udp_close(struct sock *sk, long timeout) | ||
916 | { | ||
917 | sk_common_release(sk); | ||
918 | } | ||
919 | |||
920 | /* return: | 914 | /* return: |
921 | * 1 if the the UDP system should process it | 915 | * 1 if the the UDP system should process it |
922 | * 0 if we should drop this packet | 916 | * 0 if we should drop this packet |
@@ -928,23 +922,32 @@ static int udp_encap_rcv(struct sock * sk, struct sk_buff *skb) | |||
928 | return 1; | 922 | return 1; |
929 | #else | 923 | #else |
930 | struct udp_sock *up = udp_sk(sk); | 924 | struct udp_sock *up = udp_sk(sk); |
931 | struct udphdr *uh = skb->h.uh; | 925 | struct udphdr *uh; |
932 | struct iphdr *iph; | 926 | struct iphdr *iph; |
933 | int iphlen, len; | 927 | int iphlen, len; |
934 | 928 | ||
935 | __u8 *udpdata = (__u8 *)uh + sizeof(struct udphdr); | 929 | __u8 *udpdata; |
936 | __be32 *udpdata32 = (__be32 *)udpdata; | 930 | __be32 *udpdata32; |
937 | __u16 encap_type = up->encap_type; | 931 | __u16 encap_type = up->encap_type; |
938 | 932 | ||
939 | /* if we're overly short, let UDP handle it */ | 933 | /* if we're overly short, let UDP handle it */ |
940 | if (udpdata > skb->tail) | 934 | len = skb->len - sizeof(struct udphdr); |
935 | if (len <= 0) | ||
941 | return 1; | 936 | return 1; |
942 | 937 | ||
943 | /* if this is not encapsulated socket, then just return now */ | 938 | /* if this is not encapsulated socket, then just return now */ |
944 | if (!encap_type) | 939 | if (!encap_type) |
945 | return 1; | 940 | return 1; |
946 | 941 | ||
947 | len = skb->tail - udpdata; | 942 | /* If this is a paged skb, make sure we pull up |
943 | * whatever data we need to look at. */ | ||
944 | if (!pskb_may_pull(skb, sizeof(struct udphdr) + min(len, 8))) | ||
945 | return 1; | ||
946 | |||
947 | /* Now we can get the pointers */ | ||
948 | uh = skb->h.uh; | ||
949 | udpdata = (__u8 *)uh + sizeof(struct udphdr); | ||
950 | udpdata32 = (__be32 *)udpdata; | ||
948 | 951 | ||
949 | switch (encap_type) { | 952 | switch (encap_type) { |
950 | default: | 953 | default: |
@@ -1013,7 +1016,7 @@ static int udp_encap_rcv(struct sock * sk, struct sk_buff *skb) | |||
1013 | * Note that in the success and error cases, the skb is assumed to | 1016 | * Note that in the success and error cases, the skb is assumed to |
1014 | * have either been requeued or freed. | 1017 | * have either been requeued or freed. |
1015 | */ | 1018 | */ |
1016 | static int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) | 1019 | int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) |
1017 | { | 1020 | { |
1018 | struct udp_sock *up = udp_sk(sk); | 1021 | struct udp_sock *up = udp_sk(sk); |
1019 | int rc; | 1022 | int rc; |
@@ -1021,10 +1024,8 @@ static int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) | |||
1021 | /* | 1024 | /* |
1022 | * Charge it to the socket, dropping if the queue is full. | 1025 | * Charge it to the socket, dropping if the queue is full. |
1023 | */ | 1026 | */ |
1024 | if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb)) { | 1027 | if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb)) |
1025 | kfree_skb(skb); | 1028 | goto drop; |
1026 | return -1; | ||
1027 | } | ||
1028 | nf_reset(skb); | 1029 | nf_reset(skb); |
1029 | 1030 | ||
1030 | if (up->encap_type) { | 1031 | if (up->encap_type) { |
@@ -1048,31 +1049,68 @@ static int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) | |||
1048 | if (ret < 0) { | 1049 | if (ret < 0) { |
1049 | /* process the ESP packet */ | 1050 | /* process the ESP packet */ |
1050 | ret = xfrm4_rcv_encap(skb, up->encap_type); | 1051 | ret = xfrm4_rcv_encap(skb, up->encap_type); |
1051 | UDP_INC_STATS_BH(UDP_MIB_INDATAGRAMS); | 1052 | UDP_INC_STATS_BH(UDP_MIB_INDATAGRAMS, up->pcflag); |
1052 | return -ret; | 1053 | return -ret; |
1053 | } | 1054 | } |
1054 | /* FALLTHROUGH -- it's a UDP Packet */ | 1055 | /* FALLTHROUGH -- it's a UDP Packet */ |
1055 | } | 1056 | } |
1056 | 1057 | ||
1057 | if (sk->sk_filter && skb->ip_summed != CHECKSUM_UNNECESSARY) { | 1058 | /* |
1058 | if (__udp_checksum_complete(skb)) { | 1059 | * UDP-Lite specific tests, ignored on UDP sockets |
1059 | UDP_INC_STATS_BH(UDP_MIB_INERRORS); | 1060 | */ |
1060 | kfree_skb(skb); | 1061 | if ((up->pcflag & UDPLITE_RECV_CC) && UDP_SKB_CB(skb)->partial_cov) { |
1061 | return -1; | 1062 | |
1063 | /* | ||
1064 | * MIB statistics other than incrementing the error count are | ||
1065 | * disabled for the following two types of errors: these depend | ||
1066 | * on the application settings, not on the functioning of the | ||
1067 | * protocol stack as such. | ||
1068 | * | ||
1069 | * RFC 3828 here recommends (sec 3.3): "There should also be a | ||
1070 | * way ... to ... at least let the receiving application block | ||
1071 | * delivery of packets with coverage values less than a value | ||
1072 | * provided by the application." | ||
1073 | */ | ||
1074 | if (up->pcrlen == 0) { /* full coverage was set */ | ||
1075 | LIMIT_NETDEBUG(KERN_WARNING "UDPLITE: partial coverage " | ||
1076 | "%d while full coverage %d requested\n", | ||
1077 | UDP_SKB_CB(skb)->cscov, skb->len); | ||
1078 | goto drop; | ||
1062 | } | 1079 | } |
1080 | /* The next case involves violating the min. coverage requested | ||
1081 | * by the receiver. This is subtle: if receiver wants x and x is | ||
1082 | * greater than the buffersize/MTU then receiver will complain | ||
1083 | * that it wants x while sender emits packets of smaller size y. | ||
1084 | * Therefore the above ...()->partial_cov statement is essential. | ||
1085 | */ | ||
1086 | if (UDP_SKB_CB(skb)->cscov < up->pcrlen) { | ||
1087 | LIMIT_NETDEBUG(KERN_WARNING | ||
1088 | "UDPLITE: coverage %d too small, need min %d\n", | ||
1089 | UDP_SKB_CB(skb)->cscov, up->pcrlen); | ||
1090 | goto drop; | ||
1091 | } | ||
1092 | } | ||
1093 | |||
1094 | if (sk->sk_filter && skb->ip_summed != CHECKSUM_UNNECESSARY) { | ||
1095 | if (__udp_lib_checksum_complete(skb)) | ||
1096 | goto drop; | ||
1063 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 1097 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
1064 | } | 1098 | } |
1065 | 1099 | ||
1066 | if ((rc = sock_queue_rcv_skb(sk,skb)) < 0) { | 1100 | if ((rc = sock_queue_rcv_skb(sk,skb)) < 0) { |
1067 | /* Note that an ENOMEM error is charged twice */ | 1101 | /* Note that an ENOMEM error is charged twice */ |
1068 | if (rc == -ENOMEM) | 1102 | if (rc == -ENOMEM) |
1069 | UDP_INC_STATS_BH(UDP_MIB_RCVBUFERRORS); | 1103 | UDP_INC_STATS_BH(UDP_MIB_RCVBUFERRORS, up->pcflag); |
1070 | UDP_INC_STATS_BH(UDP_MIB_INERRORS); | 1104 | goto drop; |
1071 | kfree_skb(skb); | ||
1072 | return -1; | ||
1073 | } | 1105 | } |
1074 | UDP_INC_STATS_BH(UDP_MIB_INDATAGRAMS); | 1106 | |
1107 | UDP_INC_STATS_BH(UDP_MIB_INDATAGRAMS, up->pcflag); | ||
1075 | return 0; | 1108 | return 0; |
1109 | |||
1110 | drop: | ||
1111 | UDP_INC_STATS_BH(UDP_MIB_INERRORS, up->pcflag); | ||
1112 | kfree_skb(skb); | ||
1113 | return -1; | ||
1076 | } | 1114 | } |
1077 | 1115 | ||
1078 | /* | 1116 | /* |
@@ -1081,14 +1119,16 @@ static int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) | |||
1081 | * Note: called only from the BH handler context, | 1119 | * Note: called only from the BH handler context, |
1082 | * so we don't need to lock the hashes. | 1120 | * so we don't need to lock the hashes. |
1083 | */ | 1121 | */ |
1084 | static int udp_v4_mcast_deliver(struct sk_buff *skb, struct udphdr *uh, | 1122 | static int __udp4_lib_mcast_deliver(struct sk_buff *skb, |
1085 | __be32 saddr, __be32 daddr) | 1123 | struct udphdr *uh, |
1124 | __be32 saddr, __be32 daddr, | ||
1125 | struct hlist_head udptable[]) | ||
1086 | { | 1126 | { |
1087 | struct sock *sk; | 1127 | struct sock *sk; |
1088 | int dif; | 1128 | int dif; |
1089 | 1129 | ||
1090 | read_lock(&udp_hash_lock); | 1130 | read_lock(&udp_hash_lock); |
1091 | sk = sk_head(&udp_hash[ntohs(uh->dest) & (UDP_HTABLE_SIZE - 1)]); | 1131 | sk = sk_head(&udptable[ntohs(uh->dest) & (UDP_HTABLE_SIZE - 1)]); |
1092 | dif = skb->dev->ifindex; | 1132 | dif = skb->dev->ifindex; |
1093 | sk = udp_v4_mcast_next(sk, uh->dest, daddr, uh->source, saddr, dif); | 1133 | sk = udp_v4_mcast_next(sk, uh->dest, daddr, uh->source, saddr, dif); |
1094 | if (sk) { | 1134 | if (sk) { |
@@ -1122,65 +1162,75 @@ static int udp_v4_mcast_deliver(struct sk_buff *skb, struct udphdr *uh, | |||
1122 | * Otherwise, csum completion requires chacksumming packet body, | 1162 | * Otherwise, csum completion requires chacksumming packet body, |
1123 | * including udp header and folding it to skb->csum. | 1163 | * including udp header and folding it to skb->csum. |
1124 | */ | 1164 | */ |
1125 | static void udp_checksum_init(struct sk_buff *skb, struct udphdr *uh, | 1165 | static inline void udp4_csum_init(struct sk_buff *skb, struct udphdr *uh) |
1126 | unsigned short ulen, __be32 saddr, __be32 daddr) | ||
1127 | { | 1166 | { |
1128 | if (uh->check == 0) { | 1167 | if (uh->check == 0) { |
1129 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 1168 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
1130 | } else if (skb->ip_summed == CHECKSUM_COMPLETE) { | 1169 | } else if (skb->ip_summed == CHECKSUM_COMPLETE) { |
1131 | if (!udp_check(uh, ulen, saddr, daddr, skb->csum)) | 1170 | if (!csum_tcpudp_magic(skb->nh.iph->saddr, skb->nh.iph->daddr, |
1171 | skb->len, IPPROTO_UDP, skb->csum )) | ||
1132 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 1172 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
1133 | } | 1173 | } |
1134 | if (skb->ip_summed != CHECKSUM_UNNECESSARY) | 1174 | if (skb->ip_summed != CHECKSUM_UNNECESSARY) |
1135 | skb->csum = csum_tcpudp_nofold(saddr, daddr, ulen, IPPROTO_UDP, 0); | 1175 | skb->csum = csum_tcpudp_nofold(skb->nh.iph->saddr, |
1176 | skb->nh.iph->daddr, | ||
1177 | skb->len, IPPROTO_UDP, 0); | ||
1136 | /* Probably, we should checksum udp header (it should be in cache | 1178 | /* Probably, we should checksum udp header (it should be in cache |
1137 | * in any case) and data in tiny packets (< rx copybreak). | 1179 | * in any case) and data in tiny packets (< rx copybreak). |
1138 | */ | 1180 | */ |
1181 | |||
1182 | /* UDP = UDP-Lite with a non-partial checksum coverage */ | ||
1183 | UDP_SKB_CB(skb)->partial_cov = 0; | ||
1139 | } | 1184 | } |
1140 | 1185 | ||
1141 | /* | 1186 | /* |
1142 | * All we need to do is get the socket, and then do a checksum. | 1187 | * All we need to do is get the socket, and then do a checksum. |
1143 | */ | 1188 | */ |
1144 | 1189 | ||
1145 | int udp_rcv(struct sk_buff *skb) | 1190 | int __udp4_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[], |
1191 | int is_udplite) | ||
1146 | { | 1192 | { |
1147 | struct sock *sk; | 1193 | struct sock *sk; |
1148 | struct udphdr *uh; | 1194 | struct udphdr *uh = skb->h.uh; |
1149 | unsigned short ulen; | 1195 | unsigned short ulen; |
1150 | struct rtable *rt = (struct rtable*)skb->dst; | 1196 | struct rtable *rt = (struct rtable*)skb->dst; |
1151 | __be32 saddr = skb->nh.iph->saddr; | 1197 | __be32 saddr = skb->nh.iph->saddr; |
1152 | __be32 daddr = skb->nh.iph->daddr; | 1198 | __be32 daddr = skb->nh.iph->daddr; |
1153 | int len = skb->len; | ||
1154 | 1199 | ||
1155 | /* | 1200 | /* |
1156 | * Validate the packet and the UDP length. | 1201 | * Validate the packet. |
1157 | */ | 1202 | */ |
1158 | if (!pskb_may_pull(skb, sizeof(struct udphdr))) | 1203 | if (!pskb_may_pull(skb, sizeof(struct udphdr))) |
1159 | goto no_header; | 1204 | goto drop; /* No space for header. */ |
1160 | |||
1161 | uh = skb->h.uh; | ||
1162 | 1205 | ||
1163 | ulen = ntohs(uh->len); | 1206 | ulen = ntohs(uh->len); |
1164 | 1207 | if (ulen > skb->len) | |
1165 | if (ulen > len || ulen < sizeof(*uh)) | ||
1166 | goto short_packet; | 1208 | goto short_packet; |
1167 | 1209 | ||
1168 | if (pskb_trim_rcsum(skb, ulen)) | 1210 | if(! is_udplite ) { /* UDP validates ulen. */ |
1169 | goto short_packet; | 1211 | |
1212 | if (ulen < sizeof(*uh) || pskb_trim_rcsum(skb, ulen)) | ||
1213 | goto short_packet; | ||
1170 | 1214 | ||
1171 | udp_checksum_init(skb, uh, ulen, saddr, daddr); | 1215 | udp4_csum_init(skb, uh); |
1216 | |||
1217 | } else { /* UDP-Lite validates cscov. */ | ||
1218 | if (udplite4_csum_init(skb, uh)) | ||
1219 | goto csum_error; | ||
1220 | } | ||
1172 | 1221 | ||
1173 | if(rt->rt_flags & (RTCF_BROADCAST|RTCF_MULTICAST)) | 1222 | if(rt->rt_flags & (RTCF_BROADCAST|RTCF_MULTICAST)) |
1174 | return udp_v4_mcast_deliver(skb, uh, saddr, daddr); | 1223 | return __udp4_lib_mcast_deliver(skb, uh, saddr, daddr, udptable); |
1175 | 1224 | ||
1176 | sk = udp_v4_lookup(saddr, uh->source, daddr, uh->dest, skb->dev->ifindex); | 1225 | sk = __udp4_lib_lookup(saddr, uh->source, daddr, uh->dest, |
1226 | skb->dev->ifindex, udptable ); | ||
1177 | 1227 | ||
1178 | if (sk != NULL) { | 1228 | if (sk != NULL) { |
1179 | int ret = udp_queue_rcv_skb(sk, skb); | 1229 | int ret = udp_queue_rcv_skb(sk, skb); |
1180 | sock_put(sk); | 1230 | sock_put(sk); |
1181 | 1231 | ||
1182 | /* a return value > 0 means to resubmit the input, but | 1232 | /* a return value > 0 means to resubmit the input, but |
1183 | * it it wants the return to be -protocol, or 0 | 1233 | * it wants the return to be -protocol, or 0 |
1184 | */ | 1234 | */ |
1185 | if (ret > 0) | 1235 | if (ret > 0) |
1186 | return -ret; | 1236 | return -ret; |
@@ -1192,10 +1242,10 @@ int udp_rcv(struct sk_buff *skb) | |||
1192 | nf_reset(skb); | 1242 | nf_reset(skb); |
1193 | 1243 | ||
1194 | /* No socket. Drop packet silently, if checksum is wrong */ | 1244 | /* No socket. Drop packet silently, if checksum is wrong */ |
1195 | if (udp_checksum_complete(skb)) | 1245 | if (udp_lib_checksum_complete(skb)) |
1196 | goto csum_error; | 1246 | goto csum_error; |
1197 | 1247 | ||
1198 | UDP_INC_STATS_BH(UDP_MIB_NOPORTS); | 1248 | UDP_INC_STATS_BH(UDP_MIB_NOPORTS, is_udplite); |
1199 | icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); | 1249 | icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); |
1200 | 1250 | ||
1201 | /* | 1251 | /* |
@@ -1206,36 +1256,40 @@ int udp_rcv(struct sk_buff *skb) | |||
1206 | return(0); | 1256 | return(0); |
1207 | 1257 | ||
1208 | short_packet: | 1258 | short_packet: |
1209 | LIMIT_NETDEBUG(KERN_DEBUG "UDP: short packet: From %u.%u.%u.%u:%u %d/%d to %u.%u.%u.%u:%u\n", | 1259 | LIMIT_NETDEBUG(KERN_DEBUG "UDP%s: short packet: From %u.%u.%u.%u:%u %d/%d to %u.%u.%u.%u:%u\n", |
1260 | is_udplite? "-Lite" : "", | ||
1210 | NIPQUAD(saddr), | 1261 | NIPQUAD(saddr), |
1211 | ntohs(uh->source), | 1262 | ntohs(uh->source), |
1212 | ulen, | 1263 | ulen, |
1213 | len, | 1264 | skb->len, |
1214 | NIPQUAD(daddr), | 1265 | NIPQUAD(daddr), |
1215 | ntohs(uh->dest)); | 1266 | ntohs(uh->dest)); |
1216 | no_header: | 1267 | goto drop; |
1217 | UDP_INC_STATS_BH(UDP_MIB_INERRORS); | ||
1218 | kfree_skb(skb); | ||
1219 | return(0); | ||
1220 | 1268 | ||
1221 | csum_error: | 1269 | csum_error: |
1222 | /* | 1270 | /* |
1223 | * RFC1122: OK. Discards the bad packet silently (as far as | 1271 | * RFC1122: OK. Discards the bad packet silently (as far as |
1224 | * the network is concerned, anyway) as per 4.1.3.4 (MUST). | 1272 | * the network is concerned, anyway) as per 4.1.3.4 (MUST). |
1225 | */ | 1273 | */ |
1226 | LIMIT_NETDEBUG(KERN_DEBUG "UDP: bad checksum. From %d.%d.%d.%d:%d to %d.%d.%d.%d:%d ulen %d\n", | 1274 | LIMIT_NETDEBUG(KERN_DEBUG "UDP%s: bad checksum. From %d.%d.%d.%d:%d to %d.%d.%d.%d:%d ulen %d\n", |
1275 | is_udplite? "-Lite" : "", | ||
1227 | NIPQUAD(saddr), | 1276 | NIPQUAD(saddr), |
1228 | ntohs(uh->source), | 1277 | ntohs(uh->source), |
1229 | NIPQUAD(daddr), | 1278 | NIPQUAD(daddr), |
1230 | ntohs(uh->dest), | 1279 | ntohs(uh->dest), |
1231 | ulen); | 1280 | ulen); |
1232 | drop: | 1281 | drop: |
1233 | UDP_INC_STATS_BH(UDP_MIB_INERRORS); | 1282 | UDP_INC_STATS_BH(UDP_MIB_INERRORS, is_udplite); |
1234 | kfree_skb(skb); | 1283 | kfree_skb(skb); |
1235 | return(0); | 1284 | return(0); |
1236 | } | 1285 | } |
1237 | 1286 | ||
1238 | static int udp_destroy_sock(struct sock *sk) | 1287 | __inline__ int udp_rcv(struct sk_buff *skb) |
1288 | { | ||
1289 | return __udp4_lib_rcv(skb, udp_hash, 0); | ||
1290 | } | ||
1291 | |||
1292 | int udp_destroy_sock(struct sock *sk) | ||
1239 | { | 1293 | { |
1240 | lock_sock(sk); | 1294 | lock_sock(sk); |
1241 | udp_flush_pending_frames(sk); | 1295 | udp_flush_pending_frames(sk); |
@@ -1246,8 +1300,9 @@ static int udp_destroy_sock(struct sock *sk) | |||
1246 | /* | 1300 | /* |
1247 | * Socket option code for UDP | 1301 | * Socket option code for UDP |
1248 | */ | 1302 | */ |
1249 | static int do_udp_setsockopt(struct sock *sk, int level, int optname, | 1303 | int udp_lib_setsockopt(struct sock *sk, int level, int optname, |
1250 | char __user *optval, int optlen) | 1304 | char __user *optval, int optlen, |
1305 | int (*push_pending_frames)(struct sock *)) | ||
1251 | { | 1306 | { |
1252 | struct udp_sock *up = udp_sk(sk); | 1307 | struct udp_sock *up = udp_sk(sk); |
1253 | int val; | 1308 | int val; |
@@ -1266,7 +1321,7 @@ static int do_udp_setsockopt(struct sock *sk, int level, int optname, | |||
1266 | } else { | 1321 | } else { |
1267 | up->corkflag = 0; | 1322 | up->corkflag = 0; |
1268 | lock_sock(sk); | 1323 | lock_sock(sk); |
1269 | udp_push_pending_frames(sk, up); | 1324 | (*push_pending_frames)(sk); |
1270 | release_sock(sk); | 1325 | release_sock(sk); |
1271 | } | 1326 | } |
1272 | break; | 1327 | break; |
@@ -1284,6 +1339,32 @@ static int do_udp_setsockopt(struct sock *sk, int level, int optname, | |||
1284 | } | 1339 | } |
1285 | break; | 1340 | break; |
1286 | 1341 | ||
1342 | /* | ||
1343 | * UDP-Lite's partial checksum coverage (RFC 3828). | ||
1344 | */ | ||
1345 | /* The sender sets actual checksum coverage length via this option. | ||
1346 | * The case coverage > packet length is handled by send module. */ | ||
1347 | case UDPLITE_SEND_CSCOV: | ||
1348 | if (!up->pcflag) /* Disable the option on UDP sockets */ | ||
1349 | return -ENOPROTOOPT; | ||
1350 | if (val != 0 && val < 8) /* Illegal coverage: use default (8) */ | ||
1351 | val = 8; | ||
1352 | up->pcslen = val; | ||
1353 | up->pcflag |= UDPLITE_SEND_CC; | ||
1354 | break; | ||
1355 | |||
1356 | /* The receiver specifies a minimum checksum coverage value. To make | ||
1357 | * sense, this should be set to at least 8 (as done below). If zero is | ||
1358 | * used, this again means full checksum coverage. */ | ||
1359 | case UDPLITE_RECV_CSCOV: | ||
1360 | if (!up->pcflag) /* Disable the option on UDP sockets */ | ||
1361 | return -ENOPROTOOPT; | ||
1362 | if (val != 0 && val < 8) /* Avoid silly minimal values. */ | ||
1363 | val = 8; | ||
1364 | up->pcrlen = val; | ||
1365 | up->pcflag |= UDPLITE_RECV_CC; | ||
1366 | break; | ||
1367 | |||
1287 | default: | 1368 | default: |
1288 | err = -ENOPROTOOPT; | 1369 | err = -ENOPROTOOPT; |
1289 | break; | 1370 | break; |
@@ -1292,26 +1373,28 @@ static int do_udp_setsockopt(struct sock *sk, int level, int optname, | |||
1292 | return err; | 1373 | return err; |
1293 | } | 1374 | } |
1294 | 1375 | ||
1295 | static int udp_setsockopt(struct sock *sk, int level, int optname, | 1376 | int udp_setsockopt(struct sock *sk, int level, int optname, |
1296 | char __user *optval, int optlen) | 1377 | char __user *optval, int optlen) |
1297 | { | 1378 | { |
1298 | if (level != SOL_UDP) | 1379 | if (level == SOL_UDP || level == SOL_UDPLITE) |
1299 | return ip_setsockopt(sk, level, optname, optval, optlen); | 1380 | return udp_lib_setsockopt(sk, level, optname, optval, optlen, |
1300 | return do_udp_setsockopt(sk, level, optname, optval, optlen); | 1381 | udp_push_pending_frames); |
1382 | return ip_setsockopt(sk, level, optname, optval, optlen); | ||
1301 | } | 1383 | } |
1302 | 1384 | ||
1303 | #ifdef CONFIG_COMPAT | 1385 | #ifdef CONFIG_COMPAT |
1304 | static int compat_udp_setsockopt(struct sock *sk, int level, int optname, | 1386 | int compat_udp_setsockopt(struct sock *sk, int level, int optname, |
1305 | char __user *optval, int optlen) | 1387 | char __user *optval, int optlen) |
1306 | { | 1388 | { |
1307 | if (level != SOL_UDP) | 1389 | if (level == SOL_UDP || level == SOL_UDPLITE) |
1308 | return compat_ip_setsockopt(sk, level, optname, optval, optlen); | 1390 | return udp_lib_setsockopt(sk, level, optname, optval, optlen, |
1309 | return do_udp_setsockopt(sk, level, optname, optval, optlen); | 1391 | udp_push_pending_frames); |
1392 | return compat_ip_setsockopt(sk, level, optname, optval, optlen); | ||
1310 | } | 1393 | } |
1311 | #endif | 1394 | #endif |
1312 | 1395 | ||
1313 | static int do_udp_getsockopt(struct sock *sk, int level, int optname, | 1396 | int udp_lib_getsockopt(struct sock *sk, int level, int optname, |
1314 | char __user *optval, int __user *optlen) | 1397 | char __user *optval, int __user *optlen) |
1315 | { | 1398 | { |
1316 | struct udp_sock *up = udp_sk(sk); | 1399 | struct udp_sock *up = udp_sk(sk); |
1317 | int val, len; | 1400 | int val, len; |
@@ -1333,6 +1416,16 @@ static int do_udp_getsockopt(struct sock *sk, int level, int optname, | |||
1333 | val = up->encap_type; | 1416 | val = up->encap_type; |
1334 | break; | 1417 | break; |
1335 | 1418 | ||
1419 | /* The following two cannot be changed on UDP sockets, the return is | ||
1420 | * always 0 (which corresponds to the full checksum coverage of UDP). */ | ||
1421 | case UDPLITE_SEND_CSCOV: | ||
1422 | val = up->pcslen; | ||
1423 | break; | ||
1424 | |||
1425 | case UDPLITE_RECV_CSCOV: | ||
1426 | val = up->pcrlen; | ||
1427 | break; | ||
1428 | |||
1336 | default: | 1429 | default: |
1337 | return -ENOPROTOOPT; | 1430 | return -ENOPROTOOPT; |
1338 | }; | 1431 | }; |
@@ -1344,21 +1437,21 @@ static int do_udp_getsockopt(struct sock *sk, int level, int optname, | |||
1344 | return 0; | 1437 | return 0; |
1345 | } | 1438 | } |
1346 | 1439 | ||
1347 | static int udp_getsockopt(struct sock *sk, int level, int optname, | 1440 | int udp_getsockopt(struct sock *sk, int level, int optname, |
1348 | char __user *optval, int __user *optlen) | 1441 | char __user *optval, int __user *optlen) |
1349 | { | 1442 | { |
1350 | if (level != SOL_UDP) | 1443 | if (level == SOL_UDP || level == SOL_UDPLITE) |
1351 | return ip_getsockopt(sk, level, optname, optval, optlen); | 1444 | return udp_lib_getsockopt(sk, level, optname, optval, optlen); |
1352 | return do_udp_getsockopt(sk, level, optname, optval, optlen); | 1445 | return ip_getsockopt(sk, level, optname, optval, optlen); |
1353 | } | 1446 | } |
1354 | 1447 | ||
1355 | #ifdef CONFIG_COMPAT | 1448 | #ifdef CONFIG_COMPAT |
1356 | static int compat_udp_getsockopt(struct sock *sk, int level, int optname, | 1449 | int compat_udp_getsockopt(struct sock *sk, int level, int optname, |
1357 | char __user *optval, int __user *optlen) | 1450 | char __user *optval, int __user *optlen) |
1358 | { | 1451 | { |
1359 | if (level != SOL_UDP) | 1452 | if (level == SOL_UDP || level == SOL_UDPLITE) |
1360 | return compat_ip_getsockopt(sk, level, optname, optval, optlen); | 1453 | return udp_lib_getsockopt(sk, level, optname, optval, optlen); |
1361 | return do_udp_getsockopt(sk, level, optname, optval, optlen); | 1454 | return compat_ip_getsockopt(sk, level, optname, optval, optlen); |
1362 | } | 1455 | } |
1363 | #endif | 1456 | #endif |
1364 | /** | 1457 | /** |
@@ -1378,7 +1471,8 @@ unsigned int udp_poll(struct file *file, struct socket *sock, poll_table *wait) | |||
1378 | { | 1471 | { |
1379 | unsigned int mask = datagram_poll(file, sock, wait); | 1472 | unsigned int mask = datagram_poll(file, sock, wait); |
1380 | struct sock *sk = sock->sk; | 1473 | struct sock *sk = sock->sk; |
1381 | 1474 | int is_lite = IS_UDPLITE(sk); | |
1475 | |||
1382 | /* Check for false positives due to checksum errors */ | 1476 | /* Check for false positives due to checksum errors */ |
1383 | if ( (mask & POLLRDNORM) && | 1477 | if ( (mask & POLLRDNORM) && |
1384 | !(file->f_flags & O_NONBLOCK) && | 1478 | !(file->f_flags & O_NONBLOCK) && |
@@ -1388,8 +1482,8 @@ unsigned int udp_poll(struct file *file, struct socket *sock, poll_table *wait) | |||
1388 | 1482 | ||
1389 | spin_lock_bh(&rcvq->lock); | 1483 | spin_lock_bh(&rcvq->lock); |
1390 | while ((skb = skb_peek(rcvq)) != NULL) { | 1484 | while ((skb = skb_peek(rcvq)) != NULL) { |
1391 | if (udp_checksum_complete(skb)) { | 1485 | if (udp_lib_checksum_complete(skb)) { |
1392 | UDP_INC_STATS_BH(UDP_MIB_INERRORS); | 1486 | UDP_INC_STATS_BH(UDP_MIB_INERRORS, is_lite); |
1393 | __skb_unlink(skb, rcvq); | 1487 | __skb_unlink(skb, rcvq); |
1394 | kfree_skb(skb); | 1488 | kfree_skb(skb); |
1395 | } else { | 1489 | } else { |
@@ -1411,7 +1505,7 @@ unsigned int udp_poll(struct file *file, struct socket *sock, poll_table *wait) | |||
1411 | struct proto udp_prot = { | 1505 | struct proto udp_prot = { |
1412 | .name = "UDP", | 1506 | .name = "UDP", |
1413 | .owner = THIS_MODULE, | 1507 | .owner = THIS_MODULE, |
1414 | .close = udp_close, | 1508 | .close = udp_lib_close, |
1415 | .connect = ip4_datagram_connect, | 1509 | .connect = ip4_datagram_connect, |
1416 | .disconnect = udp_disconnect, | 1510 | .disconnect = udp_disconnect, |
1417 | .ioctl = udp_ioctl, | 1511 | .ioctl = udp_ioctl, |
@@ -1422,8 +1516,8 @@ struct proto udp_prot = { | |||
1422 | .recvmsg = udp_recvmsg, | 1516 | .recvmsg = udp_recvmsg, |
1423 | .sendpage = udp_sendpage, | 1517 | .sendpage = udp_sendpage, |
1424 | .backlog_rcv = udp_queue_rcv_skb, | 1518 | .backlog_rcv = udp_queue_rcv_skb, |
1425 | .hash = udp_v4_hash, | 1519 | .hash = udp_lib_hash, |
1426 | .unhash = udp_v4_unhash, | 1520 | .unhash = udp_lib_unhash, |
1427 | .get_port = udp_v4_get_port, | 1521 | .get_port = udp_v4_get_port, |
1428 | .obj_size = sizeof(struct udp_sock), | 1522 | .obj_size = sizeof(struct udp_sock), |
1429 | #ifdef CONFIG_COMPAT | 1523 | #ifdef CONFIG_COMPAT |
@@ -1442,7 +1536,7 @@ static struct sock *udp_get_first(struct seq_file *seq) | |||
1442 | 1536 | ||
1443 | for (state->bucket = 0; state->bucket < UDP_HTABLE_SIZE; ++state->bucket) { | 1537 | for (state->bucket = 0; state->bucket < UDP_HTABLE_SIZE; ++state->bucket) { |
1444 | struct hlist_node *node; | 1538 | struct hlist_node *node; |
1445 | sk_for_each(sk, node, &udp_hash[state->bucket]) { | 1539 | sk_for_each(sk, node, state->hashtable + state->bucket) { |
1446 | if (sk->sk_family == state->family) | 1540 | if (sk->sk_family == state->family) |
1447 | goto found; | 1541 | goto found; |
1448 | } | 1542 | } |
@@ -1463,7 +1557,7 @@ try_again: | |||
1463 | } while (sk && sk->sk_family != state->family); | 1557 | } while (sk && sk->sk_family != state->family); |
1464 | 1558 | ||
1465 | if (!sk && ++state->bucket < UDP_HTABLE_SIZE) { | 1559 | if (!sk && ++state->bucket < UDP_HTABLE_SIZE) { |
1466 | sk = sk_head(&udp_hash[state->bucket]); | 1560 | sk = sk_head(state->hashtable + state->bucket); |
1467 | goto try_again; | 1561 | goto try_again; |
1468 | } | 1562 | } |
1469 | return sk; | 1563 | return sk; |
@@ -1513,6 +1607,7 @@ static int udp_seq_open(struct inode *inode, struct file *file) | |||
1513 | if (!s) | 1607 | if (!s) |
1514 | goto out; | 1608 | goto out; |
1515 | s->family = afinfo->family; | 1609 | s->family = afinfo->family; |
1610 | s->hashtable = afinfo->hashtable; | ||
1516 | s->seq_ops.start = udp_seq_start; | 1611 | s->seq_ops.start = udp_seq_start; |
1517 | s->seq_ops.next = udp_seq_next; | 1612 | s->seq_ops.next = udp_seq_next; |
1518 | s->seq_ops.show = afinfo->seq_show; | 1613 | s->seq_ops.show = afinfo->seq_show; |
@@ -1579,7 +1674,7 @@ static void udp4_format_sock(struct sock *sp, char *tmpbuf, int bucket) | |||
1579 | atomic_read(&sp->sk_refcnt), sp); | 1674 | atomic_read(&sp->sk_refcnt), sp); |
1580 | } | 1675 | } |
1581 | 1676 | ||
1582 | static int udp4_seq_show(struct seq_file *seq, void *v) | 1677 | int udp4_seq_show(struct seq_file *seq, void *v) |
1583 | { | 1678 | { |
1584 | if (v == SEQ_START_TOKEN) | 1679 | if (v == SEQ_START_TOKEN) |
1585 | seq_printf(seq, "%-127s\n", | 1680 | seq_printf(seq, "%-127s\n", |
@@ -1602,6 +1697,7 @@ static struct udp_seq_afinfo udp4_seq_afinfo = { | |||
1602 | .owner = THIS_MODULE, | 1697 | .owner = THIS_MODULE, |
1603 | .name = "udp", | 1698 | .name = "udp", |
1604 | .family = AF_INET, | 1699 | .family = AF_INET, |
1700 | .hashtable = udp_hash, | ||
1605 | .seq_show = udp4_seq_show, | 1701 | .seq_show = udp4_seq_show, |
1606 | .seq_fops = &udp4_seq_fops, | 1702 | .seq_fops = &udp4_seq_fops, |
1607 | }; | 1703 | }; |
@@ -1624,6 +1720,8 @@ EXPORT_SYMBOL(udp_ioctl); | |||
1624 | EXPORT_SYMBOL(udp_get_port); | 1720 | EXPORT_SYMBOL(udp_get_port); |
1625 | EXPORT_SYMBOL(udp_prot); | 1721 | EXPORT_SYMBOL(udp_prot); |
1626 | EXPORT_SYMBOL(udp_sendmsg); | 1722 | EXPORT_SYMBOL(udp_sendmsg); |
1723 | EXPORT_SYMBOL(udp_lib_getsockopt); | ||
1724 | EXPORT_SYMBOL(udp_lib_setsockopt); | ||
1627 | EXPORT_SYMBOL(udp_poll); | 1725 | EXPORT_SYMBOL(udp_poll); |
1628 | 1726 | ||
1629 | #ifdef CONFIG_PROC_FS | 1727 | #ifdef CONFIG_PROC_FS |
diff --git a/net/ipv4/udp_impl.h b/net/ipv4/udp_impl.h new file mode 100644 index 000000000000..f6f4277ba6dc --- /dev/null +++ b/net/ipv4/udp_impl.h | |||
@@ -0,0 +1,38 @@ | |||
1 | #ifndef _UDP4_IMPL_H | ||
2 | #define _UDP4_IMPL_H | ||
3 | #include <net/udp.h> | ||
4 | #include <net/udplite.h> | ||
5 | #include <net/protocol.h> | ||
6 | #include <net/inet_common.h> | ||
7 | |||
8 | extern int __udp4_lib_rcv(struct sk_buff *, struct hlist_head [], int ); | ||
9 | extern void __udp4_lib_err(struct sk_buff *, u32, struct hlist_head []); | ||
10 | |||
11 | extern int __udp_lib_get_port(struct sock *sk, unsigned short snum, | ||
12 | struct hlist_head udptable[], int *port_rover, | ||
13 | int (*)(const struct sock*,const struct sock*)); | ||
14 | extern int ipv4_rcv_saddr_equal(const struct sock *, const struct sock *); | ||
15 | |||
16 | |||
17 | extern int udp_setsockopt(struct sock *sk, int level, int optname, | ||
18 | char __user *optval, int optlen); | ||
19 | extern int udp_getsockopt(struct sock *sk, int level, int optname, | ||
20 | char __user *optval, int __user *optlen); | ||
21 | |||
22 | #ifdef CONFIG_COMPAT | ||
23 | extern int compat_udp_setsockopt(struct sock *sk, int level, int optname, | ||
24 | char __user *optval, int optlen); | ||
25 | extern int compat_udp_getsockopt(struct sock *sk, int level, int optname, | ||
26 | char __user *optval, int __user *optlen); | ||
27 | #endif | ||
28 | extern int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | ||
29 | size_t len, int noblock, int flags, int *addr_len); | ||
30 | extern int udp_sendpage(struct sock *sk, struct page *page, int offset, | ||
31 | size_t size, int flags); | ||
32 | extern int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb); | ||
33 | extern int udp_destroy_sock(struct sock *sk); | ||
34 | |||
35 | #ifdef CONFIG_PROC_FS | ||
36 | extern int udp4_seq_show(struct seq_file *seq, void *v); | ||
37 | #endif | ||
38 | #endif /* _UDP4_IMPL_H */ | ||
diff --git a/net/ipv4/udplite.c b/net/ipv4/udplite.c new file mode 100644 index 000000000000..b28fe1edf98b --- /dev/null +++ b/net/ipv4/udplite.c | |||
@@ -0,0 +1,119 @@ | |||
1 | /* | ||
2 | * UDPLITE An implementation of the UDP-Lite protocol (RFC 3828). | ||
3 | * | ||
4 | * Version: $Id: udplite.c,v 1.25 2006/10/19 07:22:36 gerrit Exp $ | ||
5 | * | ||
6 | * Authors: Gerrit Renker <gerrit@erg.abdn.ac.uk> | ||
7 | * | ||
8 | * Changes: | ||
9 | * Fixes: | ||
10 | * This program is free software; you can redistribute it and/or | ||
11 | * modify it under the terms of the GNU General Public License | ||
12 | * as published by the Free Software Foundation; either version | ||
13 | * 2 of the License, or (at your option) any later version. | ||
14 | */ | ||
15 | #include "udp_impl.h" | ||
16 | DEFINE_SNMP_STAT(struct udp_mib, udplite_statistics) __read_mostly; | ||
17 | |||
18 | struct hlist_head udplite_hash[UDP_HTABLE_SIZE]; | ||
19 | static int udplite_port_rover; | ||
20 | |||
21 | int udplite_get_port(struct sock *sk, unsigned short p, | ||
22 | int (*c)(const struct sock *, const struct sock *)) | ||
23 | { | ||
24 | return __udp_lib_get_port(sk, p, udplite_hash, &udplite_port_rover, c); | ||
25 | } | ||
26 | |||
27 | static int udplite_v4_get_port(struct sock *sk, unsigned short snum) | ||
28 | { | ||
29 | return udplite_get_port(sk, snum, ipv4_rcv_saddr_equal); | ||
30 | } | ||
31 | |||
32 | static int udplite_rcv(struct sk_buff *skb) | ||
33 | { | ||
34 | return __udp4_lib_rcv(skb, udplite_hash, 1); | ||
35 | } | ||
36 | |||
37 | static void udplite_err(struct sk_buff *skb, u32 info) | ||
38 | { | ||
39 | return __udp4_lib_err(skb, info, udplite_hash); | ||
40 | } | ||
41 | |||
42 | static struct net_protocol udplite_protocol = { | ||
43 | .handler = udplite_rcv, | ||
44 | .err_handler = udplite_err, | ||
45 | .no_policy = 1, | ||
46 | }; | ||
47 | |||
48 | struct proto udplite_prot = { | ||
49 | .name = "UDP-Lite", | ||
50 | .owner = THIS_MODULE, | ||
51 | .close = udp_lib_close, | ||
52 | .connect = ip4_datagram_connect, | ||
53 | .disconnect = udp_disconnect, | ||
54 | .ioctl = udp_ioctl, | ||
55 | .init = udplite_sk_init, | ||
56 | .destroy = udp_destroy_sock, | ||
57 | .setsockopt = udp_setsockopt, | ||
58 | .getsockopt = udp_getsockopt, | ||
59 | .sendmsg = udp_sendmsg, | ||
60 | .recvmsg = udp_recvmsg, | ||
61 | .sendpage = udp_sendpage, | ||
62 | .backlog_rcv = udp_queue_rcv_skb, | ||
63 | .hash = udp_lib_hash, | ||
64 | .unhash = udp_lib_unhash, | ||
65 | .get_port = udplite_v4_get_port, | ||
66 | .obj_size = sizeof(struct udp_sock), | ||
67 | #ifdef CONFIG_COMPAT | ||
68 | .compat_setsockopt = compat_udp_setsockopt, | ||
69 | .compat_getsockopt = compat_udp_getsockopt, | ||
70 | #endif | ||
71 | }; | ||
72 | |||
73 | static struct inet_protosw udplite4_protosw = { | ||
74 | .type = SOCK_DGRAM, | ||
75 | .protocol = IPPROTO_UDPLITE, | ||
76 | .prot = &udplite_prot, | ||
77 | .ops = &inet_dgram_ops, | ||
78 | .capability = -1, | ||
79 | .no_check = 0, /* must checksum (RFC 3828) */ | ||
80 | .flags = INET_PROTOSW_PERMANENT, | ||
81 | }; | ||
82 | |||
83 | #ifdef CONFIG_PROC_FS | ||
84 | static struct file_operations udplite4_seq_fops; | ||
85 | static struct udp_seq_afinfo udplite4_seq_afinfo = { | ||
86 | .owner = THIS_MODULE, | ||
87 | .name = "udplite", | ||
88 | .family = AF_INET, | ||
89 | .hashtable = udplite_hash, | ||
90 | .seq_show = udp4_seq_show, | ||
91 | .seq_fops = &udplite4_seq_fops, | ||
92 | }; | ||
93 | #endif | ||
94 | |||
95 | void __init udplite4_register(void) | ||
96 | { | ||
97 | if (proto_register(&udplite_prot, 1)) | ||
98 | goto out_register_err; | ||
99 | |||
100 | if (inet_add_protocol(&udplite_protocol, IPPROTO_UDPLITE) < 0) | ||
101 | goto out_unregister_proto; | ||
102 | |||
103 | inet_register_protosw(&udplite4_protosw); | ||
104 | |||
105 | #ifdef CONFIG_PROC_FS | ||
106 | if (udp_proc_register(&udplite4_seq_afinfo)) /* udplite4_proc_init() */ | ||
107 | printk(KERN_ERR "%s: Cannot register /proc!\n", __FUNCTION__); | ||
108 | #endif | ||
109 | return; | ||
110 | |||
111 | out_unregister_proto: | ||
112 | proto_unregister(&udplite_prot); | ||
113 | out_register_err: | ||
114 | printk(KERN_CRIT "%s: Cannot add UDP-Lite protocol.\n", __FUNCTION__); | ||
115 | } | ||
116 | |||
117 | EXPORT_SYMBOL(udplite_hash); | ||
118 | EXPORT_SYMBOL(udplite_prot); | ||
119 | EXPORT_SYMBOL(udplite_get_port); | ||
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c index 1bed0cdf53e3..d4107bb701b5 100644 --- a/net/ipv4/xfrm4_policy.c +++ b/net/ipv4/xfrm4_policy.c | |||
@@ -72,8 +72,8 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int | |||
72 | struct dst_entry *dst, *dst_prev; | 72 | struct dst_entry *dst, *dst_prev; |
73 | struct rtable *rt0 = (struct rtable*)(*dst_p); | 73 | struct rtable *rt0 = (struct rtable*)(*dst_p); |
74 | struct rtable *rt = rt0; | 74 | struct rtable *rt = rt0; |
75 | u32 remote = fl->fl4_dst; | 75 | __be32 remote = fl->fl4_dst; |
76 | u32 local = fl->fl4_src; | 76 | __be32 local = fl->fl4_src; |
77 | struct flowi fl_tunnel = { | 77 | struct flowi fl_tunnel = { |
78 | .nl_u = { | 78 | .nl_u = { |
79 | .ip4_u = { | 79 | .ip4_u = { |
@@ -199,11 +199,12 @@ _decode_session4(struct sk_buff *skb, struct flowi *fl) | |||
199 | if (!(iph->frag_off & htons(IP_MF | IP_OFFSET))) { | 199 | if (!(iph->frag_off & htons(IP_MF | IP_OFFSET))) { |
200 | switch (iph->protocol) { | 200 | switch (iph->protocol) { |
201 | case IPPROTO_UDP: | 201 | case IPPROTO_UDP: |
202 | case IPPROTO_UDPLITE: | ||
202 | case IPPROTO_TCP: | 203 | case IPPROTO_TCP: |
203 | case IPPROTO_SCTP: | 204 | case IPPROTO_SCTP: |
204 | case IPPROTO_DCCP: | 205 | case IPPROTO_DCCP: |
205 | if (pskb_may_pull(skb, xprth + 4 - skb->data)) { | 206 | if (pskb_may_pull(skb, xprth + 4 - skb->data)) { |
206 | u16 *ports = (u16 *)xprth; | 207 | __be16 *ports = (__be16 *)xprth; |
207 | 208 | ||
208 | fl->fl_ip_sport = ports[0]; | 209 | fl->fl_ip_sport = ports[0]; |
209 | fl->fl_ip_dport = ports[1]; | 210 | fl->fl_ip_dport = ports[1]; |