embedded IPsec source code documentation


ipsecdev.c

Go to the documentation of this file.
00001 /*
00002  * embedded IPsec
00003  * Copyright (c) 2003 Niklaus Schild and Christian Scheurer, HTI Biel/Bienne
00004  * All rights reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without modification,
00007  * are permitted provided that the following conditions are met:
00008  *
00009  * 1. Redistributions of source code must retain the above copyright notice,
00010  *    this list of conditions and the following disclaimer.
00011  * 2. Redistributions in binary form must reproduce the above copyright notice,
00012  *    this list of conditions and the following disclaimer in the documentation
00013  *    and/or other materials provided with the distribution.
00014  * 3. The name of the author may not be used to endorse or promote products
00015  *    derived from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
00018  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00019  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
00020  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00021  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
00022  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00023  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00024  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
00025  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
00026  * OF SUCH DAMAGE.
00027  *
00028  */
00029 
00069 #include "lwip/mem.h"
00070 
00071 #include "netif/ipsecdev.h"
00072 
00073 #include "ipsec/debug.h"
00074 #include "ipsec/ipsec.h"
00075 #include "ipsec/util.h"
00076 #include "ipsec/sa.h"
00077 
00078 
00079 #define IPSECDEV_NAME0 'i'              
00080 #define IPSECDEV_NAME1 's'              
00082 extern sad_entry inbound_sad_config[]; 
00083 extern spd_entry inbound_spd_config[]; 
00084 extern sad_entry outbound_sad_config[];
00085 extern spd_entry outbound_spd_config[];
00087 extern db_set_netif     db_sets[];
00088 db_set_netif    *databases;     
00089 struct netif    mapped_netif;   
00090 __u32                   tunnel_src_addr;
00091 __u32                   tunnel_dst_addr;
00100 void ipsecdev_service(struct netif *netif)
00101 {
00102         struct netif *i ;
00103         IPSEC_LOG_TRC(IPSEC_TRACE_ENTER, "ipsecdev_service", ("netif=%p", (void *)netif) );
00104         i = netif ;
00105         IPSEC_LOG_TRC(IPSEC_TRACE_RETURN, "ipsecdev_service", ("void") );
00106         return ;
00107 }
00108 
00109 
00123 err_t ipsecdev_input(struct pbuf *p, struct netif *inp)
00124 {
00125         int retcode;
00126         int payload_offset      = 0;
00127         int payload_size        = 0;
00128         spd_entry               *spd ;
00129 
00130         IPSEC_LOG_TRC(IPSEC_TRACE_ENTER, 
00131                       "ipsecdev_input", 
00132                                   ("p=%p, inp=%p",
00133                               (void *)p, (void *)inp)
00134                                  );
00135 
00136         IPSEC_DUMP_BUFFER("ipsecdev_input", p->payload, 0, p->len) ;
00137 
00138         if(p == NULL || p->payload == NULL)
00139         {
00140                 IPSEC_LOG_DBG("ipsecdev_input", IPSEC_STATUS_DATA_SIZE_ERROR, ("Packet has no payload. Can't pass it to higher level protocol stacks."));
00141                 pbuf_free(p) ;
00142         }
00143         else 
00144         {
00145 
00146                 /* minimal sanity check of inbound data (packet buffer & IP header fields must be <= MTU) */
00147                 if((p->tot_len > IPSEC_MTU) || (ipsec_ntohs(((ipsec_ip_header *)((unsigned char *)p->payload))->len) > IPSEC_MTU))
00148                 {
00149                         IPSEC_LOG_DBG("ipsecdev_input", IPSEC_STATUS_DATA_SIZE_ERROR, ("Packet to long (%d > %d (IPSEC_MTU))", p->tot_len, IPSEC_MTU) );
00150                         /* in case of error, free pbuf and return ERR_OK as lwIP does */
00151                         pbuf_free(p) ;
00152                         IPSEC_LOG_TRC(IPSEC_TRACE_RETURN, "ipsecdev_input", ("return = %d", ERR_OK) );
00153                         return ERR_OK;
00154                 }
00155 
00156                 if(p->next != NULL)
00157                 {
00158                         IPSEC_LOG_DBG("ipsecdev_input", IPSEC_STATUS_DATA_SIZE_ERROR, ("can not handle chained pbuf - (packet must be < %d bytes )", PBUF_POOL_BUFSIZE - PBUF_LINK_HLEN - IPSEC_HLEN) );
00159                         /* in case of error, free pbuf and return ERR_OK as lwIP does */
00160                         pbuf_free(p) ;
00161                         IPSEC_LOG_TRC(IPSEC_TRACE_RETURN, "ipsecdev_input", ("return = %d", ERR_OK) );
00162                         return ERR_OK;
00163                 }
00164 
00165 
00166                 if( ((ipsec_ip_header*)(p->payload))->protocol == IPSEC_PROTO_ESP || ((ipsec_ip_header*)(p->payload))->protocol == IPSEC_PROTO_AH)
00167                 {
00168                         /* we got an IPsec packet which must be handled by the IPsec engine */
00169                         retcode = ipsec_input(p->payload, p->len, (int *)&payload_offset, (int *)&payload_size, databases);
00170 
00171                         if(retcode == IPSEC_STATUS_SUCCESS)
00172                         {
00174                                 /* remove obsolete ESP headers */
00175                                 p->payload = (unsigned char *)(p->payload) + payload_offset;
00176                                 p->len = payload_size;
00177                                 p->tot_len = payload_size;
00178 
00179                                 IPSEC_LOG_MSG("ipsecdev_input", ("fwd decapsulated IPsec packet to ip_input()") );
00180                                 retcode = ip_input(p, inp);             
00181                                 IPSEC_LOG_TRC(IPSEC_TRACE_RETURN, "ipsecdev_input", ("retcode = %d", retcode) );
00182                                 return retcode;
00183 
00184                         }
00185                         else
00186                         {
00187                                 IPSEC_LOG_ERR("ipsecdev_input", retcode, ("error on ipsec_input() processing (retcode = %d)", retcode));
00188                                 pbuf_free(p) ;
00189                         }                       
00190                 }
00191                 else
00192                 {
00193                         /* check what the policy says about non-IPsec traffic */
00194                         spd = ipsec_spd_lookup(p->payload, &databases->inbound_spd) ;
00195                         if(spd == NULL)
00196                         {
00197                                 IPSEC_LOG_ERR("ipsecdev_input", IPSEC_STATUS_NO_POLICY_FOUND, ("no matching SPD policy found")) ;
00198                                 pbuf_free(p) ;
00199                         }
00200                         else
00201                         {
00202                                 switch(spd->policy)
00203                                 {
00204                                         case POLICY_APPLY:
00205                                                 IPSEC_LOG_AUD("ipsecdev_input", IPSEC_AUDIT_APPLY, ("POLICY_APPLY: got non-IPsec packet which should be one")) ;
00206                                                 pbuf_free(p) ;
00207                                                 break;
00208                                         case POLICY_DISCARD:
00209                                                 IPSEC_LOG_AUD("ipsecdev_input", IPSEC_AUDIT_DISCARD, ("POLICY_DISCARD: dropping packet")) ;
00210                                                 pbuf_free(p) ;
00211                                                 break;
00212                                         case POLICY_BYPASS:
00213                                                 IPSEC_LOG_AUD("ipsecdev_input", IPSEC_AUDIT_BYPASS, ("POLICY_BYPASS: forwarding packet to ip_input")) ;
00214                                                 ip_input(p, inp);
00215                                                 break;
00216                                         default:
00217                                                 pbuf_free(p) ;
00218                                                 IPSEC_LOG_ERR("ipsecdev_input", IPSEC_STATUS_FAILURE, ("IPSEC_STATUS_FAILURE: dropping packet")) ;
00219                                                 IPSEC_LOG_AUD("ipsecdev_input", IPSEC_AUDIT_FAILURE, ("unknown Security Policy: dropping packet")) ;
00220                                 } 
00221                         }
00222                 }
00223         }
00224 
00225         /* usually return ERR_OK as lwIP does */
00226         IPSEC_LOG_TRC(IPSEC_TRACE_RETURN, "ipsecdev_input", ("retcode = %d", ERR_OK) );
00227         return ERR_OK;
00228 }
00229 
00230 
00243 err_t ipsecdev_output(struct netif *netif, struct pbuf *p, struct ip_addr *ipaddr)
00244 {
00245         struct pbuf *p_cpy = NULL;
00246         int payload_size ;
00247         int payload_offset ;
00248         spd_entry *spd ;
00249         ipsec_status status ;
00250         struct ip_addr dest_addr;
00251         int retcode;
00252 
00253         IPSEC_LOG_TRC(IPSEC_TRACE_ENTER, 
00254                       "ipsecdev_output", 
00255                                   ("netif=%p, p=%p, ipaddr=%p", (void *)netif, (void *)p, (void *)ipaddr ) 
00256                                  );
00257 
00258 
00259         /* minimal sanity check of inbound data (packet buffer & IP header fields must be <= MTU) */
00260         if((p->tot_len > IPSEC_MTU) || (ipsec_ntohs(((ipsec_ip_header *)((unsigned char *)p->payload))->len) > IPSEC_MTU))
00261         {
00262                 IPSEC_LOG_DBG("ipsecdev_output", IPSEC_STATUS_DATA_SIZE_ERROR, ("Packet to long (> IPSEC_MTU) on interface '%c%c'", netif->name[0], netif->name[1]));
00263                 IPSEC_LOG_TRC(IPSEC_TRACE_RETURN, "ipsecdev_output", ("return = %d", ERR_CONN) );
00264                 return ERR_CONN;
00265         }
00266 
00267         if(p->next != NULL)
00268         {
00269                 IPSEC_LOG_DBG("ipsecdev_output", IPSEC_STATUS_DATA_SIZE_ERROR, ("can not handle chained pbuf - use pbuf size of %d bytes", IPSEC_MTU));
00270                 IPSEC_LOG_TRC(IPSEC_TRACE_RETURN, "ipsecdev_output", ("return = %d", ERR_CONN) );
00271                 return ERR_CONN;
00272         }
00273 
00274         if(p->ref != 1)
00275         {
00276                 IPSEC_LOG_DBG("ipsecdev_output", IPSEC_STATUS_DATA_SIZE_ERROR, ("can not handle pbuf->ref != 1 - p->ref == %d", p->ref));
00277                 IPSEC_LOG_TRC(IPSEC_TRACE_RETURN, "ipsecdev_output", ("return = %d", ERR_CONN) );
00278                 return ERR_CONN;
00279         }
00280 
00281 
00283         memcpy(&dest_addr, ipaddr, sizeof(struct ip_addr));
00284 
00287         /* RFC conform IPsec processing */
00288         spd = ipsec_spd_lookup((ipsec_ip_header*)p->payload, &databases->outbound_spd) ;
00289         if(spd == NULL)
00290         {
00291                 IPSEC_LOG_ERR("ipsecdev_output", IPSEC_STATUS_NO_POLICY_FOUND, ("no matching SPD policy found")) ;
00292                 /* free local pbuf here */
00293                 pbuf_free(p);
00294                 IPSEC_LOG_TRC(IPSEC_TRACE_RETURN, "ipsecdev_output", ("retcode = %d", ERR_CONN) );
00295                 return ERR_CONN ;
00296         }
00297 
00298         switch(spd->policy)
00299         {
00300                 case POLICY_APPLY:                                                                                                                                              
00301                                 IPSEC_LOG_AUD("ipsecdev_output", IPSEC_AUDIT_APPLY, ("POLICY_APPLY: processing IPsec packet")) ;
00302 
00308                                 p_cpy = p;
00309                                 if(spd->sa->protocol == IPSEC_PROTO_ESP)
00310                                 {
00311                                         // alloc 50 more bytes for ESP trailer and the optional ESP authentication data
00312                                     p_cpy = pbuf_alloc(PBUF_RAW, p->len + 50, PBUF_POOL);
00313 
00314                                         if(p_cpy != NULL) {
00315                                                 memcpy(p_cpy->payload, p->payload, p->len);
00316                                                 p_cpy->next = NULL;
00317                                                 p_cpy->len = p->len + 50;
00318                                                 p_cpy->tot_len = p->tot_len + 50;
00319                                                 p_cpy->ref = p->ref;
00320                                                 IPSEC_LOG_MSG("ipsecdev_output", ("lwIP ESP TCP workaround: successfully allocated new pbuf (tot_len = %d)", p_cpy->tot_len) );
00321                                         }
00322                                         else {
00323                                                 IPSEC_LOG_ERR("ipsecdev_output", IPSEC_AUDIT_FAILURE, ("can't alloc new pbuf for lwIP ESP TCP workaround!") ) ;
00324                                         }
00325                                 }
00326 
00327                                 status = ipsec_output(p_cpy->payload, p_cpy->len, &payload_offset, &payload_size, tunnel_src_addr, tunnel_dst_addr, spd) ;
00328 
00329                                 if(status == IPSEC_STATUS_SUCCESS)
00330                                 {
00331                                         /* adjust pbuf structure according to the real packet size */
00332                                         p_cpy->payload = (unsigned char *)(p_cpy->payload) + payload_offset;
00333                                         p_cpy->len = payload_size;
00334                                         p_cpy->tot_len = payload_size;
00335 
00336                                         IPSEC_LOG_MSG("ipsec_output", ("fwd IPsec packet to HW mapped device") );
00337                                         retcode = mapped_netif.output(&mapped_netif, p_cpy, (void *)&tunnel_dst_addr);
00338                                         if(spd->sa->protocol == IPSEC_PROTO_ESP) pbuf_free(p_cpy);
00339                                 }
00340                                 else {
00341                                         IPSEC_LOG_ERR("ipsec_output", status, ("error on ipsec_output() processing"));
00342                                         if(spd->sa->protocol == IPSEC_PROTO_ESP) pbuf_free(p_cpy);
00343                                         IPSEC_LOG_TRC(IPSEC_TRACE_RETURN, "ipsecdev_output", ("retcode = %d", ERR_CONN) );
00344                                 }
00345 
00346                                 IPSEC_LOG_TRC(IPSEC_TRACE_RETURN, "ipsecdev_output", ("retcode = %d", ERR_OK) );
00347                         return ERR_OK;
00348                         break;
00349                 case POLICY_DISCARD:
00350                                 IPSEC_LOG_AUD("ipsecdev_output", IPSEC_AUDIT_DISCARD, ("POLICY_DISCARD: dropping packet")) ;
00351                         break;
00352                 case POLICY_BYPASS:
00353                                 IPSEC_LOG_AUD("ipsecdev_output", IPSEC_AUDIT_BYPASS, ("POLICY_BYPASS: forwarding packet to ip_output")) ;
00354                                 retcode = mapped_netif.output(&mapped_netif, p, &dest_addr);
00355                                 IPSEC_LOG_TRC(IPSEC_TRACE_RETURN, "ipsecdev_output", ("retcode = %d", retcode) );
00356                                 return retcode;
00357                         break;
00358                 default:
00359                         IPSEC_LOG_ERR("ipsecdev_input", IPSEC_STATUS_FAILURE, ("POLICY_DIRCARD: dropping packet")) ;
00360                         IPSEC_LOG_AUD("ipsecdev_input", IPSEC_AUDIT_FAILURE, ("unknown Security Policy: dropping packet")) ;
00361         }
00362 
00363         IPSEC_LOG_TRC(IPSEC_TRACE_RETURN, "ipsecdev_output", ("return = %d", ERR_CONN) );
00364         return ERR_CONN;
00365 }
00366 
00367 
00378 err_t ipsecdev_netlink_output(struct netif *netif, struct pbuf *p)
00379 {
00380         int retcode;
00381         IPSEC_LOG_TRC(IPSEC_TRACE_ENTER, 
00382                       "ipsecdev_netlink_output", 
00383                                   ("netif=%p, p=%d", (void *)netif, (void *)p ) 
00384                                  );
00385         IPSEC_LOG_MSG("ipsecdev_netlink_output", ("fwd from interface '%c%c' to real HW linkoutput",  netif->name[0], netif->name[1]) );
00386 
00387         retcode = mapped_netif.linkoutput(&mapped_netif, p);
00388         IPSEC_LOG_TRC(IPSEC_TRACE_RETURN, "ipsecdev_netlink_output", ("retcode = %d", retcode) );
00389         return retcode; 
00390 }
00391 
00392 
00402 err_t ipsecdev_init(struct netif *netif)
00403 {
00404         struct ipsecdev_stats *ipsecdev_stats;
00405 
00406         IPSEC_LOG_TRC(IPSEC_TRACE_ENTER, 
00407                       "ipsecdev_init", 
00408                                   ("netif=%p", (void *)netif ) 
00409                                  );
00410 
00411 
00412         ipsecdev_stats = mem_malloc(sizeof(struct ipsecdev_stats));
00413         if (ipsecdev_stats == NULL)
00414         {
00415                 IPSEC_LOG_DBG("ipsecdev_init", IPSEC_STATUS_DATA_SIZE_ERROR, ("out of memory for ipsecdev_stats"));
00416                 IPSEC_LOG_TRC(IPSEC_TRACE_RETURN, "ipsecdev_init", ("retcode = %d", ERR_MEM) );
00417                 return ERR_MEM;
00418         }
00419 
00420         /* set the name of this interface */
00421         netif->name[0] = IPSECDEV_NAME0;
00422         netif->name[1] = IPSECDEV_NAME1;
00423 
00424         /* use the same output function for all operations */
00425         netif->output = (void *)ipsecdev_output;                                /* usually called if the IP module wants to send data */
00426         netif->linkoutput = (void *)ipsecdev_netlink_output;    /* usually called if the ARP module wants to send data "as-is" */
00427 
00429         /* initialize the db_sets structure */
00430         memset(db_sets, 0, IPSEC_NR_NETIFS*sizeof(db_set_netif)) ;
00431 
00432         /* swap output devices */
00434         /* save mapped netif */
00435         memcpy(&mapped_netif, netif_list, sizeof(struct netif)) ;
00436         netif_list->output = (void *)ipsecdev_output;
00437 
00438         /* setup ipsec databases/configuration */
00439         databases = ipsec_spd_load_dbs(inbound_spd_config, outbound_spd_config, inbound_sad_config, outbound_sad_config) ;
00440         if (databases == NULL)
00441         {
00442                 IPSEC_LOG_ERR("ipsecdev_init", -1, ("not able to load SPD and SA configuration for ipsec device")) ;
00443         }
00444 
00445         ipsecdev_stats->sentbytes = 0;                  /* reset statistic */
00446         netif->state = ipsecdev_stats;                  /* assign statistic */
00447         netif->mtu = 1500;                                              /* set MTU */
00448         netif->flags = NETIF_FLAG_LINK_UP | NETIF_FLAG_BROADCAST;       /* device is always connected and supports broadcasts */
00449         netif->hwaddr_len = 6;                                  /* set hardware address (MAC address) */
00450 
00452 #ifdef PHYCORE167HSE 
00453         netif->hwaddr_len = 6;                                  /* set hardware address (MAC address) */
00454         netif->hwaddr[0] = 0xA4;
00455         netif->hwaddr[1] = 0xB4;
00456         netif->hwaddr[2] = 0xC4;
00457         netif->hwaddr[3] = 0xD4;
00458         netif->hwaddr[4] = 0xE4;
00459         netif->hwaddr[5] = 0xF4;
00460 #else
00461         netif->hwaddr_len = 6;                                  /* set hardware address (MAC address) */
00462         netif->hwaddr[0] = 0xA3;
00463         netif->hwaddr[1] = 0xB3;
00464         netif->hwaddr[2] = 0xC3;
00465         netif->hwaddr[3] = 0xD3;
00466         netif->hwaddr[4] = 0xE3;
00467         netif->hwaddr[5] = 0xF3;
00468 #endif
00469 
00470         IPSEC_LOG_TRC(IPSEC_TRACE_RETURN, "ipsecdev_init", ("retcode = %d", IPSEC_STATUS_SUCCESS) );
00471         return IPSEC_STATUS_SUCCESS;
00472 }
00473 
00481 void ipsec_set_tunnel(char *src, char *dst)
00482 {
00483         tunnel_src_addr = ipsec_inet_addr(src) ;
00484         tunnel_dst_addr = ipsec_inet_addr(dst) ;
00485         return ;
00486 }

Copyright 2003 by Christian Scheurer and Niklaus Schild