int stun_attr_encode(struct mbuf *mb, uint16_t type, const void *v, const uint8_t *tid, uint8_t padding) { const struct stun_change_req *ch_req = v; const struct stun_errcode *err_code = v; const struct stun_unknown_attr *ua = v; const unsigned int *num = v; const struct mbuf *mbd = v; size_t start, len; uint32_t i, n; int err = 0; if (!mb || !v) return EINVAL; mb->pos += 4; start = mb->pos; switch (type) { case STUN_ATTR_MAPPED_ADDR: case STUN_ATTR_ALT_SERVER: case STUN_ATTR_RESP_ORIGIN: case STUN_ATTR_OTHER_ADDR: tid = NULL; /*@fallthrough@*/ case STUN_ATTR_XOR_PEER_ADDR: case STUN_ATTR_XOR_RELAY_ADDR: case STUN_ATTR_XOR_MAPPED_ADDR: err |= stun_addr_encode(mb, v, tid); break; case STUN_ATTR_CHANGE_REQ: n = (uint32_t)ch_req->ip << 2 | (uint32_t)ch_req->port << 1; err |= mbuf_write_u32(mb, htonl(n)); break; case STUN_ATTR_USERNAME: case STUN_ATTR_REALM: case STUN_ATTR_NONCE: case STUN_ATTR_SOFTWARE: err |= mbuf_write_str(mb, v); break; case STUN_ATTR_MSG_INTEGRITY: err |= mbuf_write_mem(mb, v, 20); break; case STUN_ATTR_ERR_CODE: err |= mbuf_write_u16(mb, 0x00); err |= mbuf_write_u8(mb, err_code->code/100); err |= mbuf_write_u8(mb, err_code->code%100); err |= mbuf_write_str(mb, err_code->reason); break; case STUN_ATTR_UNKNOWN_ATTR: for (i=0; i<ua->typec; i++) err |= mbuf_write_u16(mb, htons(ua->typev[i])); break; case STUN_ATTR_CHANNEL_NUMBER: case STUN_ATTR_RESP_PORT: err |= mbuf_write_u16(mb, htons(*num)); err |= mbuf_write_u16(mb, 0x0000); break; case STUN_ATTR_LIFETIME: case STUN_ATTR_PRIORITY: case STUN_ATTR_FINGERPRINT: err |= mbuf_write_u32(mb, htonl(*num)); break; case STUN_ATTR_DATA: case STUN_ATTR_PADDING: if (mb == mbd) { mb->pos = mb->end; break; } err |= mbuf_write_mem(mb, mbuf_buf(mbd), mbuf_get_left(mbd)); break; case STUN_ATTR_REQ_ADDR_FAMILY: case STUN_ATTR_REQ_TRANSPORT: err |= mbuf_write_u8(mb, *num); err |= mbuf_write_u8(mb, 0x00); err |= mbuf_write_u16(mb, 0x0000); break; case STUN_ATTR_EVEN_PORT: err |= mbuf_write_u8(mb, ((struct stun_even_port *)v)->r << 7); break; case STUN_ATTR_DONT_FRAGMENT: case STUN_ATTR_USE_CAND: /* no value */ break; case STUN_ATTR_RSV_TOKEN: case STUN_ATTR_CONTROLLED: case STUN_ATTR_CONTROLLING: err |= mbuf_write_u64(mb, sys_htonll(*(uint64_t *)v)); break; default: err = EINVAL; break; } /* header */ len = mb->pos - start; mb->pos = start - 4; err |= mbuf_write_u16(mb, htons(type)); err |= mbuf_write_u16(mb, htons(len)); mb->pos += len; /* padding */ while ((mb->pos - start) & 0x03) err |= mbuf_write_u8(mb, padding); return err; }
int test_sys_endian(void) { uint16_t s_le, s_ho; uint8_t *s = (uint8_t *)&s_le; uint32_t l_le, l_ho; uint8_t *l = (uint8_t *)&l_le; uint64_t ll0, ll1 = 0x0102030405060708ULL; /* Little endian: LSB first - 0x1234 * * 0x0000: 0x34 * 0x0001: 0x12 */ s[0] = 0x34; s[1] = 0x12; s_ho = sys_ltohs(s_le); if (0x1234 != s_ho) { DEBUG_WARNING("endian short: 0x%04x\n", s_ho); return EINVAL; } if (s_le != sys_htols(s_ho)) { DEBUG_WARNING("sys_htols failed: 0x%04x\n", sys_htols(s_ho)); return EINVAL; } /* 0x12345678 * * 0x0000: 0x78 * 0x0001: 0x56 * 0x0002: 0x34 * 0x0003: 0x12 */ l[0] = 0x78; l[1] = 0x56; l[2] = 0x34; l[3] = 0x12; l_ho = sys_ltohl(l_le); if (0x12345678 != l_ho) { DEBUG_WARNING("endian long: 0x%08x\n", l_ho); return EINVAL; } if (l_le != sys_htoll(l_ho)) { DEBUG_WARNING("sys_htoll failed: 0x%08x\n", sys_htoll(l_ho)); return EINVAL; } /* Test 64-bit */ ll0 = sys_ntohll(sys_htonll(ll1)); if (ll0 != ll1) { DEBUG_WARNING("endian long-long: 0x%llx\n", ll0); return EINVAL; } return 0; }