?? avdtp.c
字號:
/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2006-2007 Nokia Corporation * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org> * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */#ifdef HAVE_CONFIG_H#include <config.h>#endif#include <stdio.h>#include <stdint.h>#include <errno.h>#include <unistd.h>#include <assert.h>#include <signal.h>#include <netinet/in.h>#include <glib.h>#include <bluetooth/bluetooth.h>#include <bluetooth/sdp.h>#include "dbus.h"#include "logging.h"#include "device.h"#include "manager.h"#include "control.h"#include "avdtp.h"#include <bluetooth/l2cap.h>#define AVDTP_PSM 25#define MAX_SEID 0x3E#define AVDTP_DISCOVER 0x01#define AVDTP_GET_CAPABILITIES 0x02#define AVDTP_SET_CONFIGURATION 0x03#define AVDTP_GET_CONFIGURATION 0x04#define AVDTP_RECONFIGURE 0x05#define AVDTP_OPEN 0x06#define AVDTP_START 0x07#define AVDTP_CLOSE 0x08#define AVDTP_SUSPEND 0x09#define AVDTP_ABORT 0x0A#define AVDTP_SECURITY_CONTROL 0x0B#define AVDTP_PKT_TYPE_SINGLE 0x00#define AVDTP_PKT_TYPE_START 0x01#define AVDTP_PKT_TYPE_CONTINUE 0x02#define AVDTP_PKT_TYPE_END 0x03#define AVDTP_MSG_TYPE_COMMAND 0x00#define AVDTP_MSG_TYPE_ACCEPT 0x02#define AVDTP_MSG_TYPE_REJECT 0x03#define REQ_TIMEOUT 4000#define DISCONNECT_TIMEOUT 5000#define STREAM_TIMEOUT 20000typedef enum { AVDTP_SESSION_STATE_DISCONNECTED, AVDTP_SESSION_STATE_CONNECTING, AVDTP_SESSION_STATE_CONNECTED} avdtp_session_state_t;#if __BYTE_ORDER == __LITTLE_ENDIANstruct avdtp_header { uint8_t message_type:2; uint8_t packet_type:2; uint8_t transaction:4; uint8_t signal_id:6; uint8_t rfa0:2;} __attribute__ ((packed));struct seid_info { uint8_t rfa0:1; uint8_t inuse:1; uint8_t seid:6; uint8_t rfa2:3; uint8_t type:1; uint8_t media_type:4;} __attribute__ ((packed));struct seid { uint8_t rfa0:2; uint8_t seid:6;} __attribute__ ((packed));#elif __BYTE_ORDER == __BIG_ENDIANstruct avdtp_header { uint8_t transaction:4; uint8_t packet_type:2; uint8_t message_type:2; uint8_t rfa0:2; uint8_t signal_id:6;} __attribute__ ((packed));struct seid_info { uint8_t seid:6; uint8_t inuse:1; uint8_t rfa0:1; uint8_t media_type:4; uint8_t type:1; uint8_t rfa2:3;} __attribute__ ((packed));struct seid { uint8_t seid:6; uint8_t rfa0:2;} __attribute__ ((packed));#else#error "Unknown byte order"#endif/* packets */struct gen_req { struct avdtp_header header;} __attribute__ ((packed));struct gen_resp { struct avdtp_header header;} __attribute__ ((packed));struct discover_resp { struct avdtp_header header; struct seid_info seps[0];} __attribute__ ((packed));struct getcap_resp { struct avdtp_header header; uint8_t caps[0];} __attribute__ ((packed));struct start_req { struct avdtp_header header; struct seid first_seid; struct seid other_seids[0];} __attribute__ ((packed));struct suspend_req { struct avdtp_header header; struct seid first_seid; struct seid other_seids[0];} __attribute__ ((packed));struct seid_rej { struct avdtp_header header; uint8_t error;} __attribute__ ((packed));struct conf_rej { struct avdtp_header header; uint8_t category; uint8_t error;} __attribute__ ((packed));#if __BYTE_ORDER == __LITTLE_ENDIANstruct seid_req { struct avdtp_header header; uint8_t rfa0:2; uint8_t acp_seid:6;} __attribute__ ((packed));struct setconf_req { struct avdtp_header header; uint8_t rfa0:2; uint8_t acp_seid:6; uint8_t rfa1:2; uint8_t int_seid:6; uint8_t caps[0];} __attribute__ ((packed));struct stream_rej { struct avdtp_header header; uint8_t rfa0:2; uint8_t acp_seid:6; uint8_t error;} __attribute__ ((packed));struct reconf_req { struct avdtp_header header; uint8_t rfa0:2; uint8_t acp_seid:6; uint8_t serv_cap; uint8_t serv_cap_len; uint8_t caps[0];} __attribute__ ((packed));struct avdtp_general_rej { uint8_t message_type:2; uint8_t packet_type:2; uint8_t transaction:4; uint8_t rfa0;} __attribute__ ((packed));#elif __BYTE_ORDER == __BIG_ENDIANstruct seid_req { struct avdtp_header header; uint8_t acp_seid:6; uint8_t rfa0:2;} __attribute__ ((packed));struct setconf_req { struct avdtp_header header; uint8_t acp_seid:6; uint8_t rfa0:2; uint8_t int_seid:6; uint8_t rfa1:2; uint8_t caps[0];} __attribute__ ((packed));struct stream_rej { struct avdtp_header header; uint8_t acp_seid:6; uint8_t rfa0:2; uint8_t error;} __attribute__ ((packed));struct reconf_req { struct avdtp_header header; uint8_t acp_seid:6; uint8_t rfa0:2; uint8_t serv_cap; uint8_t serv_cap_len; uint8_t caps[0];} __attribute__ ((packed));struct avdtp_general_rej { uint8_t transaction:4; uint8_t packet_type:2; uint8_t message_type:2; uint8_t rfa0;} __attribute__ ((packed));#else#error "Unknown byte order"#endifstruct pending_req { struct avdtp_header *msg; int msg_size; struct avdtp_stream *stream; /* Set if the request targeted a stream */ guint timeout;};struct avdtp_remote_sep { uint8_t seid; uint8_t type; uint8_t media_type; struct avdtp_service_capability *codec; GSList *caps; /* of type struct avdtp_service_capability */ struct avdtp_stream *stream;};struct avdtp_local_sep { avdtp_state_t state; struct avdtp_stream *stream; struct seid_info info; uint8_t codec; GSList *caps; struct avdtp_sep_ind *ind; struct avdtp_sep_cfm *cfm; void *user_data;};struct stream_callback { avdtp_stream_state_cb cb; void *user_data; unsigned int id;};struct avdtp_stream { int sock; uint16_t imtu; uint16_t omtu; struct avdtp *session; struct avdtp_local_sep *lsep; uint8_t rseid; GSList *caps; GSList *callbacks; struct avdtp_service_capability *codec; guint io; /* Transport GSource ID */ guint timer; /* Waiting for other side to close or open the transport channel */ gboolean open_acp; /* If we are in ACT role for Open */ gboolean close_int; /* If we are in INT role for Close */ guint idle_timer;};/* Structure describing an AVDTP connection between two devices */struct avdtp { int ref; int free_lock; bdaddr_t src; bdaddr_t dst; avdtp_session_state_t last_state; avdtp_session_state_t state; guint io; int sock; GSList *seps; /* Elements of type struct avdtp_remote_sep * */ GSList *streams; /* Elements of type struct avdtp_stream * */ GSList *req_queue; /* Elements of type struct pending_req * */ GSList *prio_queue; /* Same as req_queue but is processed before it */ struct avdtp_stream *pending_open; uint16_t mtu; char *buf; avdtp_discover_cb_t discov_cb; void *user_data; struct pending_req *req; guint dc_timer; DBusPendingCall *pending_auth;};static uint8_t free_seid = 1;static GSList *local_seps = NULL;static GIOChannel *avdtp_server = NULL;static GSList *sessions = NULL;static int send_request(struct avdtp *session, gboolean priority, struct avdtp_stream *stream, void *buffer, int size);static gboolean avdtp_parse_resp(struct avdtp *session, struct avdtp_stream *stream, struct avdtp_header *header, int size);static gboolean avdtp_parse_rej(struct avdtp *session, struct avdtp_stream *stream, struct avdtp_header *header, int size);static int process_queue(struct avdtp *session);static void connection_lost(struct avdtp *session, int err);static void avdtp_sep_set_state(struct avdtp *session, struct avdtp_local_sep *sep, avdtp_state_t state);static const char *avdtp_statestr(avdtp_state_t state){ switch (state) { case AVDTP_STATE_IDLE: return "IDLE"; case AVDTP_STATE_CONFIGURED: return "CONFIGURED"; case AVDTP_STATE_OPEN: return "OPEN"; case AVDTP_STATE_STREAMING: return "STREAMING"; case AVDTP_STATE_CLOSING: return "CLOSING"; case AVDTP_STATE_ABORTING: return "ABORTING"; default: return "<unknown state>"; }}static gboolean avdtp_send(struct avdtp *session, void *data, int len){ int ret; if (session->sock < 0) { error("avdtp_send: session is closed"); return FALSE; } ret = send(session->sock, data, len, 0); if (ret < 0) ret = -errno; else if (ret != len) ret = -EIO; if (ret < 0) { error("avdtp_send: %s (%d)", strerror(-ret), -ret); return FALSE; } return TRUE;}static void pending_req_free(struct pending_req *req){ if (req->timeout) g_source_remove(req->timeout); g_free(req->msg); g_free(req);}static gboolean stream_close_timeout(gpointer user_data){ struct avdtp_stream *stream = user_data; debug("Timed out waiting for peer to close the transport channel"); stream->timer = 0; close(stream->sock); return FALSE;}static gboolean stream_open_timeout(gpointer user_data){ struct avdtp_stream *stream = user_data; debug("Timed out waiting for peer to open the transport channel"); stream->timer = 0; stream->session->pending_open = NULL; avdtp_abort(stream->session, stream); return FALSE;}static gboolean disconnect_timeout(gpointer user_data){ struct avdtp *session = user_data; assert(session->ref == 1); session->dc_timer = 0; connection_lost(session, -ETIMEDOUT); return FALSE;}static void remove_disconnect_timer(struct avdtp *session){ g_source_remove(session->dc_timer); session->dc_timer = 0;}static void set_disconnect_timer(struct avdtp *session){ if (session->dc_timer) remove_disconnect_timer(session); session->dc_timer = g_timeout_add(DISCONNECT_TIMEOUT, disconnect_timeout, session);}void avdtp_error_init(struct avdtp_error *err, uint8_t type, int id){ err->type = type; switch (type) { case AVDTP_ERROR_ERRNO: err->err.posix_errno = id; break; case AVDTP_ERROR_ERROR_CODE: err->err.error_code = id; break; }}avdtp_error_type_t avdtp_error_type(struct avdtp_error *err){ return err->type;}int avdtp_error_error_code(struct avdtp_error *err){ assert(err->type == AVDTP_ERROR_ERROR_CODE); return err->err.error_code;}int avdtp_error_posix_errno(struct avdtp_error *err){ assert(err->type == AVDTP_ERROR_ERRNO); return err->err.posix_errno;}static struct avdtp_stream *find_stream_by_rseid(struct avdtp *session, uint8_t rseid){ GSList *l; for (l = session->streams; l != NULL; l = g_slist_next(l)) { struct avdtp_stream *stream = l->data; if (stream->rseid == rseid) return stream; } return NULL;}static struct avdtp_remote_sep *find_remote_sep(GSList *seps, uint8_t seid){ GSList *l; for (l = seps; l != NULL; l = g_slist_next(l)) { struct avdtp_remote_sep *sep = l->data; if (sep->seid == seid) return sep; } return NULL;}static void stream_free(struct avdtp_stream *stream){ struct avdtp_remote_sep *rsep; stream->lsep->info.inuse = 0; stream->lsep->stream = NULL; rsep = find_remote_sep(stream->session->seps, stream->rseid); if (rsep) rsep->stream = NULL; if (stream->timer) g_source_remove(stream->timer); if (stream->sock >= 0) close(stream->sock); if (stream->io) g_source_remove(stream->io); g_slist_foreach(stream->callbacks, (GFunc) g_free, NULL); g_slist_free(stream->callbacks); g_slist_foreach(stream->caps, (GFunc) g_free, NULL); g_slist_free(stream->caps);
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -