Skip to content

Commit

Permalink
WIP: mgmt: hawkbit: allow different tenants
Browse files Browse the repository at this point in the history
allow the use of other tenants.

Signed-off-by: Fin Maaß <[email protected]>
  • Loading branch information
maass-hamburg committed Apr 22, 2024
1 parent d647197 commit 2a5891a
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 130 deletions.
2 changes: 0 additions & 2 deletions include/zephyr/mgmt/hawkbit.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@
#ifndef ZEPHYR_INCLUDE_MGMT_HAWKBIT_H_
#define ZEPHYR_INCLUDE_MGMT_HAWKBIT_H_

#define HAWKBIT_JSON_URL "/default/controller/v1"

/**
* @brief Response message from hawkBit.
*
Expand Down
6 changes: 6 additions & 0 deletions subsys/mgmt/hawkbit/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ config HAWKBIT_SHELL
help
Activate shell module that provides hawkBit commands.

config HAWKBIT_TENANT
string "Tenant name for the hawkbit server"
default "default"
help
Configure the tenant name for the hawkbit server.

config HAWKBIT_SERVER
string "User address for the hawkbit server"
default ""
Expand Down
190 changes: 62 additions & 128 deletions subsys/mgmt/hawkbit/hawkbit.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,17 +40,16 @@

LOG_MODULE_REGISTER(hawkbit, CONFIG_HAWKBIT_LOG_LEVEL);

#define CANCEL_BASE_SIZE 50
#define RECV_BUFFER_SIZE 640
#define URL_BUFFER_SIZE 300
#define SHA256_HASH_SIZE 32
#define DOWNLOAD_HTTP_SIZE 200
#define DEPLOYMENT_BASE_SIZE 50
#define RESPONSE_BUFFER_SIZE 1100
#define DDI_SECURITY_TOKEN_SIZE 32
#define HAWKBIT_RECV_TIMEOUT (300 * MSEC_PER_SEC)
#define HAWKBIT_SET_SERVER_TIMEOUT K_MSEC(300)

#define HAWKBIT_JSON_URL "/" CONFIG_HAWKBIT_TENANT "/controller/v1"

#define HTTP_HEADER_CONTENT_TYPE_JSON "application/json;charset=UTF-8"

#define SLOT1_LABEL slot1_partition
Expand Down Expand Up @@ -142,7 +141,6 @@ static const struct smf_state hawkbit_states[];
enum hawkbit_state {
S_HAWKBIT_START,
S_HAWKBIT_HTTP,
S_HAWKBIT_RESPONSE_DATA,
S_HAWKBIT_PROBE,
S_HAWKBIT_CONFIG_DEVICE,
S_HAWKBIT_CLOSE,
Expand Down Expand Up @@ -523,42 +521,38 @@ static void hawkbit_update_sleep(struct hawkbit_ctl_res *hawkbit_res)
}
}

static const char *hawkbit_get_url(const char *href)
{
const char *helper;

helper = strstr(href, "//");
if (helper != NULL) {
helper = strstr(helper + 2u, "/");
}

if (!helper) {
LOG_ERR("Unexpected href format: %s", helper);
return NULL;
}
return helper;
}

/*
* Find URL component for the device cancel operation and action id
* Find URL component for the device cancel action id
*/
static int hawkbit_find_cancelAction_base(struct hawkbit_context *hb_context,
struct hawkbit_ctl_res *res, char *cancel_base,
static int hawkbit_find_cancel_action_id(struct hawkbit_ctl_res *res,
int32_t *cancel_action_id)
{
size_t len;
const char *href;
char *helper, *endptr;

href = res->_links.cancelAction.href;
if (!href) {
*cancel_base = '\0';
return 0;
}

LOG_DBG("_links.%s.href=%s", "cancelAction", href);

helper = strstr(href, "cancelAction/");
helper = strstr(res->_links.cancelAction.href, "cancelAction/");
if (!helper) {
/* A badly formatted cancel base is a server error */
LOG_ERR("Missing %s/ in href %s", "cancelAction", href);
return -EINVAL;
}

len = strlen(helper);
if (len > CANCEL_BASE_SIZE - 1) {
/* Lack of memory is an application error */
LOG_ERR("%s %s is too big (len %zu, max %zu)", "cancelAction", helper, len,
CANCEL_BASE_SIZE - 1);
return -ENOMEM;
}

strncpy(cancel_base, helper, CANCEL_BASE_SIZE);

helper = strtok(helper, "/");
if (helper == 0) {
return -EINVAL;
Expand All @@ -578,43 +572,6 @@ static int hawkbit_find_cancelAction_base(struct hawkbit_context *hb_context,
return 0;
}

/*
* Find URL component for the device's deployment operations
* resource
*/
static int hawkbit_find_deployment_base(struct hawkbit_ctl_res *res, char *deployment_base)
{
const char *href;
const char *helper;
size_t len;

href = res->_links.deploymentBase.href;
if (!href) {
*deployment_base = '\0';
return 0;
}

LOG_DBG("_links.%s.href=%s", "deploymentBase", href);

helper = strstr(href, "deploymentBase/");
if (!helper) {
/* A badly formatted deployment base is a server error */
LOG_ERR("Missing %s/ in href %s", "deploymentBase", href);
return -EINVAL;
}

len = strlen(helper);
if (len > DEPLOYMENT_BASE_SIZE - 1) {
/* Lack of memory is an application error */
LOG_ERR("%s %s is too big (len %zu, max %zu)", "deploymentBase", helper, len,
DEPLOYMENT_BASE_SIZE - 1);
return -ENOMEM;
}

strncpy(deployment_base, helper, DEPLOYMENT_BASE_SIZE);
return 0;
}

static int hawkbit_deployment_get_action_id(struct hawkbit_dep_res *res, int32_t *action_id)
{
int32_t id;
Expand All @@ -635,11 +592,10 @@ static int hawkbit_deployment_get_action_id(struct hawkbit_dep_res *res, int32_t
* resource.
*/
static int hawkbit_parse_deployment(struct hawkbit_context *hb_context, struct hawkbit_dep_res *res,
char *download_http, int32_t *file_size)
char **download_http, int32_t *file_size)
{
int32_t size;
const char *href;
const char *helper;
struct hawkbit_dep_res_chunk *chunk;
size_t len, num_chunks, num_artifacts;
struct hawkbit_dep_res_arts *artifact;
Expand Down Expand Up @@ -670,6 +626,10 @@ static int hawkbit_parse_deployment(struct hawkbit_context *hb_context, struct h

size = artifact->size;

if (file_size != NULL) {
*file_size = size;
}

if (size > SLOT1_SIZE) {
LOG_ERR("Artifact file size too big (got %d, max is %d)", size, SLOT1_SIZE);
return -ENOSPC;
Expand All @@ -685,28 +645,13 @@ static int hawkbit_parse_deployment(struct hawkbit_context *hb_context, struct h
return -EINVAL;
}

helper = strstr(href, "/DEFAULT/controller/v1");
if (!helper) {
LOG_ERR("Unexpected %s href format: %s", "download-http", helper);
return -EINVAL;
}

len = strlen(helper);
if (len == 0) {
LOG_ERR("Empty %s", "download-http");
return -EINVAL;
} else if (len > DOWNLOAD_HTTP_SIZE - 1) {
LOG_ERR("%s %s is too big (len %zu, max %zu)", "download-http", helper, len,
DOWNLOAD_HTTP_SIZE - 1);
return -ENOMEM;
}

/* Success. */
if (download_http != NULL) {
strncpy(download_http, helper, DOWNLOAD_HTTP_SIZE);
}
if (file_size != NULL) {
*file_size = size;
*download_http = hawkbit_get_url(href);
if (*download_http == NULL) {
LOG_ERR("Failed to parse %s url: %d", "deploymentBase", ret);
return -EINVAL;
}
}
return 0;
}
Expand Down Expand Up @@ -1151,32 +1096,22 @@ static void s_http_start(void *o)
s->hb_context.code_status = HAWKBIT_NETWORKING_ERROR;
smf_set_state(SMF_CTX(s), &hawkbit_states[S_HAWKBIT_TERMINATE]);
}
}

static void s_http_end(void *o)
{
struct s_object *s = (struct s_object *)o;

cleanup_connection(&s->hb_context.sock);
}

static void s_response_data_start(void *o)
{
struct s_object *s = (struct s_object *)o;

s->hb_context.response_buffer_size = RESPONSE_BUFFER_SIZE;

s->hb_context.response_data = calloc(s->hb_context.response_buffer_size, sizeof(uint8_t));
if (s->hb_context.response_data == NULL) {
cleanup_connection(&s->hb_context.sock);
s->hb_context.code_status = HAWKBIT_ALLOC_ERROR;
smf_set_state(SMF_CTX(s), &hawkbit_states[S_HAWKBIT_TERMINATE]);
}
}

static void s_response_data_end(void *o)
static void s_http_end(void *o)
{
struct s_object *s = (struct s_object *)o;

cleanup_connection(&s->hb_context.sock);
free(s->hb_context.response_data);
}

Expand Down Expand Up @@ -1247,21 +1182,24 @@ static void s_hawbit_close(void *o)
int ret = 0;
int32_t cancel_action_id = 0;
struct s_object *s = (struct s_object *)o;
char cancel_base[CANCEL_BASE_SIZE] = {0};
uint8_t status_buffer[CONFIG_HAWKBIT_STATUS_BUFFER_SIZE] = {0};
uint8_t url_buffer[URL_BUFFER_SIZE] = {0};
uint8_t *url_buffer;

ret = hawkbit_find_cancelAction_base(&s->hb_context, &s->hb_context.results.base,
cancel_base, &cancel_action_id);
if (ret < 0) {
LOG_ERR("Can't find cancelAction base: %d", ret);
url_buffer = hawkbit_get_url(&s->hb_context.results.base._links.cancelAction.href);
if (url_buffer == NULL) {
LOG_ERR("Can't find %s url: %d", "cancelAction", ret);
s->hb_context.code_status = HAWKBIT_METADATA_ERROR;
smf_set_state(SMF_CTX(s), &hawkbit_states[S_HAWKBIT_TERMINATE]);
return;
}

snprintk(url_buffer, sizeof(url_buffer), "%s/%s-%s/%s/%s", HAWKBIT_JSON_URL, CONFIG_BOARD,
s->device_id, cancel_base, "feedback");
ret = hawkbit_find_cancel_action_id(&s->hb_context.results.base, &cancel_action_id);
if (ret < 0) {
LOG_ERR("Can't find %s id: %d", "cancelAction", ret);
s->hb_context.code_status = HAWKBIT_METADATA_ERROR;
smf_set_state(SMF_CTX(s), &hawkbit_states[S_HAWKBIT_TERMINATE]);
return;
}

struct hawkbit_close close = {
.status.execution = hawkbit_status_execution(HAWKBIT_STATUS_EXEC_CLOSED),
Expand Down Expand Up @@ -1298,10 +1236,15 @@ static void s_config_device(void *o)
int ret = 0;
struct s_object *s = (struct s_object *)o;
uint8_t status_buffer[CONFIG_HAWKBIT_STATUS_BUFFER_SIZE] = {0};
uint8_t url_buffer[URL_BUFFER_SIZE] = {0};
uint8_t *url_buffer;

snprintk(url_buffer, sizeof(url_buffer), "%s/%s-%s/%s", HAWKBIT_JSON_URL, CONFIG_BOARD,
s->device_id, "configData");
url_buffer = hawkbit_get_url(&s->hb_context.results.base._links.configData.href);
if (url_buffer == NULL) {
LOG_ERR("Can't find %s url: %d", "configData", ret);
s->hb_context.code_status = HAWKBIT_METADATA_ERROR;
smf_set_state(SMF_CTX(s), &hawkbit_states[S_HAWKBIT_TERMINATE]);
return;
}

ret = hawkbit_config_device_data_cb_handler(s->device_id, status_buffer,
sizeof(status_buffer));
Expand Down Expand Up @@ -1329,20 +1272,16 @@ static void s_probe_deployment_base(void *o)
{
int ret = 0;
struct s_object *s = (struct s_object *)o;
char deployment_base[DEPLOYMENT_BASE_SIZE] = {0};
uint8_t url_buffer[URL_BUFFER_SIZE] = {0};
uint8_t *url_buffer;

ret = hawkbit_find_deployment_base(&s->hb_context.results.base, deployment_base);
if (ret < 0) {
LOG_ERR("Unable to find URL for the device's deploymentBase: %d", ret);
url_buffer = hawkbit_get_url(&s->hb_context.results.base._links.deploymentBase.href);
if (url_buffer == NULL) {
LOG_ERR("Can't find %s url: %d", "deploymentBase", ret);
s->hb_context.code_status = HAWKBIT_METADATA_ERROR;
smf_set_state(SMF_CTX(s), &hawkbit_states[S_HAWKBIT_TERMINATE]);
return;
}

snprintk(url_buffer, sizeof(url_buffer), "%s/%s-%s/%s", HAWKBIT_JSON_URL, CONFIG_BOARD,
s->device_id, deployment_base);

if (!send_request(&s->hb_context, HAWKBIT_PROBE_DEPLOYMENT_BASE, url_buffer, NULL)) {
LOG_ERR("Send request failed (%s)", "HAWKBIT_PROBE_DEPLOYMENT_BASE");
smf_set_state(SMF_CTX(s), &hawkbit_states[S_HAWKBIT_TERMINATE]);
Expand Down Expand Up @@ -1423,12 +1362,12 @@ static void s_download(void *o)
{
int ret = 0;
struct s_object *s = (struct s_object *)o;
uint8_t url_buffer[DOWNLOAD_HTTP_SIZE] = {0};
uint8_t *url_buffer;

ret = hawkbit_parse_deployment(&s->hb_context, &s->hb_context.results.dep, url_buffer,
ret = hawkbit_parse_deployment(&s->hb_context, &s->hb_context.results.dep, &url_buffer,
NULL);
if (ret < 0) {
LOG_ERR("Failed to parse deploymentBase: %d", ret);
LOG_ERR("Failed to parse %s: %d", "deploymentBase", ret);
s->hb_context.code_status = HAWKBIT_METADATA_ERROR;
smf_set_state(SMF_CTX(s), &hawkbit_states[S_HAWKBIT_TERMINATE]);
return;
Expand Down Expand Up @@ -1500,16 +1439,11 @@ static const struct smf_state hawkbit_states[] = {
NULL,
s_http_end,
&hawkbit_states[S_HAWKBIT_START]),
[S_HAWKBIT_RESPONSE_DATA] = SMF_CREATE_STATE(
s_response_data_start,
NULL,
s_response_data_end,
&hawkbit_states[S_HAWKBIT_HTTP]),
[S_HAWKBIT_PROBE] = SMF_CREATE_STATE(
NULL,
s_probe,
NULL,
&hawkbit_states[S_HAWKBIT_RESPONSE_DATA]),
&hawkbit_states[S_HAWKBIT_HTTP]),
[S_HAWKBIT_CONFIG_DEVICE] = SMF_CREATE_STATE(
NULL,
s_config_device,
Expand All @@ -1523,7 +1457,7 @@ static const struct smf_state hawkbit_states[] = {
NULL,
s_probe_deployment_base,
NULL,
&hawkbit_states[S_HAWKBIT_RESPONSE_DATA]),
&hawkbit_states[S_HAWKBIT_HTTP]),
[S_HAWKBIT_REPORT] = SMF_CREATE_STATE(
NULL,
s_report,
Expand Down

0 comments on commit 2a5891a

Please sign in to comment.