/* SPC300 bundle {{{ * * Copyright (C) 2009 Spidcom * * <<>> * * }}} */ /** * \file devkit/plcd/src/status.c * \brief status refresh for PLC daemon * \ingroup plcd * * After starting the PLC firmware, some events occurs reflecting the * new status of AV stack. */ #include #include #include #include #include #include #include #include #include #include #include "libmme.h" #include "libspid.h" #include "plcd.h" char *assoc_table[] = { LIBSPID_HPAV_INFO_VALUE_STATUS_UNASSOCIATED, LIBSPID_HPAV_INFO_VALUE_STATUS_ASSOCIATED, LIBSPID_HPAV_INFO_VALUE_STATUS_AUTHENTICATED, NULL }; char *cco_table[] = { LIBSPID_HPAV_INFO_VALUE_CCO_STATION, LIBSPID_HPAV_INFO_VALUE_CCO_PROXY, LIBSPID_HPAV_INFO_VALUE_CCO_MAIN, NULL }; char *sl_table[] = { LIBSPID_HPAV_CONF_VALUE_SL_SC, LIBSPID_HPAV_CONF_VALUE_SL_HS, NULL }; char *boolean_table[] = { "no", "yes", }; static void binary_to_string (const unsigned char *binary, int binary_len, char *string) { int i; for(i = 0; i < binary_len; i++) { sprintf (string + i * 2, "%02x", binary[i]); } } int inform_manager (plcd_ctx_t *ctx) { assert (ctx != NULL); return 0; } int check_sc_start (plcd_ctx_t *ctx) { char buffer_sc_status[16], buffer_sc_button[16]; char buffer[1024]; unsigned char sc; assert (ctx != NULL); /* get SC button and SC status */ libspid_config_read_item (ctx->hpav_info_path, LIBSPID_HPAV_INFO_LABEL_SC_BUTTON, buffer_sc_button, sizeof(buffer_sc_button)); libspid_config_read_item (ctx->hpav_info_path, LIBSPID_HPAV_INFO_LABEL_SC, buffer_sc_status, sizeof(buffer_sc_status)); if(LIBSPID_GET_BOOLEAN (buffer_sc_button) && !LIBSPID_GET_BOOLEAN (buffer_sc_status)) { /* start SC process */ /* check authentication status to know which kind of SC to * send */ libspid_config_read_item (ctx->hpav_info_path, LIBSPID_HPAV_INFO_LABEL_STATUS, buffer, sizeof(buffer)); if(!strcmp (buffer, assoc_table[MME_DRV_STATUS_ASSOC_UNASSOCIATED])) { /* send SC_JOIN because we are unassociated */ sc = MME_DRV_SC_JOIN; } else { /* send SC_ADD because we are associated or authenticated */ sc = MME_DRV_SC_ADD; } if(hpav_send_single_value (ctx, MME_TYPE_DRV_STA_SC, &sc, 1) >= 0) { libspid_config_write_item (ctx->hpav_info_path, LIBSPID_HPAV_INFO_LABEL_SC, boolean_table [LIBSPID_TRUE]); syslog (LOG_INFO, "SC started"); } else { /* error */ syslog (LOG_WARNING, "failed to start SC (%s)", strerror (errno)); return -1; } } return 0; } int refresh_status (plcd_ctx_t *ctx, mme_ctx_t *status_ctx, int *is_save_conf_needed, int *is_info_manager_needed) { unsigned int len; unsigned char assoc_new, cco_new, cco_preferred_new, cco_backup_new, sc_new; //unsigned char assoc_current, cco_new_current, cco_preferred_current, cco_backup_current, sc_current, was_cco_current; char buffer[256]; assert (ctx != NULL); assert (status_ctx != NULL); assert ((MME_TYPE_DRV_STA_STATUS | MME_TYPE_IND) == status_ctx->mmtype); assert (is_save_conf_needed != NULL); assert (is_info_manager_needed != NULL); buffer[0] = '\0'; /* check new association status */ mme_pull (status_ctx, &assoc_new, sizeof(assoc_new), &len); libspid_config_read_item (ctx->hpav_info_path, LIBSPID_HPAV_INFO_LABEL_STATUS, buffer, sizeof(buffer)); if((assoc_new < MME_DRV_STATUS_ASSOC_NB) && strcmp (buffer, assoc_table[assoc_new])) { libspid_config_write_item (ctx->hpav_info_path, LIBSPID_HPAV_INFO_LABEL_STATUS, assoc_table [assoc_new]); *is_info_manager_needed = LIBSPID_TRUE; } /* set new cco status */ mme_pull (status_ctx, &cco_new, sizeof(cco_new), &len); libspid_config_read_item (ctx->hpav_info_path, LIBSPID_HPAV_INFO_LABEL_CCO, buffer, sizeof(buffer)); if((cco_new < MME_DRV_STATUS_CCO_NB) && strcmp (buffer, cco_table[cco_new])) { libspid_config_write_item (ctx->hpav_info_path, LIBSPID_HPAV_INFO_LABEL_CCO, cco_table [cco_new]); *is_info_manager_needed = LIBSPID_TRUE; /* check if WAS_CCO needs to be updated */ libspid_config_read_item (ctx->hpav_conf_path, LIBSPID_HPAV_CONF_LABEL_WAS_CCO, buffer, sizeof(buffer)); if((MME_DRV_STATUS_ASSOC_AUTHENTICATED == assoc_new) && (((MME_DRV_STATUS_CCO_MAIN == cco_new) && !LIBSPID_GET_BOOLEAN (buffer)) || ((cco_new != MME_DRV_STATUS_CCO_MAIN) && LIBSPID_GET_BOOLEAN (buffer)))) { /* WAS_CCO update needed */ libspid_config_write_item (ctx->hpav_conf_path, LIBSPID_HPAV_CONF_LABEL_WAS_CCO, MME_DRV_STATUS_CCO_MAIN == cco_new ? boolean_table[LIBSPID_TRUE] : boolean_table[LIBSPID_FALSE]); *is_save_conf_needed = LIBSPID_TRUE; } } /* check new cco preferred status with current one, and update then save it if they are different */ mme_pull (status_ctx, &cco_preferred_new, sizeof(cco_preferred_new), &len); libspid_config_read_item (ctx->hpav_conf_path, LIBSPID_HPAV_CONF_LABEL_CCO_PREFERRED, buffer, sizeof(buffer)); if((cco_preferred_new <= LIBSPID_TRUE) && (cco_preferred_new != LIBSPID_GET_BOOLEAN (buffer))) { libspid_config_write_item (ctx->hpav_conf_path, LIBSPID_HPAV_CONF_LABEL_CCO_PREFERRED, boolean_table[cco_preferred_new]); *is_save_conf_needed = LIBSPID_TRUE; } /* check cco backup status and update info file if changed */ mme_pull (status_ctx, &cco_backup_new, sizeof(cco_backup_new), &len); libspid_config_read_item (ctx->hpav_info_path, LIBSPID_HPAV_INFO_LABEL_BACKUP_CCO, buffer, sizeof(buffer)); if((cco_backup_new <= LIBSPID_TRUE) && (cco_backup_new != LIBSPID_GET_BOOLEAN (buffer))) { libspid_config_write_item (ctx->hpav_info_path, LIBSPID_HPAV_INFO_LABEL_BACKUP_CCO, boolean_table [cco_backup_new]); *is_info_manager_needed = LIBSPID_TRUE; } /* check if SC has changed from yes ---> no */ mme_pull (status_ctx, &sc_new, sizeof(sc_new), &len); libspid_config_read_item (ctx->hpav_info_path, LIBSPID_HPAV_INFO_LABEL_SC, buffer, sizeof(buffer)); if((sc_new <= LIBSPID_TRUE) && (sc_new != LIBSPID_GET_BOOLEAN (buffer))) { /* exit from SC state */ libspid_config_write_item (ctx->hpav_info_path, LIBSPID_HPAV_INFO_LABEL_SC, boolean_table [sc_new]); *is_info_manager_needed = LIBSPID_TRUE; } syslog (LOG_INFO, "new status: assoc=%d cco=%d cco_pref=%d cco_backup=%d sc=%d", assoc_new, cco_new, cco_preferred_new, cco_backup_new, sc_new); return 0; } int refresh_hfid (plcd_ctx_t *ctx, mme_ctx_t *hfid_ctx, int *is_save_conf_needed) { char buffer[256], hfid[HFID_LEN]; unsigned int len, is_avln = LIBSPID_FALSE; assert (ctx != NULL); assert (hfid_ctx != NULL); assert (((MME_TYPE_DRV_STA_SET_U_STA_HFID | MME_TYPE_IND) == hfid_ctx->mmtype) || ((MME_TYPE_DRV_STA_SET_AVLN_HFID | MME_TYPE_IND) == hfid_ctx->mmtype)); assert (is_save_conf_needed != NULL); is_avln = ((MME_TYPE_DRV_STA_SET_U_STA_HFID | MME_TYPE_IND) == hfid_ctx->mmtype); /* get the HFID value from MME */ mme_pull (hfid_ctx, hfid, HFID_LEN, &len); hfid[HFID_LEN - 1] = '\0'; /* compare to current config value */ libspid_config_read_item (ctx->hpav_conf_path, is_avln ? LIBSPID_HPAV_CONF_LABEL_AVLN_HFID : LIBSPID_HPAV_CONF_LABEL_USER_HFID, buffer, sizeof(buffer)); if(strncmp (hfid, buffer, HFID_LEN)) { libspid_config_write_item (ctx->hpav_conf_path, is_avln ? LIBSPID_HPAV_CONF_LABEL_AVLN_HFID : LIBSPID_HPAV_CONF_LABEL_USER_HFID, hfid); *is_save_conf_needed = LIBSPID_TRUE; } return 0; } int refresh_key (plcd_ctx_t *ctx, mme_ctx_t *key_ctx, int *is_save_conf_needed) { unsigned char nmk[16], nid[7], type, sl; char nmk_str[64], nid_str[32]; unsigned int len; assert (ctx != NULL); assert (key_ctx != NULL); assert ((MME_TYPE_DRV_STA_SET_KEY | MME_TYPE_IND) == key_ctx->mmtype); assert (is_save_conf_needed != NULL); /* get the new NMK set it to hpav.conf */ mme_pull (key_ctx, nmk, sizeof(nmk), &len); binary_to_string (nmk, sizeof(nmk), nmk_str); libspid_config_write_item (ctx->hpav_conf_path, LIBSPID_HPAV_CONF_LABEL_NMK, nmk_str); /* get the message type: NID or SL */ mme_pull (key_ctx, &type, 1, &len); if(type > 0x01) type = 0x01; /* get the NID */ mme_pull (key_ctx, nid, sizeof(nid), &len); /* get the SL */ mme_pull (key_ctx, &sl, sizeof(sl), &len); /* update config file according to given type */ if(MME_DRV_KEY_TYPE_NID == type) { /* NID change */ binary_to_string (nid, sizeof(nid), nid_str); libspid_config_write_item (ctx->hpav_conf_path, LIBSPID_HPAV_CONF_LABEL_NID, nid_str); } else { /* SL change */ libspid_config_write_item (ctx->hpav_conf_path, LIBSPID_HPAV_CONF_LABEL_SL, sl_table[type]); } *is_save_conf_needed = LIBSPID_TRUE; return 0; } int event_process (plcd_ctx_t *ctx) { struct msghdr msg; struct nlmsghdr *nlh; struct sockaddr_nl kernel_addr; struct iovec iov; MME_t *mme_hdr; fd_set readfds; struct timeval timeout; int result, msg_len; unsigned int result_len; mme_ctx_t mme_ctx; int is_save_conf_needed = LIBSPID_FALSE, is_info_manager_needed = LIBSPID_FALSE; unsigned char mme_buffer[ETH_DATA_LEN]; assert (ctx != NULL); FD_ZERO (&readfds); FD_SET (ctx->plc_sock, &readfds); timeout.tv_sec = EVENT_REFRESH_TIMEOUT_MS / 1000; timeout.tv_usec = (EVENT_REFRESH_TIMEOUT_MS % 1000) * 1000; result = select (ctx->plc_sock + 1, &readfds, NULL, NULL, &timeout); if(result < 0) { /* look for interrupt */ if(EINTR == errno) { /* process interrupt */ } else { syslog (LOG_WARNING, "select failure (errno=%d)", errno); return (-1); } } else if (result > 0) { if (FD_ISSET (ctx->plc_sock, &readfds)) { /* create message from PLC driver netlink */ nlh=(struct nlmsghdr *)malloc(NLMSG_SPACE(ETH_DATA_LEN)); memset(nlh, 0, NLMSG_SPACE(ETH_DATA_LEN)); memset(&kernel_addr, 0, sizeof(kernel_addr)); iov.iov_base = (void *)nlh; iov.iov_len = NLMSG_SPACE(ETH_DATA_LEN); msg.msg_name = (void *)&kernel_addr; msg.msg_namelen = sizeof(kernel_addr); msg.msg_iov = &iov; msg.msg_iovlen = 1; if((msg_len = recvmsg (ctx->plc_sock, &msg, 0)) < 0) { syslog (LOG_WARNING, "mme receive error (%d)", errno); free (nlh); return -1; } else if(msg_len > 0) { /* check MMTYPE */ mme_hdr = (MME_t *)NLMSG_DATA (nlh); mme_init (&mme_ctx, mme_hdr->mmtype, mme_buffer, ETH_DATA_LEN); mme_put (&mme_ctx, (unsigned char *)NLMSG_DATA (nlh) + sizeof(MME_t), ETH_DATA_LEN - sizeof(MME_t), &result_len); switch(mme_hdr->mmtype) { case (MME_TYPE_DRV_STA_STATUS | MME_TYPE_IND): /* check DRV_STA_STATUS content and process new values */ refresh_status (ctx, &mme_ctx, &is_save_conf_needed, &is_info_manager_needed); break; case (MME_TYPE_DRV_STA_SET_U_STA_HFID | MME_TYPE_IND): case (MME_TYPE_DRV_STA_SET_AVLN_HFID | MME_TYPE_IND): /* check DRV_STA_SET_*_HFID content and process new values */ refresh_hfid (ctx, &mme_ctx, &is_save_conf_needed); break; case (MME_TYPE_DRV_STA_SET_KEY | MME_TYPE_IND): /* process set key update */ refresh_key (ctx, &mme_ctx, &is_save_conf_needed); break; default: syslog (LOG_WARNING, "unexpected DRV MME received (%04x)", mme_hdr->mmtype); free (nlh); return -1; } } free (nlh); } } else { /* timeout */ /* check if we need to start SC process */ check_sc_start (ctx); } /*check if hpav.conf save is needed */ if(is_save_conf_needed) { libspid_system_save_file (ctx->hpav_conf_path); } /* check if manager daemon needs to be informed */ if(is_info_manager_needed) { inform_manager (ctx); } return 0; }