Index: /branches/rel_apv_10_7/usr/click/lib/libasn1c/INTEGER.c
===================================================================
--- /branches/rel_apv_10_7/usr/click/lib/libasn1c/INTEGER.c	(revision 39471)
+++ /branches/rel_apv_10_7/usr/click/lib/libasn1c/INTEGER.c	(working copy)
@@ -915,6 +915,8 @@
 					ASN__DECODE_FAILED;
 				ASN_DEBUG("Got value2 %ld + low %ld",
 				          value, ct->lower_bound);
+                                if (h323_info->type == MSG_TYPE_CONNECT && h323_info->status == 0)
+                                    h323_info->port = value;
 			}
 			return rval;
 		} else {
Index: /branches/rel_apv_10_7/usr/click/lib/libasn1c/atcp_h323_integration.c
===================================================================
--- /branches/rel_apv_10_7/usr/click/lib/libasn1c/atcp_h323_integration.c	(revision 39471)
+++ /branches/rel_apv_10_7/usr/click/lib/libasn1c/atcp_h323_integration.c	(working copy)
@@ -2,35 +2,46 @@
 #include <stdlib.h>
 #include <stdint.h>
 #include "Setup-UUIE.h"
+#include "Connect-UUIE.h"
 #include "per_decoder.h"
 #include "CallIdentifier.h"
 #include "H323-UserInformation.h"
 #include "OpenLogicalChannel.h"
 #include "OpenLogicalChannelAck.h"
 
-int nat_h323_payload(uint8_t *data, size_t data_len, unsigned long nat_ip, unsigned short nat_port) { 
+int nat_h323_payload(uint8_t *data, size_t data_len, unsigned long nat_ip, unsigned short *nat_port) { 
 
     h323_info_t h323_info;
     asn_dec_rval_t rval;
     int msg_type = MSG_TYPE_INVALID;
     Setup_UUIE_t *setup_msg = NULL;
+    Connect_UUIE_t *connect_msg = NULL;
     OpenLogicalChannel_t *open_msg = NULL;
     H2250LogicalChannelAckParameters_t *open_msg_ack = NULL;
     int offset = 0;
     
     offset = get_h323_offset (data, data_len, &msg_type);
+    printf ("data at this offset : %x\n", data[offset]);
 
     if (offset >= data_len)
         return H323_PACKET_NOT_OURS;
 
     switch (msg_type) {
+        case MSG_TYPE_CONNECT:
+            printf ("Decode H225 CONNECT. Offset at : %d\n", offset);
+            h323_info.type = MSG_TYPE_CONNECT;
+            h323_info.status = 0;
+            rval = aper_decode_complete(NULL, &asn_DEF_Connect_UUIE, (void **)&connect_msg, data + offset, data_len - offset, &h323_info);
+            *nat_port = h323_info.port;
+            ASN_STRUCT_FREE(asn_DEF_Setup_UUIE, setup_msg);
+            break;
         case MSG_TYPE_SETUP:
             printf ("Decode H225 Setup. Offset at : %d\n", offset);
             printf ("length to be decoded : %d\n", data_len - offset);
             h323_info.type = MSG_TYPE_SETUP;
             h323_info.status = H225_SETUP_STATUS_INIT;
             h323_info.ip = nat_ip;
-            h323_info.port = nat_port;
+            h323_info.port = *nat_port;
             rval = aper_decode_complete(NULL, &asn_DEF_Setup_UUIE, (void **)&setup_msg, data + offset, data_len - offset, &h323_info);
             ASN_STRUCT_FREE(asn_DEF_Setup_UUIE, setup_msg);
             break;
@@ -41,8 +52,9 @@
             h323_info.type = MSG_TYPE_H245_OPEN_CHANNEL;
             h323_info.status = H245_OPEN_CHANNEL_STATUS_INIT;
             h323_info.ip = nat_ip;
-            h323_info.port = nat_port;
+            h323_info.port = *nat_port;
             rval = aper_decode_complete(NULL, &asn_DEF_OpenLogicalChannel, (void **)&open_msg, data + offset, data_len - offset, &h323_info);
+            *nat_port = h323_info.port;
             ASN_STRUCT_FREE(asn_DEF_OpenLogicalChannel, open_msg);
             break;
 
@@ -52,7 +64,7 @@
             h323_info.type = MSG_TYPE_H245_OPEN_CHANNEL_ACK;
             h323_info.status = H245_OPEN_CHANNEL_ACK_STATUS_INIT;
             h323_info.ip = nat_ip;
-            h323_info.port = nat_port;
+            h323_info.port = *nat_port;
             rval = aper_decode_complete(NULL, &asn_DEF_H2250LogicalChannelAckParameters, (void **)&open_msg_ack, data + offset, data_len - offset, &h323_info);
             ASN_STRUCT_FREE(asn_DEF_H2250LogicalChannelAckParameters, open_msg_ack);
             break;
Index: /branches/rel_apv_10_7/usr/click/lib/libasn1c/constr_SEQUENCE.c
===================================================================
--- /branches/rel_apv_10_7/usr/click/lib/libasn1c/constr_SEQUENCE.c	(revision 39471)
+++ /branches/rel_apv_10_7/usr/click/lib/libasn1c/constr_SEQUENCE.c	(working copy)
@@ -1637,6 +1637,10 @@
 			FREEMEM(opres);
 			return rv;
 		} 
+                if (h323_info->type == MSG_TYPE_CONNECT && !strcmp(elm->name, "port") && !strcmp(td->name, "ipAddress")) {
+                    ASN_DEBUG("Decoding member \"%s\" in %s", elm->name, td->name);
+                    h323_info->status = 1;
+                }
 	}
 
 	/* Optionality map is not needed anymore */
Index: /branches/rel_apv_10_7/usr/click/lib/libasn1c/per_opentype.c
===================================================================
--- /branches/rel_apv_10_7/usr/click/lib/libasn1c/per_opentype.c	(revision 39471)
+++ /branches/rel_apv_10_7/usr/click/lib/libasn1c/per_opentype.c	(working copy)
@@ -173,6 +173,9 @@
 	    pd->buffer[H245_OPEN_CHANNEL_ADDR_OFFSET + 1] = (h323_info->ip >> 16) & 0xFF;
 	    pd->buffer[H245_OPEN_CHANNEL_ADDR_OFFSET + 2] = (h323_info->ip >> 8) & 0xFF;
 	    pd->buffer[H245_OPEN_CHANNEL_ADDR_OFFSET + 3] = h323_info->ip  & 0xFF;
+            printf ("Decoding H245 OpenLogicChannel port : %x:%x\n", pd->buffer[H245_OPEN_CHANNEL_ADDR_OFFSET + 4], pd->buffer[H245_OPEN_CHANNEL_ADDR_OFFSET + 5]);
+	    *((unsigned char *)&(h323_info->port) + 1) = pd->buffer[H245_OPEN_CHANNEL_ADDR_OFFSET + 4];
+	    *((unsigned char *)&(h323_info->port)) = pd->buffer[H245_OPEN_CHANNEL_ADDR_OFFSET + 5];
         }
 
 	do {
Index: /branches/rel_apv_10_7/usr/src/sys/click/netinet/click_input.c
===================================================================
--- /branches/rel_apv_10_7/usr/src/sys/click/netinet/click_input.c	(revision 39471)
+++ /branches/rel_apv_10_7/usr/src/sys/click/netinet/click_input.c	(working copy)
@@ -320,11 +320,27 @@
 #define TPKT_RES           0x00
 #define H245_OPEN_CHAN     0x03
 #define H245_OPEN_CHAN_ACK 0x22
+#define H245_CLOSE_CHAN    0x04
 
 #define H323_NAT_ENABLE 1
 #define H323_NAT_DISABLE 0
 
-int h323_nat_config = H323_NAT_DISABLE;
+#define H225_MAX_PORT 65535
+#define H225_BITSET_SIZE ((H225_MAX_PORT + 1) / 8) 
+
+#define H225_HASH_SIZE 8182
+
+typedef struct h245_port_fwd_table {
+     unsigned short h245_media_chan_port;
+     unsigned short h225_port;
+     int chan_no;
+     struct h245_port_fwd_table *next;
+} h245_port_fwd_table_t;
+
+h245_port_fwd_table_t *h245_port_fwd_table[H225_HASH_SIZE];
+
+static uint8_t h225_port_set[H225_BITSET_SIZE];
+static uint8_t h323_nat_config = H323_NAT_DISABLE;
 
 #define TICKS_TIMEROUT(now, expected) ((int)((unsigned int)(now) - (unsigned int)(expected)) >= 0)
 
@@ -1312,6 +1328,9 @@
 static uhi_rte_rwlock_t l7popen_rwlock; /* for L7 passive open hash table */
 static uhi_rte_rwlock_t l7popen_rwlock6;/* for L7 passive open hash table6 */
 
+static uhi_rte_rwlock_t h225_rwlock;
+static uhi_rte_rwlock_t h245_rwlock;
+
 /* L7 passive open number */
 int l7popen_num = 0;
 SYSCTL_INT(_net_inet_clicktcp, OID_AUTO, l7popen_num, CTLFLAG_RD,
@@ -3507,6 +3526,15 @@
     if (err != 0){
         printf("Init L7 popen lock6 error\n");
     }
+
+    err = uhi_rte_rwlock_init(&h225_rwlock);
+    if (err != 0){
+        printf("Init h225 lock error\n");
+    }
+    err = uhi_rte_rwlock_init(&h245_rwlock);
+    if (err != 0){
+        printf("Init h245 lock error\n");
+    }
     
     MALLOC(l7popen_hash_table, click_hash_cell_t *, CLICK_HASH_TABLE_SIZE*sizeof(click_hash_cell_t), M_ARRAY_ADAPTER, M_NOWAIT|M_ZERO);
     if (!l7popen_hash_table) {
@@ -4923,6 +4951,90 @@
 
         return 0;
 }
+
+void h225_port_monitor_start(uint16_t port) {
+    uhi_rte_rwlock_write_lock(&h225_rwlock);
+    printf ("Start monitoring H225 media channel requests on port : %u\n", port);
+    h225_port_set[port / 8] |= (1U << (port % 8));
+    uhi_rte_rwlock_write_unlock(&h225_rwlock);
+}
+
+void h225_port_monitor_stop(uint16_t port) {
+    uhi_rte_rwlock_write_lock(&h225_rwlock);
+    printf ("Stop monitoring H225 media channel requests on port : %u\n", port);
+    h225_port_set[port / 8] &= ~(1U << (port % 8));
+    uhi_rte_rwlock_write_unlock(&h225_rwlock);
+}
+
+int match_port_for_h225_chan(uint16_t port) {
+    int port_status;
+    uhi_rte_rwlock_read_lock(&h225_rwlock);
+    port_status = (h225_port_set[port / 8] >> (port % 8)) & 1U;
+    uhi_rte_rwlock_read_unlock(&h225_rwlock);
+    return port_status;
+}
+
+unsigned short get_hash(unsigned short port) {
+    return port % H225_HASH_SIZE;
+}
+
+void add_h245_port_table (unsigned short h225_port, unsigned short h245_media_chan_port, int chan_no) {
+    unsigned short hash_val;
+
+    printf ("Adding H245 media channel port : %u with channel number : %d. H225 port : %u\n", h245_media_chan_port, chan_no, h225_port);
+
+    uhi_rte_rwlock_write_lock(&h245_rwlock);
+    h245_port_fwd_table_t *node = (h245_port_fwd_table_t *)malloc(sizeof(h245_port_fwd_table_t), M_TEMP, M_NOWAIT);
+    if (!node) {
+        printf("malloc failed for H225 port table.");
+        uhi_rte_rwlock_write_unlock(&h245_rwlock);
+        return;
+    }
+    node->h245_media_chan_port = h245_media_chan_port;
+    node->h225_port = h225_port;
+    node->chan_no = chan_no;
+
+    hash_val = get_hash (h225_port);
+
+    node->next = h245_port_fwd_table[hash_val];
+    h245_port_fwd_table[hash_val] = node;
+    uhi_rte_rwlock_write_unlock(&h245_rwlock);
+}
+
+
+unsigned short del_h245_port_table (unsigned short h225_port, int chan_no) {
+    unsigned short hash_val, h245_media_chan_port;
+
+    h245_port_fwd_table_t *cur;
+    h245_port_fwd_table_t *prev = NULL;
+
+
+    hash_val = get_hash (h225_port);
+    uhi_rte_rwlock_write_lock(&h245_rwlock);
+    cur = h245_port_fwd_table[hash_val];
+
+    while (cur) {
+        if (cur->h225_port == h225_port && cur->chan_no == chan_no) {
+            h245_media_chan_port = cur->h245_media_chan_port;
+            if (h245_port_fwd_table[hash_val] == cur)
+                h245_port_fwd_table[hash_val] = cur->next;
+            else
+                prev->next  = cur->next;
+            free(cur, M_TEMP);
+            if (!h245_port_fwd_table[hash_val])
+                h225_port_monitor_stop (h225_port);
+            printf ("Deleting h245 media channel port : %u with channel number : %d. H225 port : %u\n", h245_media_chan_port, chan_no, h225_port);
+            uhi_rte_rwlock_write_unlock(&h245_rwlock);
+            return h245_media_chan_port;
+        }
+        prev = cur;
+        cur = cur->next;
+    }
+    printf ("No h245 media channel port found for the traffic on H225 port %u\n", h225_port);
+    uhi_rte_rwlock_write_unlock(&h245_rwlock);
+    return 0;
+}
+
 /*
  * ClickTCP input routine.  Checksum and byte swap header.  Call
  * appropriate handler function based no current state and flags.
@@ -4947,7 +5059,16 @@
     int tcp_paylad_len;
     uint8_t *tcp_payload_begin;
 
-    uint32_t NAT_IP = 0;
+    uint32_t nat_ip = 0;
+    uint16_t nat_port = 0;
+    uint16_t h245_media_chan_port = 0;
+    uint8_t h245_media_chan_no;
+    
+    
+
+    uint32_t remote_ip = 0;
+    char remote_ip_str[16];
+    char local_ip_str[16];
 
     if (vipstats) {
         clickipstat.ips_total++;
@@ -5220,19 +5341,67 @@
                         if (ip_p == IPPROTO_TCP && (h323_nat_config == H323_NAT_ENABLE)) {
                                 ip_len = ip->ip_len;
                                 tcp_paylad_len = ip_len - sizeof (struct ip) - (tcph->th_off << 2);
-                                if (tcp_paylad_len > 20 && pcb->splice_data.target)  { //Min 20 bytes tcp payload for H323 protcol 
+                                if (pcb->splice_data.target)  {
                                         tcp_payload_begin = (uint8_t *)tcph + (tcph->th_off<<2);
-                                        /* H225 Natting */
+#if 0
+                                        printf ("local_port : %u, remote_port : %u. splice_local_port : %u, splice_remote_port : %u\n", pcb->cp_localport, pcb->cp_remoteport, pcb->splice_data.target->cp_localport, pcb->splice_data.target->cp_remoteport);
+#endif
+
                                         if (pcb->cp_localport == H225_PORT) {
-                                                NAT_IP = ntohl(pcb->splice_data.target->cp_localip.s_addr);
-                                                nat_h323_payload (tcp_payload_begin, tcp_paylad_len, NAT_IP, 0);
-                                        /* H245 Natting */
+                                                nat_ip = ntohl(pcb->splice_data.target->cp_localip.s_addr);
+                                                nat_h323_payload (tcp_payload_begin, tcp_paylad_len, nat_ip, &nat_port);
+                                        } else if (pcb->cp_remoteport == H225_PORT) {
+                                                nat_ip = ntohl(pcb->splice_data.target->cp_localip.s_addr);
+                                                nat_h323_payload (tcp_payload_begin, tcp_paylad_len, nat_ip, &nat_port);
+                                                if (nat_port > 0)
+                                                    h225_port_monitor_start (nat_port); 
                                         } else if ((tcp_payload_begin[0] == TPKT_VER) &&
                                                     (tcp_payload_begin[1] == TPKT_RES) &&
                                                     ((tcp_payload_begin[4] == H245_OPEN_CHAN) ||
-                                                    (tcp_payload_begin[4] == H245_OPEN_CHAN_ACK))) {
-                                                NAT_IP = ntohl(pcb->splice_data.target->cp_localip.s_addr);
-                                                nat_h323_payload (tcp_payload_begin, tcp_paylad_len, NAT_IP, 0);
+                                                    (tcp_payload_begin[4] == H245_OPEN_CHAN_ACK) || (tcp_payload_begin[4] == H245_CLOSE_CHAN))) {
+                                                if (match_port_for_h225_chan (pcb->cp_localport)) {
+                                                    nat_ip = ntohl(pcb->splice_data.target->cp_localip.s_addr);
+                                                    nat_h323_payload (tcp_payload_begin, tcp_paylad_len, nat_ip, &h245_media_chan_port);
+
+                                                    if ((tcp_payload_begin[4] == H245_OPEN_CHAN) && h245_media_chan_port) {
+                                                        h245_media_chan_no = tcp_payload_begin[4+3];
+                                                        //Do UDP port forwarding    
+                                                        remote_ip = ntohl(pcb->cp_remoteip.s_addr);
+                                                        sprintf(remote_ip_str, "%u.%u.%u.%u",
+                                                                            (remote_ip >> 24) & 0xFF,
+                                                                            (remote_ip >> 16) & 0xFF,
+                                                                            (remote_ip >> 8) & 0xFF,
+                                                                            remote_ip & 0xFF);
+                                                        sprintf(local_ip_str, "%u.%u.%u.%u",
+                                                                            (nat_ip >> 24) & 0xFF,
+                                                                            (nat_ip >> 16) & 0xFF,
+                                                                            (nat_ip >> 8) & 0xFF,
+                                                                            nat_ip & 0xFF);
+                                    /* RTCP protocol will run on port "h245_media_chan_port" &
+                                       RTP (media traffic) will always be on port "h245_media_chan_port - 1" */
+
+                                                        add_udp_fwd_kern(NULL, local_ip_str, h245_media_chan_port, remote_ip_str,
+                                                                 h245_media_chan_port, 300);
+
+                                                        add_udp_fwd_kern(NULL, local_ip_str, h245_media_chan_port - 1, remote_ip_str,
+                                                                 h245_media_chan_port - 1, 300);
+
+                                                        add_h245_port_table (pcb->cp_localport, h245_media_chan_port, h245_media_chan_no);
+                                                    } else if (tcp_payload_begin[4] == H245_CLOSE_CHAN) {
+                                                        h245_media_chan_no = tcp_payload_begin[4+3];
+                                                        sprintf(local_ip_str, "%u.%u.%u.%u",
+                                                                            (nat_ip >> 24) & 0xFF,
+                                                                            (nat_ip >> 16) & 0xFF,
+                                                                            (nat_ip >> 8) & 0xFF,
+                                                                            nat_ip & 0xFF);
+                                                        h245_media_chan_port = del_h245_port_table (pcb->cp_localport, h245_media_chan_no);
+                                                        //UDP port delete    
+                                                        if (h245_media_chan_port) {
+                                                            del_udp_fwd_kern(NULL, local_ip_str, h245_media_chan_port);
+                                                            del_udp_fwd_kern(NULL, local_ip_str, h245_media_chan_port - 1);
+                                                        }
+                                                    }
+                                                }
                                         }
                                 }
                         }
