kernel: Fix Cisco SIP NAT patch to build with 3.7
[openwrt.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;