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