void coap_createCoapRequest(void * context, coap_method_t method, const char * uri, ContentType contentType, const char * payload, int payloadLen, TransactionCallback callback) { coap_packet_t request; uip_ipaddr_t * remote_ipaddr = coap_getIpFromURI(uri); int remote_port = coap_getPortFromURI(uri); coap_transaction_t *transaction; char path[128] = {0}; char query[128] = {0}; coap_getPathQueryFromURI(uri, path, query); Lwm2m_Debug("Coap request: %s\n", uri); Lwm2m_Debug("Coap IPv6 request address: " PRINT6ADDR(remote_ipaddr)); Lwm2m_Debug("Coap request port: %d\n", remote_port); Lwm2m_Debug("Coap request path: %s\n", path); Lwm2m_Debug("Coap request query: %s\n", query); coap_init_message(&request, COAP_TYPE_CON, method, coap_get_mid()); coap_set_header_uri_path(&request, path); coap_set_header_uri_query(&request, query); if (contentType != ContentType_None) { coap_set_header_content_format(&request, contentType); coap_set_payload(&request, payload, payloadLen); } if (CurrentTransaction[CurrentTransactionIndex].TransactionUsed && CurrentTransaction[CurrentTransactionIndex].TransactionPtr) { Lwm2m_Warning("Canceled previous transaction [%d]: %p\n", CurrentTransactionIndex, CurrentTransaction[CurrentTransactionIndex].TransactionPtr); coap_clear_transaction(CurrentTransaction[CurrentTransactionIndex].TransactionPtr); } if ((transaction = coap_new_transaction(request.mid, remote_ipaddr, uip_htons(remote_port)))) { transaction->callback = coap_CoapRequestCallback; CurrentTransaction[CurrentTransactionIndex].Callback = callback; CurrentTransaction[CurrentTransactionIndex].Context = context; CurrentTransaction[CurrentTransactionIndex].TransactionUsed = true; CurrentTransaction[CurrentTransactionIndex].TransactionPtr = transaction; memcpy(&CurrentTransaction[CurrentTransactionIndex].Address.Addr, remote_ipaddr, sizeof(uip_ipaddr_t)); CurrentTransaction[CurrentTransactionIndex].Address.Port = uip_htons(remote_port); transaction->callback_data = &CurrentTransaction[CurrentTransactionIndex]; transaction->packet_len = coap_serialize_message(&request, transaction->packet); Lwm2m_Debug("Sending transaction [%d]: %p\n", CurrentTransactionIndex, CurrentTransaction[CurrentTransactionIndex].TransactionPtr); coap_send_transaction(transaction); CurrentTransactionIndex++; if(CurrentTransactionIndex >= MAX_COAP_TRANSACTIONS) { CurrentTransactionIndex = 0; } } }
int Lwm2mCore_GetIPAddressFromInterface(const char * interface, int addressFamily, char * destAddress, size_t destAddressLength) { int returnCode = 0; if (addressFamily != AF_INET && addressFamily != AF_INET6) { Lwm2m_Error("Unsupported address family: %d. Only AF_INET and AF_INET6 are supported.\n", addressFamily); returnCode = 1; goto error; } struct ifaddrs *interfaceAddresses, *interfaceAddress; char host[NI_MAXHOST]; if (getifaddrs(&interfaceAddresses) == -1) { perror("getifaddrs"); returnCode = 1; goto error; } char linkLocalIpv6Address[NI_MAXHOST] = { 0 }; char globalIpv6Address[NI_MAXHOST] = { 0 }; bool found = false; int index = 0; for (interfaceAddress = interfaceAddresses; interfaceAddress != NULL; interfaceAddress = interfaceAddress->ifa_next) { if (interfaceAddress->ifa_addr == NULL) { continue; } if ((strcmp(interfaceAddress->ifa_name, interface)==0)&&(interfaceAddress->ifa_addr->sa_family==addressFamily)) { int socketAddressLength = 0; switch(addressFamily) { case AF_INET: socketAddressLength = sizeof(struct sockaddr_in); break; default: socketAddressLength = sizeof(struct sockaddr_in6); break; } returnCode = getnameinfo(interfaceAddress->ifa_addr, socketAddressLength, host, sizeof(host), NULL, 0, NI_NUMERICHOST); if (returnCode != 0) { Lwm2m_Error("getnameinfo() failed: %s\n", gai_strerror(returnCode)); goto error_free; } size_t addressLength = strlen(host); if (destAddressLength < addressLength) { Lwm2m_Error("Error: Address is longer than %zu characters\n", destAddressLength); goto error_free; } switch(addressFamily) { case AF_INET: strcpy(destAddress, host); found = true; break; default: if (strncmp(host, "fe80", 4) == 0) { Lwm2m_Debug("Address %d: %s (local)\n", index, host); strcpy(linkLocalIpv6Address, host); } else { Lwm2m_Debug("Address %d: %s (global)\n", index, host); strcpy(globalIpv6Address, host); } break; } index++; } } if (addressFamily == AF_INET6) { if (strlen(globalIpv6Address) > 0) { Lwm2m_Debug("Global IPv6 address found for interface %s: %s\n", interface, globalIpv6Address); strcpy(destAddress, globalIpv6Address); found = true; } else if (strlen(linkLocalIpv6Address) > 0) { Lwm2m_Warning("No global IPv6 address found for interface %s: using local: %s\n", interface, linkLocalIpv6Address); strcpy(destAddress, linkLocalIpv6Address); found = true; } } if (!found) { Lwm2m_Error("Could not find an %s IP address for interface %s\n", addressFamily == AF_INET? "IPv4" : "IPv6", interface); returnCode = 1; } error_free: freeifaddrs(interfaceAddresses); error: return returnCode; }
/* The LWM2M Client MUST follow the procedure specified as below when attempting to bootstrap a LWM2M Device: * 1. If the LWM2M Device has Smartcard, the LWM2M Client tries to obtain Bootstrap Information * from the Smartcard using the Bootstrap from Smartcard mode. * 2. If the LWM2M Client is not configured using the Bootstrap from Smartcard mode, the LWM2M * Client tries to obtain the Bootstrap Information by using Factory Bootstrap mode. * 3. If the LWM2M Client has any LWM2M Server Object Instances from the previous steps, the LWM2M * Client tries to register to the LWM2M Server(s) configured in the LWM2M Server Object Instance(s). * 4. If LWM2M Client fails to register to all the LWM2M Servers or the Client doesn’t have any * LWM2M Server Object Instances, and the LWM2M Client hasn’t received a Server Initiated Bootstrap * within the ClientHoldOffTime, the LWM2M Client performs the Client Initiated Bootstrap. */ void Lwm2m_UpdateBootStrapState(Lwm2mContextType * context) { uint32_t now = Lwm2mCore_GetTickCountMs(); uint32_t clientHoldOff; enum { SERVER_BOOTSTRAP = 0 }; switch (Lwm2mCore_GetBootstrapState(context)) { case Lwm2mBootStrapState_NotBootStrapped: // First attempt smart card bootstrap. if (BootStrapFromSmartCard(context)) { Lwm2mCore_SetBootstrapState(context, Lwm2mBootStrapState_BootStrapped); } // If that fails try and use the factory information. else if (BootStrapFromFactory(context)) { Lwm2mCore_SetBootstrapState(context, Lwm2mBootStrapState_BootStrapped); } // If that fails wait for the client hold off time, for a server initiated bootstrap. else { Lwm2m_Info("Try existing server entries\n"); Lwm2mCore_SetBootstrapState(context, Lwm2mBootStrapState_CheckExisting); } Lwm2mCore_UpdateAllServers(context, Lwm2mRegistrationState_Register); Lwm2mCore_SetLastBootStrapUpdate(context, now); break; case Lwm2mBootStrapState_CheckExisting: // Pass control to Registration process, if this fails then we will // drop into the ClientHoldOff State break; case Lwm2mBootStrapState_ClientHoldOff: // Wait for server initiated bootstrap. // Only one bootstrap server is supported. // If the hold off timer has expired, then request a boot strap. Lwm2m_GetClientHoldOff(context, SERVER_BOOTSTRAP, &clientHoldOff); if (now - Lwm2mCore_GetLastBootStrapUpdate(context) >= (clientHoldOff * 1000)) { Lwm2m_Info("Hold Off expired - attempt client-initiated bootstrap\n"); Lwm2mCore_SetBootstrapState(context, Lwm2mBootStrapState_BootStrapPending); SendBootStrapRequest(context, SERVER_BOOTSTRAP); Lwm2mCore_SetLastBootStrapUpdate(context, now); } break; case Lwm2mBootStrapState_BootStrapPending: if (now - Lwm2mCore_GetLastBootStrapUpdate(context) >= BOOTSTRAP_TIMEOUT) { Lwm2m_Error("No response to client initiated bootstrap\n"); Lwm2mCore_SetBootstrapState(context, Lwm2mBootStrapState_BootStrapFailed); Lwm2mCore_SetLastBootStrapUpdate(context, now); } break; case Lwm2mBootStrapState_BootStrapFinishPending: // The 2015/07/07 LWM2M draft requires that the server sends a bootstrap finished to the clients /bs endpoint, // however for now lets just wait up to 15 seconds and then move to BootStrapped state. if (now - Lwm2mCore_GetLastBootStrapUpdate(context) >= BOOTSTRAP_FINISHED_TIMEOUT) { Lwm2m_Warning("No bootstrap finished after 15 seconds, retrying...\n"); Lwm2mCore_SetBootstrapState(context, Lwm2mBootStrapState_BootStrapFailed); } break; case Lwm2mBootStrapState_BootStrapped: break; case Lwm2mBootStrapState_BootStrapFailed: // If the hold off timer has expired, then request a boot strap. Lwm2m_GetClientHoldOff(context, SERVER_BOOTSTRAP, &clientHoldOff); if (now - Lwm2mCore_GetLastBootStrapUpdate(context) >= (clientHoldOff * 1000)) { Lwm2m_Warning("HoldOff Expired - Re-attempt bootstrap\n"); Lwm2mCore_SetBootstrapState(context, Lwm2mBootStrapState_NotBootStrapped); } break; default: Lwm2m_Error("Unhandled bootstrap state %d\n", Lwm2mCore_GetBootstrapState(context)); } }
void coap_createCoapRequest(coap_method_t method, const char * uri, ContentType contentType, ObserveState observeState, const char * payload, int payloadLen, TransactionCallback callback, void * context) { coap_packet_t request; char path[MAX_COAP_PATH] = { 0 }; char query[128] = { 0 }; coap_transaction_t *transaction; NetworkAddress * remoteAddress = NetworkAddress_New(uri, strlen(uri)); coap_getPathQueryFromURI(uri, path, query); Lwm2m_Info("Coap request: %s\n", uri); //Lwm2m_Debug("Coap request path: %s\n", path); //Lwm2m_Debug("Coap request query: %s\n", query); coap_init_message(&request, COAP_TYPE_CON, method, coap_get_mid()); coap_set_header_uri_path(&request, path); if (strlen(query) > 0) coap_set_header_uri_query(&request, query); // TODO - REVIEW: Erbium must copy path/query from request - else mem out of scope if (contentType != ContentType_None) { if ((method == COAP_POST) || (method == COAP_PUT)) { coap_set_header_content_format(&request, contentType); coap_set_payload(&request, payload, payloadLen); } else { coap_set_header_accept(&request, contentType); } } if (method == COAP_GET) { if (observeState == ObserveState_Establish) { coap_set_header_observe(&request, 0); int token = addObserve(remoteAddress, path, callback, context); if (token != 0) coap_set_token(&request, (const uint8_t *) &token, sizeof(token)); } else if (observeState == ObserveState_Cancel) { coap_set_header_observe(&request, 1); int token = removeObserve(remoteAddress, path); if (token != 0) coap_set_token(&request, (const uint8_t *) &token, sizeof(token)); } } if (CurrentTransaction[CurrentTransactionIndex].TransactionUsed && CurrentTransaction[CurrentTransactionIndex].TransactionPtr) { Lwm2m_Warning("Canceled previous transaction [%d]: %p\n", CurrentTransactionIndex, CurrentTransaction[CurrentTransactionIndex].TransactionPtr); coap_clear_transaction(&CurrentTransaction[CurrentTransactionIndex].TransactionPtr); } //if ((transaction = coap_new_transaction(request.mid, remote_ipaddr, uip_htons(remote_port)))) if ((transaction = coap_new_transaction(networkSocket, request.mid, remoteAddress))) { transaction->callback = coap_CoapRequestCallback; memcpy(CurrentTransaction[CurrentTransactionIndex].Path, path, MAX_COAP_PATH); CurrentTransaction[CurrentTransactionIndex].Callback = callback; CurrentTransaction[CurrentTransactionIndex].Context = context; CurrentTransaction[CurrentTransactionIndex].TransactionUsed = true; CurrentTransaction[CurrentTransactionIndex].TransactionPtr = transaction; NetworkAddress_SetAddressType(remoteAddress, &CurrentTransaction[CurrentTransactionIndex].Address); transaction->callback_data = &CurrentTransaction[CurrentTransactionIndex]; transaction->packet_len = coap_serialize_message(&request, transaction->packet); Lwm2m_Debug("Sending transaction [%d]: %p\n", CurrentTransactionIndex, CurrentTransaction[CurrentTransactionIndex].TransactionPtr); coap_send_transaction(transaction); CurrentTransactionIndex++; if (CurrentTransactionIndex >= MAX_COAP_TRANSACTIONS) { CurrentTransactionIndex = 0; } } }