common: Adding common library for sample vnf
[samplevnf.git] / common / VIL / alg / lib_ftp_alg.c
1 /*
2 // Copyright (c) 2017 Intel Corporation
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //      http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 */
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <stdint.h>
19 #include <string.h>
20 #include <unistd.h>
21
22 #include <app.h>
23 #include <rte_common.h>
24 #include <rte_malloc.h>
25 #include <rte_mbuf.h>
26 #include <rte_ip.h>
27 #include <rte_byteorder.h>
28 #include <rte_table_lpm.h>
29 #include <rte_table_hash.h>
30 #include <rte_pipeline.h>
31 #include <rte_arp.h>
32 #include <rte_icmp.h>
33 #include <rte_hash.h>
34 #include <rte_jhash.h>
35 #include <rte_cycles.h>
36 #include "pipeline_cgnapt_common.h"
37 #include "pipeline_actions_common.h"
38 #include "pipeline_cgnapt_be.h"
39 #include "hash_func.h"
40 #include "lib_ftp_alg.h"
41 #include "vnf_common.h"
42 #include "pipeline_common_be.h"
43 #include "rte_ct_tcp.h"
44 #include "rte_cnxn_tracking.h"
45 #define ALG_DEBUG 1
46
47 #if 1
48 extern uint8_t
49 rte_ct_create_cnxn_hashkey(
50         uint32_t *src_addr,
51         uint32_t *dst_addr,
52         uint16_t src_port,
53         uint16_t dst_port,
54         uint8_t proto,
55         uint32_t *key,
56         uint8_t type);
57 #endif
58
59 struct rte_mbuf *lib_alg_pkt;
60 enum {PRIVATE, PUBLIC};
61 struct rte_hash_parameters ftp_alg_hash_params = {
62         .name = "FTP ALG",
63         .entries = 1024,
64         .reserved = 0,
65         .key_len = sizeof(struct ftp_alg_key),
66         .hash_func = rte_jhash,
67         .hash_func_init_val = 0,
68 };
69
70 struct rte_hash *ftp_alg_hash_handle;
71
72 /**
73  * ftp_alg Init function
74  */
75 void lib_ftp_alg_init(void)
76 {
77 printf("NAT FTP ALG initialization ...\n");
78
79         /* FTP ALG hash table initialization */
80
81         ftp_alg_hash_handle = rte_hash_create(&ftp_alg_hash_params);
82
83         #ifdef ALGDBG
84         if (ftp_alg_hash_handle == NULL)
85                 printf("FTP ALG rte_hash_create failed ...\n");
86         else
87                 printf("ftp_alg_hash_table %p\n\n",
88                         (void *)ftp_alg_hash_handle);
89
90         #endif
91 }
92
93 /*
94  * ftp_alg table retreive function
95  * Input - alg key
96  * Output - Entry
97  */
98
99 struct ftp_alg_table_entry *retrieve_ftp_alg_entry(struct ftp_alg_key alg_key)
100 {
101         struct ftp_alg_table_entry *ret_alg_data = NULL;
102         alg_key.filler1 = 0;
103         alg_key.filler2 = 0;
104
105         int ret = rte_hash_lookup_data(ftp_alg_hash_handle, &alg_key,
106                                                          (void **)&ret_alg_data);
107         if (ret < 0) {
108                 #ifdef ALGDBG
109                 printf("alg-hash lookup failed ret %d, EINVAL %d, ENOENT %d\n",
110                                          ret, EINVAL, ENOENT);
111                 #endif
112         } else {
113                 return ret_alg_data;
114         }
115
116         return NULL;
117 }
118
119 /*
120  * ftp_alg table entry delete
121  * Input - ipaddress, portid
122  * Output - sucess or failure
123  */
124 static int remove_ftp_alg_entry(uint32_t ipaddr, uint8_t portid)
125 {
126
127         /* need to lock here if multi-threaded... */
128         /* rte_hash_del_key is not thread safe */
129         struct ftp_alg_key alg_key;
130         alg_key.l4port = rte_bswap16(portid);
131         alg_key.ip_address = rte_bswap32(ipaddr);
132         alg_key.filler1 = 0;
133         alg_key.filler2 = 0;
134
135         #ifdef ALGDBG
136                 printf("remove_alg_entry ip %x, port %d\n", alg_key.ip_address,
137                                          alg_key.l4port);
138         #endif
139         return rte_hash_del_key(ftp_alg_hash_handle, &alg_key);
140 }
141 /*
142  * ftp_alg table entry add
143  * Input - ipaddress, portid
144  * Output - sucess or failure
145  */
146 void
147 populate_ftp_alg_entry(uint32_t ipaddr, uint8_t portid)
148 {
149         /* need to lock here if multi-threaded */
150         /* rte_hash_add_key_data is not thread safe */
151         struct ftp_alg_key alg_key;
152         alg_key.l4port = rte_bswap16(portid);
153         //arp_key.ip = rte_bswap32(ipaddr);
154         alg_key.ip_address = rte_bswap32(ipaddr);
155         alg_key.filler1 = 0;
156         alg_key.filler2 = 0;
157
158
159         //lib_arp_populate_called++;
160
161         #ifdef ALGDBG
162         printf("populate_ftp_alg_entry ip %x, port %d\n", alg_key.ip_address,
163                                          alg_key.l4port);
164         #endif
165
166         struct ftp_alg_table_entry *new_alg_data =
167                 retrieve_ftp_alg_entry(alg_key);
168         if (new_alg_data) {
169                 #ifdef ALGDBG
170                 printf("alg_entry exists ip%x, port %d\n", alg_key.ip_address,
171                                 alg_key.l4port);
172                 #endif
173                 //lib_arp_duplicate_found++;
174                 return;
175         }
176         new_alg_data = (struct ftp_alg_table_entry *)
177                         malloc(sizeof(new_alg_data));
178         //new_alg_data->status = INCOMPLETE;
179         new_alg_data->l4port = rte_bswap16(portid);
180         new_alg_data->ip_address = rte_bswap32(ipaddr);
181         rte_hash_add_key_data(ftp_alg_hash_handle, &alg_key, new_alg_data);
182
183         #ifdef ALGDBG
184                 // print entire hash table
185                 printf
186                                 ("\tALG: table update - ip=%d.%d.%d.%d  on port=%d\n",
187                                  (alg_key.ip_address >> 24),
188                                  ((alg_key.ip_address & 0x00ff0000) >> 16),
189                                  ((alg_key.ip_address & 0x0000ff00) >> 8),
190                                  ((alg_key.ip_address & 0x000000ff)), portid);
191                 /* print_arp_table(); */
192                 puts("");
193         #endif
194 }
195
196 /*
197  * ftp_alg payload modification for PORT and PASV command
198  * Input - cgnapt table entry - for taking the public /translated ip/port ,
199  * incoming PORT/PASV string, Session type - PORT or PASV
200  * Output - Translated string
201  */
202 int ftp_alg_modify_payload(
203         struct cgnapt_table_entry *egress_entry,
204         char *port_string,
205         char *port_string_translated, int ftp_session_type)
206 {
207         uint32_t transport_ip;
208         uint16_t transport_port;
209         uint16_t tmp1, tmp2, tmp3, tmp4, tmp5, tmp6;
210         uint16_t new_port_string_length;
211
212         uint8_t *bptr_public_address;
213
214         transport_ip = egress_entry->data.pub_ip;
215         transport_port = egress_entry->data.pub_port;
216         tmp5 = (uint16_t) (transport_port/0x100);
217         tmp6 = (uint16_t) (transport_port % 0x100);
218
219         transport_ip = rte_bswap32(transport_ip);
220
221         bptr_public_address = (uint8_t *) &transport_ip;
222
223         tmp4 = bptr_public_address[3];
224         tmp3 = bptr_public_address[2];
225         tmp2 = bptr_public_address[1];
226         tmp1 = bptr_public_address[0];
227
228         if (ftp_session_type == 1)
229                 sprintf(port_string_translated, FTP_PASV_PARAMETER_STRING,
230                         FTP_PASV_RETURN_CODE, tmp1, tmp2, tmp3, tmp4,
231                         tmp5, tmp6);
232         else
233                 sprintf(port_string_translated, FTP_PORT_PARAMETER_STRING,
234                         tmp1, tmp2, tmp3, tmp4, tmp5, tmp6);
235         #ifdef ALGDBG
236         printf("FTP ALG: FTP new string: Len:%d %s\n",
237                         (uint16_t) strlen(port_string_translated)-2,
238                         port_string_translated);
239
240         printf("FTP non translated PASV string: Len:%d, %s\n",
241                 (uint16_t)strlen(port_string)-2, port_string);
242                 printf("old strlen:%d  new strlen:%d\n",
243                 (int)strlen(port_string),
244                 (int)strlen(port_string_translated));
245         #endif
246
247         return(new_port_string_length =
248                 (uint16_t) strlen(port_string_translated));
249 }
250
251 /*
252  * ftp_alg modify packet len (due to change in len of FTP payload )
253  * Input - pkt
254  * Output - Length append /Trimmed Pkt
255 **/
256 static inline void ftp_alg_modify_pkt_len(struct rte_mbuf *pkt)
257 {
258         uint16_t pkt_length = 0;
259         int ip_hdr_size_bytes = rte_ct_get_IP_hdr_size(pkt);
260         void *iphdr = RTE_MBUF_METADATA_UINT32_PTR(pkt, IP_START);
261
262         if (ip_hdr_size_bytes == IPv4_HEADER_SIZE) {
263                 struct ipv4_hdr *ihdr4 = (struct ipv4_hdr *)iphdr;
264                 pkt_length = rte_bswap16(ihdr4->total_length) + ETH_HDR_SIZE;
265         } else if (ip_hdr_size_bytes == IPv6_HEADER_SIZE) {
266                 struct ipv6_hdr *ihdr6 = (struct ipv6_hdr *)iphdr;
267                 pkt_length = rte_bswap16(ihdr6->payload_len) +
268                         IPv6_HEADER_SIZE + ETH_HDR_SIZE;
269         }
270
271         uint16_t mbuf_pkt_length = rte_pktmbuf_pkt_len(pkt);
272
273         if (pkt_length == mbuf_pkt_length)
274                 return;
275
276         if (pkt_length < mbuf_pkt_length) {
277                 rte_pktmbuf_trim(pkt, mbuf_pkt_length - pkt_length);
278                 return;
279         }
280
281         /* pkt_length > mbuf_pkt_length */
282         rte_pktmbuf_append(pkt, pkt_length - mbuf_pkt_length);
283 }
284
285 /*
286  * ftp_alg IP HDR size calculation
287  * Input - pkt
288  * Output - Length of IP HDR
289  */
290
291 /* same as rte_ct_get_IP_hdr_size()*/
292 uint16_t ftp_alg_get_IP_hdr_size(struct rte_mbuf *pkt)
293 {
294         /* NOTE: Only supporting IP headers with no options at this time
295         * so header is fixed size
296         */
297
298         uint8_t hdr_chk = RTE_MBUF_METADATA_UINT8(pkt, IP_START);
299         hdr_chk = hdr_chk >> 4;
300
301         if (hdr_chk == IP_VERSION_4)
302                 return IPv4_HEADER_SIZE;
303         else if (hdr_chk == IP_VERSION_6)
304                 return IPv6_HEADER_SIZE;
305         else            /* Not IPv4 header with no options, return negative. */
306                 return -1;
307
308 }
309
310 /*
311  * ftp_alg checksum re-computing due to change in payload , uses rte function,
312  * if HW Checksum is supported s/w checksum will be disabled
313  * Input - IP HDR and TCP HDR
314  * Output - Length of IP HDR
315  */
316 static void ftp_alg_compute_checksums(
317         void *i_hdr,
318         struct tcp_hdr *t_hdr)
319 /* same as rte_synproxy_compute_checksums*/
320 {
321         /*
322         * calculate IP and TCP checksums.
323         * Note that both checksum routines require
324         * checksum fields to be set to zero, and the the checksum is in the
325         * correct byte order, so no rte_bswap16 is required.
326         */
327
328         int8_t hdr_chk = rte_ct_ipversion(i_hdr);
329         t_hdr->cksum = 0;
330
331         if (hdr_chk == IP_VERSION_4) {
332                 struct ipv4_hdr *i4_hdr = (struct ipv4_hdr *)i_hdr;
333                 i4_hdr->hdr_checksum = 0;
334                 t_hdr->cksum = 0;
335                 t_hdr->cksum = rte_ipv4_udptcp_cksum(i4_hdr, t_hdr);
336
337                 #ifdef ALGDBG
338                 printf("cksum %x\n", rte_bswap32(t_hdr->cksum));
339                 #endif
340
341                 i4_hdr->hdr_checksum = rte_ipv4_cksum(i4_hdr);
342         } else if (hdr_chk == IP_VERSION_6) {
343                 struct ipv6_hdr *i6_hdr = (struct ipv6_hdr *)i_hdr;
344                 t_hdr->cksum = 0;
345                 t_hdr->cksum = rte_ipv6_udptcp_cksum(i6_hdr, t_hdr);
346         }
347 }
348
349 /*
350  * ftp_alg adjusting ACK from other end ;
351  * ACK field of return packet to be adjusted
352  * to the same value of length modified in the payload
353  * Input - pkt, ack diff - delta
354  * Output - None(void)
355  */
356 static void  ftp_alg_adjust_tcp_ack(struct rte_mbuf *pkt, int16_t ackSeqdiff)
357 {
358         /*Since v6 is not supported now*/
359         uint16_t ip_hdr_size_bytes = IPv4_HEADER_SIZE;
360         struct ipv4_hdr *iphdr = (struct ipv4_hdr *)
361                 RTE_MBUF_METADATA_UINT32_PTR(pkt, IP_START);
362         struct tcp_hdr *thdr = (struct tcp_hdr *)
363                 RTE_MBUF_METADATA_UINT32_PTR(pkt,
364                         IP_START + ip_hdr_size_bytes);
365         /*
366         * recv_ack and total length first to be chnaged to host byte order
367         * and then do the addition and then set back to network byte order
368         */
369         uint32_t temp;
370         temp = rte_bswap32(thdr->recv_ack);
371         //printf("%s: ackSeqdiff :%d %u\n", __FUNCTION__, ackSeqdiff, temp);
372         if (ackSeqdiff < 0)
373                 temp += abs(ackSeqdiff);
374         else
375                 temp -= abs(ackSeqdiff);
376
377         thdr->recv_ack = rte_bswap32(temp);
378 }
379 /*
380  * ftp_alg adjusting SEQ from other end ; SEQ field of onward/egress  packet
381  * to be adjusted to the same value of length modified in the payload
382  * Input - pkt, ack diff - delta
383  * Output - None(void)
384  */
385
386 static void  ftp_alg_adjust_tcp_seq(struct rte_mbuf *pkt, int16_t ackSeqdiff)
387 {
388         /*Since v6 is not supported now*/
389         uint16_t ip_hdr_size_bytes = IPv4_HEADER_SIZE;
390         struct ipv4_hdr *iphdr = (struct ipv4_hdr *)
391                 RTE_MBUF_METADATA_UINT32_PTR(pkt, IP_START);
392         struct tcp_hdr *thdr = (struct tcp_hdr *)
393                 RTE_MBUF_METADATA_UINT32_PTR(pkt,
394                         IP_START + ip_hdr_size_bytes);
395         uint32_t temp;
396
397         temp = rte_bswap32(thdr->sent_seq);
398         if (ackSeqdiff < 0)
399                 temp -= abs(ackSeqdiff);
400         else
401                 temp += abs(ackSeqdiff);
402
403         thdr->sent_seq = rte_bswap32(temp);
404 }
405 /*
406  * ftp_alg adjusting SEQ from other end ; SEQ field of onward/egress  packet
407  * to be adjusted to the same value of length modified in the payload;
408  * This function computes the delta and calls adjust_seq for chaging the packet
409  * Input - pkt,Original incoming String, Translated string and corresponding
410  * lengths of the string
411  * Output - Seq Diff between Original and translated string
412  */
413
414 static int ftp_alg_delta_tcp_sequence(
415         struct rte_mbuf *pkt,
416         char *port_string,
417         int16_t existing_tcpSeqdiff,
418         uint16_t old_port_string_length,
419         uint16_t new_port_string_length)
420 {
421         int16_t current_sequence_number_delta=0;
422         int16_t final_sequence_number_delta;
423         /*Since v6 is not supported now*/
424         uint16_t ip_hdr_size_bytes = IPv4_HEADER_SIZE;
425         struct ipv4_hdr *iphdr = (struct ipv4_hdr *)
426                                 RTE_MBUF_METADATA_UINT32_PTR(pkt, IP_START);
427         struct tcp_hdr *thdr = (struct tcp_hdr *)
428                                 RTE_MBUF_METADATA_UINT32_PTR(pkt,
429                                         IP_START + ip_hdr_size_bytes);
430         /*
431         * recv_ack and total length first to be chnaged to host byte order
432         * and then do the addition and then set back to network byte order
433         */
434         current_sequence_number_delta = (int16_t) (new_port_string_length -
435                                         old_port_string_length);
436         iphdr->total_length = rte_bswap16(iphdr->total_length);
437
438         #ifdef ALGDBG
439         printf("total_length :%u\n", iphdr->total_length);
440         #endif
441         if(current_sequence_number_delta < 0)
442                 iphdr->total_length -= abs(current_sequence_number_delta);
443         else
444                 iphdr->total_length += current_sequence_number_delta;
445
446         iphdr->total_length = rte_bswap16(iphdr->total_length);
447         if (existing_tcpSeqdiff !=0)
448                 ftp_alg_adjust_tcp_seq(pkt,existing_tcpSeqdiff);
449         final_sequence_number_delta= current_sequence_number_delta + existing_tcpSeqdiff;
450         return final_sequence_number_delta;
451 }
452
453
454 /*
455  * ftp_alg dpi - this function parses the packet and does the respective
456  * action based on the type PORT or PASV, based on the direction of packet
457  * (Private or Public) This is called from CGNAPT
458  * Input - cgnapt pipeline struct, cgnapt key, pkt, CT ,
459  * position of packet assigned by CT, direction of packet
460  * Output - None - as it calls respective action functions
461  */
462 void ftp_alg_dpi(
463         struct pipeline_cgnapt *p_nat,
464         struct pipeline_cgnapt_entry_key *nat_entry_key,
465         struct rte_mbuf *pkt,
466         struct rte_ct_cnxn_tracker *cgnat_cnxn_tracker,
467         int32_t ct_position,
468         uint8_t direction)
469 {
470         /*
471         * recv_ack and total length first to be chnaged to host byte order
472         * and then do the addition and then set back to network byte order
473         */
474
475         /*entry key to be framed in cgnat and pass it over here*/
476         char *port_cmd_string;
477         char *port_cmd_end_string;
478         char *tcp_header_end;
479         char *tcp_start;
480
481
482         uint16_t private_port_number;
483         uint16_t public_port_number;
484         uint16_t ip1, ip2, ip3, ip4, port1, port2;
485         int16_t tcpSeqdiff;
486         int16_t ackSeqdiff, ackAdjust;
487         uint32_t private_address;
488         uint32_t public_address;
489         uint8_t *bptr_private_address;
490         /* also for PASV string */
491         char port_string[FTP_MAXIMUM_PORT_STRING_LENGTH];
492         char port_string_translated[FTP_MAXIMUM_PORT_STRING_LENGTH];
493         int16_t new_port_string_length;
494         int16_t old_port_string_length;
495         int dummy_value;
496         struct cgnapt_table_entry *egress_entry, *ingress_entry;
497         uint32_t ct_key[10];
498         uint8_t key_direction;
499         /*Since v6 is not supported now*/
500         uint16_t ip_hdr_size_bytes = IPv4_HEADER_SIZE;
501
502         struct ipv4_hdr *ip_hdr = rte_pktmbuf_mtod_offset(pkt,
503                         struct ipv4_hdr *, sizeof(struct ether_hdr));
504         /* TCP and UDP ports at same offset,
505         * just use TCP for offset calculation
506         */
507         struct tcp_hdr *thdr = rte_pktmbuf_mtod_offset(pkt, struct tcp_hdr *,
508                         (sizeof(struct ether_hdr)+sizeof(struct ipv4_hdr)));
509         uint16_t src_port = rte_bswap16(thdr->src_port);
510         uint16_t dst_port = rte_bswap16(thdr->dst_port);
511         uint8_t proto = ip_hdr->next_proto_id;
512         uint32_t src_addr = rte_bswap32(ip_hdr->src_addr);
513         uint32_t dst_addr = rte_bswap32(ip_hdr->dst_addr);
514         uint32_t tmp_tcp_paylod_size;
515
516         #if 0
517         - src_port & dst_port checking to be moved from cgnat to dpi
518         - For control channel
519                 first validation of tcpSeqdiff to be checked
520                 IF <  > 0
521                         ftp_alg_tcp_ack() to be called(this includes PORT
522                         response and PASV response ack as well)
523                         Return
524                 ELSE
525                         the port/pasv paramter checkign to be done
526         - For data channel
527         -retreive ALG entry
528                 IF found
529                         - remove the ALG entry
530                 even if not found(found cases too)
531         - set the bypass flag in the CT session table
532
533         #endif
534
535         #ifdef ALGDBG
536         {
537                 printf("ftp port number: %d, %d\n", src_port, dst_port);
538                 printf("ftp TCP seq num diff: %d\n",
539                         cgnat_cnxn_tracker->hash_table_entries[
540                                         ct_position].tcpSeqdiff);
541                 printf("tcp data offset: %d\n",
542                         ((thdr->data_off & 0xf0) >> 2));
543                 printf("ct position in dpi:%d\n", ct_position);
544         }
545         #endif
546
547         if (src_port == 21 || dst_port == 21)/* Control Channel*/{
548         /* Control Channel Start */
549         /*
550         * need to look for the port or pasv command.  Then have to look for
551         * the IP address and the port address. Then must create a TCP control
552         * block and spoof the port number, and change the ip address, and do
553         * the sequence number setting.
554         */
555         /* Handle TCP headers.*/
556         tcp_start = (char *)thdr;
557
558         /* start of TCP payload */
559         port_cmd_string = (char * )(tcp_start+((thdr->data_off & 0xf0) >> 2));
560         tcp_header_end = port_cmd_string;
561
562         if (direction == PRIVATE) {
563
564                 #ifdef ALGDBG
565                 printf("In PRIVATE  ");
566                 #endif
567
568                 cgnat_cnxn_tracker->hash_table_entries[ct_position].seq_client
569                                 = rte_bswap32(thdr->sent_seq);
570                 cgnat_cnxn_tracker->hash_table_entries[ct_position].ack_client
571                                 = rte_bswap32(thdr->recv_ack);
572                 #ifdef ALGDBG
573                 printf("-->Seq_cli:%u, Ack_cli:%u, Len:%4d\n",
574                         rte_bswap32(thdr->sent_seq),
575                         rte_bswap32(thdr->recv_ack),
576                         (rte_bswap16(ip_hdr->total_length) -
577                         (((thdr->data_off & 0xf0) >> 4) * 4)) - 20);
578                 #endif
579         } else {
580
581                 #ifdef ALGDBG
582                 printf("In PUBLIC  ");
583                 #endif
584                 cgnat_cnxn_tracker->hash_table_entries[ct_position].seq_server
585                                 = rte_bswap32(thdr->sent_seq);
586                 cgnat_cnxn_tracker->hash_table_entries[ct_position].ack_server
587                                 = rte_bswap32(thdr->recv_ack);
588                 #ifdef ALGDBG
589                 printf("<--Seq_cli:%4d, Ack_cli%4d, Len:%4d\n",
590                 rte_bswap32(thdr->sent_seq), rte_bswap32(thdr->recv_ack),
591                 (ip_hdr->total_length - (((thdr->data_off & 0xf0) >> 2))
592                         - 20));
593                 #endif
594         }
595
596         if (sscanf(port_cmd_string, FTP_PASV_PARAMETER_STRING, &dummy_value,
597                 &ip1, &ip2, &ip3, &ip4, &port1, &port2) ==
598                 FTP_PASV_PARAMETER_COUNT){
599
600         sprintf (port_string, FTP_PASV_PARAMETER_STRING, FTP_PASV_RETURN_CODE,
601                 ip1, ip2, ip3, ip4, port1, port2);
602
603         int i = 0;
604         while (port_cmd_string[i] != '\r' && port_cmd_string[i+1] != '\n')
605                 i++;
606
607         i += 2; // now it points to end of port cmd string.
608
609         old_port_string_length = i;
610
611         private_port_number = (uint16_t) (port1 * 0x100 + port2);
612         bptr_private_address = (uint8_t *) &private_address;
613
614         bptr_private_address[3] = (uint8_t) (ip4 & 0x00FF);
615         bptr_private_address[2] = (uint8_t) (ip3 & 0x00FF);
616         bptr_private_address[1] = (uint8_t) (ip2 & 0x00FF);
617         bptr_private_address[0] = (uint8_t) (ip1 & 0x00FF);
618
619         /* Not needed as got the position from CT*/
620
621         if (direction == PUBLIC) {
622         /*Client in Private, Server in Public*/
623         /* Not to convert in the payload for PASV resp from Pub side*/
624         /* Only Table creation and no payload modification*/
625         /* DAta Channel also no need to create as it will be done by NAT
626         * when initiated by Client later
627         */
628         populate_ftp_alg_entry(private_address, private_port_number);
629         /*
630         * Bypass ALG flag to be set ,
631         * seqnumber -delta either to be 0 or not needed ,
632         * direction checking for all scenarios
633         */
634         cgnat_cnxn_tracker->hash_table_entries[ct_position].
635                         server_direction = SERVER_IN_PUBLIC;
636         cgnat_cnxn_tracker->hash_table_entries[ct_position].
637                         ftp_session_type= 1; // Passive session type
638         } else if (direction == PRIVATE) {
639         /*Client in Public , Server in Private*/
640
641         struct pipeline_cgnapt_entry_key data_channel_key;
642         private_address = rte_bswap32(private_address);
643         data_channel_key.ip = private_address;
644         data_channel_key.port = private_port_number;
645         /* to be checked if it can be passed as param from NAT*/
646         data_channel_key.pid = pkt->port;
647
648         /* add_dynamic_cgnat_entry() */ /* for DAta Channel*/
649         /*Will be getting Private IP and port from Server ,
650         * with that NAPT entry egress and ingress can be added ,
651         * for further data channel communication
652         */
653
654         if (add_dynamic_cgnapt_entry_alg((struct pipeline *)p_nat,
655         &data_channel_key, &egress_entry, &ingress_entry) == 0){
656
657                 #ifdef ALGDBG
658                 printf("Wrong FTP ALG packet\n");
659                 #endif
660                 //p_nat->invalid_packets |= pkt_mask;
661
662                 p_nat->naptDroppedPktCount++;
663
664                 #ifdef CGNAPT_DEBUGGING
665                 p_nat->naptDroppedPktCount4++;
666                 #endif
667                 return;
668         }
669
670         tmp_tcp_paylod_size = rte_bswap16(ip_hdr->total_length) -
671                         ((thdr->data_off & 0xf0) >> 2) - ip_hdr_size_bytes;
672         cgnat_cnxn_tracker->hash_table_entries[ct_position].
673                         tcp_payload_size = tmp_tcp_paylod_size;
674
675         /*Adding ALG entry , params to be derived from egress entry*/
676         populate_ftp_alg_entry(egress_entry->data.pub_ip,
677                         egress_entry->data.pub_port);
678         /* payload modification */
679         new_port_string_length = ftp_alg_modify_payload(egress_entry,
680                                         port_string,
681                                         port_string_translated, 1);
682         strncpy(tcp_header_end, port_string_translated,
683                 strlen(port_string_translated));
684         tcpSeqdiff = ftp_alg_delta_tcp_sequence( pkt, port_string,
685                         cgnat_cnxn_tracker->hash_table_entries
686                         [ct_position].tcpSeqdiff,
687                         old_port_string_length,
688                         new_port_string_length);
689
690         /* same as rte_synproxy_adjust_pkt_length() in ct */
691         ftp_alg_modify_pkt_len(pkt);
692         /*
693         * Store sequence_number_delta in Session_data structure, also bypass
694         * flag to be set as NO (expecting TCP ack from other end then set the
695         * bypass accordingly , handled earlier in the function
696         */
697
698         cgnat_cnxn_tracker->hash_table_entries[ct_position].
699                         alg_bypass_flag = NO_BYPASS;
700         cgnat_cnxn_tracker->hash_table_entries[ct_position].
701                         tcpSeqdiff = tcpSeqdiff;
702         cgnat_cnxn_tracker->hash_table_entries[ct_position].
703                         server_direction = SERVER_IN_PRIVATE;
704         cgnat_cnxn_tracker->hash_table_entries[ct_position].
705                         ftp_session_type = 1; // Passive session type
706                 return;
707
708         } /* PRIVATE dir */
709         } else if (sscanf(port_cmd_string, FTP_PORT_PARAMETER_STRING,
710                         &ip1, &ip2, &ip3, &ip4, &port1, &port2) ==
711                                 FTP_PORT_PARAMETER_COUNT){
712
713                 int i = 0;
714                 static uint8_t port_hit;
715                 while (port_cmd_string[i] != '\r' &&
716                         port_cmd_string[i+1] != '\n')
717                         i++;
718
719                 i += 2; // now it points to end of port cmd string.
720
721                 old_port_string_length = i;
722
723                 #ifdef ALGDBG
724                 printf( " Existing Seq Diff = %d", cgnat_cnxn_tracker->
725                         hash_table_entries[ct_position].tcpSeqdiff);
726                 printf("FTP ALG: FTP PORT command length: %d\n",
727                         old_port_string_length);
728                 #endif
729
730                 private_port_number = (uint16_t) (port1 * 0x100 + port2);
731
732                 #ifdef ALGDBG
733                 printf("FTP ALG: private port number before swap: %u\n",
734                                 private_port_number);
735                 #endif
736
737                 bptr_private_address = (uint8_t *) &private_address;
738                 bptr_private_address[3] = (uint8_t) (ip4 & 0x00FF);
739                 bptr_private_address[2] = (uint8_t) (ip3 & 0x00FF);
740                 bptr_private_address[1] = (uint8_t) (ip2 & 0x00FF);
741                 bptr_private_address[0] = (uint8_t) (ip1 & 0x00FF);
742
743                 sprintf(port_string, FTP_PORT_PARAMETER_STRING, ip1, ip2,
744                                 ip3, ip4, port1, port2);
745
746                 #ifdef ALGDBG
747                 printf("FTP ALG: FTP original PORT string: %d,%s\n",
748                                 (int) strlen(port_string)-2, port_string);
749                 printf("prv addr: %x\n", private_address);
750                 #endif
751
752
753                 if (direction == PUBLIC) {
754                         /* Client in Public*/
755                         /* retreive_cgnat_entry()* for Data Channel*/
756                         /* Pub port and ip address to be used for framing key ,
757                         * the private phrase is a misnomer
758                         */
759                         struct pipeline_cgnapt_entry_key data_channel_key;
760                         data_channel_key.ip = private_address;
761                         data_channel_key.port = private_port_number;
762                         data_channel_key.pid = 0xffff;
763
764
765                         cgnat_cnxn_tracker->hash_table_entries[ct_position].
766                                 server_direction = SERVER_IN_PRIVATE;
767                         cgnat_cnxn_tracker->hash_table_entries[ct_position].
768                                 ftp_session_type= 0; // Active session type
769
770                         /* No payload modificaiton*/
771                         #ifdef ALGDBG
772                         printf("<--Seq_cli:%4d, Ack_cli%4d, Len:%4d\n",
773                         rte_bswap32(thdr->sent_seq),
774                         rte_bswap32(thdr->recv_ack),
775                         (ip_hdr->total_length -
776                                 (((thdr->data_off & 0xf0) >> 2)) - 20));
777                         #endif
778                         populate_ftp_alg_entry(private_address, private_port_number);
779                 } else if (direction == PRIVATE) {
780
781                         /* Client in Private Server in Public*/
782                         /* Populate_alg_entry*/
783                         /*add_dynamic_cgnapt_entry()*/
784                         /* payload modificaion*/
785                         struct pipeline_cgnapt_entry_key data_channel_key;
786                         private_address = rte_bswap32(private_address);
787                         data_channel_key.ip = private_address;
788                         data_channel_key.port = private_port_number;
789                         /* to be checked if it can be passed as param from NAT*/
790                         data_channel_key.pid = pkt->port;
791
792                         /* add_dynamic_cgnat_entry() */ /* for DAta Channel*/
793                         /*
794                         * Will be getting Private IP and port from Client ,
795                         * with that NAPT entry egress and ingress can be added ,
796                         * for further data channel communication
797                         */
798
799                         if (add_dynamic_cgnapt_entry_alg((struct pipeline *)
800                                 p_nat, &data_channel_key, &egress_entry,
801                                 &ingress_entry) == 0){
802
803                                 #ifdef ALGDBG
804                                 printf("Wrong FTP ALG packet\n");
805                                 #endif
806                                 //p_nat->invalid_packets |= pkt_mask;
807                                 p_nat->naptDroppedPktCount++;
808
809                                 #ifdef CGNAPT_DEBUGGING
810                                 p_nat->naptDroppedPktCount4++;
811                                 #endif
812                                 return;
813                         }
814
815                 tmp_tcp_paylod_size = rte_bswap16(ip_hdr->total_length) -
816                                         ((thdr->data_off & 0xf0) >> 2) -
817                                         ip_hdr_size_bytes;
818                 cgnat_cnxn_tracker->hash_table_entries[ct_position].
819                         tcp_payload_size = tmp_tcp_paylod_size;
820                 /*ALG entry add, params to be derived from egress entry*/
821
822                 populate_ftp_alg_entry(egress_entry->data.pub_ip,
823                         egress_entry->data.pub_port);
824                 /* payload modification */
825                 new_port_string_length = ftp_alg_modify_payload(egress_entry,
826                                                 port_string,
827                                                 port_string_translated, 0);
828                 strncpy(tcp_header_end, port_string_translated,
829                                 strlen(port_string_translated));
830                 tcpSeqdiff = ftp_alg_delta_tcp_sequence( pkt, port_string,
831                                 cgnat_cnxn_tracker->hash_table_entries
832                                 [ct_position].tcpSeqdiff,
833                                 old_port_string_length,
834                                 new_port_string_length);
835                 /* same as rte_synproxy_adjust_pkt_length() in ct */
836                 ftp_alg_modify_pkt_len(pkt);
837
838                 /*
839                 * Store sequence_number_delta in Session_data structure ,
840                 * also bypass flag to be set as NO
841                 * While response from other end is received ,
842                 * modify the ack no using reverse sign of sequen
843                 */
844
845                 cgnat_cnxn_tracker->hash_table_entries[ct_position].
846                         alg_bypass_flag = NO_BYPASS;
847                 cgnat_cnxn_tracker->hash_table_entries[ct_position].
848                         tcpSeqdiff = tcpSeqdiff;
849                 cgnat_cnxn_tracker->hash_table_entries[ct_position].
850                         server_direction = SERVER_IN_PUBLIC;
851                 cgnat_cnxn_tracker->hash_table_entries[ct_position].
852                         ftp_session_type = 0; // Active session type
853
854                 #ifdef ALGDBG
855                 printf("<--Seq_cli:%4d, Ack_cli%4d, Len:%4d\n",
856                         rte_bswap32(thdr->sent_seq),
857                         rte_bswap32(thdr->recv_ack),
858                         (ip_hdr->total_length -
859                         (((thdr->data_off & 0xf0) >> 2)) - 20));
860
861                 #endif
862                 return;
863                 } /* PRIVATE dir */
864         } /* PORT cmd message */
865
866         if ((ackAdjust=cgnat_cnxn_tracker->hash_table_entries[
867                         ct_position].tcpSeqdiff) != 0) {
868                 if (direction == PRIVATE) {
869                         if (
870                                 cgnat_cnxn_tracker->hash_table_entries
871                                 [ct_position].seq_client !=
872                                 cgnat_cnxn_tracker->hash_table_entries
873                                 [ct_position].ack_server) {
874                                 static int Seqhits;
875                                 ftp_alg_adjust_tcp_seq( pkt,ackAdjust);
876                                 tmp_tcp_paylod_size = rte_bswap16(
877                                         ip_hdr->total_length) -
878                                         ((thdr->data_off & 0xf0) >> 2) -
879                                         ip_hdr_size_bytes;
880                                 cgnat_cnxn_tracker->hash_table_entries
881                                 [ct_position].tcp_payload_size = tmp_tcp_paylod_size;
882                 #ifdef ALGDBG
883                 printf("<--Seq_cli:%4d, Ack_cli%4d, Len:%4d\n",
884                         rte_bswap32(thdr->sent_seq),
885                         rte_bswap32(thdr->recv_ack),
886                         (ip_hdr->total_length -(((thdr->data_off & 0xf0) >> 2))- 20));
887                 #endif
888                         }
889                 } else {
890                         if (cgnat_cnxn_tracker->hash_table_entries
891                                 [ct_position].ack_server !=
892                                 (cgnat_cnxn_tracker->hash_table_entries
893                                 [ct_position].seq_client +
894                                 cgnat_cnxn_tracker->hash_table_entries
895                                 [ct_position].tcp_payload_size)) {
896                                 static int Ackhits;
897                                 ftp_alg_adjust_tcp_ack( pkt,ackAdjust);
898                 #ifdef ALGDBG
899                 printf("<--Seq_cli:%4d, Ack_cli%4d, Len:%4d\n",
900                         rte_bswap32(thdr->sent_seq),
901                         rte_bswap32(thdr->recv_ack),
902                         (ip_hdr->total_length -(((thdr->data_off & 0xf0) >> 2))- 20));
903                 #endif
904                         }
905                 }
906                 return;
907                         } /* expected_ack and sequence number updation for PUBLIC dir TCP window */
908         } /* Control Channel End */
909         else {
910                 /*remove the ALG entry, retreival is taken care by rte function  */
911                 #ifdef ALGDBG
912                 printf("In Data Channel \n");
913                 #endif
914                 remove_ftp_alg_entry (dst_addr,dst_port);/* remove the ALG entry */
915                 cgnat_cnxn_tracker->hash_table_entries[ct_position].alg_bypass_flag = BYPASS;
916         } /* Data Channel End */
917 }