Update 2.6.38 to 2.6.38.2
[openwrt/svn-archive/archive.git] / target / linux / generic / patches-2.6.38 / 160-netfilter_cisco_794x_iphone.patch
1 --- a/include/linux/netfilter/nf_conntrack_sip.h
2 +++ b/include/linux/netfilter/nf_conntrack_sip.h
3 @@ -2,12 +2,15 @@
4 #define __NF_CONNTRACK_SIP_H__
5 #ifdef __KERNEL__
6
7 +#include <linux/types.h>
8 +
9 #define SIP_PORT 5060
10 #define SIP_TIMEOUT 3600
11
12 struct nf_ct_sip_master {
13 unsigned int register_cseq;
14 unsigned int invite_cseq;
15 + __be16 forced_dport;
16 };
17
18 enum sip_expectation_classes {
19 --- a/net/ipv4/netfilter/nf_nat_sip.c
20 +++ b/net/ipv4/netfilter/nf_nat_sip.c
21 @@ -73,6 +73,7 @@ static int map_addr(struct sk_buff *skb,
22 enum ip_conntrack_info ctinfo;
23 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
24 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
25 + struct nf_conn_help *help = nfct_help(ct);
26 char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")];
27 unsigned int buflen;
28 __be32 newaddr;
29 @@ -85,7 +86,8 @@ static int map_addr(struct sk_buff *skb,
30 } else if (ct->tuplehash[dir].tuple.dst.u3.ip == addr->ip &&
31 ct->tuplehash[dir].tuple.dst.u.udp.port == port) {
32 newaddr = ct->tuplehash[!dir].tuple.src.u3.ip;
33 - newport = ct->tuplehash[!dir].tuple.src.u.udp.port;
34 + newport = help->help.ct_sip_info.forced_dport ? :
35 + ct->tuplehash[!dir].tuple.src.u.udp.port;
36 } else
37 return 1;
38
39 @@ -121,6 +123,7 @@ static unsigned int ip_nat_sip(struct sk
40 enum ip_conntrack_info ctinfo;
41 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
42 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
43 + struct nf_conn_help *help = nfct_help(ct);
44 unsigned int coff, matchoff, matchlen;
45 enum sip_header_types hdr;
46 union nf_inet_addr addr;
47 @@ -229,6 +232,20 @@ next:
48 !map_sip_addr(skb, dataoff, dptr, datalen, SIP_HDR_TO))
49 return NF_DROP;
50
51 + /* Mangle destination port for Cisco phones, then fix up checksums */
52 + if (dir == IP_CT_DIR_REPLY && help->help.ct_sip_info.forced_dport) {
53 + struct udphdr *uh;
54 +
55 + if (!skb_make_writable(skb, skb->len))
56 + return NF_DROP;
57 +
58 + uh = (struct udphdr *)(skb->data + ip_hdrlen(skb));
59 + uh->dest = help->help.ct_sip_info.forced_dport;
60 +
61 + if (!nf_nat_mangle_udp_packet(skb, ct, ctinfo, 0, 0, NULL, 0))
62 + return NF_DROP;
63 + }
64 +
65 return NF_ACCEPT;
66 }
67
68 @@ -280,8 +297,10 @@ static unsigned int ip_nat_sip_expect(st
69 enum ip_conntrack_info ctinfo;
70 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
71 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
72 + struct nf_conn_help *help = nfct_help(ct);
73 __be32 newip;
74 u_int16_t port;
75 + __be16 srcport;
76 char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")];
77 unsigned buflen;
78
79 @@ -294,8 +313,9 @@ static unsigned int ip_nat_sip_expect(st
80 /* If the signalling port matches the connection's source port in the
81 * original direction, try to use the destination port in the opposite
82 * direction. */
83 - if (exp->tuple.dst.u.udp.port ==
84 - ct->tuplehash[dir].tuple.src.u.udp.port)
85 + srcport = help->help.ct_sip_info.forced_dport ? :
86 + ct->tuplehash[dir].tuple.src.u.udp.port;
87 + if (exp->tuple.dst.u.udp.port == srcport)
88 port = ntohs(ct->tuplehash[!dir].tuple.dst.u.udp.port);
89 else
90 port = ntohs(exp->tuple.dst.u.udp.port);
91 --- a/net/netfilter/nf_conntrack_sip.c
92 +++ b/net/netfilter/nf_conntrack_sip.c
93 @@ -1363,8 +1363,25 @@ static int process_sip_request(struct sk
94 {
95 enum ip_conntrack_info ctinfo;
96 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
97 + struct nf_conn_help *help = nfct_help(ct);
98 + enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
99 unsigned int matchoff, matchlen;
100 unsigned int cseq, i;
101 + union nf_inet_addr addr;
102 + __be16 port;
103 +
104 + /* Many Cisco IP phones use a high source port for SIP requests, but
105 + * listen for the response on port 5060. If we are the local
106 + * router for one of these phones, save the port number from the
107 + * Via: header so that nf_nat_sip can redirect the responses to
108 + * the correct port.
109 + */
110 + if (ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen,
111 + SIP_HDR_VIA_UDP, NULL, &matchoff,
112 + &matchlen, &addr, &port) > 0 &&
113 + port != ct->tuplehash[dir].tuple.src.u.udp.port &&
114 + nf_inet_addr_cmp(&addr, &ct->tuplehash[dir].tuple.src.u3))
115 + help->help.ct_sip_info.forced_dport = port;
116
117 for (i = 0; i < ARRAY_SIZE(sip_handlers); i++) {
118 const struct sip_handler *handler;