• Main Page
  • Modules
  • Index
  • File List
  • Globals

gazell/common/gzp_host.c

Go to the documentation of this file.
00001 /* Copyright (c) 2009 Nordic Semiconductor. All Rights Reserved.
00002  *
00003  * The information contained herein is confidential property of Nordic
00004  * Semiconductor ASA.Terms and conditions of usage are described in detail
00005  * in NORDIC SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
00006  *
00007  * Licensees are granted free, non-transferable use of the information. NO
00008  * WARRENTY of ANY KIND is provided. This heading must NOT be removed from
00009  * the file.
00010  *
00011  * $LastChangedRevision: 230 $
00012  */
00013 
00019 #include "gzp.h"
00020 #include "gzll.h"
00021 #include "string.h"
00022 #include "stdint.h"
00023 #include "stdbool.h"
00024 #include "hal_aes.h"
00025 #include "hal_flash.h"
00026 #include "memdefs.h"
00027 
00028 //lint -esym(40, GZP_PARAMS_STORAGE_ADR) "Undeclared identifier"
00029 
00030 //-----------------------------------------------------------------------------
00031 // Typedefs
00032 //-----------------------------------------------------------------------------
00033 
00037 typedef enum
00038 {
00039   GZP_ID_REQ_IDLE,
00040   GZP_ID_REQ_PENDING,
00041   GZP_ID_REQ_PENDING_AND_GRANTED,
00042   GZP_ID_REQ_PENDING_AND_REJECTED,
00043 } gzp_id_req_stat_t;
00044 
00045 //-----------------------------------------------------------------------------
00046 // Internal (static) functions
00047 //-----------------------------------------------------------------------------
00048 
00052 static void gzp_session_counter_inc();
00053 
00057 static void gzp_get_session_counter(uint8_t* dst);
00058 
00065 static bool gzp_set_host_id(const uint8_t* dst);
00066 
00070 static void gzp_process_address_req(uint8_t* gzp_req);
00071 
00075 static void gzp_process_id_req(uint8_t* rx_payload);
00076 static void gzp_process_id_fetch(uint8_t* rx_payload);
00077 static void gzp_process_key_update_prepare();
00078 static void gzp_process_key_update(uint8_t* rx_payload);
00079 static void gzp_process_encrypted_user_data(uint8_t* rx_payload, uint8_t length);
00080 
00084 static void gzp_preload_ack(uint8_t* src, uint8_t length, uint8_t pipe);
00085 
00089 void gzp_host_chip_id_read(uint8_t *dst, uint8_t n);
00090 
00091 //-----------------------------------------------------------------------------
00092 // Global variables
00093 //-----------------------------------------------------------------------------
00094 
00095 static gzp_id_req_stat_t gzp_id_req_stat;
00096 static xdata bool gzp_pairing_enabled_f;
00097 static xdata bool gzp_address_exchanged_f;
00098 static xdata uint8_t gzp_session_counter[GZP_SESSION_TOKEN_LENGTH];
00099 static xdata uint8_t gzp_encrypted_user_data_length;
00100 static xdata bool gzp_encrypted_user_data[GZP_ENCRYPTED_USER_DATA_MAX_LENGTH];
00101 extern __no_init uint8_t gzp_dyn_key[GZP_DYN_KEY_LENGTH];
00102 
00103 //-----------------------------------------------------------------------------
00104 // Implementation: Application programming interface (API)
00105 //-----------------------------------------------------------------------------
00106 
00107 void gzp_init()
00108 {
00109   uint8_t system_address[GZP_SYSTEM_ADDRESS_WIDTH];
00110 
00111   // Read "chip id", of which 4 bytes (GZP_SYSTEM_ADDRESS_WIDTH)
00112   // are used as system address
00113   gzp_host_chip_id_read(system_address, GZP_SYSTEM_ADDRESS_WIDTH);
00114 
00115   // Set up radio parameters (addresses and channel subset) from system_address
00116   gzp_update_radio_params(system_address);
00117 
00118   // Only "data pipe" enabled by default
00119   gzll_set_param(GZLL_PARAM_RX_PIPES, gzll_get_param(GZLL_PARAM_RX_PIPES) | (1 << GZP_DATA_PIPE));
00120 
00121   gzp_pairing_enabled_f = false;
00122   gzp_address_exchanged_f = false;
00123   gzp_id_req_stat = GZP_ID_REQ_IDLE;
00124   gzp_encrypted_user_data_length = 0;
00125 
00126   // Infinite RX timeout
00127   gzll_set_param(GZLL_PARAM_RX_TIMEOUT, 0);
00128 }
00129 
00130 void gzp_pairing_enable(bool enable)
00131 {
00132   gzll_states_t temp_gzll_state;
00133 
00134   temp_gzll_state = gzll_get_state();
00135 
00136   if(gzp_pairing_enabled_f != enable)
00137   {
00138     gzll_goto_idle();
00139 
00140     if(enable)
00141     {
00142       gzll_set_param(GZLL_PARAM_RX_PIPES, gzll_get_param(GZLL_PARAM_RX_PIPES) | (1 << GZP_PAIRING_PIPE));
00143     }
00144     else
00145     {
00146       gzll_set_param(GZLL_PARAM_RX_PIPES, gzll_get_param(GZLL_PARAM_RX_PIPES) & ~(1 << GZP_PAIRING_PIPE));
00147       gzp_id_req_stat = GZP_ID_REQ_IDLE;
00148     }
00149 
00150     gzp_pairing_enabled_f = enable;
00151 
00152     if(temp_gzll_state == GZLL_HOST_ACTIVE)
00153     {
00154       gzll_rx_start();
00155     }
00156   }
00157 }
00158 
00159 void gzp_host_execute()
00160 {
00161   uint8_t rx_pipe;
00162   uint8_t payload_length;
00163   uint8_t rx_payload[GZLL_MAX_FW_PAYLOAD_LENGTH];
00164 
00165   gzp_address_exchanged_f = false;
00166 
00167   rx_pipe = gzll_get_rx_data_ready_pipe_number();
00168 
00169   if((rx_pipe == GZP_PAIRING_PIPE) || ((rx_pipe == GZP_DATA_PIPE) && (gzp_encrypted_user_data_length == 0)))
00170   {
00171     gzll_rx_fifo_read(rx_payload, &payload_length, NULL);
00172 
00173     switch(rx_payload[0])
00174     {
00175       case GZP_CMD_HOST_ADDRESS_REQ:
00176         gzp_process_address_req(rx_payload);
00177         break;
00178 
00179       #ifndef GZP_CRYPT_DISABLE
00180 
00181       case GZP_CMD_HOST_ID_REQ:
00182         gzp_process_id_req(rx_payload);
00183         break;
00184       case GZP_CMD_HOST_ID_FETCH:
00185         gzp_process_id_fetch(rx_payload);
00186         break;
00187       case GZP_CMD_KEY_UPDATE_PREPARE:
00188         gzp_process_key_update_prepare();
00189         break;
00190       case GZP_CMD_KEY_UPDATE:
00191         gzp_process_key_update(rx_payload);
00192         break;
00193       case GZP_CMD_ENCRYPTED_USER_DATA:
00194         gzp_process_encrypted_user_data(rx_payload, payload_length);
00195         break;
00196 
00197       #endif
00198 
00199       case GZP_CMD_FETCH_RESP:
00200       default:
00201         break;
00202     }
00203   }
00204 
00205   // Restart reception if "not proximity backoff" period has elapsed
00206   if(gzll_get_state() == GZLL_IDLE)
00207   {
00208     gzll_set_param(GZLL_PARAM_RX_TIMEOUT, 0);
00209     if(gzp_pairing_enabled_f)
00210     {
00211       gzll_set_param(GZLL_PARAM_RX_PIPES, gzll_get_param(GZLL_PARAM_RX_PIPES) | (1 << GZP_PAIRING_PIPE));
00212     }
00213     gzll_rx_start();
00214   }
00215 
00216   #ifndef GZP_CRYPT_DISABLE
00217   gzp_session_counter_inc();
00218   #endif
00219 }
00220 
00221 static void gzp_process_address_req(uint8_t* gzp_req)
00222 {
00223   uint8_t temp_rx_pipes, temp_host_mode;
00224   uint8_t pairing_resp[GZP_CMD_HOST_ADDRESS_RESP_PAYLOAD_LENGTH];
00225 
00226   gzp_address_exchanged_f = false;
00227 
00228   gzll_goto_idle();
00229   temp_rx_pipes = gzll_get_param(GZLL_PARAM_RX_PIPES);
00230   temp_host_mode =  gzll_get_param(GZLL_PARAM_HOST_MODE);
00231 
00232   // If requesting Device within close proximity
00233   if(gzll_rx_power_high())
00234   {
00235     gzll_set_param(GZLL_PARAM_RX_PIPES, 0);
00236     gzll_set_param(GZLL_PARAM_HOST_MODE, 0);
00237     gzll_set_param(GZLL_PARAM_RX_TIMEOUT, GZP_CLOSE_PROXIMITY_BACKOFF_RX_TIMEOUT);
00238     gzll_rx_fifo_flush();
00239 
00240     // Start "proximity" back off period
00241     gzll_rx_start();
00242 
00243     while(gzll_get_state() != GZLL_IDLE)
00244     ;
00245 
00246     // Build pairing response packet
00247     pairing_resp[0] = GZP_CMD_HOST_ADDRESS_RESP;
00248     gzp_host_chip_id_read(&pairing_resp[GZP_CMD_HOST_ADDRESS_RESP_ADDRESS], GZP_SYSTEM_ADDRESS_WIDTH);
00249     gzll_ack_payload_write(&pairing_resp[0], GZP_CMD_HOST_ADDRESS_RESP_PAYLOAD_LENGTH, 0);
00250     gzll_set_param(GZLL_PARAM_RX_TIMEOUT, GZP_STEP1_RX_TIMEOUT);
00251 
00252     // Enable only pairing pipe when waiting for pairing request step 1
00253     gzll_set_param(GZLL_PARAM_RX_PIPES, (1 << GZP_PAIRING_PIPE));
00254     gzll_rx_start();
00255 
00256     while(gzll_get_state() != GZLL_IDLE)
00257     {
00258       if(gzll_rx_fifo_read(&gzp_req[0], NULL, NULL))
00259       {
00260         // Validate step 1 of pairing request
00261         if(gzp_req[0] == GZP_CMD_HOST_ADDRESS_FETCH)
00262         {
00263           gzp_address_exchanged_f = true;
00264         }
00265       }
00266     }
00267 
00268     gzll_tx_fifo_flush();
00269     gzll_rx_fifo_flush();
00270     gzll_set_param(GZLL_PARAM_RX_TIMEOUT, 0);
00271     gzll_set_param(GZLL_PARAM_RX_PIPES, temp_rx_pipes);
00272     gzll_set_param(GZLL_PARAM_HOST_MODE, temp_host_mode);
00273 
00274     // Return to normal operation
00275     gzll_rx_start();
00276   }
00277   else
00278   {
00279     gzll_set_param(GZLL_PARAM_RX_PIPES, temp_rx_pipes & ~(1 << GZP_PAIRING_PIPE));
00280     gzll_set_param(GZLL_PARAM_RX_TIMEOUT, GZP_NOT_PROXIMITY_BACKOFF_RX_TIMEOUT);
00281     // Start "not proximity" backoff period
00282     gzll_rx_start();
00283   }
00284 }
00285 
00286 static void gzp_preload_ack(uint8_t* src, uint8_t length, uint8_t pipe)
00287 {
00288   gzll_goto_idle();
00289   gzll_tx_fifo_flush();
00290   gzll_ack_payload_write(src, length, pipe);
00291   gzll_rx_start();
00292 }
00293 
00294 bool gzp_address_exchanged()
00295 {
00296   return gzp_address_exchanged_f;
00297 }
00298 
00299 #ifndef GZP_CRYPT_DISABLE
00300 
00301 bool gzp_crypt_user_data_received()
00302 {
00303   return (gzp_encrypted_user_data_length > 0);
00304 }
00305 
00306 bool gzp_crypt_user_data_read(uint8_t* dst, uint8_t* length)
00307 {
00308   if(gzp_encrypted_user_data_length > 0)
00309   {
00310     memcpy(dst, (void*)gzp_encrypted_user_data, gzp_encrypted_user_data_length);
00311 
00312     if(length != NULL)
00313     {
00314       *length = gzp_encrypted_user_data_length;
00315     }
00316     gzp_encrypted_user_data_length = 0;
00317 
00318     return true;
00319   }
00320   else
00321   {
00322     return false;
00323   }
00324 }
00325 
00326 bool gzp_id_req_received()
00327 {
00328   return (gzp_id_req_stat != GZP_ID_REQ_IDLE);
00329 }
00330 
00331 void gzp_id_req_reject()
00332 {
00333   if(gzp_id_req_received())
00334   {
00335     gzp_id_req_stat = GZP_ID_REQ_PENDING_AND_REJECTED;
00336   }
00337 }
00338 
00339 void gzp_id_req_grant()
00340 {
00341   if(gzp_id_req_received())
00342   {
00343     gzp_id_req_stat = GZP_ID_REQ_PENDING_AND_GRANTED;
00344   }
00345 }
00346 
00347 void gzp_id_req_cancel()
00348 {
00349   if(gzp_id_req_received())
00350   {
00351     gzp_id_req_stat = GZP_ID_REQ_IDLE;
00352   }
00353 }
00354 
00355 static void gzp_session_counter_inc()
00356 {
00357   uint8_t i;
00358 
00359   for(i = 0; i < GZP_SESSION_TOKEN_LENGTH; i++)
00360   {
00361     gzp_session_counter[i]++;
00362     if(gzp_session_counter[i] != 0)
00363     {
00364       break;
00365     }
00366   }
00367 }
00368 
00369 static void gzp_get_session_counter(uint8_t* dst)
00370 {
00371   memcpy(dst, (void*)gzp_session_counter, GZP_SESSION_TOKEN_LENGTH);
00372 }
00373 
00374 static bool gzp_set_host_id(const uint8_t* src)
00375 {
00376   if(hal_flash_byte_read(GZP_PARAMS_STORAGE_ADR) == 0xff)
00377   {
00378     hal_flash_byte_write(GZP_PARAMS_STORAGE_ADR, 0x00);
00379     hal_flash_bytes_write(GZP_PARAMS_STORAGE_ADR + 1, src, GZP_HOST_ID_LENGTH);
00380     return true;
00381   }
00382   else
00383   {
00384     return false;
00385   }
00386 }
00387 
00388 bool gzp_get_host_id(uint8_t* dst)
00389 {
00390   if(hal_flash_byte_read(GZP_PARAMS_STORAGE_ADR) == 0)
00391   {
00392     hal_flash_bytes_read(GZP_PARAMS_STORAGE_ADR + 1, dst, GZP_HOST_ID_LENGTH);
00393     return true;
00394   }
00395   else
00396   {
00397     return false;
00398   }
00399 }
00400 
00401 static void gzp_process_id_req(uint8_t* rx_payload)
00402 {
00403   uint8_t temp_host_id[GZP_HOST_ID_LENGTH];
00404 
00405   if(gzp_pairing_enabled_f)
00406   {
00407     if(!gzp_id_req_received())
00408     {
00409       gzp_crypt_set_session_token(&rx_payload[GZP_CMD_HOST_ID_REQ_SESSION_TOKEN]);
00410       gzp_id_req_stat = GZP_ID_REQ_PENDING;
00411     }
00412 
00413     // If host ID not generated yet
00414     if(!gzp_get_host_id(temp_host_id))
00415     {
00416       // Generate new host ID from "session counter" and received "session token"
00417       gzp_get_session_counter(temp_host_id);
00418       if(GZP_HOST_ID_LENGTH > GZP_SESSION_TOKEN_LENGTH)
00419       {
00420         gzp_xor_cipher(temp_host_id, temp_host_id, &rx_payload[GZP_CMD_HOST_ID_REQ_SESSION_TOKEN], GZP_SESSION_TOKEN_LENGTH);
00421       }
00422       else
00423       {
00424         gzp_xor_cipher(temp_host_id, temp_host_id, &rx_payload[GZP_CMD_HOST_ID_REQ_SESSION_TOKEN], GZP_HOST_ID_LENGTH);
00425       }
00426 
00427       gzp_set_host_id(temp_host_id);
00428     }
00429   }
00430 }
00431 
00432 static void gzp_process_id_fetch(uint8_t* rx_payload)
00433 {
00434   uint8_t tx_payload[GZP_CMD_HOST_ID_FETCH_RESP_PAYLOAD_LENGTH];
00435 
00436   if(gzp_id_req_received())
00437   {
00438     gzp_crypt_select_key(GZP_ID_EXCHANGE);
00439     gzp_crypt(&rx_payload[1], &rx_payload[1], GZP_CMD_HOST_ID_FETCH_PAYLOAD_LENGTH - 1);
00440     if(gzp_validate_id(&rx_payload[GZP_CMD_HOST_ID_FETCH_VALIDATION_ID]))
00441     {
00442       switch(gzp_id_req_stat)
00443       {
00444         case GZP_ID_REQ_PENDING_AND_GRANTED:
00445           tx_payload[GZP_CMD_HOST_ID_FETCH_RESP_STATUS] = GZP_ID_RESP_GRANTED;
00446           gzp_get_host_id(&tx_payload[GZP_CMD_HOST_ID_FETCH_RESP_HOST_ID]);
00447           gzp_id_req_stat = GZP_ID_REQ_IDLE;
00448           break;
00449         case GZP_ID_REQ_PENDING_AND_REJECTED:
00450           tx_payload[GZP_CMD_HOST_ID_FETCH_RESP_STATUS] = GZP_ID_RESP_REJECTED;
00451           gzp_id_req_stat = GZP_ID_REQ_IDLE;
00452           break;
00453         case GZP_ID_REQ_PENDING:
00454         default:
00455           tx_payload[GZP_CMD_HOST_ID_FETCH_RESP_STATUS] = GZP_ID_RESP_PENDING;
00456           break;
00457       }
00458 
00459       tx_payload[0] = GZP_CMD_HOST_ID_FETCH_RESP;
00460       gzp_add_validation_id(&tx_payload[GZP_CMD_HOST_ID_FETCH_RESP_VALIDATION_ID]);
00461       gzp_crypt(&tx_payload[1], &tx_payload[1], GZP_CMD_HOST_ID_FETCH_RESP_PAYLOAD_LENGTH - 1);
00462       gzp_preload_ack(tx_payload, GZP_CMD_HOST_ID_FETCH_RESP_PAYLOAD_LENGTH, GZP_DATA_PIPE);
00463     }
00464   }
00465 }
00466 
00467 static void gzp_process_key_update_prepare()
00468 {
00469   uint8_t tx_payload[GZP_CMD_KEY_UPDATE_PREPARE_RESP_PAYLOAD_LENGTH];
00470 
00471   tx_payload[0] = GZP_CMD_KEY_UPDATE_PREPARE_RESP;
00472 
00473   gzp_get_session_counter(&tx_payload[GZP_CMD_KEY_UPDATE_PREPARE_RESP_SESSION_TOKEN]);
00474 
00475   // Update session token if no ID request is pending
00476   if(!gzp_id_req_received())
00477   {
00478     gzp_crypt_set_session_token(&tx_payload[GZP_CMD_KEY_UPDATE_PREPARE_RESP_SESSION_TOKEN]);
00479   }
00480 
00481   gzp_preload_ack(tx_payload, GZP_CMD_KEY_UPDATE_PREPARE_RESP_PAYLOAD_LENGTH, GZP_DATA_PIPE);
00482 }
00483 
00484 static void gzp_process_key_update(uint8_t* rx_payload)
00485 {
00486   gzp_crypt_select_key(GZP_KEY_EXCHANGE);
00487   gzp_crypt(&rx_payload[1], &rx_payload[1], GZP_CMD_KEY_UPDATE_PAYLOAD_LENGTH - 1);
00488   if(gzp_validate_id(&rx_payload[GZP_CMD_KEY_UPDATE_VALIDATION_ID]))
00489   {
00490     gzp_crypt_set_dyn_key(&rx_payload[GZP_CMD_KEY_UPDATE_NEW_KEY]);
00491   }
00492 }
00493 
00494 static void gzp_process_encrypted_user_data(uint8_t* rx_payload, uint8_t length)
00495 {
00496   uint8_t tx_payload[GZP_CMD_ENCRYPTED_USER_DATA_RESP_PAYLOAD_LENGTH];
00497 
00498   if(gzp_id_req_received())
00499   {
00500     gzp_crypt_select_key(GZP_ID_EXCHANGE);
00501   }
00502   else
00503   {
00504     gzp_crypt_select_key(GZP_DATA_EXCHANGE);
00505   }
00506 
00507   gzp_crypt(&rx_payload[1], &rx_payload[1], length - 1);
00508   if(gzp_validate_id(&rx_payload[GZP_CMD_ENCRYPTED_USER_DATA_VALIDATION_ID]))
00509   {
00510     gzp_encrypted_user_data_length = length - GZP_USER_DATA_PACKET_OVERHEAD;
00511     memcpy((void*)gzp_encrypted_user_data, &rx_payload[GZP_CMD_ENCRYPTED_USER_DATA_PAYLOAD], gzp_encrypted_user_data_length);
00512   }
00513 
00514   // Build response packet
00515   tx_payload[0] = GZP_CMD_ENCRYPTED_USER_DATA_RESP;
00516   gzp_add_validation_id(&tx_payload[GZP_CMD_ENCRYPTED_USER_DATA_RESP_VALIDATION_ID]);
00517   gzp_crypt(&tx_payload[GZP_CMD_ENCRYPTED_USER_DATA_RESP_VALIDATION_ID], &tx_payload[GZP_CMD_ENCRYPTED_USER_DATA_RESP_VALIDATION_ID], GZP_VALIDATION_ID_LENGTH);
00518   gzp_get_session_counter(&tx_payload[GZP_CMD_ENCRYPTED_USER_DATA_RESP_SESSION_TOKEN]);
00519 
00520   // Update "session token" only if no ID request is pending
00521   if(!gzp_id_req_received())
00522   {
00523     gzp_crypt_set_session_token(&tx_payload[GZP_CMD_ENCRYPTED_USER_DATA_RESP_SESSION_TOKEN]);
00524   }
00525 
00526   gzp_preload_ack(tx_payload, GZP_CMD_ENCRYPTED_USER_DATA_RESP_PAYLOAD_LENGTH, GZP_DATA_PIPE);
00527 }
00528 
00529 #endif

Generated on Fri Apr 20 2012 14:11:44 for nRFGo SDK by  doxygen 1.7.2