/* * Parse a 'state report' and extract carrier on/off information * * @i2400m: device descriptor * @l3l4_hdr: pointer to message; it has been already validated for * consistent size. * @size: size of the message (header + payload). The header length * declaration is assumed to be congruent with @size (as in * sizeof(*l3l4_hdr) + l3l4_hdr->length == size) * * Extract from the report state the system state TLV and infer from * there if we have a carrier or not. Update our local state and tell * netdev. * * When setting the carrier, it's fine to set OFF twice (for example), * as netif_carrier_off() will not generate two OFF events (just on * the transitions). */ static void i2400m_report_state_hook(struct i2400m *i2400m, const struct i2400m_l3l4_hdr *l3l4_hdr, size_t size, const char *tag) { struct device *dev = i2400m_dev(i2400m); const struct i2400m_tlv_hdr *tlv; const struct i2400m_tlv_system_state *ss; const struct i2400m_tlv_rf_switches_status *rfss; const struct i2400m_tlv_media_status *ms; size_t tlv_size = le16_to_cpu(l3l4_hdr->length); d_fnstart(4, dev, "(i2400m %p, l3l4_hdr %p, size %zu, %s)\n", i2400m, l3l4_hdr, size, tag); tlv = NULL; while ((tlv = i2400m_tlv_buffer_walk(i2400m, &l3l4_hdr->pl, tlv_size, tlv))) { if (0 == i2400m_tlv_match(tlv, I2400M_TLV_SYSTEM_STATE, sizeof(*ss))) { ss = container_of(tlv, typeof(*ss), hdr); d_printf(2, dev, "%s: system state TLV " "found (0x%04x), state 0x%08x\n", tag, I2400M_TLV_SYSTEM_STATE, le32_to_cpu(ss->state)); i2400m_report_tlv_system_state(i2400m, ss); } if (0 == i2400m_tlv_match(tlv, I2400M_TLV_RF_STATUS, sizeof(*rfss))) { rfss = container_of(tlv, typeof(*rfss), hdr); d_printf(2, dev, "%s: RF status TLV " "found (0x%04x), sw 0x%02x hw 0x%02x\n", tag, I2400M_TLV_RF_STATUS, le32_to_cpu(rfss->sw_rf_switch), le32_to_cpu(rfss->hw_rf_switch)); i2400m_report_tlv_rf_switches_status(i2400m, rfss); } if (0 == i2400m_tlv_match(tlv, I2400M_TLV_MEDIA_STATUS, sizeof(*ms))) { ms = container_of(tlv, typeof(*ms), hdr); d_printf(2, dev, "%s: Media Status TLV: %u\n", tag, le32_to_cpu(ms->media_status)); i2400m_report_tlv_media_status(i2400m, ms); } } d_fnend(4, dev, "(i2400m %p, l3l4_hdr %p, size %zu, %s) = void\n", i2400m, l3l4_hdr, size, tag); }
/** * Find a TLV by type (and maybe length) in a buffer of TLVs * * @param tlv_hdr pointer to the first TLV in the sequence * * @param size size of the buffer in bytes; all TLVs are assumed to fit * fully in the buffer (otherwise we'll complain). * * @param tlv_type type of the TLV we are looking for * * @param tlv_size expected size of the TLV we are looking for (if -1, * don't check the size). This includes the header * * @returns NULL if the TLV is not found, otherwise a pointer to * it. If the sizes don't match, an error is printed and NULL * returned. * * @ingroup i2400m_group */ const struct i2400m_tlv_hdr *i2400m_tlv_find( const struct i2400m_tlv_hdr *tlv_hdr, size_t size, enum i2400m_tlv tlv_type, ssize_t tlv_size) { ssize_t match; const struct i2400m_tlv_hdr *tlv = NULL; while ((tlv = i2400m_tlv_buffer_walk(tlv_hdr, size, tlv))) { match = i2400m_tlv_match(tlv, tlv_type, tlv_size); if (match == 0) /* found it :) */ break; if (match > 0) wimaxll_msg(NULL, "TLV type 0x%04x found with size " "mismatch (%zu vs %zu needed)\n", tlv_type, match, tlv_size); } return tlv; }
/* * Parse a 'state report' and extract information * * @i2400m: device descriptor * @l3l4_hdr: pointer to message; it has been already validated for * consistent size. * @size: size of the message (header + payload). The header length * declaration is assumed to be congruent with @size (as in * sizeof(*l3l4_hdr) + l3l4_hdr->length == size) * * Walk over the TLVs in a report state and act on them. */ static void i2400m_report_state_hook(struct i2400m *i2400m, const struct i2400m_l3l4_hdr *l3l4_hdr, size_t size, const char *tag) { struct device *dev = i2400m_dev(i2400m); const struct i2400m_tlv_hdr *tlv; size_t tlv_size = le16_to_cpu(l3l4_hdr->length); d_fnstart(4, dev, "(i2400m %p, l3l4_hdr %p, size %zu, %s)\n", i2400m, l3l4_hdr, size, tag); tlv = NULL; while ((tlv = i2400m_tlv_buffer_walk(i2400m, &l3l4_hdr->pl, tlv_size, tlv))) i2400m_report_state_parse_tlv(i2400m, tlv, tag); d_fnend(4, dev, "(i2400m %p, l3l4_hdr %p, size %zu, %s) = void\n", i2400m, l3l4_hdr, size, tag); }
/* * Find a TLV in a buffer of sequential TLVs * * @i2400m: device descriptor * @tlv_hdr: pointer to the first TLV in the sequence * @size: size of the buffer in bytes; all TLVs are assumed to fit * fully in the buffer (otherwise we'll complain). * @tlv_type: type of the TLV we are looking for * @tlv_size: expected size of the TLV we are looking for (if -1, * don't check the size). This includes the header * * Returns: NULL if the TLV is not found, otherwise a pointer to * it. If the sizes don't match, an error is printed and NULL * returned. */ static const struct i2400m_tlv_hdr *i2400m_tlv_find( struct i2400m *i2400m, const struct i2400m_tlv_hdr *tlv_hdr, size_t size, enum i2400m_tlv tlv_type, ssize_t tlv_size) { ssize_t match; struct device *dev = i2400m_dev(i2400m); const struct i2400m_tlv_hdr *tlv = NULL; while ((tlv = i2400m_tlv_buffer_walk(i2400m, tlv_hdr, size, tlv))) { match = i2400m_tlv_match(tlv, tlv_type, tlv_size); if (match == 0) /* found it :) */ break; if (match > 0) dev_warn(dev, "TLV type 0x%04x found with size " "mismatch (%zu vs %zu needed)\n", tlv_type, match, tlv_size); } return tlv; }