http://downloads.netgear.com/files/GPL/GPL_Source_V361j_DM111PSP_series_consumer_rele...
[bcm963xx.git] / kernel / linux / net / ipv4 / netfilter / ip_nat_sip.c
1 /*
2  * SIP extension for UDP/TCP NAT alteration. 
3  */
4  
5 #include <linux/module.h>
6 #include <linux/netfilter_ipv4.h>
7 #include <linux/ip.h>
8 #include <linux/tcp.h>
9 #include <linux/udp.h>
10 #include <linux/ctype.h>
11 #include <net/tcp.h>
12 #include <net/udp.h>
13 #include <linux/netfilter_ipv4/ip_nat.h>
14 #include <linux/netfilter_ipv4/ip_nat_helper.h>
15 #include <linux/netfilter_ipv4/ip_nat_rule.h>
16 #include <linux/netfilter_ipv4/ip_conntrack_sip.h>
17 #include <linux/netfilter_ipv4/ip_conntrack_helper.h>
18
19 #if 0
20   #define DEBUG_PRINTK
21   #define DEBUGP printk
22 #else
23   #define DEBUGP(format, args...)
24 #endif
25
26 #define MAX_PORTS 8
27 static int ports[MAX_PORTS];
28 static int ports_c = 0;
29
30 #ifdef MODULE_PARM
31 MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i");
32 #endif
33
34 DECLARE_LOCK_EXTERN(ip_sip_lock);
35
36 #define RTCP_SUPPORT
37
38
39 /*dump_packet(struct sk_buff **pskb)
40 {
41         struct iphdr *iph = (*pskb)->nh.iph;
42         struct udphdr *udph = (void *)iph + iph->ihl * 4;
43         const char *data = (const char *)udph + 8;
44         printk("%s", data);
45         printk("\n");
46 }*/
47
48 /* down(stream): caller -> callee
49      up(stream): caller <- callee */
50
51
52 /* Return 1 for match, 0 for accept, -1 for partial. */
53 static int find_pattern(const char *data, size_t dlen,
54                         const char *pattern, size_t plen,
55                         char skip, char term,
56                         unsigned int *numoff,
57                         unsigned int *numlen
58                         )
59 {
60         size_t i, j, k;
61
62         //DEBUGP("find_pattern `%s': dlen = %u\n", pattern, dlen);
63         if (dlen == 0)
64                 return 0;
65
66         *numoff = 0;
67         *numlen = 0;
68
69         if (dlen <= plen) {
70                 /* Short packet: try for partial? */
71                 if (strnicmp(data, pattern, dlen) == 0)
72                         return -1;
73                 else return 0;
74         }
75
76         for(i=0; i<= (dlen - plen); i++){
77                 if( memcmp(data + i, pattern, plen ) != 0 ) continue;   
78
79                 /* patten match !! */   
80                 *numoff=i + plen;
81                 for (j=*numoff, k=0; data[j] != term; j++, k++)
82                         if( j > dlen ) return -1 ;      /* no terminal char */
83
84                 *numlen = k;
85                 return 1;
86         }
87
88         return 0;
89 }
90
91 static unsigned int
92 sip_nat_expected(struct sk_buff **pskb,
93                  unsigned int hooknum,
94                  struct ip_conntrack *ct,
95                  struct ip_nat_info *info)
96 {
97         struct ip_nat_multi_range mr;
98         u_int32_t newdstip, newsrcip, newip;
99         struct ip_ct_sip_expect *exp_sip_info;
100         struct ip_conntrack *master = master_ct(ct);
101
102         IP_NF_ASSERT(info);
103         IP_NF_ASSERT(master);
104         IP_NF_ASSERT(!(info->initialized & (1<<HOOK2MANIP(hooknum))));
105
106         exp_sip_info = &ct->master->help.exp_sip_info;
107
108         LOCK_BH(&ip_sip_lock);
109
110         /* Outer machine IP */
111         newsrcip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
112         /* Client (virtual) IP under NAT */
113         newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
114
115         UNLOCK_BH(&ip_sip_lock);
116
117         if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC)
118                 newip = newsrcip;
119         else
120                 newip = newdstip;
121
122         DEBUGP("sip_nat_expected: IP to %u.%u.%u.%u:%u\n", NIPQUAD(newip),
123                         htons(exp_sip_info->port));
124
125         mr.rangesize = 1;
126         /* We don't want to manip the per-protocol, just the IPs... */
127         mr.range[0].flags = IP_NAT_RANGE_MAP_IPS;
128         mr.range[0].min_ip = mr.range[0].max_ip = newip;
129
130         /* ... unless we're doing a MANIP_DST, in which case, make
131            sure we map to the correct port */
132         if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST) {
133                 mr.range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
134                 mr.range[0].min.udp.port = mr.range[0].max.udp.port     = exp_sip_info->port;
135         }
136
137         return ip_nat_setup_info(ct, &mr, hooknum);
138 }
139
140 static int _find_sip_via_addrport(const char *data, size_t dlen,
141                         unsigned int *numoff, unsigned int *numlen)
142 {
143         const char *addr, *p = data;
144         const char *limit = data + dlen;
145
146         *numoff = 0;
147         *numlen = 0;
148
149         while (p < limit) {
150                 /* Find the topmost via tag */
151                 if (strnicmp(p, "\nvia:",5) && strnicmp(p, "\nv:",3) &&
152                     strnicmp(p, "\rvia:",5) && strnicmp(p, "\rv:",3)) {
153                         p++;
154                         continue;
155                 }
156
157                 /* Look for UDP */
158                 while (*p!='U' && *p!='u') {
159                         if (p == limit)
160                                 return 0;
161                         p++;
162                 }
163                 p+= 3;
164
165                 if (p >= limit)
166                         return 0;
167
168                 /* Skip a space */
169                 while (*p == ' '){
170                         if (p == limit)
171                                 return 0;
172                         p++;
173                 }
174
175                 /* IP address */
176                 addr = p;
177
178                 /* FQDNs or dotted quads */
179                 while (isalpha(*p) || isdigit(*p) || (*p=='.') || (*p=='-')) {
180                         p++;
181                         if (p == limit)
182                                 return 0;
183                 }
184
185                 /* If there is a port number, skip it */
186                 if (*p == ':') {
187                         p++;
188                         if (p == limit)
189                                 return 0;
190
191                         while (isdigit(*p)) {
192                                 p++;
193                                 if (p == limit)
194                                         return 0;
195                         }
196                 }
197
198                 *numoff = addr - data;
199                 *numlen = p - addr;
200
201                 return 1;
202         }
203
204         return 0;       /* Not found */
205 }
206
207 static int _mangle_sip_via(struct ip_conntrack *ct, enum ip_conntrack_info ctinfo,
208                 struct sk_buff **pskb, u_int32_t newip, u_int16_t newport,
209                 unsigned int numoff, unsigned int numlen)
210 {
211         int buflen;
212         char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")];
213
214         sprintf(buffer, "%u.%u.%u.%u:%u", NIPQUAD(newip), newport);
215         buflen = strlen(buffer);
216
217         MUST_BE_LOCKED(&ip_sip_lock);
218
219         if(numlen == 0)
220                 return 0;
221
222         if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo, numoff, 
223                                 numlen, buffer, buflen) )
224                 return 0;
225
226         DEBUGP("(SIP) Via is changed to %s.\n", buffer);
227
228         return buflen - numlen;
229 }
230
231 static int mangle_sip_via(struct ip_conntrack *ct, enum ip_conntrack_info ctinfo,
232                 struct sk_buff **pskb, u_int32_t newip, u_int16_t newport)
233 {
234         struct iphdr *iph = (*pskb)->nh.iph;
235         struct udphdr *udph = (void *)iph + iph->ihl * 4;
236         const char *data = (const char *)udph + 8;
237         unsigned int udplen = ntohs(iph->tot_len) - (iph->ihl * 4);
238         unsigned int datalen = udplen - 8;
239         unsigned int matchoff, matchlen;
240
241          /* Find the topmost via tag */
242         _find_sip_via_addrport(data , datalen, &matchoff, &matchlen);
243         return _mangle_sip_via(ct, ctinfo, pskb, newip, newport,
244                         matchoff, matchlen);
245 }
246
247 static int mangle_sip_contact_in(struct ip_conntrack *ct, enum ip_conntrack_info ctinfo,
248                 struct sk_buff **pskb, u_int32_t newip, u_int16_t newport)
249 {
250         struct iphdr *iph = (*pskb)->nh.iph;
251         struct udphdr *udph = (void *)iph + iph->ihl * 4;
252         const char *data = (const char *)udph + 8;
253         unsigned int udplen = ntohs(iph->tot_len) - (iph->ihl * 4);
254         unsigned int datalen = udplen - 8;
255         int buflen, diff_len = 0;
256         char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")];
257         const char *uri, *addr, *p = data;
258         const char *limit = data + datalen;
259         u_int32_t wanip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;     // NAT wan ip
260         char buffer1[16];
261         char buffer2[16];
262
263         memset(buffer2,0,16);
264         sprintf(buffer2,"%u.%u.%u.%u",NIPQUAD(wanip));
265         while (p < limit) {
266                 if (strnicmp(p, "\ncontact:", 9) && strnicmp(p, "\nm:", 3) &&
267                     strnicmp(p, "\rcontact:", 9) && strnicmp(p, "\rm:", 3)) {
268                         p++;
269                         continue;
270                 }
271
272                 while (strnicmp(p, "sip:", 4)) {
273                         if (p == limit)
274                                 return 0;
275                         p++;
276                 }
277                 p += 4;
278
279                 /* If there is user info in the contact */
280                 uri = p;
281
282                 while (*p!='@' && *p!='>' && *p!=';' && *p!='\n' && *p!='\r' && *p!='?' && *p!=',') {
283                         if (p == limit)
284                                 return 0;
285                         p++;
286                 }
287
288                 if (*p=='@')
289                         p++;
290                 else
291                         p = uri;        /* back to previous URI pointer */
292
293                 /* IP address */
294                 addr = p;
295                 while (*p!=':' && *p!='>' && *p!=';') {
296                         if (p == limit)
297                                 return 0;
298                         p++;
299                 }
300                 if ((p-addr) > 16)
301                         return 0;
302                 memset(buffer1,0,16);           
303                 memcpy(buffer1,addr,p-addr);
304                 if (strcmp(buffer1, buffer2)!=0){
305                         continue;                       
306                 }
307                 /* FQDNs or dotted quads */
308                 while (isalpha(*p) || isdigit(*p) || (*p=='.') || (*p=='-')) {
309                         p++;
310                         if (p == limit)
311                                 return 0;
312                 }
313
314                 /* If there is a port number, skip it */
315                 if (*p==':') {
316                         p++;
317                         while (isdigit(*p))
318                                 p++;
319                 }
320
321                 sprintf(buffer, "%u.%u.%u.%u:%u", NIPQUAD(newip), newport);
322                 buflen = strlen(buffer);
323
324                 MUST_BE_LOCKED(&ip_sip_lock);
325
326                 if( p == addr)
327                         return 0;
328
329                 if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo, addr - data, 
330                                         p - addr, buffer, buflen) )
331                         return 0;
332         
333                 diff_len = buflen - (p - addr);
334                 DEBUGP("(SIP) Contact is changed to %s.\n", buffer);
335                 break;
336         }
337
338         return diff_len;
339 }
340
341 static int mangle_sip_contact(struct ip_conntrack *ct, enum ip_conntrack_info ctinfo,
342                 struct sk_buff **pskb, u_int32_t newip, u_int16_t newport)
343 {
344         struct iphdr *iph = (*pskb)->nh.iph;
345         struct udphdr *udph = (void *)iph + iph->ihl * 4;
346         const char *data = (const char *)udph + 8;
347         unsigned int udplen = ntohs(iph->tot_len) - (iph->ihl * 4);
348         unsigned int datalen = udplen - 8;
349
350         int buflen, diff_len = 0;
351         char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")];
352         const char *uri, *addr, *p = data;
353         const char *limit = data + datalen;
354
355
356         while (p < limit) {
357                 if (strnicmp(p, "\ncontact:", 9) && strnicmp(p, "\nm:", 3) &&
358                     strnicmp(p, "\rcontact:", 9) && strnicmp(p, "\rm:", 3)) {
359                         p++;
360                         continue;
361                 }
362
363                 while (strnicmp(p, "sip:", 4)) {
364                         if (p == limit)
365                                 return 0;
366                         p++;
367                 }
368                 p += 4;
369
370                 /* If there is user info in the contact */
371                 uri = p;
372
373                 while (*p!='@' && *p!='>' && *p!=';' && *p!='\n' && *p!='\r' && *p!='?' && *p!=',') {
374                         if (p == limit)
375                                 return 0;
376                         p++;
377                 }
378
379                 if (*p=='@')
380                         p++;
381                 else
382                         p = uri;        /* back to previous URI pointer */
383
384                 /* IP address */
385                 addr = p;
386
387                 /* FQDNs or dotted quads */
388                 while (isalpha(*p) || isdigit(*p) || (*p=='.') || (*p=='-')) {
389                         p++;
390                         if (p == limit)
391                                 return 0;
392                 }
393
394                 /* If there is a port number, skip it */
395                 if (*p==':') {
396                         p++;
397                         while (isdigit(*p))
398                                 p++;
399                 }
400
401                 sprintf(buffer, "%u.%u.%u.%u:%u", NIPQUAD(newip), newport);
402                 buflen = strlen(buffer);
403
404                 MUST_BE_LOCKED(&ip_sip_lock);
405
406                 if( p == addr)
407                         return 0;
408
409                 if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo, addr - data, 
410                                         p - addr, buffer, buflen) )
411                         return 0;
412         
413                 diff_len = buflen - (p - addr);
414                 DEBUGP("(SIP) Contact is changed to %s.\n", buffer);
415                 break;
416         }
417
418         return diff_len;
419 }
420
421 static int mangle_sip_requestline(struct ip_conntrack *ct, enum ip_conntrack_info ctinfo,
422                 struct sk_buff **pskb, u_int32_t newip, u_int16_t newport)
423 {
424         struct iphdr *iph = (*pskb)->nh.iph;
425         struct udphdr *udph = (void *)iph + iph->ihl * 4;
426         const char *data = (const char *)udph + 8;
427         unsigned int udplen = ntohs(iph->tot_len) - (iph->ihl * 4);
428         unsigned int datalen = udplen - 8;
429
430         int buflen, diff_len = 0;
431         char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")];
432         const char *uri, *addr, *p = data;
433         const char *limit = data + datalen;
434
435         while (p < limit) {
436                 while (strnicmp(p, "sip:", 4)) {
437                         if (p == limit)
438                                 return 0;
439                         p++;
440                 }
441                 p += 4;
442
443                 /* If there is user info in the contact */
444                 uri = p;
445
446                 while (*p!='@' && *p!='>' && *p!=';' && *p!='\n' && *p!='\r' && *p!='?' && *p!=',') {
447                         if (p == limit)
448                                 return 0;
449                         p++;
450                 }
451
452                 if (*p=='@')
453                         p++;
454                 else
455                         p = uri;        /* back to previous URI pointer */
456
457                 /* IP address */
458                 addr = p;
459
460                 /* FQDNs or dotted quads */
461                 while (isalpha(*p) || isdigit(*p) || (*p=='.') || (*p=='-')) {
462                         p++;
463                         if (p == limit)
464                                 return 0;
465                 }
466
467                 /* If there is a port number, skip it */
468                 if (*p==':') {
469                         p++;
470                         while (isdigit(*p))
471                                 p++;
472                 }
473
474                 sprintf(buffer, "%u.%u.%u.%u:%u", NIPQUAD(newip), newport);
475                 buflen = strlen(buffer);
476
477                 MUST_BE_LOCKED(&ip_sip_lock);
478
479                 if( p == addr)
480                         return 0;
481
482                 if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo, addr - data, p - addr, buffer, buflen) )
483                         return 0;
484         
485                 diff_len = buflen - (p - addr);
486                 break;
487         }
488
489         return diff_len;
490 }
491
492 static int _find_sip_content_length_size(const char *data, size_t dlen,
493                         unsigned int *numoff, unsigned int *numlen)
494 {
495         char *st, *p = (char *)data;
496         const char *limit = data + dlen;
497         int size = 0;
498
499         *numoff = 0;
500         *numlen = 0;
501
502         while (p < limit) {
503                 if (strnicmp(p, "\nContent-Length:", 16) && strnicmp(p, "\nl:", 3) &&
504                     strnicmp(p, "\rContent-Length:", 16) && strnicmp(p, "\rm:", 3)) {
505                         p++;
506                         continue;
507                 }
508
509                 /* Go through the string above */
510                 while (*p != ':') {
511                         if (p == limit)
512                                 return 0;
513                         p++;
514                 }
515                 p++;
516
517                 while (*p == ' ') {
518                         if (p == limit)
519                                 return 0;
520                         p++;
521                 }
522
523                 st = p;
524                 size = simple_strtoul(p, &p, 10);
525
526                 *numoff = st - data;
527                 *numlen = p - st;
528
529                 return size;
530         }
531
532         return 0;
533 }
534
535 static int mangle_sip_content_length(struct ip_conntrack *ct, enum ip_conntrack_info ctinfo,
536                 struct sk_buff **pskb, int diff_len)
537 {
538         struct iphdr *iph = (*pskb)->nh.iph;
539         struct udphdr *udph = (void *)iph + iph->ihl * 4;
540         const char *data = (const char *)udph + 8;
541         unsigned int udplen = ntohs(iph->tot_len) - (iph->ihl * 4);
542         unsigned int datalen = udplen - 8;
543
544         unsigned int matchlen, matchoff;
545         int size, buflen;
546         char buffer[sizeof("nnnnn")];
547
548         /* original legth */
549         size = _find_sip_content_length_size(data, datalen, &matchoff, &matchlen);
550
551         /* new legth */
552         sprintf(buffer, "%u", size + diff_len);
553         buflen = strlen(buffer);
554
555         if (matchlen == 0)
556                 return 0;
557
558         if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo, matchoff, 
559                                 matchlen, buffer, buflen) )
560                 return 0;
561
562         DEBUGP("(SDP) Content-Length is changed %d->%s.\n", size, buffer);
563         return buflen - matchlen;
564
565 }
566
567 static int mangle_sip_sdp_content(struct ip_conntrack *ct, enum ip_conntrack_info ctinfo,
568                 struct sk_buff **pskb, u_int32_t newip, u_int16_t newport, u_int16_t isvideoport)
569 {
570         struct iphdr *iph = (*pskb)->nh.iph;
571         struct udphdr *udph = (void *)iph + iph->ihl * 4;
572         const char *data = (const char *)udph + 8;
573         unsigned int udplen = ntohs(iph->tot_len) - (iph->ihl * 4);
574         unsigned int datalen = udplen - 8;
575
576         unsigned int matchlen, matchoff;
577         int found, buflen, diff_len = 0;
578         char buffer[sizeof("nnn.nnn.nnn.nnn")];
579         char *addr, *p;
580         char *limit = (char *)data + datalen;
581         u_int32_t ipaddr = 0;
582         u_int16_t getport;
583         int dir;
584
585         /* Find RTP address */
586         found = find_sdp_rtp_addr(data, datalen, &matchoff, &matchlen, &ipaddr);
587         if (found && matchlen != 0) {
588                 /* If it's a null address, then the call is on hold */
589                 if (found == 2 && ipaddr == 0)
590                         return 0;
591                         
592                 sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(newip));
593                 buflen = strlen(buffer);
594
595                 MUST_BE_LOCKED(&ip_sip_lock);
596
597                 if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo, matchoff, 
598                                         matchlen, buffer, buflen) )
599                         return 0;
600         
601                 diff_len += (buflen - matchlen);
602                 DEBUGP("(SDP) RTP address is changed to %s.\n", buffer);
603         }
604
605         /* Find audio port */
606         if (isvideoport == 0){
607                 getport = find_sdp_audio_port(data, datalen, &matchoff, &matchlen);
608                 if (getport != newport && matchlen != 0) {
609                         sprintf(buffer, "%d", newport);
610                         buflen = strlen(buffer);
611
612                         MUST_BE_LOCKED(&ip_sip_lock);
613                         matchoff = matchoff+diff_len;  
614                         if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo, matchoff, 
615                                                 matchlen, buffer, buflen) )
616                                 return 0;
617
618                         diff_len += (buflen - matchlen);
619                         DEBUGP("(SDP) audio port is changed to %d.\n", newport);
620                 }
621         }       
622
623         /* Find video port */
624         if (isvideoport == 1){
625                 getport = find_sdp_video_port(data, datalen, &matchoff, &matchlen);
626                 if (getport != newport && matchlen != 0) {
627                         sprintf(buffer, "%d", newport);
628                         buflen = strlen(buffer);
629
630                         MUST_BE_LOCKED(&ip_sip_lock);
631                         matchoff = matchoff+diff_len;  
632                         if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo, matchoff, 
633                                                 matchlen, buffer, buflen) )
634                                 return 0;
635
636                         diff_len += (buflen - matchlen);
637                         DEBUGP("(SDP) video port is changed to %d.\n", newport);
638                 }
639         }
640
641         dir = CTINFO2DIR(ctinfo);
642         if (dir == IP_CT_DIR_ORIGINAL)
643                 return diff_len;
644
645         /* Find Session ID address */
646         found = find_pattern(data, datalen, " IN IP4 ", 8, ' ', '\r',
647                         &matchoff, &matchlen);
648         if (found && matchlen != 0) {
649                 p = addr = (char *)data + matchoff;
650
651                 /* FQDNs or dotted quads */
652                 while (isalpha(*p) || isdigit(*p) || (*p=='.') || (*p=='-')) {
653                         p++;
654                         if (p == limit)
655                                 return 0;
656                 }
657
658                 sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(newip));
659                 buflen = strlen(buffer);
660
661                 MUST_BE_LOCKED(&ip_sip_lock);
662
663                 if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo, addr - data, 
664                                         p - addr, buffer, buflen) )
665                         return 0;
666         
667                 diff_len += (buflen - (p - addr));
668                 DEBUGP("(SDP) Session ID is changed to %s.\n", buffer);
669         }
670
671         return diff_len;
672 }
673
674 static int mangle_sip_packet(struct ip_conntrack *ct, enum ip_conntrack_info ctinfo,
675                 struct sk_buff **pskb, u_int32_t newip,  u_int16_t isvideoport)
676 {
677         struct iphdr *iph = (*pskb)->nh.iph;
678         struct udphdr *udph = (void *)iph + iph->ihl * 4;
679         const char *data = (const char *)udph + 8;
680         int diff_len = 0;
681         struct ip_ct_sip_master *ct_sip_info = &ct->help.ct_sip_info;
682         u_int16_t natport = ntohs(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.udp.port); 
683
684         DEBUGP("nat_sip: %s:(%d)\n", __FUNCTION__, __LINE__);
685         if (isvideoport == 0){
686                 ct_sip_info->mangled = 1;
687         }
688
689         /* Changes the via, if this is a request */
690         if (strnicmp(data,"SIP/2.0",7) != 0) {
691                 mangle_sip_via(ct, ctinfo, pskb, newip, natport);
692         }
693
694         /*SIP ALG can't change contact field in 3xx response packets*/
695         if (strnicmp(data, "SIP/2.0 3", 9) != 0) {//This packet is not 3xx response
696         mangle_sip_contact(ct, ctinfo, pskb, newip, natport);
697         }
698
699         if ((diff_len = mangle_sip_sdp_content(ct, ctinfo, pskb, newip, ct_sip_info->rtpport, isvideoport)) != 0)
700                 mangle_sip_content_length(ct, ctinfo, pskb, diff_len);
701
702         return 1;
703 }
704
705 static int sip_out_data_fixup(struct ip_conntrack *ct,
706                 struct sk_buff **pskb,
707                 enum ip_conntrack_info ctinfo,
708                 struct ip_conntrack_expect *expect)
709 {
710         struct ip_conntrack_tuple newtuple;
711         struct ip_ct_sip_master *ct_sip_info = &ct->help.ct_sip_info;
712         struct ip_ct_sip_expect *exp_sip_info;
713         u_int32_t wanip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;     // NAT wan ip
714         u_int16_t port = 0;
715         u_int16_t videoport = 0;
716         u_int16_t isvideoport = 2;
717 #ifdef RTCP_SUPPORT
718         struct ip_conntrack_expect *rtcp_exp;
719 #endif
720
721
722         MUST_BE_LOCKED(&ip_sip_lock);
723
724         if (expect) {
725                 DEBUGP("nat_sip: %s: There is a exp %p.\n", __FUNCTION__, expect);
726
727                 exp_sip_info = &expect->help.exp_sip_info;
728                 if (exp_sip_info->nated) {
729                         DEBUGP("nat_sip: %s: The exp %p had been changed.\n", __FUNCTION__, expect);
730                         goto mangle;
731                 }
732
733                 DEBUGP("nat_sip: %s: The exp type is %d.\n", __FUNCTION__, exp_sip_info->type);
734
735                 if (exp_sip_info->type == CONN_SIP) {
736                         exp_sip_info->nated = 1;
737                         DEBUGP("nat_sip: %s: There is a SIP exp %p.\n", __FUNCTION__, expect);
738                 } else if (exp_sip_info->type == CONN_RTP) {
739                         DEBUGP("nat_sip: %s: There is a RTP exp %p.\n", __FUNCTION__, expect);
740                         /* RTP expect */
741                         isvideoport = 0;
742                         port = ntohs(expect->tuple.dst.u.udp.port); 
743 #ifdef RTCP_SUPPORT
744                         rtcp_exp = expect_find(ct, expect->tuple.dst.ip, port + 1); 
745 #endif
746                         /* RFC1889 - If an application is supplied with an odd number
747                          * for use as the RTP port, it should replace this number with
748                          * the next lower (even) number. */
749                         if (port & 0x01) 
750                                 port++;
751
752                         /* fullfill newtuple */
753                         memset(&newtuple, 0, sizeof(struct ip_conntrack_tuple));
754                         newtuple.dst.ip = wanip;
755                         newtuple.src.ip = expect->tuple.src.ip;
756                         newtuple.src.u.all = 0;
757                         newtuple.dst.protonum = expect->tuple.dst.protonum;
758                         /* Try to get same port: if not, try to change it. */
759                         for (; port != 0; port += 2) {
760                                 newtuple.dst.u.udp.port = htons(port);
761                                 if (ip_conntrack_change_expect(expect, &newtuple) == 0) {
762 #ifdef RTCP_SUPPORT
763                                         /* Change RTCP */
764                                         if (rtcp_exp) {
765                                                 DEBUGP("nat_sip: %s: RTCP exp %p found.\n",
766                                                                 __FUNCTION__, rtcp_exp);
767                                                 newtuple.dst.u.udp.port = htons(port + 1);
768                                                 if (ip_conntrack_change_expect(rtcp_exp, &newtuple) != 0) {
769                                                         DEBUGP("nat_sip: %s: Can't change RTCP exp %p.\n",
770                                                                         __FUNCTION__, rtcp_exp);
771                                                         continue;
772                                                 }
773                                                 rtcp_exp->help.exp_sip_info.nated = 1;
774                                         }
775 #endif
776                                         break;
777                                 }
778                         }
779                         if (port == 0)
780                                 return 0;
781
782                         exp_sip_info->nated = 1;
783                         ct_sip_info->rtpport = port;
784                         DEBUGP("nat_sip: %s: RTP exp %p, masq port=%d\n", __FUNCTION__, expect, port);
785                 } else if (exp_sip_info->type == CONN_RTPVIDEO){
786                         DEBUGP("nat_sip: %s: There is a RTP exp %p.\n", __FUNCTION__, expect);
787                         /* RTP Video expect */
788                         isvideoport = 1;
789                         videoport = ntohs(expect->tuple.dst.u.udp.port);
790 #ifdef RTCP_SUPPORT
791                         rtcp_exp = expect_find(ct, expect->tuple.dst.ip, port + 1);
792 #endif
793                         /* RFC1889 - If an application is supplied with an odd number
794                          * for use as the RTP port, it should replace this number with
795                          * the next lower (even) number. */
796                         if (videoport & 0x01) 
797                                 videoport++;
798                         /* fullfill newtuple */
799                         memset(&newtuple, 0, sizeof(struct ip_conntrack_tuple));
800                         newtuple.dst.ip = wanip;
801                         newtuple.src.ip = expect->tuple.src.ip;
802                         newtuple.src.u.all = 0;
803                         newtuple.dst.protonum = expect->tuple.dst.protonum;
804                         /* Try to get same port: if not, try to change it. */
805                         for (; videoport != 0; videoport += 2) {
806                                 newtuple.dst.u.udp.port = htons(videoport);
807                                 if (ip_conntrack_change_expect(expect, &newtuple) == 0) {
808 #ifdef RTCP_SUPPORT
809                                         /* Change RTCP */
810                                         if (rtcp_exp) {
811                                                 DEBUGP("nat_sip: %s: RTCP exp %p found.\n",
812                                                                 __FUNCTION__, rtcp_exp);
813                                                 newtuple.dst.u.udp.port = htons(videoport + 1);
814                                                 if (ip_conntrack_change_expect(rtcp_exp, &newtuple) != 0) {
815                                                         DEBUGP("nat_sip: %s: Can't change RTCP exp %p.\n",
816                                                                         __FUNCTION__, rtcp_exp);
817                                                         continue;
818                                                 }
819                                                 rtcp_exp->help.exp_sip_info.nated = 1;
820                                         }
821 #endif
822                                         break;
823                                 }
824                         }
825                         if (videoport == 0)
826                                 return 0;
827
828                         exp_sip_info->nated = 1;
829                         ct_sip_info->rtpport = videoport;
830                         DEBUGP("nat_sip: %s: RTP video exp %p, masq port=%d\n", __FUNCTION__, expect, videoport);                               
831                 }
832 #ifdef RTCP_SUPPORT
833                 else {
834                         /* We ignore the RTCP expect, and will adjust it later
835                          * during RTP expect */
836                         DEBUGP("nat_sip: %s: There is a RTCP exp %p, by-pass.\n", __FUNCTION__, expect);
837                         return 1;
838                 }
839 #endif
840         }
841
842 mangle:
843         /* Change address inside packet to match way we're mapping
844            this connection. */
845         if (!ct_sip_info->mangled){
846                 if (!mangle_sip_packet(ct, ctinfo, pskb, wanip, isvideoport))
847                         return 0;
848         }               
849
850         return 1;
851 }
852
853 static int sip_in_data_fixup(struct ip_conntrack *ct,
854                 struct sk_buff **pskb,
855                 enum ip_conntrack_info ctinfo,
856                 struct ip_conntrack_expect *expect)
857 {
858         struct iphdr *iph = (*pskb)->nh.iph;
859         struct udphdr *udph = (void *)iph + iph->ihl * 4;
860         const char *data = (const char *)udph + 8;
861         unsigned int udplen = ntohs(iph->tot_len) - (iph->ihl * 4);
862         unsigned int datalen = udplen - 8;
863         struct ip_ct_sip_master *ct_sip_info = &ct->help.ct_sip_info;
864         u_int32_t wanip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;     // NAT wan ip
865         unsigned int matchlen, matchoff;
866         int found, diff_len = 0;
867         u_int32_t ipaddr = 0, vip = 0;
868         u_int16_t port = 0, vport = 0, aport = 0;
869         u_int16_t videoport = 0, rport = 0;
870         struct ip_conntrack_expect *exp;
871 #ifdef RTCP_SUPPORT
872         struct ip_conntrack_expect *rtcpexp;
873 #endif
874
875         if (expect){
876                 DEBUGP("nat_sip: %s: There is a exp %p.\n", __FUNCTION__, expect);
877         } else {
878                 return 1;
879         }
880         DEBUGP("nat_sip: ct_sip_info->mangled=[%d]\n", ct_sip_info->mangled);
881
882         /* Prevent from mangling the packet or expect twice */
883         if (ct_sip_info->mangled) {
884                 DEBUGP("nat_sip: %s: the conntrack %p had been mangled.\n", __FUNCTION__, ct);
885                 return 1;
886         }
887         //u_int32_t srcaddr = iph->daddr;//source address of ip field in packet
888
889         ct_sip_info->mangled = 1;
890         //if (srcaddr != wanip){ //private ip
891                 if (strnicmp(data, "SIP/2.0 ", 8) != 0) {//This packet is request
892                         found = 0;
893                         /* Find CSeq field */
894                         found = find_pattern(data, datalen, "CSeq: ", 6, ' ', '\r',
895                                 &matchoff, &matchlen);
896                         if (found && matchlen != 0) {
897                                 vip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
898                                 vport = ntohs(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.udp.port);
899                                 mangle_sip_requestline(ct, ctinfo, pskb, vip, vport);
900                                 //return 1;
901                         }
902                 }
903         
904                 if (strnicmp(data, "SIP/2.0 200", 11) == 0) {
905                         /* Find CSeq field */
906                         found = find_pattern(data, datalen, "CSeq: ", 6, ' ', '\r',
907                                         &matchoff, &matchlen);
908                         if (found && matchlen != 0) {
909                                 char *p = (char *)data + matchoff;
910
911                                 simple_strtoul(p, &p, 10);
912                                 if (strnicmp(p, " REGISTER", 9) == 0) {
913                                         DEBUGP("nat_sip: 200 OK - REGISTER\n");
914                                         vip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
915                                         vport = ntohs(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.udp.port);
916                                         mangle_sip_via(ct, ctinfo, pskb, vip, vport);
917                                 mangle_sip_contact_in(ct, ctinfo, pskb, vip, vport);
918                                         return 1;
919                                 } else if (strnicmp(p, " INVITE", 7) == 0){
920                                         DEBUGP("nat_sip: 200 OK - INVITE\n");
921                                         vip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
922                                         vport = ntohs(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.udp.port);
923                                         mangle_sip_via(ct, ctinfo, pskb, vip, vport);
924                                         //return 1;
925                                 } else {//Don't care SDP session
926                                         vip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
927                                         vport = ntohs(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.udp.port);
928                                         mangle_sip_via(ct, ctinfo, pskb, vip, vport);
929                                         return 1;
930                                 }
931                         }
932                 }
933         
934                 if (strnicmp(data, "SIP/2.0 1", 9) == 0) {//This packet is 1xx response 
935                         found = 0;
936                         /* Find CSeq field */
937                         found = find_pattern(data, datalen, "CSeq: ", 6, ' ', '\r',
938                                 &matchoff, &matchlen);
939                         if (found && matchlen != 0) {
940                                 //char *p = (char *)data + matchoff;
941                                 //simple_strtoul(p, &p, 8);
942                                 DEBUGP("nat_sip: pre change via and contact field\n");
943                                 vip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
944                                 vport = ntohs(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.udp.port);
945                                 mangle_sip_via(ct, ctinfo, pskb, vip, vport);
946                                 mangle_sip_contact(ct, ctinfo, pskb, vip, vport);
947                                 return 1;
948                         }
949                 }
950         
951                 if (strnicmp(data, "SIP/2.0 3", 9) == 0) {//This packet is 3xx response 
952                         found = 0;
953                         /* Find CSeq field */
954                         found = find_pattern(data, datalen, "CSeq: ", 6, ' ', '\r',
955                                         &matchoff, &matchlen);
956                         if (found && matchlen != 0) {
957                                 //char *p = (char *)data + matchoff;
958                                 //simple_strtoul(p, &p, 8);
959                                 DEBUGP("nat_sip: pre change via and contact field\n");
960                                 vip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
961                                 vport = ntohs(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.udp.port);
962                                 mangle_sip_via(ct, ctinfo, pskb, vip, vport);
963                                 return 1;
964                         }
965                 }
966
967                 if (strnicmp(data, "SIP/2.0 4", 9) == 0) {//This packet is 4xx response 
968                 found = 0;
969                 /* Find CSeq field */
970                 found = find_pattern(data, datalen, "CSeq: ", 6, ' ', '\r',
971                                 &matchoff, &matchlen);
972                 if (found && matchlen != 0) {
973                         //char *p = (char *)data + matchoff;
974                         //simple_strtoul(p, &p, 8);
975                         DEBUGP("nat_sip: pre change via and contact field\n");
976                         vip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
977                         vport = ntohs(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.udp.port);
978                         mangle_sip_via(ct, ctinfo, pskb, vip, vport);
979                         mangle_sip_contact(ct, ctinfo, pskb, vip, vport);
980                         return 1;
981                 }
982         }       
983                 
984                 if (strnicmp(data, "SIP/2.0 5", 9) == 0) {//This packet is 5xx response 
985                         found = 0;
986                         /* Find CSeq field */
987                         found = find_pattern(data, datalen, "CSeq: ", 6, ' ', '\r',
988                                 &matchoff, &matchlen);
989                         if (found && matchlen != 0) {
990                                 //char *p = (char *)data + matchoff;
991                                 //simple_strtoul(p, &p, 8);
992                                 DEBUGP("nat_sip: pre change via and contact field\n");
993                                 vip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
994                                 vport = ntohs(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.udp.port);
995                                 mangle_sip_via(ct, ctinfo, pskb, vip, vport);
996                                 mangle_sip_contact(ct, ctinfo, pskb, vip, vport);
997                                 return 1;
998                         }
999                 }
1000                 
1001                 if (strnicmp(data, "SIP/2.0 6", 9) == 0) {//This packet is 6xx response 
1002                         found = 0;
1003                         /* Find CSeq field */
1004                         found = find_pattern(data, datalen, "CSeq: ", 6, ' ', '\r',
1005                                 &matchoff, &matchlen);
1006                         if (found && matchlen != 0) {
1007                                 //char *p = (char *)data + matchoff;
1008                                 //simple_strtoul(p, &p, 8);
1009                                 DEBUGP("nat_sip: pre change via and contact field\n");
1010                                 vip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
1011                                 vport = ntohs(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.udp.port);
1012                                 mangle_sip_via(ct, ctinfo, pskb, vip, vport);
1013                                 mangle_sip_contact(ct, ctinfo, pskb, vip, vport);
1014                                 return 1;
1015                         }
1016                 }
1017         
1018         //}
1019         
1020         /* Only interesting the SDP content. */
1021         if (strnicmp(data, "INVITE", 6) != 0 && strnicmp(data, "SIP/2.0 200", 11) != 0)
1022                 return 1;
1023         
1024         /* Find RTP address */
1025         found = find_sdp_rtp_addr(data, datalen, &matchoff, &matchlen, &ipaddr);
1026
1027         DEBUGP("nat_sip: sdp address found = %d, ipaddr = %u.%u.%u.%u\n", found, NIPQUAD(ipaddr));
1028         if (found < 2)
1029                 return 1;
1030
1031         DEBUGP("nat_sip: wanip = %u.%u.%u.%u\n", NIPQUAD(wanip));
1032         /* Is it a null address or our WAN address? */
1033         if (ipaddr == 0 || (htonl(ipaddr) != wanip))
1034                 return 1;
1035
1036         DEBUGP("nat_sip: %s: This is a loopback RTP connection.\n", __FUNCTION__);
1037
1038         /* Find audio port, and we don't like the well-known ports,
1039          * which is less than 1024 */
1040         port = find_sdp_audio_port(data, datalen, &matchoff, &matchlen);
1041         if (port < 1024)
1042                 return 0;
1043         
1044         DEBUGP("nat_sip: RTP audio port = %u\n", port);
1045
1046         exp = expect_find(ct, wanip, port);
1047         if (exp) {
1048                 DEBUGP("nat_sip: %s: Found exp %p, tuple.dst=%u.%u.%u.%u:%u.\n",
1049                                 __FUNCTION__, exp, NIPQUAD(ipaddr), port);
1050
1051                 /* Restore masq-ed SDP */
1052                 vip = exp->expectant->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
1053                 aport = exp->help.exp_sip_info.port;
1054                 if ((diff_len = mangle_sip_sdp_content(ct, ctinfo, pskb, vip, aport, 0)) != 0)
1055                         mangle_sip_content_length(ct, ctinfo, pskb, diff_len);
1056
1057                 /*************************************************************
1058                  * linux kernel 2.4 need to unexpect the related expectation *
1059                  * but in kernel 2.6, the function seem don't need anymore   *
1060                  * I still need to find why? but anyway, comment it now      *
1061                  *                                                                      Andrew (2005/08/01)      *
1062                  *************************************************************/
1063 #if 1
1064                 /* Unset RTP, RTCP expect, respectively */
1065                 //ip_conntrack_unexpect_related(exp);
1066 #ifdef RTCP_SUPPORT
1067                 rtcpexp = expect_find(ct, wanip, port + 1);
1068                 if (rtcpexp && ct != rtcpexp->expectant)
1069                         ip_conntrack_unexpect_related(rtcpexp);
1070 #endif //#ifdef RTCP_SUPPORT
1071 #endif //#if 0
1072         } else {
1073                 DEBUGP("nat_sip: %s: Can't find exp for tuple.dst=%u.%u.%u.%u:%u.\n",
1074                                 __FUNCTION__, NIPQUAD(ipaddr), port);
1075         }
1076
1077         
1078         /* Find video port, and we don't like the well-known ports,
1079          * which is less than 1024 */
1080         videoport = find_sdp_video_port(data, datalen, &matchoff, &matchlen);
1081         if (videoport < 1024)
1082                 return 0;
1083         DEBUGP("nat_sip: RTP video port = %u\n", videoport);
1084         if (videoport != port){
1085                 exp = expect_find(ct, wanip, videoport);
1086                 if (exp) {
1087                         DEBUGP("nat_sip: %s: Found video exp %p, tuple.dst=%u.%u.%u.%u:%u.\n",
1088                                         __FUNCTION__, exp, NIPQUAD(ipaddr), videoport);
1089
1090                         /* Restore masq-ed SDP */
1091                         vip = exp->expectant->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
1092                         rport = exp->help.exp_sip_info.port;
1093                         if ((diff_len = mangle_sip_sdp_content(ct, ctinfo, pskb, vip, rport, 1)) != 0)
1094                                 mangle_sip_content_length(ct, ctinfo, pskb, diff_len);
1095                         /* Unset RTP, RTCP expect, respectively */
1096                         //ip_conntrack_unexpect_related(exp);
1097 #ifdef RTCP_SUPPORT
1098                         rtcpexp = expect_find(ct, wanip, videoport + 1);
1099                         if (rtcpexp && ct != rtcpexp->expectant)
1100                                 ip_conntrack_unexpect_related(rtcpexp);
1101 #endif //#ifdef RTCP_SUPPORT
1102                 } else {
1103                         DEBUGP("nat_sip: %s: Can't find exp for tuple.dst=%u.%u.%u.%u:%u.\n",
1104                                         __FUNCTION__, NIPQUAD(ipaddr), videoport);
1105                 }               
1106                                 
1107         }       
1108         
1109
1110         return 1;
1111 }
1112
1113 static unsigned int nat_help(struct ip_conntrack *ct,
1114                          struct ip_conntrack_expect *exp,
1115                          struct ip_nat_info *info,
1116                          enum ip_conntrack_info ctinfo,
1117                          unsigned int hooknum,
1118                          struct sk_buff **pskb)
1119 {
1120         int dir;
1121
1122         /* Only mangle things once: original direction in POST_ROUTING
1123            and reply direction on PRE_ROUTING. */
1124         dir = CTINFO2DIR(ctinfo);
1125         if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_ORIGINAL)
1126               || (hooknum == NF_IP_PRE_ROUTING && dir == IP_CT_DIR_REPLY))) {
1127                 DEBUGP("nat_sip: Not touching dir %s at hook %s\n",
1128                        dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY",
1129                        hooknum == NF_IP_POST_ROUTING ? "POSTROUTING"
1130                        : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING"
1131                        : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???");
1132                 return NF_ACCEPT;
1133         }
1134
1135 #ifdef DEBUG_PRINTK
1136         struct iphdr *iph = (*pskb)->nh.iph;
1137         struct udphdr *udph = (void *)iph + iph->ihl * 4;
1138         const char *data = (const char *)udph + 8;
1139
1140         if (strnicmp(data, "REGISTER" , 8) == 0)
1141                 DEBUGP("nat_sip: REGISTER\n");
1142         else if (strnicmp(data, "INVITE" , 6) == 0)
1143                 DEBUGP("nat_sip: INVITE\n");
1144         else if (strnicmp(data, "ACK" , 3) == 0)
1145                 DEBUGP("nat_sip: ACK\n");
1146         else if (strnicmp(data, "BYE", 3) == 0)
1147                 DEBUGP("nat_sip: BYE\n");
1148         else if (strnicmp(data, "CANCEL", 6) == 0)
1149                 DEBUGP("nat_sip: CANCEL\n");
1150         else if (strnicmp(data, "SIP/2.0 200", 11) == 0)
1151                 DEBUGP("nat_sip: 200 OK\n");
1152         else if (strnicmp(data, "SIP/2.0 100", 11) == 0)
1153                 DEBUGP("nat_sip: 100 Trying\n");
1154         else if (strnicmp(data, "SIP/2.0 180", 11) == 0)
1155                 DEBUGP("nat_sip: 180 Ringing\n");
1156         else if (strnicmp(data, "SIP/2.0 401", 11) == 0)
1157                 DEBUGP("nat_sip: 401 Unauthorized\n");  
1158 #endif
1159
1160         LOCK_BH(&ip_sip_lock);
1161
1162         if (dir == IP_CT_DIR_ORIGINAL) {
1163                 DEBUGP("call sip_out_data_fixup\n");
1164                 sip_out_data_fixup(ct, pskb, ctinfo, exp);
1165                 DEBUGP("exit sip_out_data_fixup\n");
1166         } else {
1167                 DEBUGP("call sip_in_data_fixup\n");
1168                 sip_in_data_fixup(ct, pskb, ctinfo, exp);
1169                 DEBUGP("exit sip_in_data_fixup\n");
1170         }
1171
1172         UNLOCK_BH(&ip_sip_lock);
1173
1174         return NF_ACCEPT;
1175 }
1176
1177 static struct ip_nat_helper sip[MAX_PORTS];
1178 static char sip_names[MAX_PORTS][6];
1179
1180 /* Not __exit: called from init() */
1181 static void fini(void)
1182 {
1183         int i;
1184         for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
1185                 DEBUGP("ip_nat_sip: unregistering port %d\n", ports[i]);
1186                 ip_nat_helper_unregister(&sip[i]);
1187         }
1188 }
1189
1190 static int __init init(void)
1191 {
1192         int i, ret=0;
1193         char *tmpname;
1194
1195         //printk("ip_nat_sip v0.01 loading\n");
1196
1197         if (ports[0] == 0)
1198                 ports[0] = SIP_PORT;
1199
1200         for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
1201
1202                 memset(&sip[i], 0, sizeof(struct ip_nat_helper));
1203
1204                 sip[i].tuple.src.u.udp.port = htons(ports[i]);
1205                 sip[i].tuple.dst.protonum = IPPROTO_UDP;
1206                 sip[i].mask.src.u.udp.port = 0xFFFF;
1207                 sip[i].mask.dst.protonum = 0xFFFF;
1208                 sip[i].help = nat_help;
1209                 sip[i].expect = sip_nat_expected;
1210                 sip[i].flags = IP_NAT_HELPER_F_ALWAYS;
1211
1212                 tmpname = &sip_names[i][0];
1213                 sprintf(tmpname, "sip%2.2d", i);
1214                 sip[i].name = tmpname;
1215
1216                 DEBUGP("ip_nat_sip: Trying to register for port %d\n",
1217                                 ports[i]);
1218                 ret = ip_nat_helper_register(&sip[i]);
1219
1220                 if (ret) {
1221                         printk("ip_nat_sip: error registering "
1222                                "helper for port %d\n", ports[i]);
1223                         fini();
1224                         return ret;
1225                 }
1226                 ports_c++;
1227         }
1228         return ret;
1229 }
1230
1231 module_init(init);
1232 module_exit(fini);