CDC/ECM driver for mbed, based on USBDevice by mbed-official. Uses PicoTCP to access Ethernet USB device. License: GPLv2

Dependents:   USBEthernet_TEST

Fork of USB_Ethernet by Daniele Lacamera

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers pico_nat.c Source File

pico_nat.c

00001 /*********************************************************************
00002 PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved.
00003 See LICENSE and COPYING for usage.
00004 
00005 .
00006 
00007 Authors: Kristof Roelants, Brecht Van Cauwenberghe,
00008          Simon Maes, Philippe Mariman
00009 *********************************************************************/
00010 
00011 #include "pico_stack.h"
00012 #include "pico_frame.h"
00013 #include "pico_tcp.h"
00014 #include "pico_udp.h"
00015 #include "pico_ipv4.h"
00016 #include "pico_addressing.h"
00017 #include "pico_nat.h"
00018 
00019 
00020 #ifdef PICO_SUPPORT_IPV4
00021 #ifdef PICO_SUPPORT_NAT
00022 
00023 #define nat_dbg(...) do{}while(0)
00024 //#define nat_dbg dbg
00025 #define NAT_TCP_TIMEWAIT 240000 /* 4mins (in msec) */
00026 //#define NAT_TCP_TIMEWAIT 10000 /* 10 sec (in msec)  - for testing purposes only*/
00027 
00028 
00029 struct pico_nat_key {
00030   struct pico_ip4 pub_addr;
00031   uint16_t pub_port;
00032   struct pico_ip4 priv_addr;
00033   uint16_t priv_port;
00034   uint8_t proto;
00035   /*
00036   del_flags:
00037               1                   0 
00038     5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
00039    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
00040    |F|B|S|R|P|~| CONNECTION ACTIVE |
00041    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
00042 
00043   F: FIN from Forwarding packet
00044   B: FIN from Backwarding packet
00045   S: SYN 
00046   R: RST  
00047   P: Persistant
00048          
00049   */
00050   uint16_t del_flags;
00051   /* Connector for trees */
00052 };
00053 
00054 static struct pico_ipv4_link pub_link;
00055 static uint8_t enable_nat_flag = 0;
00056 
00057 static int nat_cmp_backward(void * ka, void * kb)
00058 {
00059     struct pico_nat_key *a = ka, *b = kb;
00060   if (a->pub_port < b->pub_port) {
00061     return -1;
00062   }
00063   else if (a->pub_port > b->pub_port) {
00064     return 1;
00065   }
00066   else {
00067     if (a->proto < b->proto) {
00068       return -1;
00069     }
00070     else if (a->proto > b->proto) {
00071       return 1;
00072     }
00073     else {
00074       /* a and b are identical */
00075       return 0;
00076     }
00077   }
00078 }
00079 
00080 static int nat_cmp_forward(void * ka, void * kb)
00081 {
00082     struct pico_nat_key *a =ka, *b = kb;
00083   if (a->priv_addr.addr < b->priv_addr.addr) {
00084     return -1;
00085   }
00086   else if (a->priv_addr.addr > b->priv_addr.addr) {
00087     return 1;
00088   }
00089   else {
00090     if (a->priv_port < b->priv_port) {
00091       return -1;
00092     }
00093     else if (a->priv_port > b->priv_port) {
00094       return 1;
00095     }
00096     else {
00097       if (a->proto < b->proto) {
00098         return -1;
00099       }
00100       else if (a->proto > b->proto) {
00101         return 1;
00102       }
00103       else {
00104         /* a and b are identical */
00105         return 0;
00106       }
00107     }
00108   }
00109 }
00110 
00111 PICO_TREE_DECLARE(KEYTable_forward,nat_cmp_forward);
00112 PICO_TREE_DECLARE(KEYTable_backward,nat_cmp_backward);
00113 
00114 /* 
00115   2 options: 
00116     find on proto and pub_port 
00117     find on priv_addr, priv_port and proto 
00118   zero the unused parameters 
00119 */
00120 static struct pico_nat_key *pico_ipv4_nat_find_key(uint16_t pub_port, struct pico_ip4 *priv_addr, uint16_t priv_port, uint8_t proto)
00121 {
00122   struct pico_nat_key test;
00123   test.pub_port = pub_port;
00124   test.priv_port = priv_port;
00125   test.proto = proto;
00126   if (priv_addr)
00127     test.priv_addr = *priv_addr;
00128   else
00129     test.priv_addr.addr = 0;
00130 
00131   /* returns NULL if test can not be found */ 
00132   if (!pub_port)
00133       return pico_tree_findKey(&KEYTable_forward,&test);
00134   else
00135       return pico_tree_findKey(&KEYTable_backward, &test);
00136 }
00137 
00138 int pico_ipv4_nat_find(uint16_t pub_port, struct pico_ip4 *priv_addr, uint16_t priv_port, uint8_t proto)
00139 {
00140   struct pico_nat_key *k = NULL;
00141 
00142   k = pico_ipv4_nat_find_key(pub_port, priv_addr, priv_port, proto); 
00143   if (k)
00144     return 0;
00145   else
00146     return -1;
00147 }
00148 
00149 int pico_ipv4_nat_snif_forward(struct pico_nat_key *nk, struct pico_frame *f)
00150 {
00151   uint8_t proto;
00152   struct pico_ipv4_hdr *ipv4_hdr = (struct pico_ipv4_hdr *)f->net_hdr;
00153   struct pico_tcp_hdr *tcp_hdr;
00154  
00155   if (!ipv4_hdr)
00156     return -1;
00157   proto = ipv4_hdr->proto;
00158 
00159   if (proto == PICO_PROTO_TCP) {
00160     tcp_hdr = (struct pico_tcp_hdr *) f->transport_hdr;
00161     if (!tcp_hdr)
00162       return -1;
00163     if (tcp_hdr->flags & PICO_TCP_FIN) {
00164       nk->del_flags |= PICO_DEL_FLAGS_FIN_FORWARD; //FIN from forwarding packet
00165     }
00166     if (tcp_hdr->flags & PICO_TCP_SYN) {
00167       nk->del_flags |= PICO_DEL_FLAGS_SYN; 
00168     }
00169     if (tcp_hdr->flags & PICO_TCP_RST) {
00170       nk->del_flags |= PICO_DEL_FLAGS_RST;
00171     }
00172   } else if (proto == PICO_PROTO_UDP) {
00173     /* set conn active to 1 */
00174     nk->del_flags &= 0xFE00; 
00175     nk->del_flags++;
00176   } 
00177   return 0; 
00178 }
00179 
00180 
00181 int pico_ipv4_nat_snif_backward(struct pico_nat_key *nk, struct pico_frame *f)
00182 {
00183   uint8_t proto;
00184   struct pico_ipv4_hdr *ipv4_hdr = (struct pico_ipv4_hdr *)f->net_hdr;
00185   struct pico_tcp_hdr *tcp_hdr;
00186 
00187   if (!ipv4_hdr)
00188     return -1;
00189   proto = ipv4_hdr->proto;
00190 
00191   if (proto == PICO_PROTO_TCP) {
00192     tcp_hdr = (struct pico_tcp_hdr *) f->transport_hdr;
00193     if (!tcp_hdr)
00194       return -1;
00195     if (tcp_hdr->flags & PICO_TCP_FIN) {
00196       nk->del_flags |= PICO_DEL_FLAGS_FIN_BACKWARD; //FIN from backwarding packet
00197     }
00198     if (tcp_hdr->flags & PICO_TCP_SYN) {
00199       nk->del_flags |= PICO_DEL_FLAGS_SYN;
00200     }
00201     if (tcp_hdr->flags & PICO_TCP_RST) {
00202       nk->del_flags |= PICO_DEL_FLAGS_RST;
00203     }
00204   } else if (proto == PICO_PROTO_UDP) {
00205     /* set conn active to 1 */
00206     nk->del_flags &= 0xFE00; 
00207     nk->del_flags++;
00208   }
00209   return 0;
00210 }
00211 
00212 void pico_ipv4_nat_table_cleanup(unsigned long now, void *_unused)
00213 {
00214   struct pico_tree_node * idx, * safe;
00215   struct pico_nat_key *k = NULL;
00216     nat_dbg("NAT: before table cleanup:\n");
00217   pico_ipv4_nat_print_table();
00218 
00219   //struct pico_nat_key *tmp;
00220   pico_tree_foreach_reverse_safe(idx,&KEYTable_forward,safe){
00221       k = idx->keyValue;
00222     switch (k->proto)
00223     {
00224       case PICO_PROTO_TCP:
00225         if ((k->del_flags & 0x0800) >> 11) {
00226           /* entry is persistant */
00227           break;
00228         }
00229         else if ((k->del_flags & 0x01FF) == 0) {
00230           /* conn active is zero, delete entry */
00231           pico_ipv4_nat_del(k->pub_port, k->proto);
00232         }
00233         else if ((k->del_flags & 0x1000) >> 12) {
00234           /* RST flag set, set conn active to zero */
00235           k->del_flags &= 0xFE00;
00236         }
00237         else if (((k->del_flags & 0x8000) >> 15) && ((k->del_flags & 0x4000) >> 14)) {
00238           /* FIN1 and FIN2 set, set conn active to zero */
00239           k->del_flags &= 0xFE00; 
00240         }
00241         else if ((k->del_flags & 0x01FF) > 360) {
00242           /* conn is active for 24 hours, delete entry */
00243           pico_ipv4_nat_del(k->pub_port, k->proto);
00244         }
00245         else {
00246           k->del_flags++;
00247         } 
00248         break;
00249 
00250       case PICO_PROTO_UDP:
00251         if ((k->del_flags & 0x0800) >> 11) {
00252           /* entry is persistant */
00253           break;
00254         }
00255         else if ((k->del_flags & 0x01FF) > 1) {
00256           /* Delete entry when it has existed NAT_TCP_TIMEWAIT */
00257           pico_ipv4_nat_del(k->pub_port, k->proto);
00258         }
00259         else {
00260           k->del_flags++;
00261         }
00262         break;
00263 
00264       default:
00265         /* Unknown protocol in NAT table, delete when it has existed NAT_TCP_TIMEWAIT */
00266         if ((k->del_flags & 0x01FF) > 1) {
00267           pico_ipv4_nat_del(k->pub_port, k->proto);
00268         }
00269         else {
00270           k->del_flags++;
00271         }
00272     }
00273   }
00274 
00275   nat_dbg("NAT: after table cleanup:\n");
00276   pico_ipv4_nat_print_table();
00277   pico_timer_add(NAT_TCP_TIMEWAIT, pico_ipv4_nat_table_cleanup, NULL);
00278 }
00279 
00280 int pico_ipv4_nat_add(struct pico_ip4 pub_addr, uint16_t pub_port, struct pico_ip4 priv_addr, uint16_t priv_port, uint8_t proto)
00281 {
00282   struct pico_nat_key *key = pico_zalloc(sizeof(struct pico_nat_key));
00283   if (!key) {
00284     pico_err = PICO_ERR_ENOMEM;
00285     return -1;
00286   }
00287 
00288   key->pub_addr = pub_addr;
00289   key->pub_port = pub_port;
00290   key->priv_addr = priv_addr;
00291   key->priv_port = priv_port;
00292   key->proto = proto;
00293   key->del_flags = 0x0001; /* set conn active to 1, other flags to 0 */
00294 
00295   /* RB_INSERT returns NULL when element added, pointer to the element if already in tree */
00296   if(!pico_tree_insert(&KEYTable_forward, key) && !pico_tree_insert(&KEYTable_backward, key)){
00297     return 0; /* New element added */
00298   }
00299   else {
00300     pico_free(key);
00301     pico_err = PICO_ERR_EINVAL;
00302     return -1; /* Element key already exists */
00303   }
00304 }
00305 
00306 
00307 int pico_ipv4_nat_del(uint16_t pub_port, uint8_t proto)
00308 {
00309   struct pico_nat_key *key = NULL;
00310   key = pico_ipv4_nat_find_key(pub_port, NULL, 0, proto);
00311   if (!key) {
00312     nat_dbg("NAT: key to delete not found: proto %u | pub_port %u\n", proto, pub_port);
00313     return -1;
00314   }
00315   else {
00316     nat_dbg("NAT: key to delete found: proto %u | pub_port %u\n", proto, pub_port);  
00317     /* RB_REMOVE returns pointer to removed element, NULL to indicate error */
00318     if(pico_tree_delete(&KEYTable_forward, key) && pico_tree_delete(&KEYTable_backward, key))
00319           pico_free(key);
00320     else
00321       return -1; /* Error on removing element, do not free! */
00322   }
00323   return 0;
00324 }
00325 
00326 int pico_ipv4_port_forward(struct pico_ip4 pub_addr, uint16_t pub_port, struct pico_ip4 priv_addr, uint16_t priv_port, uint8_t proto, uint8_t persistant)
00327 {
00328   struct pico_nat_key *key = NULL;
00329 
00330   switch (persistant)
00331   {
00332     case PICO_IPV4_FORWARD_ADD:
00333       if (pico_ipv4_nat_add(pub_addr, pub_port, priv_addr, priv_port, proto) != 0)
00334         return -1;  /* pico_err set in nat_add */
00335       key = pico_ipv4_nat_find_key(pub_port, &priv_addr, priv_port, proto);
00336       if (!key) {
00337         pico_err = PICO_ERR_EAGAIN;
00338         return -1;
00339       }
00340       key->del_flags = (key->del_flags & ~(0x1 << 11)) | (persistant << 11);
00341       break;
00342 
00343     case PICO_IPV4_FORWARD_DEL:
00344       return pico_ipv4_nat_del(pub_port, proto);
00345 
00346     default:
00347       pico_err = PICO_ERR_EINVAL;
00348       return -1;
00349   }
00350   pico_ipv4_nat_print_table();
00351   return 0;
00352 }
00353 
00354 
00355 void pico_ipv4_nat_print_table(void)
00356 {
00357   struct pico_nat_key __attribute__((unused)) *k = NULL ;
00358   struct pico_tree_node * index;
00359   uint16_t i = 0;
00360 
00361   nat_dbg("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
00362   nat_dbg("+                                                       NAT table                                                       +\n");
00363   nat_dbg("+-----------------------------------------------------------------------------------------------------------------------+\n");
00364   nat_dbg("+  pointer   | private_addr | private_port | proto | pub_addr | pub_port | conn active | FIN1 | FIN2 | SYN | RST | PERS +\n");
00365   nat_dbg("+-----------------------------------------------------------------------------------------------------------------------+\n");
00366 
00367   pico_tree_foreach(index,&KEYTable_forward){
00368       k = index->keyValue;
00369     nat_dbg("+ %10p |   %08X   |    %05u     |  %04u | %08X |  %05u   |     %03u     |   %u  |   %u  |  %u  |  %u  |   %u  +\n", 
00370            k, k->priv_addr.addr, k->priv_port, k->proto, k->pub_addr.addr, k->pub_port, (k->del_flags)&0x01FF, ((k->del_flags)&0x8000)>>15, 
00371            ((k->del_flags)&0x4000)>>14, ((k->del_flags)&0x2000)>>13, ((k->del_flags)&0x1000)>>12, ((k->del_flags)&0x0800)>>11);
00372     i++;
00373   }
00374   nat_dbg("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
00375 }
00376 
00377 int pico_ipv4_nat_generate_key(struct pico_nat_key* nk, struct pico_frame* f, struct pico_ip4 pub_addr)
00378 {
00379   uint16_t pub_port = 0;
00380   uint8_t proto;
00381   struct pico_tcp_hdr *tcp_hdr = NULL;  /* forced to use pico_trans */
00382   struct pico_udp_hdr *udp_hdr = NULL;  /* forced to use pico_trans */
00383   struct pico_ipv4_hdr *ipv4_hdr = (struct pico_ipv4_hdr *)f->net_hdr;
00384   if (!ipv4_hdr)
00385     return -1;
00386   proto = ipv4_hdr->proto;
00387   do {
00388     /* 1. generate valid new NAT port entry */
00389     uint32_t rand = pico_rand();
00390     pub_port = (uint16_t) (rand & 0xFFFFU);
00391     pub_port = (uint16_t)(pub_port % (65535 - 1024)) + 1024U;
00392         pub_port = short_be(pub_port);
00393 
00394     /* 2. check if already in table, if no exit */
00395     nat_dbg("NAT: check if generated port %u is free\n", short_be(pub_port));
00396     if (pico_is_port_free(proto, pub_port, NULL, &pico_proto_ipv4))
00397       break;
00398   
00399   } while (1);
00400   nat_dbg("NAT: port %u is free\n", short_be(pub_port));
00401     
00402   if (proto == PICO_PROTO_TCP) {  
00403     tcp_hdr = (struct pico_tcp_hdr *) f->transport_hdr;
00404     if (!tcp_hdr)
00405       return -1;
00406     nk->priv_port = tcp_hdr->trans.sport; 
00407   } else if (proto == PICO_PROTO_UDP) {
00408     udp_hdr = (struct pico_udp_hdr *) f->transport_hdr;
00409     if (!udp_hdr)
00410       return -1;
00411     nk->priv_port = udp_hdr->trans.sport; 
00412   } else if (proto == PICO_PROTO_ICMP4) {
00413     nk->priv_port = (uint16_t)(ipv4_hdr->src.addr & 0x00FF); 
00414     pub_port = (uint16_t)(ipv4_hdr->dst.addr & 0x00FF);
00415     if (!pico_is_port_free(proto, pub_port, NULL, &pico_proto_ipv4))
00416       return -1;
00417   }
00418 
00419   nk->pub_addr = pub_addr; /* get public ip address from device */
00420   nk->pub_port = pub_port;
00421   nk->priv_addr = ipv4_hdr->src;
00422   nk->proto = ipv4_hdr->proto;
00423   nk->del_flags = 0x0001; /* set conn active to 1 */
00424   if (pico_ipv4_nat_add(nk->pub_addr, nk->pub_port, nk->priv_addr, nk->priv_port, nk->proto) < 0) {
00425     return -1;
00426   } else {
00427     return 0;
00428   }
00429 }
00430 
00431 
00432 static int pico_nat_tcp_checksum(struct pico_frame *f)
00433 {
00434   struct pico_tcp_hdr *trans_hdr = (struct pico_tcp_hdr *) f->transport_hdr;
00435   struct pico_ipv4_hdr *net_hdr = (struct pico_ipv4_hdr *) f->net_hdr;
00436 
00437   struct tcp_pseudo_hdr_ipv4 pseudo;
00438   if (!trans_hdr || !net_hdr)
00439     return -1;
00440 
00441   pseudo.src.addr = net_hdr->src.addr;
00442   pseudo.dst.addr = net_hdr->dst.addr;
00443   pseudo.res = 0;
00444   pseudo.proto = PICO_PROTO_TCP;
00445   pseudo.tcp_len = short_be(f->transport_len);
00446 
00447   trans_hdr->crc = 0;
00448   trans_hdr->crc = pico_dualbuffer_checksum(&pseudo, sizeof(struct tcp_pseudo_hdr_ipv4), trans_hdr, f->transport_len);
00449   trans_hdr->crc = short_be(trans_hdr->crc);
00450   return 0;
00451 }
00452 
00453 
00454 int pico_ipv4_nat_translate(struct pico_nat_key* nk, struct pico_frame* f)
00455 {
00456   uint8_t proto;
00457   struct pico_tcp_hdr *tcp_hdr = NULL;  /* forced to use pico_trans */
00458   struct pico_udp_hdr *udp_hdr = NULL;  /* forced to use pico_trans */
00459 
00460   struct pico_ipv4_hdr* ipv4_hdr = (struct pico_ipv4_hdr *)f->net_hdr;
00461   if (!ipv4_hdr)
00462     return -1;
00463   proto = ipv4_hdr->proto;
00464   
00465   if (proto == PICO_PROTO_TCP) {
00466     tcp_hdr = (struct pico_tcp_hdr *) f->transport_hdr;
00467     if (!tcp_hdr)
00468       return -1;
00469     tcp_hdr->trans.sport = nk->pub_port;
00470   } else if (proto == PICO_PROTO_UDP) {  
00471     udp_hdr = (struct pico_udp_hdr *) f->transport_hdr;
00472     if (!udp_hdr)
00473       return -1;
00474     udp_hdr->trans.sport = nk->pub_port;
00475   }
00476 
00477   //if(f->proto == PICO_PROTO_ICMP){
00478   //} XXX no action
00479 
00480   ipv4_hdr->src = nk->pub_addr;
00481 
00482   if (proto == PICO_PROTO_TCP) {
00483     pico_nat_tcp_checksum(f);
00484   } else if (proto == PICO_PROTO_UDP){
00485     udp_hdr->crc = 0;
00486     udp_hdr->crc = short_be(pico_udp_checksum_ipv4(f));
00487   }
00488 
00489   // pico_ipv4_checksum(f);
00490   ipv4_hdr->crc = 0;
00491   ipv4_hdr->crc = short_be(pico_checksum(ipv4_hdr, f->net_len));
00492 
00493   return 0;
00494 }
00495 
00496 
00497 int pico_ipv4_nat_port_forward(struct pico_frame* f)
00498 {
00499   struct pico_nat_key *nk = NULL;
00500   struct pico_tcp_hdr *tcp_hdr = NULL;
00501   struct pico_udp_hdr *udp_hdr = NULL; 
00502   struct pico_icmp4_hdr *icmp_hdr = NULL;
00503   struct pico_ipv4_hdr* ipv4_hdr;
00504   uint16_t pub_port = 0; 
00505   uint8_t proto;
00506 
00507   ipv4_hdr = (struct pico_ipv4_hdr *)f->net_hdr;
00508   if (!ipv4_hdr)
00509     return -1; 
00510   proto = ipv4_hdr->proto; 
00511   
00512   if (proto == PICO_PROTO_TCP) {
00513     tcp_hdr = (struct pico_tcp_hdr *) f->transport_hdr;
00514     if (!tcp_hdr)
00515       return -1;
00516     pub_port = tcp_hdr->trans.dport;  
00517   } else if (proto == PICO_PROTO_UDP) {  
00518     udp_hdr = (struct pico_udp_hdr *) f->transport_hdr;
00519     if (!udp_hdr)
00520       return -1;
00521     pub_port = udp_hdr->trans.dport;
00522   } else if (proto == PICO_PROTO_ICMP4) {
00523     icmp_hdr = (struct pico_icmp4_hdr *) f->transport_hdr;
00524     if (!icmp_hdr)
00525       return -1;
00526     /* XXX PRELIMINARY ONLY LAST 16 BITS OF IP */
00527     pub_port = (uint16_t)(ipv4_hdr->src.addr & 0x00FF);
00528   }
00529 
00530   nk = pico_ipv4_nat_find_key(pub_port, 0, 0, proto);
00531 
00532   if (!nk) {
00533     nat_dbg("\nNAT: ERROR key not found in table\n");
00534     return -1;
00535   } else {
00536     pico_ipv4_nat_snif_forward(nk,f);
00537     ipv4_hdr->dst.addr = nk->priv_addr.addr;
00538 
00539     if (proto == PICO_PROTO_TCP) {
00540        tcp_hdr->trans.dport = nk->priv_port;
00541        pico_nat_tcp_checksum(f);
00542     } else if (proto == PICO_PROTO_UDP) {
00543       udp_hdr->trans.dport = nk->priv_port;
00544       udp_hdr->crc = 0;
00545       udp_hdr->crc = short_be(pico_udp_checksum_ipv4(f));
00546     }
00547   }
00548 
00549   ipv4_hdr->crc = 0;
00550   ipv4_hdr->crc = short_be(pico_checksum(ipv4_hdr, f->net_len));
00551  
00552   return 0; 
00553 }
00554 
00555 
00556 
00557 int pico_ipv4_nat(struct pico_frame *f, struct pico_ip4 pub_addr)
00558 {
00559   /*do nat---------*/
00560   struct pico_nat_key *nk = NULL;
00561   struct pico_nat_key key;
00562   struct pico_ipv4_hdr *net_hdr = (struct pico_ipv4_hdr *) f->net_hdr; 
00563   struct pico_tcp_hdr *tcp_hdr = NULL;  
00564   struct pico_udp_hdr *udp_hdr = NULL;  
00565   int ret;
00566   uint8_t proto = net_hdr->proto;
00567   uint16_t priv_port = 0;
00568   struct pico_ip4 priv_addr= net_hdr->src;
00569 
00570   nk= &key;
00571 
00572   /* TODO DELME check if IN */
00573   if (pub_addr.addr == net_hdr->dst.addr) {
00574     nat_dbg("NAT: backward translation {dst.addr, dport}: {%08X,%u} ->", net_hdr->dst.addr, ((struct pico_trans *)f->transport_hdr)->dport);
00575     ret = pico_ipv4_nat_port_forward(f);  /* our IN definition */
00576     nat_dbg(" {%08X,%u}\n", net_hdr->dst.addr, short_be(((struct pico_trans *)f->transport_hdr)->dport));
00577   } else {
00578     if (net_hdr->proto == PICO_PROTO_TCP) {
00579       tcp_hdr = (struct pico_tcp_hdr *) f->transport_hdr;
00580       priv_port = tcp_hdr->trans.sport;
00581     } else if (net_hdr->proto == PICO_PROTO_UDP) {
00582       udp_hdr = (struct pico_udp_hdr *) f->transport_hdr;
00583       priv_port = udp_hdr->trans.sport;
00584     } else if (net_hdr->proto == PICO_PROTO_ICMP4) {
00585       //udp_hdr = (struct pico_udp_hdr *) f->transport_hdr;
00586       priv_port = (uint16_t)(net_hdr->src.addr & 0x00FF);
00587     }
00588 
00589     ret = pico_ipv4_nat_find(0, &priv_addr, priv_port, proto);
00590     if (ret >= 0) {
00591       // Key is available in table
00592       nk = pico_ipv4_nat_find_key(0, &priv_addr, priv_port, proto);
00593     } else {
00594       nat_dbg("NAT: key not found in NAT table -> generate key\n");
00595       pico_ipv4_nat_generate_key(nk, f, pub_addr);
00596     }
00597     pico_ipv4_nat_snif_backward(nk,f);
00598     nat_dbg("NAT: forward translation {src.addr, sport}: {%08X,%u} ->", net_hdr->src.addr, short_be(((struct pico_trans *)f->transport_hdr)->sport));
00599     pico_ipv4_nat_translate(nk, f); /* our OUT definition */
00600     nat_dbg(" {%08X,%u}\n", net_hdr->src.addr, short_be(((struct pico_trans *)f->transport_hdr)->sport));
00601   } 
00602   return 0;
00603 }
00604 
00605 
00606 int pico_ipv4_nat_enable(struct pico_ipv4_link *link)
00607 {
00608   if (link == NULL) {
00609     pico_err = PICO_ERR_EINVAL;
00610     return -1;
00611   }
00612 
00613   pub_link = *link;
00614   pico_timer_add(NAT_TCP_TIMEWAIT, pico_ipv4_nat_table_cleanup, NULL);
00615   enable_nat_flag = 1;
00616   return 0;
00617 }
00618  
00619 int pico_ipv4_nat_disable(void)
00620 {
00621   pub_link.address.addr = 0;
00622   enable_nat_flag = 0;   
00623   return 0;
00624 }
00625 
00626 
00627 int pico_ipv4_nat_isenabled_out(struct pico_ipv4_link *link)
00628 {
00629   if (enable_nat_flag) {
00630     // is pub_link = *link
00631     if (pub_link.address.addr == link->address.addr)
00632       return 0;
00633     else
00634       return -1;
00635   } else {
00636     return -1;
00637   }
00638 }
00639 
00640 
00641 int pico_ipv4_nat_isenabled_in(struct pico_frame *f)
00642 {
00643   if (enable_nat_flag) {
00644     struct pico_tcp_hdr *tcp_hdr = NULL;
00645     struct pico_udp_hdr *udp_hdr = NULL;
00646     uint16_t pub_port = 0;
00647     int ret;
00648     uint8_t proto;
00649  
00650     struct pico_ipv4_hdr *ipv4_hdr = (struct pico_ipv4_hdr *) f->net_hdr; 
00651     if (!ipv4_hdr)
00652       return -1;
00653     proto = ipv4_hdr->proto;    
00654 
00655     if (proto == PICO_PROTO_TCP) {
00656       tcp_hdr = (struct pico_tcp_hdr *) f->transport_hdr;
00657       if (!tcp_hdr)
00658         return -1;
00659       pub_port= tcp_hdr->trans.dport;
00660     } else if (proto == PICO_PROTO_UDP) {
00661       udp_hdr = (struct pico_udp_hdr *) f->transport_hdr;
00662       if (!udp_hdr)
00663         return -1;
00664       pub_port= udp_hdr->trans.dport;
00665     } else if (proto == PICO_PROTO_ICMP4) {
00666       //icmp_hdr = (struct pico_icmp4_hdr *) f->transport_hdr;
00667       //if (!icmp_hdr)
00668       //  return -1;
00669       /* XXX PRELIMINARY ONLY LAST 16 BITS OF IP */
00670       pub_port = (uint16_t)(ipv4_hdr->src.addr & 0x00FF);
00671     }
00672     ret = pico_ipv4_nat_find(pub_port, NULL, 0, proto);
00673     if (ret == 0)
00674       return 0;
00675     else
00676       return -1;
00677   } else {
00678     return -1;    
00679   }
00680 }
00681 #endif
00682 #endif
00683