static int process_elements(struct conn *conn, uint8_t * rawmsg, int len, struct sockaddr *from) { struct cw_action_in as, *af, *afm; int offset = cw_get_hdr_msg_offset(rawmsg); uint8_t *msg_ptr = rawmsg + offset; int elems_len = cw_get_msg_elems_len(msg_ptr); int payloadlen = len - offset; /* pre-check message */ if (payloadlen - 8 != elems_len) { if (conn->strict_hdr) { cw_dbg(DBG_MSG_ERR, "Discarding message from %s, msgelems len=%d, payload len=%d, (Strict CAPWAP) ", sock_addr2str(&conn->addr), elems_len, payloadlen - 8); errno = EAGAIN; return -1; } if (elems_len < payloadlen - 8) { cw_dbg(DBG_RFC, "Packet from from %s has %d bytes of extra data, ignoring.", sock_addr2str(&conn->addr), payloadlen - 8 - elems_len); elems_len = len - 8; } if (elems_len > payloadlen - 8) { cw_dbg(DBG_RFC, "Packet from from %s has msgelems len of %d bytes, but has only %d bytes of data, truncating.", sock_addr2str(&conn->addr), elems_len, payloadlen - 8); elems_len = payloadlen - 8; } } if (!conn->detected) { //struct mod_ac *mod; struct cw_actiondef *ad = load_mods(conn, rawmsg, len, elems_len, from); if (!ad) { cw_log(LOG_ERR, "Error"); errno = EAGAIN; return -1; } conn->actions = ad; conn->detected = 1; } /* prepare struct for search operation */ as.capwap_state = conn->capwap_state; as.msg_id = cw_get_msg_id(msg_ptr); as.vendor_id = 0; as.elem_id = 0; as.proto = 0; /* Search for state/message combination */ afm = cw_actionlist_in_get(conn->actions->in, &as); if (!afm) { /* Throw away unexpected response messages */ if (!(as.msg_id & 1)) { cw_dbg(DBG_MSG_ERR, "Message type %d (%s) unexpected/illegal in %s State, discarding.", as.msg_id, cw_strmsg(as.msg_id), cw_strstate(conn->capwap_state)); errno = EAGAIN; return -1; } /* Request message not found in current state, check if we know anything else about this message type */ const char *str = cw_strheap_get(conn->actions->strmsg, as.msg_id); int result_code = 0; if (str) { /* Message found, but it was in wrong state */ cw_dbg(DBG_MSG_ERR, "Message type %d (%s) not allowed in %s State.", as.msg_id, cw_strmsg(as.msg_id), cw_strstate(as.capwap_state)); result_code = CW_RESULT_MSG_INVALID_IN_CURRENT_STATE; } else { /* Message is unknown */ cw_dbg(DBG_MSG_ERR, "Message type %d (%s) unknown.", as.msg_id, cw_strmsg(as.msg_id), cw_strstate(as.capwap_state)); result_code = CW_RESULT_MSG_UNRECOGNIZED; } cw_send_error_response(conn, rawmsg, result_code); errno = EAGAIN; return -1; } if (conn->msg_start){ conn->msg_start(conn, afm, rawmsg, len, from); } /* Execute start processor for message */ if (afm->start) { afm->start(conn, afm, rawmsg, len, from); } uint8_t *elems_ptr = cw_get_msg_elems_ptr(msg_ptr); uint8_t *elem; /* Create an avltree to catch the found mandatory elements */ conn->mand = stravltree_create(); int unrecognized = 0; /* iterate through message elements */ cw_foreach_elem(elem, elems_ptr, elems_len) { as.elem_id = cw_get_elem_id(elem); int elem_len = cw_get_elem_len(elem); af = cw_actionlist_in_get(conn->actions->in, &as); if (!af) { unrecognized++; cw_dbg(DBG_ELEM_ERR, "Element %d (%s) not allowed in msg of type %d (%s), ignoring.", as.elem_id, cw_strelemp(conn->actions, as.elem_id), as.msg_id, cw_strmsg(as.msg_id)); continue; } if (!check_len(conn, af, cw_get_elem_data(elem), elem_len, from)) { continue; } cw_dbg_elem(DBG_ELEM, conn, as.msg_id, as.elem_id, cw_get_elem_data(elem), elem_len); int afrc = 1; if (af->start) { afrc = af->start(conn, af, cw_get_elem_data(elem), elem_len, from); } if (af->mand && afrc) { /* add found mandatory message element to mand list */ stravltree_add(conn->mand, af->item_id); } if(conn->elem_end){ afrc = conn->elem_end(conn,af,afrc,cw_get_elem_data(elem), elem_len,from); } }
static int parse_config_file(const char *path) { int err; long int int_val; const char *string_val; int string_val_len; config_t config; config_setting_t *setting; memset(&g_config, 0, sizeof(struct config_s)); err = 0; config_init(&config); fprintf(stderr, "read config: %s\n", path); if (config_read_file(&config, path) == CONFIG_FALSE) { fprintf(stderr, "config_read_file(): %s - %d - %s\n", path, config_error_line(&config), config_error_text(&config)); err = 1; goto error; } setting = config_lookup(&config, "server"); if (setting != NULL) { if (!config_setting_lookup_int(setting, "listen_port", &int_val)) { fprintf(stderr, "ERROR ... no listen port in config file %s\n", path); err = 1; goto error; } if (int_val > 65535) { fprintf(stderr, "ERROR ... port has to be smaller 65535\n"); err = 1; goto error; } g_config.listen_port = (int)int_val; if (!config_setting_lookup_string(setting, "accept_ip", &string_val)) { fprintf(stderr, "ERROR ... no accept_ip in config file %s\n", path); err = 1; goto error; } string_val_len = strlen(string_val); /* check if supplied argument is max of 16 */ if (string_val_len > IP_V4_LEN - 1) { fprintf(stderr, "ERROR ... accept_ip too long\n"); err = 1; goto error; } memset(g_config.accept_ip_v4, 0, IP_V4_LEN); memcpy(g_config.accept_ip_v4, string_val, string_val_len); if (!config_setting_lookup_int(setting, "read_package_size", &int_val)) { int_val = MAX_BUF_SIZE; } if (int_val > MAX_BUF_SIZE) { fprintf(stderr, "WARNING ... read_package_size given bigger than MAX_BUF_SIZE (%d)\n", MAX_BUF_SIZE); int_val = MAX_BUF_SIZE; } else if (int_val < 100) { fprintf(stderr, "WARNING ... read_package_size to small.\n"); int_val = 100; } g_config.read_package_size = int_val; if (!config_setting_lookup_int(setting, "backlog", &int_val)) { int_val = 128; } g_config.backlog = int_val; if (!config_setting_lookup_string(setting, "base_path", &string_val)) { fprintf(stderr, "ERROR ... no base path specified\n"); err = 1; goto error; } g_config.base_path = strdup(string_val); } fprintf(stderr, "listen_port: %d\n", g_config.listen_port); fprintf(stderr, "accept_ip: %s\n", g_config.accept_ip_v4); fprintf(stderr, "read_package_size: %d\n", g_config.read_package_size); fprintf(stderr, "backlog: %d\n", g_config.backlog); fprintf(stderr, "base_path: %s\n", g_config.base_path); err = load_mods(&config, setting); error: config_destroy(&config); return err; }