/* Generated by `./lib9p/9p.gen lib9p/9P2000.txt lib9p/9P2000.u.txt lib9p/9P2000.e.txt`. DO NOT EDIT! */ #include #include #include /* for size_t */ #include /* for PRI* macros */ #include /* for memset() */ #include #include "internal.h" /* strings ********************************************************************/ static const char *version_strs[LIB9P_VER_NUM] = { [LIB9P_VER_unknown] = "unknown", [LIB9P_VER_9P2000] = "9P2000", [LIB9P_VER_9P2000_e] = "9P2000.e", [LIB9P_VER_9P2000_u] = "9P2000.u", }; const char *lib9p_version_str(enum lib9p_version ver) { assert(0 <= ver && ver < LIB9P_VER_NUM); return version_strs[ver]; } static const char *msg_type_strs[0x100] = { [0x00] = "0x00", [0x01] = "0x01", [0x02] = "0x02", [0x03] = "0x03", [0x04] = "0x04", [0x05] = "0x05", [0x06] = "0x06", [0x07] = "0x07", [0x08] = "0x08", [0x09] = "0x09", [0x0A] = "0x0A", [0x0B] = "0x0B", [0x0C] = "0x0C", [0x0D] = "0x0D", [0x0E] = "0x0E", [0x0F] = "0x0F", [0x10] = "0x10", [0x11] = "0x11", [0x12] = "0x12", [0x13] = "0x13", [0x14] = "0x14", [0x15] = "0x15", [0x16] = "0x16", [0x17] = "0x17", [0x18] = "0x18", [0x19] = "0x19", [0x1A] = "0x1A", [0x1B] = "0x1B", [0x1C] = "0x1C", [0x1D] = "0x1D", [0x1E] = "0x1E", [0x1F] = "0x1F", [0x20] = "0x20", [0x21] = "0x21", [0x22] = "0x22", [0x23] = "0x23", [0x24] = "0x24", [0x25] = "0x25", [0x26] = "0x26", [0x27] = "0x27", [0x28] = "0x28", [0x29] = "0x29", [0x2A] = "0x2A", [0x2B] = "0x2B", [0x2C] = "0x2C", [0x2D] = "0x2D", [0x2E] = "0x2E", [0x2F] = "0x2F", [0x30] = "0x30", [0x31] = "0x31", [0x32] = "0x32", [0x33] = "0x33", [0x34] = "0x34", [0x35] = "0x35", [0x36] = "0x36", [0x37] = "0x37", [0x38] = "0x38", [0x39] = "0x39", [0x3A] = "0x3A", [0x3B] = "0x3B", [0x3C] = "0x3C", [0x3D] = "0x3D", [0x3E] = "0x3E", [0x3F] = "0x3F", [0x40] = "0x40", [0x41] = "0x41", [0x42] = "0x42", [0x43] = "0x43", [0x44] = "0x44", [0x45] = "0x45", [0x46] = "0x46", [0x47] = "0x47", [0x48] = "0x48", [0x49] = "0x49", [0x4A] = "0x4A", [0x4B] = "0x4B", [0x4C] = "0x4C", [0x4D] = "0x4D", [0x4E] = "0x4E", [0x4F] = "0x4F", [0x50] = "0x50", [0x51] = "0x51", [0x52] = "0x52", [0x53] = "0x53", [0x54] = "0x54", [0x55] = "0x55", [0x56] = "0x56", [0x57] = "0x57", [0x58] = "0x58", [0x59] = "0x59", [0x5A] = "0x5A", [0x5B] = "0x5B", [0x5C] = "0x5C", [0x5D] = "0x5D", [0x5E] = "0x5E", [0x5F] = "0x5F", [0x60] = "0x60", [0x61] = "0x61", [0x62] = "0x62", [0x63] = "0x63", [0x64] = "Tversion", [0x65] = "Rversion", [0x66] = "Tauth", [0x67] = "Rauth", [0x68] = "Tattach", [0x69] = "Rattach", [0x6A] = "0x6A", [0x6B] = "Rerror", [0x6C] = "Tflush", [0x6D] = "Rflush", [0x6E] = "Twalk", [0x6F] = "Rwalk", [0x70] = "Topen", [0x71] = "Ropen", [0x72] = "Tcreate", [0x73] = "Rcreate", [0x74] = "Tread", [0x75] = "Rread", [0x76] = "Twrite", [0x77] = "Rwrite", [0x78] = "Tclunk", [0x79] = "Rclunk", [0x7A] = "Tremove", [0x7B] = "Rremove", [0x7C] = "Tstat", [0x7D] = "Rstat", [0x7E] = "Twstat", [0x7F] = "Rwstat", [0x80] = "0x80", [0x81] = "0x81", [0x82] = "0x82", [0x83] = "0x83", [0x84] = "0x84", [0x85] = "0x85", [0x86] = "0x86", [0x87] = "0x87", [0x88] = "0x88", [0x89] = "0x89", [0x8A] = "0x8A", [0x8B] = "0x8B", [0x8C] = "0x8C", [0x8D] = "0x8D", [0x8E] = "0x8E", [0x8F] = "0x8F", [0x90] = "0x90", [0x91] = "0x91", [0x92] = "0x92", [0x93] = "0x93", [0x94] = "0x94", [0x95] = "0x95", [0x96] = "Tsession", [0x97] = "Rsession", [0x98] = "Tsread", [0x99] = "Rsread", [0x9A] = "Tswrite", [0x9B] = "Rswrite", [0x9C] = "0x9C", [0x9D] = "0x9D", [0x9E] = "0x9E", [0x9F] = "0x9F", [0xA0] = "0xA0", [0xA1] = "0xA1", [0xA2] = "0xA2", [0xA3] = "0xA3", [0xA4] = "0xA4", [0xA5] = "0xA5", [0xA6] = "0xA6", [0xA7] = "0xA7", [0xA8] = "0xA8", [0xA9] = "0xA9", [0xAA] = "0xAA", [0xAB] = "0xAB", [0xAC] = "0xAC", [0xAD] = "0xAD", [0xAE] = "0xAE", [0xAF] = "0xAF", [0xB0] = "0xB0", [0xB1] = "0xB1", [0xB2] = "0xB2", [0xB3] = "0xB3", [0xB4] = "0xB4", [0xB5] = "0xB5", [0xB6] = "0xB6", [0xB7] = "0xB7", [0xB8] = "0xB8", [0xB9] = "0xB9", [0xBA] = "0xBA", [0xBB] = "0xBB", [0xBC] = "0xBC", [0xBD] = "0xBD", [0xBE] = "0xBE", [0xBF] = "0xBF", [0xC0] = "0xC0", [0xC1] = "0xC1", [0xC2] = "0xC2", [0xC3] = "0xC3", [0xC4] = "0xC4", [0xC5] = "0xC5", [0xC6] = "0xC6", [0xC7] = "0xC7", [0xC8] = "0xC8", [0xC9] = "0xC9", [0xCA] = "0xCA", [0xCB] = "0xCB", [0xCC] = "0xCC", [0xCD] = "0xCD", [0xCE] = "0xCE", [0xCF] = "0xCF", [0xD0] = "0xD0", [0xD1] = "0xD1", [0xD2] = "0xD2", [0xD3] = "0xD3", [0xD4] = "0xD4", [0xD5] = "0xD5", [0xD6] = "0xD6", [0xD7] = "0xD7", [0xD8] = "0xD8", [0xD9] = "0xD9", [0xDA] = "0xDA", [0xDB] = "0xDB", [0xDC] = "0xDC", [0xDD] = "0xDD", [0xDE] = "0xDE", [0xDF] = "0xDF", [0xE0] = "0xE0", [0xE1] = "0xE1", [0xE2] = "0xE2", [0xE3] = "0xE3", [0xE4] = "0xE4", [0xE5] = "0xE5", [0xE6] = "0xE6", [0xE7] = "0xE7", [0xE8] = "0xE8", [0xE9] = "0xE9", [0xEA] = "0xEA", [0xEB] = "0xEB", [0xEC] = "0xEC", [0xED] = "0xED", [0xEE] = "0xEE", [0xEF] = "0xEF", [0xF0] = "0xF0", [0xF1] = "0xF1", [0xF2] = "0xF2", [0xF3] = "0xF3", [0xF4] = "0xF4", [0xF5] = "0xF5", [0xF6] = "0xF6", [0xF7] = "0xF7", [0xF8] = "0xF8", [0xF9] = "0xF9", [0xFA] = "0xFA", [0xFB] = "0xFB", [0xFC] = "0xFC", [0xFD] = "0xFD", [0xFE] = "0xFE", [0xFF] = "0xFF", }; const char *lib9p_msg_type_str(enum lib9p_msg_type typ) { assert(0 <= typ && typ <= 0xFF); return msg_type_strs[typ]; } /* validate_* *****************************************************************/ static ALWAYS_INLINE bool _validate_size_net(struct _validate_ctx *ctx, uint32_t n) { if (__builtin_add_overflow(ctx->net_offset, n, &ctx->net_offset)) /* If needed-net-size overflowed uint32_t, then * there's no way that actual-net-size will live up to * that. */ return lib9p_error(ctx->ctx, LINUX_EBADMSG, "message is too short for content"); if (ctx->net_offset > ctx->net_size) return lib9p_error(ctx->ctx, LINUX_EBADMSG, "message is too short for content"); return false; } static ALWAYS_INLINE bool _validate_size_host(struct _validate_ctx *ctx, size_t n) { if (__builtin_add_overflow(ctx->host_extra, n, &ctx->host_extra)) /* If needed-host-size overflowed size_t, then there's * no way that actual-net-size will live up to * that. */ return lib9p_error(ctx->ctx, LINUX_EBADMSG, "message is too short for content"); return false; } static ALWAYS_INLINE bool _validate_list(struct _validate_ctx *ctx, size_t cnt, _validate_fn_t item_fn, size_t item_host_size) { for (size_t i = 0; i < cnt; i++) if (_validate_size_host(ctx, item_host_size) || item_fn(ctx)) return true; return false; } #define validate_1(ctx) _validate_size_net(ctx, 1) #define validate_2(ctx) _validate_size_net(ctx, 2) #define validate_4(ctx) _validate_size_net(ctx, 4) #define validate_8(ctx) _validate_size_net(ctx, 8) static ALWAYS_INLINE bool validate_d(struct _validate_ctx *ctx) { uint32_t base_offset = ctx->net_offset; if (validate_4(ctx)) return true; uint32_t len = decode_u32le(&ctx->net_bytes[base_offset]); return _validate_size_net(ctx, len) || _validate_size_host(ctx, len); } static ALWAYS_INLINE bool validate_s(struct _validate_ctx *ctx) { uint32_t base_offset = ctx->net_offset; if (validate_2(ctx)) return true; uint16_t len = decode_u16le(&ctx->net_bytes[base_offset]); if (_validate_size_net(ctx, len) || _validate_size_host(ctx, ((size_t)len)+1)) return true; if (!is_valid_utf8_without_nul(&ctx->net_bytes[base_offset+2], len)) return lib9p_error(ctx->ctx, LINUX_EBADMSG, "message contains invalid UTF-8"); return false; } static ALWAYS_INLINE bool validate_dm(struct _validate_ctx *ctx) { if (validate_4(ctx)) return true; static const lib9p_dm_t masks[LIB9P_VER_NUM] = { [LIB9P_VER_9P2000] = 0b11101100000000000000000111111111, [LIB9P_VER_9P2000_e] = 0b11101100000000000000000111111111, [LIB9P_VER_9P2000_u] = 0b11101100101111000000000111111111, }; lib9p_dm_t mask = masks[ctx->ctx->version]; lib9p_dm_t val = decode_u32le(&ctx->net_bytes[ctx->net_offset-4]); if (val & ~mask) return lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "unknown bits in dm bitfield: %#04"PRIx32, val & ~mask); return false; } static ALWAYS_INLINE bool validate_qt(struct _validate_ctx *ctx) { if (validate_1(ctx)) return true; static const lib9p_qt_t masks[LIB9P_VER_NUM] = { [LIB9P_VER_9P2000] = 0b11101100, [LIB9P_VER_9P2000_e] = 0b11101100, [LIB9P_VER_9P2000_u] = 0b11101110, }; lib9p_qt_t mask = masks[ctx->ctx->version]; lib9p_qt_t val = decode_u8le(&ctx->net_bytes[ctx->net_offset-1]); if (val & ~mask) return lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "unknown bits in qt bitfield: %#01"PRIx8, val & ~mask); return false; } static ALWAYS_INLINE bool validate_qid(struct _validate_ctx *ctx) { return validate_qt(ctx) || validate_4(ctx) || validate_8(ctx); } static ALWAYS_INLINE bool validate_stat(struct _validate_ctx *ctx) { uint32_t size_offset = ctx->net_offset; return validate_2(ctx) || validate_2(ctx) || validate_4(ctx) || validate_qid(ctx) || validate_dm(ctx) || validate_4(ctx) || validate_4(ctx) || validate_8(ctx) || validate_s(ctx) || validate_s(ctx) || validate_s(ctx) || validate_s(ctx) || ( (ctx->ctx->version==LIB9P_VER_9P2000_u) && validate_s(ctx) ) || ( (ctx->ctx->version==LIB9P_VER_9P2000_u) && validate_4(ctx) ) || ( (ctx->ctx->version==LIB9P_VER_9P2000_u) && validate_4(ctx) ) || ( (ctx->ctx->version==LIB9P_VER_9P2000_u) && validate_4(ctx) ) || ((uint32_t)decode_u16le(&ctx->net_bytes[size_offset]) != ctx->net_offset - size_offset ? lib9p_error(ctx->ctx, LINUX_EBADMSG, "stat size does not match stat contents") : false); } static ALWAYS_INLINE bool validate_o(struct _validate_ctx *ctx) { if (validate_1(ctx)) return true; static const lib9p_o_t mask = 0b01010011; lib9p_o_t val = decode_u8le(&ctx->net_bytes[ctx->net_offset-1]); if (val & ~mask) return lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "unknown bits in o bitfield: %#01"PRIx8, val & ~mask); return false; } static FLATTEN bool validate_Tversion(struct _validate_ctx *ctx) { return validate_4(ctx) || validate_s(ctx); } static FLATTEN bool validate_Rversion(struct _validate_ctx *ctx) { return validate_4(ctx) || validate_s(ctx); } static FLATTEN bool validate_Tauth(struct _validate_ctx *ctx) { return validate_4(ctx) || validate_s(ctx) || validate_s(ctx) || ( (ctx->ctx->version==LIB9P_VER_9P2000_u) && validate_4(ctx) ); } static FLATTEN bool validate_Rauth(struct _validate_ctx *ctx) { return validate_qid(ctx); } static FLATTEN bool validate_Tattach(struct _validate_ctx *ctx) { return validate_4(ctx) || validate_4(ctx) || validate_s(ctx) || validate_s(ctx) || ( (ctx->ctx->version==LIB9P_VER_9P2000_u) && validate_4(ctx) ); } static FLATTEN bool validate_Rattach(struct _validate_ctx *ctx) { return validate_qid(ctx); } static FLATTEN bool validate_Rerror(struct _validate_ctx *ctx) { return validate_s(ctx) || ( (ctx->ctx->version==LIB9P_VER_9P2000_u) && validate_4(ctx) ); } static FLATTEN bool validate_Tflush(struct _validate_ctx *ctx) { return validate_2(ctx); } static FLATTEN bool validate_Rflush(struct _validate_ctx *UNUSED(ctx)) { return false; } static FLATTEN bool validate_Twalk(struct _validate_ctx *ctx) { return validate_4(ctx) || validate_4(ctx) || validate_2(ctx) || (decode_u16le(&ctx->net_bytes[ctx->net_offset-2]) > (uint16_t)(16) ? lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "list size is too large (%"PRIu16" > %"PRIu16")", decode_u16le(&ctx->net_bytes[ctx->net_offset-2]), (uint16_t)(16)) : false) || _validate_list(ctx, decode_u16le(&ctx->net_bytes[ctx->net_offset-2]), validate_s, sizeof(struct lib9p_s)); } static FLATTEN bool validate_Rwalk(struct _validate_ctx *ctx) { return validate_2(ctx) || (decode_u16le(&ctx->net_bytes[ctx->net_offset-2]) > (uint16_t)(16) ? lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "list size is too large (%"PRIu16" > %"PRIu16")", decode_u16le(&ctx->net_bytes[ctx->net_offset-2]), (uint16_t)(16)) : false) || _validate_list(ctx, decode_u16le(&ctx->net_bytes[ctx->net_offset-2]), validate_qid, sizeof(struct lib9p_qid)); } static FLATTEN bool validate_Topen(struct _validate_ctx *ctx) { return validate_4(ctx) || validate_o(ctx); } static FLATTEN bool validate_Ropen(struct _validate_ctx *ctx) { return validate_qid(ctx) || validate_4(ctx); } static FLATTEN bool validate_Tcreate(struct _validate_ctx *ctx) { return validate_4(ctx) || validate_s(ctx) || validate_dm(ctx) || validate_o(ctx); } static FLATTEN bool validate_Rcreate(struct _validate_ctx *ctx) { return validate_qid(ctx) || validate_4(ctx); } static FLATTEN bool validate_Tread(struct _validate_ctx *ctx) { return validate_4(ctx) || validate_8(ctx) || validate_4(ctx); } static FLATTEN bool validate_Rread(struct _validate_ctx *ctx) { return validate_d(ctx); } static FLATTEN bool validate_Twrite(struct _validate_ctx *ctx) { return validate_4(ctx) || validate_8(ctx) || validate_d(ctx); } static FLATTEN bool validate_Rwrite(struct _validate_ctx *ctx) { return validate_4(ctx); } static FLATTEN bool validate_Tclunk(struct _validate_ctx *ctx) { return validate_4(ctx); } static FLATTEN bool validate_Rclunk(struct _validate_ctx *UNUSED(ctx)) { return false; } static FLATTEN bool validate_Tremove(struct _validate_ctx *ctx) { return validate_4(ctx); } static FLATTEN bool validate_Rremove(struct _validate_ctx *UNUSED(ctx)) { return false; } static FLATTEN bool validate_Tstat(struct _validate_ctx *ctx) { return validate_4(ctx); } static FLATTEN bool validate_Rstat(struct _validate_ctx *ctx) { return validate_stat(ctx); } static FLATTEN bool validate_Twstat(struct _validate_ctx *ctx) { return validate_4(ctx) || validate_stat(ctx); } static FLATTEN bool validate_Rwstat(struct _validate_ctx *UNUSED(ctx)) { return false; } static FLATTEN bool validate_Tsession(struct _validate_ctx *ctx) { return validate_8(ctx); } static FLATTEN bool validate_Rsession(struct _validate_ctx *UNUSED(ctx)) { return false; } static FLATTEN bool validate_Tsread(struct _validate_ctx *ctx) { return validate_4(ctx) || validate_2(ctx) || _validate_list(ctx, decode_u16le(&ctx->net_bytes[ctx->net_offset-2]), validate_s, sizeof(struct lib9p_s)); } static FLATTEN bool validate_Rsread(struct _validate_ctx *ctx) { return validate_d(ctx); } static FLATTEN bool validate_Tswrite(struct _validate_ctx *ctx) { return validate_4(ctx) || validate_2(ctx) || _validate_list(ctx, decode_u16le(&ctx->net_bytes[ctx->net_offset-2]), validate_s, sizeof(struct lib9p_s)) || validate_d(ctx); } static FLATTEN bool validate_Rswrite(struct _validate_ctx *ctx) { return validate_4(ctx); } /* unmarshal_* ****************************************************************/ static ALWAYS_INLINE void unmarshal_1(struct _unmarshal_ctx *ctx, uint8_t *out) { *out = decode_u8le(&ctx->net_bytes[ctx->net_offset]); ctx->net_offset += 1; } static ALWAYS_INLINE void unmarshal_2(struct _unmarshal_ctx *ctx, uint16_t *out) { *out = decode_u16le(&ctx->net_bytes[ctx->net_offset]); ctx->net_offset += 2; } static ALWAYS_INLINE void unmarshal_4(struct _unmarshal_ctx *ctx, uint32_t *out) { *out = decode_u32le(&ctx->net_bytes[ctx->net_offset]); ctx->net_offset += 4; } static ALWAYS_INLINE void unmarshal_8(struct _unmarshal_ctx *ctx, uint64_t *out) { *out = decode_u64le(&ctx->net_bytes[ctx->net_offset]); ctx->net_offset += 8; } static ALWAYS_INLINE void unmarshal_d(struct _unmarshal_ctx *ctx, struct lib9p_d *out) { memset(out, 0, sizeof(*out)); unmarshal_4(ctx, &out->len); out->dat = ctx->extra; ctx->extra += sizeof(out->dat[0]) * out->len; for (typeof(out->len) i = 0; i < out->len; i++) unmarshal_1(ctx, (uint8_t *)&out->dat[i]); } static ALWAYS_INLINE void unmarshal_s(struct _unmarshal_ctx *ctx, struct lib9p_s *out) { memset(out, 0, sizeof(*out)); unmarshal_2(ctx, &out->len); out->utf8 = ctx->extra; ctx->extra += sizeof(out->utf8[0]) * out->len; for (typeof(out->len) i = 0; i < out->len; i++) unmarshal_1(ctx, (uint8_t *)&out->utf8[i]); } static ALWAYS_INLINE void unmarshal_dm(struct _unmarshal_ctx *ctx, lib9p_dm_t *out) { unmarshal_4(ctx, (uint32_t *)out); } static ALWAYS_INLINE void unmarshal_qt(struct _unmarshal_ctx *ctx, lib9p_qt_t *out) { unmarshal_1(ctx, (uint8_t *)out); } static ALWAYS_INLINE void unmarshal_qid(struct _unmarshal_ctx *ctx, struct lib9p_qid *out) { memset(out, 0, sizeof(*out)); unmarshal_qt(ctx, &out->type); unmarshal_4(ctx, &out->vers); unmarshal_8(ctx, &out->path); } static ALWAYS_INLINE void unmarshal_stat(struct _unmarshal_ctx *ctx, struct lib9p_stat *out) { memset(out, 0, sizeof(*out)); ctx->net_offset += 2; unmarshal_2(ctx, &out->kern_type); unmarshal_4(ctx, &out->kern_dev); unmarshal_qid(ctx, &out->file_qid); unmarshal_dm(ctx, &out->file_mode); unmarshal_4(ctx, &out->file_atime); unmarshal_4(ctx, &out->file_mtime); unmarshal_8(ctx, &out->file_size); unmarshal_s(ctx, &out->file_name); unmarshal_s(ctx, &out->file_owner_uid); unmarshal_s(ctx, &out->file_owner_gid); unmarshal_s(ctx, &out->file_last_modified_uid); if ( (ctx->ctx->version==LIB9P_VER_9P2000_u) ) unmarshal_s(ctx, &out->file_extension); if ( (ctx->ctx->version==LIB9P_VER_9P2000_u) ) unmarshal_4(ctx, &out->file_owner_n_uid); if ( (ctx->ctx->version==LIB9P_VER_9P2000_u) ) unmarshal_4(ctx, &out->file_owner_n_gid); if ( (ctx->ctx->version==LIB9P_VER_9P2000_u) ) unmarshal_4(ctx, &out->file_last_modified_n_uid); } static ALWAYS_INLINE void unmarshal_o(struct _unmarshal_ctx *ctx, lib9p_o_t *out) { unmarshal_1(ctx, (uint8_t *)out); } static FLATTEN void unmarshal_Tversion(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tversion *out) { memset(out, 0, sizeof(*out)); unmarshal_4(ctx, &out->max_msg_size); unmarshal_s(ctx, &out->version); } static FLATTEN void unmarshal_Rversion(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rversion *out) { memset(out, 0, sizeof(*out)); unmarshal_4(ctx, &out->max_msg_size); unmarshal_s(ctx, &out->version); } static FLATTEN void unmarshal_Tauth(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tauth *out) { memset(out, 0, sizeof(*out)); unmarshal_4(ctx, &out->afid); unmarshal_s(ctx, &out->uname); unmarshal_s(ctx, &out->aname); if ( (ctx->ctx->version==LIB9P_VER_9P2000_u) ) unmarshal_4(ctx, &out->n_uname); } static FLATTEN void unmarshal_Rauth(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rauth *out) { memset(out, 0, sizeof(*out)); unmarshal_qid(ctx, &out->aqid); } static FLATTEN void unmarshal_Tattach(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tattach *out) { memset(out, 0, sizeof(*out)); unmarshal_4(ctx, &out->fid); unmarshal_4(ctx, &out->afid); unmarshal_s(ctx, &out->uname); unmarshal_s(ctx, &out->aname); if ( (ctx->ctx->version==LIB9P_VER_9P2000_u) ) unmarshal_4(ctx, &out->n_uname); } static FLATTEN void unmarshal_Rattach(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rattach *out) { memset(out, 0, sizeof(*out)); unmarshal_qid(ctx, &out->qid); } static FLATTEN void unmarshal_Rerror(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rerror *out) { memset(out, 0, sizeof(*out)); unmarshal_s(ctx, &out->ename); if ( (ctx->ctx->version==LIB9P_VER_9P2000_u) ) unmarshal_4(ctx, &out->errno); } static FLATTEN void unmarshal_Tflush(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tflush *out) { memset(out, 0, sizeof(*out)); unmarshal_2(ctx, &out->oldtag); } static FLATTEN void unmarshal_Rflush(struct _unmarshal_ctx *UNUSED(ctx), struct lib9p_msg_Rflush *out) { memset(out, 0, sizeof(*out)); } static FLATTEN void unmarshal_Twalk(struct _unmarshal_ctx *ctx, struct lib9p_msg_Twalk *out) { memset(out, 0, sizeof(*out)); unmarshal_4(ctx, &out->fid); unmarshal_4(ctx, &out->newfid); unmarshal_2(ctx, &out->nwname); out->wname = ctx->extra; ctx->extra += sizeof(out->wname[0]) * out->nwname; for (typeof(out->nwname) i = 0; i < out->nwname; i++) unmarshal_s(ctx, &out->wname[i]); } static FLATTEN void unmarshal_Rwalk(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rwalk *out) { memset(out, 0, sizeof(*out)); unmarshal_2(ctx, &out->nwqid); out->wqid = ctx->extra; ctx->extra += sizeof(out->wqid[0]) * out->nwqid; for (typeof(out->nwqid) i = 0; i < out->nwqid; i++) unmarshal_qid(ctx, &out->wqid[i]); } static FLATTEN void unmarshal_Topen(struct _unmarshal_ctx *ctx, struct lib9p_msg_Topen *out) { memset(out, 0, sizeof(*out)); unmarshal_4(ctx, &out->fid); unmarshal_o(ctx, &out->mode); } static FLATTEN void unmarshal_Ropen(struct _unmarshal_ctx *ctx, struct lib9p_msg_Ropen *out) { memset(out, 0, sizeof(*out)); unmarshal_qid(ctx, &out->qid); unmarshal_4(ctx, &out->iounit); } static FLATTEN void unmarshal_Tcreate(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tcreate *out) { memset(out, 0, sizeof(*out)); unmarshal_4(ctx, &out->fid); unmarshal_s(ctx, &out->name); unmarshal_dm(ctx, &out->perm); unmarshal_o(ctx, &out->mode); } static FLATTEN void unmarshal_Rcreate(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rcreate *out) { memset(out, 0, sizeof(*out)); unmarshal_qid(ctx, &out->qid); unmarshal_4(ctx, &out->iounit); } static FLATTEN void unmarshal_Tread(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tread *out) { memset(out, 0, sizeof(*out)); unmarshal_4(ctx, &out->fid); unmarshal_8(ctx, &out->offset); unmarshal_4(ctx, &out->count); } static FLATTEN void unmarshal_Rread(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rread *out) { memset(out, 0, sizeof(*out)); unmarshal_d(ctx, &out->data); } static FLATTEN void unmarshal_Twrite(struct _unmarshal_ctx *ctx, struct lib9p_msg_Twrite *out) { memset(out, 0, sizeof(*out)); unmarshal_4(ctx, &out->fid); unmarshal_8(ctx, &out->offset); unmarshal_d(ctx, &out->data); } static FLATTEN void unmarshal_Rwrite(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rwrite *out) { memset(out, 0, sizeof(*out)); unmarshal_4(ctx, &out->count); } static FLATTEN void unmarshal_Tclunk(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tclunk *out) { memset(out, 0, sizeof(*out)); unmarshal_4(ctx, &out->fid); } static FLATTEN void unmarshal_Rclunk(struct _unmarshal_ctx *UNUSED(ctx), struct lib9p_msg_Rclunk *out) { memset(out, 0, sizeof(*out)); } static FLATTEN void unmarshal_Tremove(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tremove *out) { memset(out, 0, sizeof(*out)); unmarshal_4(ctx, &out->fid); } static FLATTEN void unmarshal_Rremove(struct _unmarshal_ctx *UNUSED(ctx), struct lib9p_msg_Rremove *out) { memset(out, 0, sizeof(*out)); } static FLATTEN void unmarshal_Tstat(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tstat *out) { memset(out, 0, sizeof(*out)); unmarshal_4(ctx, &out->fid); } static FLATTEN void unmarshal_Rstat(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rstat *out) { memset(out, 0, sizeof(*out)); unmarshal_stat(ctx, &out->stat); } static FLATTEN void unmarshal_Twstat(struct _unmarshal_ctx *ctx, struct lib9p_msg_Twstat *out) { memset(out, 0, sizeof(*out)); unmarshal_4(ctx, &out->fid); unmarshal_stat(ctx, &out->stat); } static FLATTEN void unmarshal_Rwstat(struct _unmarshal_ctx *UNUSED(ctx), struct lib9p_msg_Rwstat *out) { memset(out, 0, sizeof(*out)); } static FLATTEN void unmarshal_Tsession(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tsession *out) { memset(out, 0, sizeof(*out)); unmarshal_8(ctx, &out->key); } static FLATTEN void unmarshal_Rsession(struct _unmarshal_ctx *UNUSED(ctx), struct lib9p_msg_Rsession *out) { memset(out, 0, sizeof(*out)); } static FLATTEN void unmarshal_Tsread(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tsread *out) { memset(out, 0, sizeof(*out)); unmarshal_4(ctx, &out->fid); unmarshal_2(ctx, &out->nwname); out->wname = ctx->extra; ctx->extra += sizeof(out->wname[0]) * out->nwname; for (typeof(out->nwname) i = 0; i < out->nwname; i++) unmarshal_s(ctx, &out->wname[i]); } static FLATTEN void unmarshal_Rsread(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rsread *out) { memset(out, 0, sizeof(*out)); unmarshal_d(ctx, &out->data); } static FLATTEN void unmarshal_Tswrite(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tswrite *out) { memset(out, 0, sizeof(*out)); unmarshal_4(ctx, &out->fid); unmarshal_2(ctx, &out->nwname); out->wname = ctx->extra; ctx->extra += sizeof(out->wname[0]) * out->nwname; for (typeof(out->nwname) i = 0; i < out->nwname; i++) unmarshal_s(ctx, &out->wname[i]); unmarshal_d(ctx, &out->data); } static FLATTEN void unmarshal_Rswrite(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rswrite *out) { memset(out, 0, sizeof(*out)); unmarshal_4(ctx, &out->count); } /* marshal_* ******************************************************************/ static ALWAYS_INLINE bool _marshal_too_large(struct _marshal_ctx *ctx) { lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s too large to marshal into %s limit (limit=%"PRIu32")", (ctx->net_bytes[4] % 2 == 0) ? "T-message" : "R-message", ctx->ctx->version ? "negotiated" : ((ctx->net_bytes[4] % 2 == 0) ? "client" : "server"), ctx->ctx->max_msg_size); return true; } static ALWAYS_INLINE bool marshal_1(struct _marshal_ctx *ctx, uint8_t *val) { if (ctx->net_offset + 1 > ctx->ctx->max_msg_size) return _marshal_too_large(ctx); ctx->net_bytes[ctx->net_offset] = *val; ctx->net_offset += 1; return false; } static ALWAYS_INLINE bool marshal_2(struct _marshal_ctx *ctx, uint16_t *val) { if (ctx->net_offset + 2 > ctx->ctx->max_msg_size) return _marshal_too_large(ctx); encode_u16le(*val, &ctx->net_bytes[ctx->net_offset]); ctx->net_offset += 2; return false; } static ALWAYS_INLINE bool marshal_4(struct _marshal_ctx *ctx, uint32_t *val) { if (ctx->net_offset + 4 > ctx->ctx->max_msg_size) return true; encode_u32le(*val, &ctx->net_bytes[ctx->net_offset]); ctx->net_offset += 4; return false; } static ALWAYS_INLINE bool marshal_8(struct _marshal_ctx *ctx, uint64_t *val) { if (ctx->net_offset + 8 > ctx->ctx->max_msg_size) return true; encode_u64le(*val, &ctx->net_bytes[ctx->net_offset]); ctx->net_offset += 8; return false; } static ALWAYS_INLINE bool marshal_d(struct _marshal_ctx *ctx, struct lib9p_d *val) { return marshal_4(ctx, &val->len) || ({ bool err = false; for (typeof(val->len) i = 0; i < val->len && !err; i++) err = marshal_1(ctx, (uint8_t *)&val->dat[i]); err; }); } static ALWAYS_INLINE bool marshal_s(struct _marshal_ctx *ctx, struct lib9p_s *val) { return marshal_2(ctx, &val->len) || ({ bool err = false; for (typeof(val->len) i = 0; i < val->len && !err; i++) err = marshal_1(ctx, (uint8_t *)&val->utf8[i]); err; }); } static ALWAYS_INLINE bool marshal_dm(struct _marshal_ctx *ctx, lib9p_dm_t *val) { return marshal_4(ctx, (uint32_t *)val); } static ALWAYS_INLINE bool marshal_qt(struct _marshal_ctx *ctx, lib9p_qt_t *val) { return marshal_1(ctx, (uint8_t *)val); } static ALWAYS_INLINE bool marshal_qid(struct _marshal_ctx *ctx, struct lib9p_qid *val) { return marshal_qt(ctx, &val->type) || marshal_4(ctx, &val->vers) || marshal_8(ctx, &val->path); } static ALWAYS_INLINE bool marshal_stat(struct _marshal_ctx *ctx, struct lib9p_stat *val) { uint32_t size_offset = ctx->net_offset; return (ctx->net_offset + 2 > ctx->ctx->max_msg_size ? _marshal_too_large(ctx) : ({ ctx->net_offset += 2; false; })) || marshal_2(ctx, &val->kern_type) || marshal_4(ctx, &val->kern_dev) || marshal_qid(ctx, &val->file_qid) || marshal_dm(ctx, &val->file_mode) || marshal_4(ctx, &val->file_atime) || marshal_4(ctx, &val->file_mtime) || marshal_8(ctx, &val->file_size) || marshal_s(ctx, &val->file_name) || marshal_s(ctx, &val->file_owner_uid) || marshal_s(ctx, &val->file_owner_gid) || marshal_s(ctx, &val->file_last_modified_uid) || ( (ctx->ctx->version==LIB9P_VER_9P2000_u) && marshal_s(ctx, &val->file_extension) ) || ( (ctx->ctx->version==LIB9P_VER_9P2000_u) && marshal_4(ctx, &val->file_owner_n_uid) ) || ( (ctx->ctx->version==LIB9P_VER_9P2000_u) && marshal_4(ctx, &val->file_owner_n_gid) ) || ( (ctx->ctx->version==LIB9P_VER_9P2000_u) && marshal_4(ctx, &val->file_last_modified_n_uid) ) || ((ctx->net_offset - size_offset > UINT16_MAX) ? lib9p_error(ctx->ctx, LINUX_ERANGE, "stat object too large") : ({ encode_u16le((uint16_t)(ctx->net_offset - size_offset), &ctx->net_bytes[size_offset]); false; })); } static ALWAYS_INLINE bool marshal_o(struct _marshal_ctx *ctx, lib9p_o_t *val) { return marshal_1(ctx, (uint8_t *)val); } static FLATTEN bool marshal_Tversion(struct _marshal_ctx *ctx, struct lib9p_msg_Tversion *val) { return marshal_4(ctx, &val->max_msg_size) || marshal_s(ctx, &val->version); } static FLATTEN bool marshal_Rversion(struct _marshal_ctx *ctx, struct lib9p_msg_Rversion *val) { return marshal_4(ctx, &val->max_msg_size) || marshal_s(ctx, &val->version); } static FLATTEN bool marshal_Tauth(struct _marshal_ctx *ctx, struct lib9p_msg_Tauth *val) { return marshal_4(ctx, &val->afid) || marshal_s(ctx, &val->uname) || marshal_s(ctx, &val->aname) || ( (ctx->ctx->version==LIB9P_VER_9P2000_u) && marshal_4(ctx, &val->n_uname) ); } static FLATTEN bool marshal_Rauth(struct _marshal_ctx *ctx, struct lib9p_msg_Rauth *val) { return marshal_qid(ctx, &val->aqid); } static FLATTEN bool marshal_Tattach(struct _marshal_ctx *ctx, struct lib9p_msg_Tattach *val) { return marshal_4(ctx, &val->fid) || marshal_4(ctx, &val->afid) || marshal_s(ctx, &val->uname) || marshal_s(ctx, &val->aname) || ( (ctx->ctx->version==LIB9P_VER_9P2000_u) && marshal_4(ctx, &val->n_uname) ); } static FLATTEN bool marshal_Rattach(struct _marshal_ctx *ctx, struct lib9p_msg_Rattach *val) { return marshal_qid(ctx, &val->qid); } static FLATTEN bool marshal_Rerror(struct _marshal_ctx *ctx, struct lib9p_msg_Rerror *val) { return marshal_s(ctx, &val->ename) || ( (ctx->ctx->version==LIB9P_VER_9P2000_u) && marshal_4(ctx, &val->errno) ); } static FLATTEN bool marshal_Tflush(struct _marshal_ctx *ctx, struct lib9p_msg_Tflush *val) { return marshal_2(ctx, &val->oldtag); } static FLATTEN bool marshal_Rflush(struct _marshal_ctx *UNUSED(ctx), struct lib9p_msg_Rflush *UNUSED(val)) { return false; } static FLATTEN bool marshal_Twalk(struct _marshal_ctx *ctx, struct lib9p_msg_Twalk *val) { return marshal_4(ctx, &val->fid) || marshal_4(ctx, &val->newfid) || marshal_2(ctx, &val->nwname) || ({ bool err = false; for (typeof(val->nwname) i = 0; i < val->nwname && !err; i++) err = marshal_s(ctx, &val->wname[i]); err; }); } static FLATTEN bool marshal_Rwalk(struct _marshal_ctx *ctx, struct lib9p_msg_Rwalk *val) { return marshal_2(ctx, &val->nwqid) || ({ bool err = false; for (typeof(val->nwqid) i = 0; i < val->nwqid && !err; i++) err = marshal_qid(ctx, &val->wqid[i]); err; }); } static FLATTEN bool marshal_Topen(struct _marshal_ctx *ctx, struct lib9p_msg_Topen *val) { return marshal_4(ctx, &val->fid) || marshal_o(ctx, &val->mode); } static FLATTEN bool marshal_Ropen(struct _marshal_ctx *ctx, struct lib9p_msg_Ropen *val) { return marshal_qid(ctx, &val->qid) || marshal_4(ctx, &val->iounit); } static FLATTEN bool marshal_Tcreate(struct _marshal_ctx *ctx, struct lib9p_msg_Tcreate *val) { return marshal_4(ctx, &val->fid) || marshal_s(ctx, &val->name) || marshal_dm(ctx, &val->perm) || marshal_o(ctx, &val->mode); } static FLATTEN bool marshal_Rcreate(struct _marshal_ctx *ctx, struct lib9p_msg_Rcreate *val) { return marshal_qid(ctx, &val->qid) || marshal_4(ctx, &val->iounit); } static FLATTEN bool marshal_Tread(struct _marshal_ctx *ctx, struct lib9p_msg_Tread *val) { return marshal_4(ctx, &val->fid) || marshal_8(ctx, &val->offset) || marshal_4(ctx, &val->count); } static FLATTEN bool marshal_Rread(struct _marshal_ctx *ctx, struct lib9p_msg_Rread *val) { return marshal_d(ctx, &val->data); } static FLATTEN bool marshal_Twrite(struct _marshal_ctx *ctx, struct lib9p_msg_Twrite *val) { return marshal_4(ctx, &val->fid) || marshal_8(ctx, &val->offset) || marshal_d(ctx, &val->data); } static FLATTEN bool marshal_Rwrite(struct _marshal_ctx *ctx, struct lib9p_msg_Rwrite *val) { return marshal_4(ctx, &val->count); } static FLATTEN bool marshal_Tclunk(struct _marshal_ctx *ctx, struct lib9p_msg_Tclunk *val) { return marshal_4(ctx, &val->fid); } static FLATTEN bool marshal_Rclunk(struct _marshal_ctx *UNUSED(ctx), struct lib9p_msg_Rclunk *UNUSED(val)) { return false; } static FLATTEN bool marshal_Tremove(struct _marshal_ctx *ctx, struct lib9p_msg_Tremove *val) { return marshal_4(ctx, &val->fid); } static FLATTEN bool marshal_Rremove(struct _marshal_ctx *UNUSED(ctx), struct lib9p_msg_Rremove *UNUSED(val)) { return false; } static FLATTEN bool marshal_Tstat(struct _marshal_ctx *ctx, struct lib9p_msg_Tstat *val) { return marshal_4(ctx, &val->fid); } static FLATTEN bool marshal_Rstat(struct _marshal_ctx *ctx, struct lib9p_msg_Rstat *val) { return marshal_stat(ctx, &val->stat); } static FLATTEN bool marshal_Twstat(struct _marshal_ctx *ctx, struct lib9p_msg_Twstat *val) { return marshal_4(ctx, &val->fid) || marshal_stat(ctx, &val->stat); } static FLATTEN bool marshal_Rwstat(struct _marshal_ctx *UNUSED(ctx), struct lib9p_msg_Rwstat *UNUSED(val)) { return false; } static FLATTEN bool marshal_Tsession(struct _marshal_ctx *ctx, struct lib9p_msg_Tsession *val) { return marshal_8(ctx, &val->key); } static FLATTEN bool marshal_Rsession(struct _marshal_ctx *UNUSED(ctx), struct lib9p_msg_Rsession *UNUSED(val)) { return false; } static FLATTEN bool marshal_Tsread(struct _marshal_ctx *ctx, struct lib9p_msg_Tsread *val) { return marshal_4(ctx, &val->fid) || marshal_2(ctx, &val->nwname) || ({ bool err = false; for (typeof(val->nwname) i = 0; i < val->nwname && !err; i++) err = marshal_s(ctx, &val->wname[i]); err; }); } static FLATTEN bool marshal_Rsread(struct _marshal_ctx *ctx, struct lib9p_msg_Rsread *val) { return marshal_d(ctx, &val->data); } static FLATTEN bool marshal_Tswrite(struct _marshal_ctx *ctx, struct lib9p_msg_Tswrite *val) { return marshal_4(ctx, &val->fid) || marshal_2(ctx, &val->nwname) || ({ bool err = false; for (typeof(val->nwname) i = 0; i < val->nwname && !err; i++) err = marshal_s(ctx, &val->wname[i]); err; }) || marshal_d(ctx, &val->data); } static FLATTEN bool marshal_Rswrite(struct _marshal_ctx *ctx, struct lib9p_msg_Rswrite *val) { return marshal_4(ctx, &val->count); } /* vtables ********************************************************************/ #define _MSG(typ) [LIB9P_TYP_##typ] = { \ .basesize = sizeof(struct lib9p_msg_##typ), \ .validate = validate_##typ, \ .unmarshal = (_unmarshal_fn_t)unmarshal_##typ, \ .marshal = (_marshal_fn_t)marshal_##typ, \ } struct _vtable_version _lib9p_vtables[LIB9P_VER_NUM] = { [LIB9P_VER_unknown] = { .msgs = { _MSG(Tversion), _MSG(Rversion), _MSG(Rerror), }}, [LIB9P_VER_9P2000] = { .msgs = { _MSG(Tversion), _MSG(Rversion), _MSG(Tauth), _MSG(Rauth), _MSG(Tattach), _MSG(Rattach), _MSG(Rerror), _MSG(Tflush), _MSG(Rflush), _MSG(Twalk), _MSG(Rwalk), _MSG(Topen), _MSG(Ropen), _MSG(Tcreate), _MSG(Rcreate), _MSG(Tread), _MSG(Rread), _MSG(Twrite), _MSG(Rwrite), _MSG(Tclunk), _MSG(Rclunk), _MSG(Tremove), _MSG(Rremove), _MSG(Tstat), _MSG(Rstat), _MSG(Twstat), _MSG(Rwstat), }}, [LIB9P_VER_9P2000_e] = { .msgs = { _MSG(Tversion), _MSG(Rversion), _MSG(Tauth), _MSG(Rauth), _MSG(Tattach), _MSG(Rattach), _MSG(Rerror), _MSG(Tflush), _MSG(Rflush), _MSG(Twalk), _MSG(Rwalk), _MSG(Topen), _MSG(Ropen), _MSG(Tcreate), _MSG(Rcreate), _MSG(Tread), _MSG(Rread), _MSG(Twrite), _MSG(Rwrite), _MSG(Tclunk), _MSG(Rclunk), _MSG(Tremove), _MSG(Rremove), _MSG(Tstat), _MSG(Rstat), _MSG(Twstat), _MSG(Rwstat), _MSG(Tsession), _MSG(Rsession), _MSG(Tsread), _MSG(Rsread), _MSG(Tswrite), _MSG(Rswrite), }}, [LIB9P_VER_9P2000_u] = { .msgs = { _MSG(Tversion), _MSG(Rversion), _MSG(Tauth), _MSG(Rauth), _MSG(Tattach), _MSG(Rattach), _MSG(Rerror), _MSG(Tflush), _MSG(Rflush), _MSG(Twalk), _MSG(Rwalk), _MSG(Topen), _MSG(Ropen), _MSG(Tcreate), _MSG(Rcreate), _MSG(Tread), _MSG(Rread), _MSG(Twrite), _MSG(Rwrite), _MSG(Tclunk), _MSG(Rclunk), _MSG(Tremove), _MSG(Rremove), _MSG(Tstat), _MSG(Rstat), _MSG(Twstat), _MSG(Rwstat), }}, };