Beispiel #1
0
u_char *
mac_compute(Mac *mac, u_int32_t seqno, u_char *data, int datalen)
{
	static u_char m[EVP_MAX_MD_SIZE];
	u_char b[4], nonce[8];

	if (mac->mac_len > sizeof(m))
		fatal("mac_compute: mac too long %u %lu",
		    mac->mac_len, (u_long)sizeof(m));

	switch (mac->type) {
	case SSH_EVP:
		put_u32(b, seqno);
		/* reset HMAC context */
		HMAC_Init(&mac->evp_ctx, NULL, 0, NULL);
		HMAC_Update(&mac->evp_ctx, b, sizeof(b));
		HMAC_Update(&mac->evp_ctx, data, datalen);
		HMAC_Final(&mac->evp_ctx, m, NULL);
		break;
	case SSH_UMAC:
		put_u64(nonce, seqno);
		umac_update(mac->umac_ctx, data, datalen);
		umac_final(mac->umac_ctx, m, nonce);
		break;
	case SSH_UMAC128:
		put_u64(nonce, seqno);
		umac128_update(mac->umac_ctx, data, datalen);
		umac128_final(mac->umac_ctx, m, nonce);
		break;
	default:
		fatal("mac_compute: unknown MAC type");
	}
	return (m);
}
Beispiel #2
0
int send_cmd_hdd_file_send_with_offset(libusb_device_handle* fd, __u8 dir, char *path, __u64 offset)
{
    struct tf_packet req;
    __u16 packetSize, pad;
    int pathLen = strlen(path) + 1;
	trace(3, printf("send_cmd_hdd_file_send_with_offset:  %s  [%ld]\n",path,offset));
    if((PACKET_HEAD_SIZE + 1 + 2 + pathLen) >= MAXIMUM_PACKET_SIZE)
    {
        fprintf(stdout, "ERROR: Path is too long.\n");
        return -1;
    }

    packetSize = PACKET_HEAD_SIZE + 1 + 2 + pathLen   +8;
	pad =  ((packetSize + 1) & ~1 ) - packetSize;
	//printf("Packet padding: %d\n",pad);
	pad =  0;//((packetSize + 1) & ~1 ) - packetSize;
	//printf("Packet padding: %d\n",pad);



    packetSize +=pad;
    put_u16(&req.length, packetSize);
    put_u32(&req.cmd, CMD_HDD_FILE_SEND);
    req.data[0] = dir;
    put_u16(&req.data[1], (__u16) pathLen);
    strcpy((char *) &req.data[3], path);
	put_u64( &req.data[3+pathLen+pad],offset);
    return send_tf_packet(fd, &req);
}
Beispiel #3
0
static
long lttng_metadata_ring_buffer_compat_ioctl(struct file *filp,
		unsigned int cmd, unsigned long arg)
{
	int ret;
	struct lttng_metadata_stream *stream = filp->private_data;
	struct lib_ring_buffer *buf = stream->priv;

	switch (cmd) {
	case RING_BUFFER_GET_NEXT_SUBBUF:
	{
		struct lttng_metadata_stream *stream = filp->private_data;
		struct lib_ring_buffer *buf = stream->priv;
		struct channel *chan = buf->backend.chan;

		ret = lttng_metadata_output_channel(stream, chan);
		if (ret > 0) {
			lib_ring_buffer_switch_slow(buf, SWITCH_ACTIVE);
			ret = 0;
		} else if (ret < 0)
			goto err;
		break;
	}
	case RING_BUFFER_GET_SUBBUF:
	{
		/*
		 * Random access is not allowed for metadata channel.
		 */
		return -ENOSYS;
	}
	default:
		break;
	}
	/* PUT_SUBBUF is the one from lib ring buffer, unmodified. */

	/* Performing lib ring buffer ioctl after our own. */
	ret = lib_ring_buffer_compat_ioctl(filp, cmd, arg, buf);
	if (ret < 0)
		goto err;

	switch (cmd) {
	case RING_BUFFER_PUT_NEXT_SUBBUF:
	{
		lttng_metadata_ring_buffer_ioctl_put_next_subbuf(filp,
				cmd, arg);
		break;
	}
	case RING_BUFFER_GET_METADATA_VERSION:
	{
		struct lttng_metadata_stream *stream = filp->private_data;

		return put_u64(stream->version, arg);
	}
	default:
		break;
	}
err:
	return ret;
}
Beispiel #4
0
void
buffer_put_int64(Buffer *buffer, u_int64_t value)
{
	char buf[8];

	put_u64(buf, value);
	buffer_append(buffer, buf, 8);
}
Beispiel #5
0
u_char *
mac_compute(Mac *mac, u_int32_t seqno, u_char *data, int datalen)
{
	static union {
		u_char m[EVP_MAX_MD_SIZE];
		u_int64_t for_align;
	} u;
	u_char b[4];
#ifdef UMAC_HAS_BEEN_UNBROKEN
	u_char nonce[8];
#endif

	if (mac->mac_len > sizeof(u))
		fatal("mac_compute: mac too long %u %lu",
		    mac->mac_len, (u_long)sizeof(u));

	switch (mac->type) {
	case SSH_EVP:
		put_u32(b, seqno);
		/* reset HMAC context */
		HMAC_Init(&mac->evp_ctx, NULL, 0, NULL);
		HMAC_Update(&mac->evp_ctx, b, sizeof(b));
		HMAC_Update(&mac->evp_ctx, data, datalen);
		HMAC_Final(&mac->evp_ctx, u.m, NULL);
		break;
#ifdef UMAC_HAS_BEEN_UNBROKEN
	case SSH_UMAC:
		put_u64(nonce, seqno);
		umac_update(mac->umac_ctx, data, datalen);
		umac_final(mac->umac_ctx, u.m, nonce);
		break;
	case SSH_UMAC128:
		put_u64(nonce, seqno);
		umac128_update(mac->umac_ctx, data, datalen);
		umac128_final(mac->umac_ctx, u.m, nonce);
		break;
#endif
	default:
		fatal("mac_compute: unknown MAC type");
	}
	return (u.m);
}
Beispiel #6
0
u_char *
mac_compute(Mac *mac, u_int32_t seqno, u_char *data, int datalen)
{
	static union {
		u_char m[EVP_MAX_MD_SIZE];
		u_int64_t for_align;
	} u;
	u_char b[4];
	u_char nonce[8];

	if (mac->mac_len > sizeof(u))
		fatal("mac_compute: mac too long %u %zu",
		    mac->mac_len, sizeof(u));

	switch (mac->type) {
	case SSH_DIGEST:
		put_u32(b, seqno);
		/* reset HMAC context */
		if (ssh_hmac_init(mac->hmac_ctx, NULL, 0) < 0 ||
		    ssh_hmac_update(mac->hmac_ctx, b, sizeof(b)) < 0 ||
		    ssh_hmac_update(mac->hmac_ctx, data, datalen) < 0 ||
		    ssh_hmac_final(mac->hmac_ctx, u.m, sizeof(u.m)) < 0)
			fatal("ssh_hmac failed");
		break;
	case SSH_UMAC:
		put_u64(nonce, seqno);
		umac_update(mac->umac_ctx, data, datalen);
		umac_final(mac->umac_ctx, u.m, nonce);
		break;
	case SSH_UMAC128:
		put_u64(nonce, seqno);
		umac128_update(mac->umac_ctx, data, datalen);
		umac128_final(mac->umac_ctx, u.m, nonce);
		break;
	default:
		fatal("mac_compute: unknown MAC type");
	}
	return (u.m);
}
/* Decrypt and extract the encrypted packet length */
int
chachapoly_get_length(struct chachapoly_ctx *ctx,
    u_int *plenp, u_int seqnr, const u_char *cp, u_int len)
{
    u_char buf[4], seqbuf[8];

    if (len < 4)
        return -1; /* Insufficient length */
    put_u64(seqbuf, seqnr);
    //chacha_ivsetup(&ctx->header_ctx, seqbuf, NULL);
    //chacha_encrypt_bytes(&ctx->header_ctx, cp, buf, 4);
    *plenp = get_u32(buf);
    return 0;
}
/*
 * chachapoly_crypt() operates as following:
 * En/decrypt with header key 'aadlen' bytes from 'src', storing result
 * to 'dest'. The ciphertext here is treated as additional authenticated
 * data for MAC calculation.
 * En/decrypt 'len' bytes at offset 'aadlen' from 'src' to 'dest'. Use
 * POLY1305_TAGLEN bytes at offset 'len'+'aadlen' as the authentication
 * tag. This tag is written on encryption and verified on decryption.
 */
int
chachapoly_crypt(struct chachapoly_ctx *ctx, u_int seqnr, u_char *dest,
    const u_char *src, u_int len, u_int aadlen, u_int authlen, int do_encrypt)
{
	u_char seqbuf[8];
	const u_char one[8] = { 1, 0, 0, 0, 0, 0, 0, 0 }; /* NB little-endian */
	u_char expected_tag[POLY1305_TAGLEN], poly_key[POLY1305_KEYLEN];
	int r = -1;

	/*
	 * Run ChaCha20 once to generate the Poly1305 key. The IV is the
	 * packet sequence number.
	 */
	bzero(poly_key, sizeof(poly_key));
	put_u64(seqbuf, seqnr);
	chacha_ivsetup(&ctx->main_ctx, seqbuf, NULL);
	chacha_encrypt_bytes(&ctx->main_ctx,
	    poly_key, poly_key, sizeof(poly_key));
	/* Set Chacha's block counter to 1 */
	chacha_ivsetup(&ctx->main_ctx, seqbuf, one);

	/* If decrypting, check tag before anything else */
	if (!do_encrypt) {
		const u_char *tag = src + aadlen + len;

		poly1305_auth(expected_tag, src, aadlen + len, poly_key);
		if (timingsafe_bcmp(expected_tag, tag, POLY1305_TAGLEN) != 0)
			goto out;
	}
	/* Crypt additional data */
	if (aadlen) {
		chacha_ivsetup(&ctx->header_ctx, seqbuf, NULL);
		chacha_encrypt_bytes(&ctx->header_ctx, src, dest, aadlen);
	}
	chacha_encrypt_bytes(&ctx->main_ctx, src + aadlen,
	    dest + aadlen, len);

	/* If encrypting, calculate and append tag */
	if (do_encrypt) {
		poly1305_auth(dest + aadlen + len, dest, aadlen + len,
		    poly_key);
	}
	r = 0;

 out:
	bzero(expected_tag, sizeof(expected_tag));
	bzero(seqbuf, sizeof(seqbuf));
	bzero(poly_key, sizeof(poly_key));
	return r;
}
Beispiel #9
0
int
mac_compute(struct sshmac *mac, u_int32_t seqno, const u_char *data, int datalen,
    u_char *digest, size_t dlen)
{
	static union {
		u_char m[MAC_DIGEST_LEN_MAX];
		u_int64_t for_align;
	} u;
	u_char b[4], nonce[8];

	if (mac->mac_len > sizeof(u))
		return SSH_ERR_INTERNAL_ERROR;

	switch (mac->type) {
	case SSH_EVP:
		POKE_U32(b, seqno);
		/* reset HMAC context */
		if (HMAC_Init(&mac->evp_ctx, NULL, 0, NULL) != 1 ||
		    HMAC_Update(&mac->evp_ctx, b, sizeof(b)) != 1 ||
		    HMAC_Update(&mac->evp_ctx, data, datalen) != 1 ||
		    HMAC_Final(&mac->evp_ctx, u.m, NULL) != 1)
			return SSH_ERR_LIBCRYPTO_ERROR;
		break;
	case SSH_UMAC:
		POKE_U64(nonce, seqno);
		umac_update(mac->umac_ctx, data, datalen);
		umac_final(mac->umac_ctx, u.m, nonce);
		break;
	case SSH_UMAC128:
		put_u64(nonce, seqno);
		umac128_update(mac->umac_ctx, data, datalen);
		umac128_final(mac->umac_ctx, u.m, nonce);
		break;
	default:
		return SSH_ERR_INVALID_ARGUMENT;
	}
	if (digest != NULL) {
		if (dlen > mac->mac_len)
			dlen = mac->mac_len;
		memcpy(digest, u.m, dlen);
	}
	return 0;
}
Beispiel #10
0
static int
put_file_func (CameraFilesystem *fs, const char *folder, const char *filename, CameraFile *file,
	       void *data, GPContext *context)
{
	Camera *camera = data;

	/*
	 * Upload the file to the camera. Use gp_file_get_data_and_size etc.
	 */
	int result = -EPROTO;
	time_t startTime = time(NULL);
	enum {
		START,
		DATA,
		END,
		FINISHED
	} state;
	int src = -1;
	int r;
	int update = 0;
	struct stat srcStat;
	__u64 fileSize;
	__u64 byteCount = 0;
	const char *filename;
	char *path;
	struct tf_packet reply;

	if(0 != fstat(src, &srcStat))
	{
		gp_log (GP_LOG_ERROR, "topfield", "ERROR: Can not examine source file: %s\n",
			strerror(errno));
		result = errno;
		goto out;
	}

	fileSize = srcStat.st_size;
	if(fileSize == 0)
	{
		gp_log (GP_LOG_ERROR, "topfield", "ERROR: Source file is empty - not transfering.\n");
		result = -ENODATA;
		goto out;
	}

	path = get_path (camera, folder, filename);
	r = send_cmd_hdd_file_send(camera, PUT, path, context);
	if(r < 0)
		goto out;

	state = START;
	while(0 < get_tf_packet(camera, &reply, context)) {
		update = (update + 1) % 16;
		switch (get_u32(&reply.cmd)) {
		case SUCCESS:
			switch (state) {
			case START: {
				/* Send start */
				struct typefile *tf = (struct typefile *) packet.data;

				put_u16(&packet.length, PACKET_HEAD_SIZE + 114);
				put_u32(&packet.cmd, DATA_HDD_FILE_START);
				time_to_tfdt(srcStat.st_mtime, &tf->stamp);
				tf->filetype = 2;
				put_u64(&tf->size, srcStat.st_size);
				strncpy((char *) tf->name, path, 94);
				tf->name[94] = '\0';
				tf->unused = 0;
				tf->attrib = 0;
				gp_log (GP_LOG_DEBUG, "topfield", "%s: DATA_HDD_FILE_START\n", __func__);
				r = send_tf_packet(camera, &packet, context);
				if(r < 0)
				{
					gp_log (GP_LOG_ERROR, "topfield", "ERROR: Incomplete send.\n");
					goto out;
				}
				state = DATA;
				break;
			}

			case DATA: {
				int payloadSize = sizeof(packet.data) - 9;
				ssize_t w = read(src, &packet.data[8], payloadSize);

				/* Detect a Topfield protcol bug and prevent the sending of packets
				   that are a multiple of 512 bytes. */
				if((w > 4) && (((((PACKET_HEAD_SIZE + 8 + w) + 1) & ~1) % 0x200) == 0)) {
					lseek(src, -4, SEEK_CUR);
					w -= 4;
					payloadSize -= 4;
				}

				put_u16(&packet.length, PACKET_HEAD_SIZE + 8 + w);
				put_u32(&packet.cmd, DATA_HDD_FILE_DATA);
				put_u64(packet.data, byteCount);
				byteCount += w;

				/* Detect EOF and transition to END */
				if((w < 0) || (byteCount >= fileSize)) {
					state = END;
				}

				if(w > 0) {
					gp_log (GP_LOG_DEBUG, "topfield", "%s: DATA_HDD_FILE_DATA\n", __func__);
					r = send_tf_packet(camera, &packet, context);
					if(r < w) {
						gp_log (GP_LOG_ERROR, "topfield", "ERROR: Incomplete send.\n");
						goto out;
					}
				}

				if(!update && !quiet) {
					progressStats(fileSize, byteCount, startTime);
				}
				break;
			}

			case END:
				/* Send end */
				put_u16(&packet.length, PACKET_HEAD_SIZE);
				put_u32(&packet.cmd, DATA_HDD_FILE_END);
				gp_log (GP_LOG_DEBUG, "topfield", "%s: DATA_HDD_FILE_END\n", __func__);
				r = send_tf_packet(camera, &packet, context);
				if(r < 0) {
					gp_log (GP_LOG_ERROR, "topfield", "ERROR: Incomplete send.\n");
					goto out;
				}
				state = FINISHED;
				break;

			case FINISHED:
				result = 0;
				goto out;
				break;
			}
			break;

		case FAIL:
			gp_log (GP_LOG_ERROR, "topfield", "ERROR: Device reports %s\n", decode_error(&reply));
			goto out;
			break;

		default:
			gp_log (GP_LOG_ERROR, "topfield", "ERROR: Unhandled packet (%d)\n", get_u32(&reply.cmd));
			break;
		}
	}
	finalStats(byteCount, startTime);
out:
	close(src);
	return result;
}
Beispiel #11
0
int do_hdd_file_put(int fd, char *srcPath, char *dstPath)
{
    int result = -EPROTO;
    time_t startTime = time(NULL);
    enum
    {
        START,
        DATA,
        END,
        FINISHED
    } state;
    int src = -1;
    int r;
    int update = 0;
    struct stat64 srcStat;
    __u64 fileSize;
    __u64 byteCount = 0;

    trace(4, fprintf(stderr, "%s\n", __func__));

    src = open64(srcPath, O_RDONLY);
    if(src < 0)
    {
        fprintf(stderr, "ERROR: Can not open source file: %s\n",
                strerror(errno));
        return errno;
    }

    if(0 != fstat64(src, &srcStat))
    {
        fprintf(stderr, "ERROR: Can not examine source file: %s\n",
                strerror(errno));
        result = errno;
        goto out;
    }

    fileSize = srcStat.st_size;
    if(fileSize == 0)
    {
        fprintf(stderr, "ERROR: Source file is empty - not transfering.\n");
        result = -ENODATA;
        goto out;
    }

    r = send_cmd_hdd_file_send(fd, PUT, dstPath);
    if(r < 0)
    {
        goto out;
    }

    state = START;
    while(0 < get_tf_packet(fd, &reply))
    {
        update = (update + 1) % 16;
        switch (get_u32(&reply.cmd))
        {
            case SUCCESS:
                switch (state)
                {
                    case START:
                    {
                        /* Send start */
                        struct typefile *tf = (struct typefile *) packet.data;

                        put_u16(&packet.length, PACKET_HEAD_SIZE + 114);
                        put_u32(&packet.cmd, DATA_HDD_FILE_START);
                        time_to_tfdt(srcStat.st_mtime, &tf->stamp);
                        tf->filetype = 2;
                        put_u64(&tf->size, srcStat.st_size);
                        strncpy((char *) tf->name, dstPath, 94);
                        tf->name[94] = '\0';
                        tf->unused = 0;
                        tf->attrib = 0;
                        trace(3,
                              fprintf(stderr, "%s: DATA_HDD_FILE_START\n",
                                      __func__));
                        r = send_tf_packet(fd, &packet);
                        if(r < 0)
                        {
                            fprintf(stderr, "ERROR: Incomplete send.\n");
                            goto out;
                        }
                        state = DATA;
                        break;
                    }

                    case DATA:
                    {
                        int payloadSize = sizeof(packet.data) - 9;
                        ssize_t w = read(src, &packet.data[8], payloadSize);

                        /* Detect a Topfield protcol bug and prevent the sending of packets
                           that are a multiple of 512 bytes. */
                        if((w > 4)
                           &&
                           (((((PACKET_HEAD_SIZE + 8 + w) +
                               1) & ~1) % 0x200) == 0))
                        {
                            lseek64(src, -4, SEEK_CUR);
                            w -= 4;
                            payloadSize -= 4;
                        }

                        put_u16(&packet.length, PACKET_HEAD_SIZE + 8 + w);
                        put_u32(&packet.cmd, DATA_HDD_FILE_DATA);
                        put_u64(packet.data, byteCount);
                        byteCount += w;

                        /* Detect EOF and transition to END */
                        if((w < 0) || (byteCount >= fileSize))
                        {
                            state = END;
                        }

                        if(w > 0)
                        {
                            trace(3,
                                  fprintf(stderr, "%s: DATA_HDD_FILE_DATA\n",
                                          __func__));
                            r = send_tf_packet(fd, &packet);
                            if(r < w)
                            {
                                fprintf(stderr, "ERROR: Incomplete send.\n");
                                goto out;
                            }
                        }

                        if(!update && !quiet)
                        {
                            progressStats(fileSize, byteCount, startTime);
                        }
                        break;
                    }

                    case END:
                        /* Send end */
                        put_u16(&packet.length, PACKET_HEAD_SIZE);
                        put_u32(&packet.cmd, DATA_HDD_FILE_END);
                        trace(3,
                              fprintf(stderr, "%s: DATA_HDD_FILE_END\n",
                                      __func__));
                        r = send_tf_packet(fd, &packet);
                        if(r < 0)
                        {
                            fprintf(stderr, "ERROR: Incomplete send.\n");
                            goto out;
                        }
                        state = FINISHED;
                        break;

                    case FINISHED:
                        result = 0;
                        goto out;
                        break;
                }
                break;

            case FAIL:
                fprintf(stderr, "ERROR: Device reports %s\n",
                        decode_error(&reply));
                goto out;
                break;

            default:
                fprintf(stderr, "ERROR: Unhandled packet\n");
                break;
        }
    }
    finalStats(byteCount, startTime);

  out:
    close(src);
    return result;
}
Beispiel #12
0
static long lttng_stream_ring_buffer_compat_ioctl(struct file *filp,
		unsigned int cmd, unsigned long arg)
{
	struct lib_ring_buffer *buf = filp->private_data;
	struct channel *chan = buf->backend.chan;
	const struct lib_ring_buffer_config *config = &chan->backend.config;
	const struct lttng_channel_ops *ops = chan->backend.priv_ops;
	int ret;

	if (atomic_read(&chan->record_disabled))
		return -EIO;

	switch (cmd) {
	case LTTNG_RING_BUFFER_COMPAT_GET_TIMESTAMP_BEGIN:
	{
		uint64_t ts;

		ret = ops->timestamp_begin(config, buf, &ts);
		if (ret < 0)
			goto error;
		return put_u64(ts, arg);
	}
	case LTTNG_RING_BUFFER_COMPAT_GET_TIMESTAMP_END:
	{
		uint64_t ts;

		ret = ops->timestamp_end(config, buf, &ts);
		if (ret < 0)
			goto error;
		return put_u64(ts, arg);
	}
	case LTTNG_RING_BUFFER_COMPAT_GET_EVENTS_DISCARDED:
	{
		uint64_t ed;

		ret = ops->events_discarded(config, buf, &ed);
		if (ret < 0)
			goto error;
		return put_u64(ed, arg);
	}
	case LTTNG_RING_BUFFER_COMPAT_GET_CONTENT_SIZE:
	{
		uint64_t cs;

		ret = ops->content_size(config, buf, &cs);
		if (ret < 0)
			goto error;
		return put_u64(cs, arg);
	}
	case LTTNG_RING_BUFFER_COMPAT_GET_PACKET_SIZE:
	{
		uint64_t ps;

		ret = ops->packet_size(config, buf, &ps);
		if (ret < 0)
			goto error;
		return put_u64(ps, arg);
	}
	case LTTNG_RING_BUFFER_COMPAT_GET_STREAM_ID:
	{
		uint64_t si;

		ret = ops->stream_id(config, buf, &si);
		if (ret < 0)
			goto error;
		return put_u64(si, arg);
	}
	case LTTNG_RING_BUFFER_GET_CURRENT_TIMESTAMP:
	{
		uint64_t ts;

		ret = ops->current_timestamp(config, buf, &ts);
		if (ret < 0)
			goto error;
		return put_u64(ts, arg);
	}
	case LTTNG_RING_BUFFER_COMPAT_GET_SEQ_NUM:
	{
		uint64_t seq;

		ret = ops->sequence_number(config, buf, &seq);
		if (ret < 0)
			goto error;
		return put_u64(seq, arg);
	}
	case LTTNG_RING_BUFFER_COMPAT_INSTANCE_ID:
	{
		uint64_t id;

		ret = ops->instance_id(config, buf, &id);
		if (ret < 0)
			goto error;
		return put_u64(id, arg);
	}
	default:
		return lib_ring_buffer_file_operations.compat_ioctl(filp,
				cmd, arg);
	}

error:
	return -ENOSYS;
}
Beispiel #13
0
static
long lttng_metadata_ring_buffer_compat_ioctl(struct file *filp,
		unsigned int cmd, unsigned long arg)
{
	int ret;
	struct lttng_metadata_stream *stream = filp->private_data;
	struct lib_ring_buffer *buf = stream->priv;

	switch (cmd) {
	case RING_BUFFER_GET_NEXT_SUBBUF:
	{
		struct lttng_metadata_stream *stream = filp->private_data;
		struct lib_ring_buffer *buf = stream->priv;
		struct channel *chan = buf->backend.chan;

		ret = lttng_metadata_output_channel(stream, chan);
		if (ret > 0) {
			lib_ring_buffer_switch_slow(buf, SWITCH_ACTIVE);
			ret = 0;
		} else if (ret < 0)
			goto err;
		break;
	}
	case RING_BUFFER_GET_SUBBUF:
	{
		/*
		 * Random access is not allowed for metadata channel.
		 */
		return -ENOSYS;
	}
	case RING_BUFFER_FLUSH:
	{
		struct lttng_metadata_stream *stream = filp->private_data;
		struct lib_ring_buffer *buf = stream->priv;
		struct channel *chan = buf->backend.chan;

		/*
		 * Before doing the actual ring buffer flush, write up to one
		 * packet of metadata in the ring buffer.
		 */
		ret = lttng_metadata_output_channel(stream, chan);
		if (ret < 0)
			goto err;
		break;
	}
	case RING_BUFFER_GET_METADATA_VERSION:
	{
		struct lttng_metadata_stream *stream = filp->private_data;

		return put_u64(stream->version, arg);
	}
	case RING_BUFFER_SNAPSHOT:
	{
		/*
		 * Force the buffer to quiescent so the ring buffer
		 * don't attempt to perform a SWITCH_FLUSH, which would
		 * desynchronize the client accounting of the amount of
		 * data available in the buffer from the ring buffer
		 * view.
		 */
		buf->quiescent = true;
		break;
	}
	default:
		break;
	}
	/* PUT_SUBBUF is the one from lib ring buffer, unmodified. */

	/* Performing lib ring buffer ioctl after our own. */
	ret = lib_ring_buffer_compat_ioctl(filp, cmd, arg, buf);
	if (ret < 0)
		goto err;

	switch (cmd) {
	case RING_BUFFER_PUT_NEXT_SUBBUF:
	{
		lttng_metadata_ring_buffer_ioctl_put_next_subbuf(filp,
				cmd, arg);
		break;
	}
	default:
		break;
	}
err:
	return ret;
}