static struct pdu_wbuf* build_pdu_wbuf_msg_with_fd(struct pdu_wbuf* wbuf, int fd) { struct iovec* iov; union { struct cmsghdr chdr; unsigned char data[CMSG_SPACE(sizeof(fd))]; } cmsg; struct cmsghdr* chdr; assert(wbuf); iov = pdu_wbuf_tail(wbuf); iov->iov_base = wbuf->buf.raw; iov->iov_len = wbuf->off; memset(&wbuf->msg, 0, sizeof(wbuf->msg)); wbuf->msg.msg_iov = iov; wbuf->msg.msg_iovlen = 1; wbuf->msg.msg_control = iov + 1; wbuf->msg.msg_controllen = sizeof(cmsg); chdr = CMSG_FIRSTHDR(&wbuf->msg); chdr->cmsg_len = sizeof(fd); chdr->cmsg_level = SOL_SOCKET; chdr->cmsg_type = SCM_RIGHTS; *((int*)CMSG_DATA(chdr)) = fd; return wbuf; }
static struct pdu_wbuf* build_pdu_wbuf_msg(struct pdu_wbuf* wbuf) { struct iovec* iov; assert(wbuf); iov = pdu_wbuf_tail(wbuf); iov->iov_base = wbuf->buf.raw; iov->iov_len = wbuf->off; memset(&wbuf->msg, 0, sizeof(wbuf->msg)); wbuf->msg.msg_iov = iov; wbuf->msg.msg_iovlen = 1; return wbuf; }
static bt_status_t opcode_connect(const struct pdu* cmd) { long off; bt_bdaddr_t bd_addr; uint8_t type; uint8_t uuid[16]; uint16_t channel; uint8_t flags; struct pdu_wbuf* wbuf; struct ancillary_data* data; bt_status_t status; off = read_bt_bdaddr_t(cmd, 0, &bd_addr); if (off < 0) return BT_STATUS_PARM_INVALID; if (read_pdu_at(cmd, off, "CmsC", &type, uuid, sizeof(uuid), &channel, &flags) < 0) return BT_STATUS_PARM_INVALID; wbuf = create_pdu_wbuf(0, ALIGNMENT_PADDING + sizeof(*data), build_ancillary_data); if (!wbuf) return BT_STATUS_NOMEM; data = ceil_align(pdu_wbuf_tail(wbuf), ALIGNMENT_PADDING); status = bt_sock_connect(&bd_addr, type, uuid, channel, &data->sock_fd, flags); if (status != BT_STATUS_SUCCESS) goto err_bt_sock_listen; init_pdu(&wbuf->buf.pdu, cmd->service, cmd->opcode); send_pdu(wbuf); return BT_STATUS_SUCCESS; err_bt_sock_listen: cleanup_pdu_wbuf(wbuf); return status; }
static bt_status_t opcode_listen(const struct pdu* cmd) { uint8_t type; int8_t service_name[256]; uint8_t uuid[16]; uint16_t channel; uint8_t flags; struct pdu_wbuf* wbuf; struct ancillary_data* data; bt_status_t status; if (read_pdu_at(cmd, 0, "CmmSC", &type, service_name, (size_t)sizeof(service_name), uuid, (size_t)sizeof(uuid), &channel, &flags) < 0) return BT_STATUS_PARM_INVALID; wbuf = create_pdu_wbuf(0, ALIGNMENT_PADDING + sizeof(*data), build_ancillary_data); if (!wbuf) return BT_STATUS_NOMEM; data = ceil_align(pdu_wbuf_tail(wbuf), ALIGNMENT_PADDING); status = bt_sock_listen(type, (char*)service_name, uuid, channel, &data->sock_fd, flags); if (status != BT_STATUS_SUCCESS) goto err_bt_sock_listen; init_pdu(&wbuf->buf.pdu, cmd->service, cmd->opcode); send_pdu(wbuf); return BT_STATUS_SUCCESS; err_bt_sock_listen: cleanup_pdu_wbuf(wbuf); return status; }
static int build_ancillary_data(struct pdu_wbuf* wbuf, struct msghdr* msg) { struct ancillary_data* data; struct cmsghdr* chdr; assert(msg); data = ceil_align(pdu_wbuf_tail(wbuf), ALIGNMENT_PADDING); msg->msg_control = data->cmsgbuf; msg->msg_controllen = sizeof(data->cmsgbuf); chdr = CMSG_FIRSTHDR(msg); chdr->cmsg_len = CMSG_LEN(sizeof(data->sock_fd)); chdr->cmsg_level = SOL_SOCKET; chdr->cmsg_type = SCM_RIGHTS; memcpy(CMSG_DATA(chdr), &data->sock_fd, sizeof(data->sock_fd)); msg->msg_controllen = chdr->cmsg_len; return 0; }