// callback function - called for each name/value pair by ini parsing library static int openavbTLCfgCallback(void *user, const char *tlSection, const char *name, const char *value) { AVB_TRACE_ENTRY(AVB_TRACE_TL); parse_ini_data_t *pParseIniData = (parse_ini_data_t *)user; openavb_tl_cfg_t *pCfg = pParseIniData->pCfg; openavb_tl_cfg_name_value_t *pNVCfg = pParseIniData->pNVCfg; tl_state_t *pTLState = pParseIniData->pTLState; AVB_LOGF_DEBUG("name=[%s] value=[%s]", name, value); bool valOK = FALSE; char *pEnd; int i; if (MATCH(name, "role")) { if (MATCH(value, "talker")) { pCfg->role = AVB_ROLE_TALKER; valOK = TRUE; } else if (MATCH(value, "listener")) { pCfg->role = AVB_ROLE_LISTENER; valOK = TRUE; } } else if (MATCH(name, "dest_addr")) { valOK = parse_mac(value, &pCfg->dest_addr); } else if (MATCH(name, "stream_addr")) { valOK = parse_mac(value, &pCfg->stream_addr); } else if (MATCH(name, "stream_uid")) { errno = 0; pCfg->stream_uid = strtol(value, &pEnd, 10); if (*pEnd == '\0' && errno == 0 && pCfg->stream_uid <= UINT16_MAX) valOK = TRUE; } else if (MATCH(name, "max_interval_frames")) { errno = 0; pCfg->max_interval_frames = strtol(value, &pEnd, 10); if (*pEnd == '\0' && errno == 0 && pCfg->max_interval_frames <= UINT16_MAX) valOK = TRUE; } else if (MATCH(name, "max_frame_size")) { errno = 0; pCfg->max_frame_size = strtol(value, &pEnd, 10); if (*pEnd == '\0' && errno == 0 && pCfg->max_interval_frames <= UINT16_MAX) valOK = TRUE; } else if (MATCH(name, "sr_class")) { if (strlen(value) == 1) { if (tolower(value[0]) == 'a') { pCfg->sr_class = SR_CLASS_A; valOK = TRUE; } else if (tolower(value[0]) == 'b') { pCfg->sr_class = SR_CLASS_B; valOK = TRUE; } } } else if (MATCH(name, "sr_rank")) { if (strlen(value) == 1) { if (value[0] == '1') { pCfg->sr_rank = SR_RANK_REGULAR; valOK = TRUE; } else if (value[0] == '0') { pCfg->sr_rank = SR_RANK_EMERGENCY; valOK = TRUE; } } } else if (MATCH(name, "max_transit_usec")) { errno = 0; pCfg->max_transit_usec = strtol(value, &pEnd, 10); if (*pEnd == '\0' && errno == 0 && pCfg->max_transit_usec <= UINT32_MAX) valOK = TRUE; } else if (MATCH(name, "max_transmit_deficit_usec")) { errno = 0; pCfg->max_transmit_deficit_usec = strtol(value, &pEnd, 10); if (*pEnd == '\0' && errno == 0 && pCfg->max_transmit_deficit_usec <= UINT32_MAX) valOK = TRUE; } else if (MATCH(name, "internal_latency")) { errno = 0; pCfg->internal_latency = strtol(value, &pEnd, 10); if (*pEnd == '\0' && errno == 0 && pCfg->internal_latency <= UINT32_MAX) valOK = TRUE; } else if (MATCH(name, "batch_factor")) { errno = 0; pCfg->batch_factor = strtol(value, &pEnd, 10); if (*pEnd == '\0' && errno == 0 && pCfg->batch_factor > 0 && pCfg->batch_factor <= INT32_MAX) valOK = TRUE; } else if (MATCH(name, "max_stale")) { errno = 0; pCfg->max_stale = strtol(value, &pEnd, 10); if (*pEnd == '\0' && errno == 0 && pCfg->max_stale >= 0 && pCfg->max_stale <= INT32_MAX) valOK = TRUE; } else if (MATCH(name, "raw_tx_buffers")) { errno = 0; pCfg->raw_tx_buffers = strtol(value, &pEnd, 10); if (*pEnd == '\0' && errno == 0 && pCfg->raw_tx_buffers <= UINT32_MAX) valOK = TRUE; } else if (MATCH(name, "raw_rx_buffers")) { errno = 0; pCfg->raw_rx_buffers = strtol(value, &pEnd, 10); if (*pEnd == '\0' && errno == 0 && pCfg->raw_rx_buffers <= UINT32_MAX) valOK = TRUE; } else if (MATCH(name, "report_seconds")) { errno = 0; pCfg->report_seconds = strtol(value, &pEnd, 10); if (*pEnd == '\0' && errno == 0 && (int)pCfg->report_seconds >= 0 && pCfg->report_seconds <= INT32_MAX) valOK = TRUE; } else if (MATCH(name, "start_paused")) { // ignore this item - tl_host doesn't use it because // it pauses before reading any of its streams. errno = 0; long tmp; tmp = strtol(value, &pEnd, 10); if (*pEnd == '\0' && errno == 0 && tmp >= 0 && tmp <= 1) { pCfg->start_paused = (tmp == 1); valOK = TRUE; } } else if (MATCH(name, "ifname")) { if_info_t ifinfo; if (openavbCheckInterface(value, &ifinfo)) { strncpy(pCfg->ifname, value, IFNAMSIZ - 1); valOK = TRUE; } } else if (MATCH(name, "vlan_id")) { errno = 0; long tmp; tmp = strtol(value, &pEnd, 0); // vlanID is 12 bit field if (*pEnd == '\0' && errno == 0 && tmp >= 0x0 && tmp <= 0xFFF) { pCfg->vlan_id = tmp; valOK = TRUE; } } else if (MATCH(name, "map_lib")) { if (pTLState->mapLib.libName) free(pTLState->mapLib.libName); pTLState->mapLib.libName = strdup(value); valOK = TRUE; } else if (MATCH(name, "map_fn")) { if (pTLState->mapLib.funcName) free(pTLState->mapLib.funcName); pTLState->mapLib.funcName = strdup(value); valOK = TRUE; } else if (MATCH(name, "intf_lib")) { if (pTLState->intfLib.libName) free(pTLState->intfLib.libName); pTLState->intfLib.libName = strdup(value); valOK = TRUE; } else if (MATCH(name, "intf_fn")) { if (pTLState->intfLib.funcName) free(pTLState->intfLib.funcName); pTLState->intfLib.funcName = strdup(value); valOK = TRUE; } else if (MATCH_LEFT(name, "intf_nv_", 8) || MATCH_LEFT(name, "map_nv_", 7)) { // Need to save the interface and mapping module configuration // until later (after those libraries are loaded.) // check if this setting replaces an earlier one for (i = 0; i < pNVCfg->nLibCfgItems; i++) { if (MATCH(name, pNVCfg->libCfgNames[i])) { if (pNVCfg->libCfgValues[i]) free(pNVCfg->libCfgValues[i]); pNVCfg->libCfgValues[i] = strdup(value); valOK = TRUE; } } if (i >= pNVCfg->nLibCfgItems) { // is a new name/value if (i >= MAX_LIB_CFG_ITEMS) { AVB_LOG_ERROR("Too many INI settings for interface/mapping modules"); } else { pNVCfg->libCfgNames[i] = strdup(name); pNVCfg->libCfgValues[i] = strdup(value); pNVCfg->nLibCfgItems++; valOK = TRUE; } } } else { // unmatched item, fail AVB_LOGF_ERROR("Unrecognized configuration item: name=%s", name); return 0; } if (!valOK) { // bad value AVB_LOGF_ERROR("Invalid value: name=%s, value=%s", name, value); return 0; } AVB_TRACE_EXIT(AVB_TRACE_TL); return 1; // OK }
EXTERN_DLL_EXPORT bool openavbTLConfigure(tl_handle_t handle, openavb_tl_cfg_t *pCfgIn, openavb_tl_cfg_name_value_t *pNVCfg) { AVB_TRACE_ENTRY(AVB_TRACE_TL); tl_state_t *pTLState = (tl_state_t *)handle; if (!pTLState) { AVB_LOG_ERROR("Invalid handle."); AVB_TRACE_EXIT(AVB_TRACE_TL); return FALSE; } // Create the mediaQ pTLState->pMediaQ = openavbMediaQCreate(); if (!pTLState->pMediaQ) { AVB_LOG_ERROR("Unable to create media queue"); AVB_TRACE_EXIT(AVB_TRACE_TL); return FALSE; } // CORE_TODO: It's not safe to simply copy the openavb_tl_cfg_t since there are embedded pointers in the cfg_mac_t member. // Those pointers need to be updated after a copy. Longer term the cfg_mac_t should be changed to not contain the mac // member to remedy this issue and avoid further bugs. memcpy(&pTLState->cfg, pCfgIn, sizeof(openavb_tl_cfg_t)); pTLState->cfg.dest_addr.mac = &pTLState->cfg.dest_addr.buffer; pTLState->cfg.stream_addr.mac = &pTLState->cfg.stream_addr.buffer; openavb_tl_cfg_t *pCfg = &pTLState->cfg; if (!((pCfg->role == AVB_ROLE_TALKER) || (pCfg->role == AVB_ROLE_LISTENER))) { AVB_LOG_ERROR("Talker - Listener Config Error: invalid role"); return FALSE; } if ((pCfg->role == AVB_ROLE_TALKER) && (pCfg->max_interval_frames == 0)) { AVB_LOG_ERROR("Talker - Listener Config Error: talker role requires 'max_interval_frames'"); return FALSE; } openavbMediaQSetMaxStaleTail(pTLState->pMediaQ, pCfg->max_stale); if (!openavbTLOpenLinkLibsOsal(pTLState)) { AVB_LOG_ERROR("Failed to open mapping / interface library"); return FALSE; } if (pCfg->pMapInitFn && pCfg->pMapInitFn(pTLState->pMediaQ, &pCfg->map_cb, pCfg->max_transit_usec)) { checkMapCallbacks(&pTLState->cfg); } else { AVB_LOG_ERROR("Mapping initialize function error."); return FALSE; } if (pCfg->pIntfInitFn && pCfg->pIntfInitFn(pTLState->pMediaQ, &pCfg->intf_cb)) { checkIntfCallbacks(&pTLState->cfg); } else { AVB_LOG_ERROR("Interface initialize function error."); return FALSE; } // Submit configuration values to mapping and interface modules int i; for (i = 0; i < pNVCfg->nLibCfgItems; i++) { if (MATCH_LEFT(pNVCfg->libCfgNames[i], "intf_nv_", 8)) { if (pCfg->intf_cb.intf_cfg_cb) { pCfg->intf_cb.intf_cfg_cb(pTLState->pMediaQ, pNVCfg->libCfgNames[i], pNVCfg->libCfgValues[i]); } else { AVB_LOGF_ERROR("No interface module cfg function; ignoring %s", pNVCfg->libCfgNames[i]); } } else if (MATCH_LEFT(pNVCfg->libCfgNames[i], "map_nv_", 7)) { if (pCfg->map_cb.map_cfg_cb) { pCfg->map_cb.map_cfg_cb(pTLState->pMediaQ, pNVCfg->libCfgNames[i], pNVCfg->libCfgValues[i]); } else { AVB_LOGF_ERROR("No mapping module cfg function; ignoring %s", pNVCfg->libCfgNames[i]); } } else { assert(0); } } // for loop ends pTLState->cfg.map_cb.map_gen_init_cb(pTLState->pMediaQ); pTLState->cfg.intf_cb.intf_gen_init_cb(pTLState->pMediaQ); return TRUE; }