/** * This is called as sendMessage() by the switch. * There is only one switch interface which sends all traffic. * message is aligned on the beginning of the switch header. */ static uint8_t incomingFromSwitch(struct Message* message, struct Interface* switchIf) { struct Ducttape* context = switchIf->senderContext; struct Headers_SwitchHeader* switchHeader = (struct Headers_SwitchHeader*) message->bytes; Message_shift(message, -Headers_SwitchHeader_SIZE); // The label comes in reversed from the switch because the switch doesn't know that we aren't // another switch ready to parse more bits, bit reversing the label yields the source address. switchHeader->label_be = Bits_bitReverse64(switchHeader->label_be); if (Headers_getMessageType(switchHeader) == Headers_SwitchHeader_TYPE_CONTROL) { uint8_t labelStr[20]; uint64_t label = Endian_bigEndianToHost64(switchHeader->label_be); AddrTools_printPath(labelStr, label); if (message->length < Control_HEADER_SIZE) { Log_info1(context->logger, "dropped runt ctrl packet from [%s]", labelStr); return Error_NONE; } else { Log_debug1(context->logger, "ctrl packet from [%s]", labelStr); } struct Control* ctrl = (struct Control*) message->bytes; bool pong = false; if (ctrl->type_be == Control_ERROR_be) { if (message->length < Control_Error_MIN_SIZE) { Log_info1(context->logger, "dropped runt error packet from [%s]", labelStr); return Error_NONE; } Log_info2(context->logger, "error packet from [%s], error type [%d]", labelStr, Endian_bigEndianToHost32(ctrl->content.error.errorType_be)); RouterModule_brokenPath(Endian_bigEndianToHost64(switchHeader->label_be), context->routerModule); uint8_t causeType = Headers_getMessageType(&ctrl->content.error.cause); if (causeType == Headers_SwitchHeader_TYPE_CONTROL) { if (message->length < Control_Error_MIN_SIZE + Control_HEADER_SIZE) { Log_info1(context->logger, "error packet from [%s] containing runt cause packet", labelStr); return Error_NONE; } struct Control* causeCtrl = (struct Control*) &(&ctrl->content.error.cause)[1]; if (causeCtrl->type_be != Control_PING_be) { Log_info3(context->logger, "error packet from [%s] caused by [%s] packet ([%d])", labelStr, Control_typeString(causeCtrl->type_be), Endian_bigEndianToHost16(causeCtrl->type_be)); } else { Log_debug2(context->logger, "error packet from [%s] in response to ping, length: [%d].", labelStr, message->length); // errors resulting from pings are forwarded back to the pinger. pong = true; } } else if (causeType != Headers_SwitchHeader_TYPE_DATA) { Log_info1(context->logger, "error packet from [%s] containing cause of unknown type [%d]", labelStr); } } else if (ctrl->type_be == Control_PONG_be) { pong = true; } else if (ctrl->type_be == Control_PING_be) { ctrl->type_be = Control_PONG_be; Message_shift(message, Headers_SwitchHeader_SIZE); switchIf->receiveMessage(message, switchIf); } else { Log_info2(context->logger, "control packet of unknown type from [%s], type [%d]", labelStr, Endian_bigEndianToHost16(ctrl->type_be)); } if (pong) { // Shift back over the header Message_shift(message, Headers_SwitchHeader_SIZE); context->switchPingerIf->receiveMessage(message, context->switchPingerIf); } return Error_NONE; } uint8_t* herKey = extractPublicKey(message, switchHeader->label_be, context->logger); int herAddrIndex; if (herKey) { uint8_t herAddrStore[16]; AddressCalc_addressForPublicKey(herAddrStore, herKey); if (herAddrStore[0] != 0xFC) { Log_debug(context->logger, "Got message from peer whose address is not in fc00::/8 range.\n"); return 0; } herAddrIndex = AddressMapper_put(switchHeader->label_be, herAddrStore, &context->addrMap); } else { herAddrIndex = AddressMapper_indexOf(switchHeader->label_be, &context->addrMap); if (herAddrIndex == -1) { uint64_t label = Endian_bigEndianToHost64(switchHeader->label_be); struct Node* n = RouterModule_getNode(label, context->routerModule); if (n) { herAddrIndex = AddressMapper_put(switchHeader->label_be, n->address.ip6.bytes, &context->addrMap); } else { #ifdef Log_DEBUG uint8_t switchAddr[20]; AddrTools_printPath(switchAddr, Endian_bigEndianToHost64(switchHeader->label_be)); Log_debug1(context->logger, "Dropped traffic packet from unknown node. (%s)\n", &switchAddr); #endif return 0; } } } // If the source address is the same as the router address, no third layer of crypto. context->routerAddress = context->addrMap.entries[herAddrIndex].address; // This is needed so that the priority and other information // from the switch header can be passed on properly. context->switchHeader = switchHeader; context->session = SessionManager_getSession(context->routerAddress, herKey, context->sm); // This goes to incomingFromCryptoAuth() // then incomingFromRouter() then core() context->layer = OUTER_LAYER; context->session->receiveMessage(message, context->session); return 0; }
/********************************************************************* * @fn Data_Service_WriteAttrCB * * @brief Validate attribute data prior to a write operation * * @param connHandle - connection message was received on * @param pAttr - pointer to attribute * @param pValue - pointer to data to be written * @param len - length of data * @param offset - offset of the first octet to be written * @param method - type of write message * * @return SUCCESS, blePending or Failure */ static bStatus_t Data_Service_WriteAttrCB( uint16_t connHandle, gattAttribute_t *pAttr, uint8_t *pValue, uint16_t len, uint16_t offset, uint8_t method ) { bStatus_t status = SUCCESS; uint8_t paramID = 0xFF; uint8_t changeParamID = 0xFF; uint16_t writeLenMin; uint16_t writeLenMax; uint16_t *pValueLenVar; // See if request is regarding a Client Characterisic Configuration if (ATT_BT_UUID_SIZE == pAttr->type.len && GATT_CLIENT_CHAR_CFG_UUID == *(uint16_t *)pAttr->type.uuid) { Log_info3("WriteAttrCB (CCCD): param: %d connHandle: %d %s", (IArg)Data_Service_findCharParamId(pAttr), (IArg)connHandle, (IArg)(method == GATT_LOCAL_WRITE?"- restoring bonded state":"- OTA write")); // Allow notification and indication, but do not check if really allowed per CCCD. status = GATTServApp_ProcessCCCWriteReq( connHandle, pAttr, pValue, len, offset, GATT_CLIENT_CFG_NOTIFY | GATT_CLIENT_CFG_INDICATE ); if (SUCCESS == status && pAppCBs && pAppCBs->pfnCfgChangeCb) pAppCBs->pfnCfgChangeCb( connHandle, DATA_SERVICE_SERV_UUID, Data_Service_findCharParamId(pAttr), pValue, len ); return status; } // Find settings for the characteristic to be written. paramID = Data_Service_findCharParamId( pAttr ); switch ( paramID ) { case DS_STRING_ID: writeLenMin = DS_STRING_LEN_MIN; writeLenMax = DS_STRING_LEN; pValueLenVar = &ds_StringValLen; Log_info5("WriteAttrCB : %s connHandle(%d) len(%d) offset(%d) method(0x%02x)", (IArg)"String", (IArg)connHandle, (IArg)len, (IArg)offset, (IArg)method); /* Other considerations for String can be inserted here */ break; case DS_STREAM_ID: writeLenMin = DS_STREAM_LEN_MIN; writeLenMax = DS_STREAM_LEN; pValueLenVar = &ds_StreamValLen; Log_info5("WriteAttrCB : %s connHandle(%d) len(%d) offset(%d) method(0x%02x)", (IArg)"Stream", (IArg)connHandle, (IArg)len, (IArg)offset, (IArg)method); /* Other considerations for Stream can be inserted here */ break; default: Log_error0("Attribute was not found."); return ATT_ERR_ATTR_NOT_FOUND; } // Check whether the length is within bounds. if ( offset >= writeLenMax ) { Log_error0("An invalid offset was requested."); status = ATT_ERR_INVALID_OFFSET; } else if ( offset + len > writeLenMax ) { Log_error0("Invalid value length was received."); status = ATT_ERR_INVALID_VALUE_SIZE; } else if ( offset + len < writeLenMin && ( method == ATT_EXECUTE_WRITE_REQ || method == ATT_WRITE_REQ ) ) { // Refuse writes that are lower than minimum. // Note: Cannot determine if a Reliable Write (to several chars) is finished, so those will // only be refused if this attribute is the last in the queue (method is execute). // Otherwise, reliable writes are accepted and parsed piecemeal. Log_error0("Invalid value length was received."); status = ATT_ERR_INVALID_VALUE_SIZE; } else { // Copy pValue into the variable we point to from the attribute table. memcpy(pAttr->pValue + offset, pValue, len); // Only notify application and update length if enough data is written. // // Note: If reliable writes are used (meaning several attributes are written to using ATT PrepareWrite), // the application will get a callback for every write with an offset + len larger than _LEN_MIN. // Note: For Long Writes (ATT Prepare + Execute towards only one attribute) only one callback will be issued, // because the write fragments are concatenated before being sent here. if ( offset + len >= writeLenMin ) { changeParamID = paramID; *pValueLenVar = offset + len; // Update data length. } } // Let the application know something changed (if it did) by using the // callback it registered earlier (if it did). if (changeParamID != 0xFF) if ( pAppCBs && pAppCBs->pfnChangeCb ) pAppCBs->pfnChangeCb( connHandle, DATA_SERVICE_SERV_UUID, paramID, pValue, len+offset ); // Call app function from stack task context. return status; }