📄 sdpd-request.c
字号:
* Clients could request a subset of attributes (by id) * from a service record, instead of the whole set. The * requested identifiers are present in the PDU form of * the request */static int extract_attrs(sdp_record_t *rec, sdp_list_t *seq, uint8_t dtd, sdp_buf_t *buf){ if (!rec) return SDP_INVALID_RECORD_HANDLE; if (seq) debug("Entries in attr seq : %d", sdp_list_len(seq)); else debug("NULL attribute descriptor"); debug("AttrDataType : %d", dtd); if (seq == NULL) { debug("Attribute sequence is NULL"); return 0; } if (dtd == SDP_UINT16) for (; seq; seq = seq->next) { uint16_t attr = bt_get_unaligned((uint16_t *)seq->data); sdp_data_t *a = (sdp_data_t *)sdp_data_get(rec, attr); if (a) sdp_append_to_pdu(buf, a); } else if (dtd == SDP_UINT32) { sdp_buf_t pdu; sdp_gen_record_pdu(rec, &pdu); for (; seq; seq = seq->next) { uint32_t range = bt_get_unaligned((uint32_t *)seq->data); uint16_t attr; uint16_t low = (0xffff0000 & range) >> 16; uint16_t high = 0x0000ffff & range; sdp_data_t *data; debug("attr range : 0x%x", range); debug("Low id : 0x%x", low); debug("High id : 0x%x", high); if (low == 0x0000 && high == 0xffff && pdu.data_size <= buf->buf_size) { /* copy it */ memcpy(buf->data, pdu.data, pdu.data_size); buf->data_size = pdu.data_size; break; } /* (else) sub-range of attributes */ for (attr = low; attr < high; attr++) { data = sdp_data_get(rec, attr); if (data) sdp_append_to_pdu(buf, data); } data = sdp_data_get(rec, high); if (data) sdp_append_to_pdu(buf, data); } free(pdu.data); } else { error("Unexpected data type : 0x%x", dtd); error("Expect uint16_t or uint32_t"); return SDP_INVALID_SYNTAX; } return 0;}/* * A request for the attributes of a service record. * First check if the service record (specified by * service record handle) exists, then call the attribute * streaming function */static int service_attr_req(sdp_req_t *req, sdp_buf_t *buf){ sdp_cont_state_t *cstate = NULL; uint8_t *pResponse = NULL; short cstate_size = 0; sdp_list_t *seq = NULL; uint8_t dtd = 0; int scanned = 0; int max_rsp_size; int status = 0, plen, mlen; uint8_t *pdata = req->buf + sizeof(sdp_pdu_hdr_t); uint32_t handle = ntohl(bt_get_unaligned((uint32_t *)pdata)); pdata += sizeof(uint32_t); max_rsp_size = ntohs(bt_get_unaligned((uint16_t *)pdata)); pdata += sizeof(uint16_t); /* extract the attribute list */ scanned = extract_des(pdata, req->len - sizeof(sdp_pdu_hdr_t), &seq, &dtd, SDP_TYPE_ANY); if (scanned == -1) { status = SDP_INVALID_SYNTAX; goto done; } pdata += scanned; plen = ntohs(((sdp_pdu_hdr_t *)(req->buf))->plen); mlen = scanned + sizeof(uint32_t) + sizeof(uint16_t) + 1; // ensure we don't read past buffer if (plen < mlen || plen != mlen + *(uint8_t *)pdata) { status = SDP_INVALID_SYNTAX; goto done; } /* * if continuation state exists, attempt * to get rsp remainder from cache, else send error */ cstate = sdp_cstate_get(pdata); debug("SvcRecHandle : 0x%x", handle); debug("max_rsp_size : %d", max_rsp_size); /* * Calculate Attribute size acording to MTU * We can send only (MTU - sizeof(sdp_pdu_hdr_t) - sizeof(sdp_cont_state_t)) */ max_rsp_size = MIN(max_rsp_size, req->mtu - sizeof(sdp_pdu_hdr_t) - sizeof(uint32_t) - SDP_CONT_STATE_SIZE - sizeof(uint16_t)); /* pull header for AttributeList byte count */ buf->data += sizeof(uint16_t); buf->buf_size -= sizeof(uint16_t); if (cstate) { sdp_buf_t *pCache = sdp_get_cached_rsp(cstate); debug("Obtained cached rsp : %p", pCache); if (pCache) { short sent = MIN(max_rsp_size, pCache->data_size - cstate->cStateValue.maxBytesSent); pResponse = pCache->data; memcpy(buf->data, pResponse + cstate->cStateValue.maxBytesSent, sent); buf->data_size += sent; cstate->cStateValue.maxBytesSent += sent; debug("Response size : %d sending now : %d bytes sent so far : %d", pCache->data_size, sent, cstate->cStateValue.maxBytesSent); if (cstate->cStateValue.maxBytesSent == pCache->data_size) cstate_size = sdp_set_cstate_pdu(buf, NULL); else cstate_size = sdp_set_cstate_pdu(buf, cstate); } else { status = SDP_INVALID_CSTATE; error("NULL cache buffer and non-NULL continuation state"); } } else { sdp_record_t *rec = sdp_record_find(handle); status = extract_attrs(rec, seq, dtd, buf); if (buf->data_size > max_rsp_size) { sdp_cont_state_t newState; memset((char *)&newState, 0, sizeof(sdp_cont_state_t)); newState.timestamp = sdp_cstate_alloc_buf(buf); /* * Reset the buffer size to the maximum expected and * set the sdp_cont_state_t */ debug("Creating continuation state of size : %d", buf->data_size); buf->data_size = max_rsp_size; newState.cStateValue.maxBytesSent = max_rsp_size; cstate_size = sdp_set_cstate_pdu(buf, &newState); } else { if (buf->data_size == 0) sdp_append_to_buf(buf, 0, 0); cstate_size = sdp_set_cstate_pdu(buf, NULL); } } // push header buf->data -= sizeof(uint16_t); buf->buf_size += sizeof(uint16_t);done: if (cstate) free(cstate); if (seq) sdp_list_free(seq, free); if (status) return status; /* set attribute list byte count */ bt_put_unaligned(htons(buf->data_size - cstate_size), (uint16_t *)buf->data); buf->data_size += sizeof(uint16_t); return 0;}/* * combined service search and attribute extraction */static int service_search_attr_req(sdp_req_t *req, sdp_buf_t *buf){ int status = 0, plen, totscanned; uint8_t *pdata, *pResponse = NULL; int scanned, max, rsp_count = 0; sdp_list_t *pattern = NULL, *seq = NULL, *svcList; sdp_cont_state_t *cstate = NULL; short cstate_size = 0; uint8_t dtd = 0; sdp_buf_t tmpbuf; tmpbuf.data = NULL; pdata = req->buf + sizeof(sdp_pdu_hdr_t); scanned = extract_des(pdata, req->len - sizeof(sdp_pdu_hdr_t), &pattern, &dtd, SDP_TYPE_UUID); if (scanned == -1) { status = SDP_INVALID_SYNTAX; goto done; } totscanned = scanned; debug("Bytes scanned: %d", scanned); pdata += scanned; max = ntohs(bt_get_unaligned((uint16_t *)pdata)); pdata += sizeof(uint16_t); debug("Max Attr expected: %d", max); /* extract the attribute list */ scanned = extract_des(pdata, req->len - sizeof(sdp_pdu_hdr_t), &seq, &dtd, SDP_TYPE_ANY); if (scanned == -1) { status = SDP_INVALID_SYNTAX; goto done; } pdata += scanned; totscanned += scanned + sizeof(uint16_t) + 1; plen = ntohs(((sdp_pdu_hdr_t *)(req->buf))->plen); if (plen < totscanned || plen != totscanned + *(uint8_t *)pdata) { status = SDP_INVALID_SYNTAX; goto done; } /* * if continuation state exists attempt * to get rsp remainder from cache, else send error */ cstate = sdp_cstate_get(pdata); // continuation information svcList = sdp_get_record_list(); tmpbuf.data = malloc(USHRT_MAX); tmpbuf.data_size = 0; tmpbuf.buf_size = USHRT_MAX; memset(tmpbuf.data, 0, USHRT_MAX); /* * Calculate Attribute size acording to MTU * We can send only (MTU - sizeof(sdp_pdu_hdr_t) - sizeof(sdp_cont_state_t)) */ max = MIN(max, req->mtu - sizeof(sdp_pdu_hdr_t) - SDP_CONT_STATE_SIZE - sizeof(uint16_t)); /* pull header for AttributeList byte count */ buf->data += sizeof(uint16_t); buf->buf_size -= sizeof(uint16_t); if (cstate == NULL) { /* no continuation state -> create new response */ sdp_list_t *p; for (p = svcList; p; p = p->next) { sdp_record_t *rec = (sdp_record_t *) p->data; if (sdp_match_uuid(pattern, rec->pattern) > 0 && sdp_check_access(rec->handle, &req->device)) { rsp_count++; status = extract_attrs(rec, seq, dtd, &tmpbuf); debug("Response count : %d", rsp_count); debug("Local PDU size : %d", tmpbuf.data_size); if (status) { debug("Extract attr from record returns err"); break; } if (buf->data_size + tmpbuf.data_size < buf->buf_size) { // to be sure no relocations sdp_append_to_buf(buf, tmpbuf.data, tmpbuf.data_size); tmpbuf.data_size = 0; memset(tmpbuf.data, 0, USHRT_MAX); } else { error("Relocation needed"); break; } debug("Net PDU size : %d", buf->data_size); } } if (buf->data_size > max) { sdp_cont_state_t newState; memset((char *)&newState, 0, sizeof(sdp_cont_state_t)); newState.timestamp = sdp_cstate_alloc_buf(buf); /* * Reset the buffer size to the maximum expected and * set the sdp_cont_state_t */ buf->data_size = max; newState.cStateValue.maxBytesSent = max; cstate_size = sdp_set_cstate_pdu(buf, &newState); } else cstate_size = sdp_set_cstate_pdu(buf, NULL); } else { /* continuation State exists -> get from cache */ sdp_buf_t *pCache = sdp_get_cached_rsp(cstate); if (pCache) { uint16_t sent = MIN(max, pCache->data_size - cstate->cStateValue.maxBytesSent); pResponse = pCache->data; memcpy(buf->data, pResponse + cstate->cStateValue.maxBytesSent, sent); buf->data_size += sent; cstate->cStateValue.maxBytesSent += sent; if (cstate->cStateValue.maxBytesSent == pCache->data_size) cstate_size = sdp_set_cstate_pdu(buf, NULL); else cstate_size = sdp_set_cstate_pdu(buf, cstate); } else { status = SDP_INVALID_CSTATE; debug("Non-null continuation state, but null cache buffer"); } } if (!rsp_count && !cstate) { // found nothing buf->data_size = 0; sdp_append_to_buf(buf, tmpbuf.data, tmpbuf.data_size); sdp_set_cstate_pdu(buf, NULL); } // push header buf->data -= sizeof(uint16_t); buf->buf_size += sizeof(uint16_t); if (!status) { /* set attribute list byte count */ bt_put_unaligned(htons(buf->data_size - cstate_size), (uint16_t *)buf->data); buf->data_size += sizeof(uint16_t); }done: if (cstate) free(cstate); if (tmpbuf.data) free(tmpbuf.data); if (pattern) sdp_list_free(pattern, free); if (seq) sdp_list_free(seq, free); return status;}/* * Top level request processor. Calls the appropriate processing * function based on request type. Handles service registration * client requests also. */static void process_request(sdp_req_t *req){ sdp_pdu_hdr_t *reqhdr = (sdp_pdu_hdr_t *)req->buf; sdp_pdu_hdr_t *rsphdr; sdp_buf_t rsp; uint8_t *buf = malloc(USHRT_MAX); int sent = 0; int status = SDP_INVALID_SYNTAX; memset(buf, 0, USHRT_MAX); rsp.data = buf + sizeof(sdp_pdu_hdr_t); rsp.data_size = 0; rsp.buf_size = USHRT_MAX - sizeof(sdp_pdu_hdr_t); rsphdr = (sdp_pdu_hdr_t *)buf; if (ntohs(reqhdr->plen) != req->len - sizeof(sdp_pdu_hdr_t)) { status = SDP_INVALID_PDU_SIZE; goto send_rsp; } switch (reqhdr->pdu_id) { case SDP_SVC_SEARCH_REQ: debug("Got a svc srch req"); status = service_search_req(req, &rsp); rsphdr->pdu_id = SDP_SVC_SEARCH_RSP; break; case SDP_SVC_ATTR_REQ: debug("Got a svc attr req"); status = service_attr_req(req, &rsp); rsphdr->pdu_id = SDP_SVC_ATTR_RSP; break; case SDP_SVC_SEARCH_ATTR_REQ: debug("Got a svc srch attr req"); status = service_search_attr_req(req, &rsp); rsphdr->pdu_id = SDP_SVC_SEARCH_ATTR_RSP; break; /* Following requests are allowed only for local connections */ case SDP_SVC_REGISTER_REQ: debug("Service register request"); if (req->local) { status = service_register_req(req, &rsp); rsphdr->pdu_id = SDP_SVC_REGISTER_RSP; } break; case SDP_SVC_UPDATE_REQ: debug("Service update request"); if (req->local) { status = service_update_req(req, &rsp); rsphdr->pdu_id = SDP_SVC_UPDATE_RSP; } break; case SDP_SVC_REMOVE_REQ: debug("Service removal request"); if (req->local) { status = service_remove_req(req, &rsp); rsphdr->pdu_id = SDP_SVC_REMOVE_RSP; } break; default: error("Unknown PDU ID : 0x%x received", reqhdr->pdu_id); status = SDP_INVALID_SYNTAX; break; }send_rsp: if (status) { rsphdr->pdu_id = SDP_ERROR_RSP; bt_put_unaligned(htons(status), (uint16_t *)rsp.data); rsp.data_size = sizeof(uint16_t); } debug("Sending rsp. status %d", status); rsphdr->tid = reqhdr->tid; rsphdr->plen = htons(rsp.data_size); /* point back to the real buffer start and set the real rsp length */ rsp.data_size += sizeof(sdp_pdu_hdr_t); rsp.data = buf; /* stream the rsp PDU */ sent = send(req->sock, rsp.data, rsp.data_size, 0); debug("Bytes Sent : %d", sent); free(rsp.data); free(req->buf);}void handle_request(int sk, uint8_t *data, int len){ struct sockaddr_l2 sa; socklen_t size; sdp_req_t req; size = sizeof(sa); if (getpeername(sk, (struct sockaddr *) &sa, &size) < 0) return; if (sa.l2_family == AF_BLUETOOTH) { struct l2cap_options lo; memset(&lo, 0, sizeof(lo)); size = sizeof(lo); getsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &lo, &size); bacpy(&req.bdaddr, &sa.l2_bdaddr); req.mtu = lo.omtu; req.local = 0; memset(&sa, 0, sizeof(sa)); size = sizeof(sa); getsockname(sk, (struct sockaddr *) &sa, &size); bacpy(&req.device, &sa.l2_bdaddr); } else { bacpy(&req.device, BDADDR_ANY); bacpy(&req.bdaddr, BDADDR_LOCAL); req.mtu = 2048; req.local = 1; } req.sock = sk; req.buf = data; req.len = len; process_request(&req);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -