?? sdp.c
字號(hào):
/* * sdp.c -- Implementation of Bluetooth Service Discovery Protocol * * Copyright (C) 2000, 2001 Axis Communications AB * * Author: Mats Friden <mats.friden@axis.com> * * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Exceptionally, Axis Communications AB grants discretionary and * conditional permissions for additional use of the text contained * in the company's release of the AXIS OpenBT Stack under the * provisions set forth hereunder. * * Provided that, if you use the AXIS OpenBT Stack with other files, * that do not implement functionality as specified in the Bluetooth * System specification, to produce an executable, this does not by * itself cause the resulting executable to be covered by the GNU * General Public License. Your use of that executable is in no way * restricted on account of using the AXIS OpenBT Stack code with it. * * This exception does not however invalidate any other reasons why * the executable file might be covered by the provisions of the GNU * General Public License. * * $Id: sdp.c,v 1.81 2001/10/15 13:29:06 pkj Exp $ * *//****************** INCLUDE FILES SECTION ***********************************/#define __NO_VERSION__ /* don't define kernel_version in module.h */#ifdef __KERNEL__#include <linux/bluetooth/sysdep-2.1.h>#include <linux/malloc.h>#include <linux/bluetooth/btcommon.h>#include <linux/bluetooth/sdp.h>#include <linux/bluetooth/l2cap.h>#include <linux/bluetooth/bluetooth.h>#include <linux/bluetooth/btmem.h>#include <linux/proc_fs.h>#include <linux/random.h>#else /* user mode */#include <stdlib.h>#include <string.h>#include <sys/socket.h>#include <sys/un.h>#include <asm/unaligned.h>#include "include/bluetooth.h"#include "include/btcommon.h"#include "include/sdp.h"#include "include/l2cap.h"#include "include/btmem.h"#endif/****************** DEBUG CONSTANT AND MACRO SECTION ************************/#if SDP_DEBUG_XMIT#define D_XMIT(fmt...) printk(SDP_DBG_STR fmt)#else#define D_XMIT(fmt...)#endif#if SDP_DEBUG_REC#define D_REC(fmt...) printk(SDP_DBG_STR fmt)#else#define D_REC(fmt...)#endif#if SDP_DEBUG_MISC#define D_MISC(fmt...) printk(SDP_DBG_STR fmt)#else#define D_MISC(fmt...)#endif#if SDP_DEBUG_PROC#define D_PROC(fmt...) printk(fmt)#else#define D_PROC(fmt...)#endif#if SDP_PRINT_DATA#define PRINTPKT(str, data, len) print_data(str, data, len)#else#define PRINTPKT(str, data, len)#endif/****************** CONSTANT AND MACRO SECTION ******************************/#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,14)#define USE_NEW_PROC#endif#ifndef __KERNEL__#define SDP_SRV_SOCK "/tmp/sdp_sock"#endif#define GET_TYPE(ch) (((ch) >> 3) & 0x1f)#define GET_SIZE(ch) ((ch) & 0x7)#define SET_DE_HDR(type,size) ((((type) << 3) & 0xf8) + ((size) & 0x7))#define SDP_HDR_SIZE 5/* The size of the SDP packet header */#define DES_HDR 0x35#define DES_HDR_LEN 2#define UUID16_HDR 0x19#define UUID32_HDR 0x1a/* Maximum record counts */#define MAX_SERVICERECORD_COUNT 8#define MAX_ATTR_COUNT 0x100/* The maximum number of sdp connections */#define MAX_NBR_SDP 7/* PDU ID */#define SDP_ERROR_RSP 1#define SDP_SERVICESEARCH_REQ 2#define SDP_SERVICESEARCH_RSP 3#define SDP_SERVICEATTR_REQ 4#define SDP_SERVICEATTR_RSP 5#define SDP_SERVICESEARCHATTR_REQ 6#define SDP_SERVICESEARCHATTR_RSP 7/****************** TYPE DEFINITION SECTION *********************************//****************** LOCAL FUNCTION DECLARATION SECTION **********************/static sdp_con* get_free_sdp_con(void);#ifdef __KERNEL__#ifdef USE_NEW_PROCstatic ssize_t sdp_database_read(struct file *f, char *buf, size_t count, loff_t *offset);static ssize_t sdp_database_write(struct file *f, const char *buf, size_t count, loff_t *offset);#elsestatic s32 sdp_database_read(struct inode *inode, struct file * file, char * buf, s32 count);static s32 sdp_database_write(struct inode *inode, struct file * file, const char * buf, s32 count);#endifstatic s32 sdp_proc_dir_entry_read(char *buf, char **start, off_t offset, s32 len, s32 unused);#else /* USERMODE STACK */static s32 open_socket(char *name);static s32 sdp_doquery(s32 fd, u8 *request, s32 len);static s32 send_error_rsp(sdp_con *sdp, u16 trans_id, u16 err_code);#endif/****************** GLOBAL VARIABLE DECLARATION SECTION *********************//****************** LOCAL VARIABLE DECLARATION SECTION **********************/#ifdef __KERNEL__#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)static struct wait_queue *database_wq = NULL;#elsestatic wait_queue_head_t database_wq;#endif#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)static struct file_operations sdp_procfile_operation = { NULL, /* lseek - default */ sdp_database_read, /* read - bad */ sdp_database_write, /* write - bad */ NULL, /* readdir */ NULL, /* select - default */ NULL, /* ioctl - default */ NULL, /* mmap */ NULL, /* no special open code */ NULL, /* no special release code */ NULL /* can't fsync */};#else static struct file_operations sdp_procfile_operation = { NULL, /* module owner */ NULL, /* lseek - default */ sdp_database_read, /* read - bad */ sdp_database_write, /* write - bad */ NULL, /* readdir */ NULL, /* select - default */ NULL, /* ioctl - default */ NULL, /* mmap */ NULL, /* no special open code */ NULL, /* no special release code */ NULL /* can't fsync */};#endif /* * proc directories can do almost nothing.. */#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)static struct inode_operations sdp_proc_inode_operations = { &sdp_procfile_operation, /* default net file-ops */ NULL, /* create */ NULL, /* lookup */ NULL, /* link */ NULL, /* unlink */ NULL, /* symlink */ NULL, /* mkdir */ NULL, /* rmdir */ NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ NULL, /* truncate */ NULL /* permission */};#elsestatic struct inode_operations sdp_proc_inode_operations = { NULL, /* create */ NULL, /* lookup */ NULL, /* link */ NULL, /* unlink */ NULL, /* symlink */ NULL, /* mkdir */ NULL, /* rmdir */ NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ NULL, /* truncate */ NULL /* permission */};#endif#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)static struct proc_dir_entry sdp_proc_entry = { 0, 7, "sdp_srv", S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0, 0, &sdp_proc_inode_operations, sdp_proc_dir_entry_read,};#elsestatic struct proc_dir_entry sdp_proc_entry = { 0, 7, "sdp_srv", S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0, 0, &sdp_proc_inode_operations, &sdp_procfile_operation,};#endif /* LINUX_VERSION_CODE */#endif /* __KERNEL__ */typedef struct data_struct { u16 l2cap_mtu; u16 sdp_con_id; u16 len; u8 data[0];} __attribute__ ((packed)) data_struct;struct database_query { u32 count; u8 query[256];} database_query;sdp_con sdp_con_list[MAX_NBR_SDP];static int role;/* Transaction id used for request *///static u16 req_trans_id = 0xaabb;#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)static struct wait_queue *sdp_disc_wq = NULL;#elsestatic wait_queue_head_t sdp_disc_wq;#endif /* LINUX_VERSION_CODE */#ifdef __KERNEL__static bt_tx_buf *db_write_tx_buf;static s32 db_write_recv;#endif#ifndef __KERNEL__static s32 sdp_sock;#endif/****************** FUNCTION DEFINITION SECTION *****************************/#ifndef __KERNEL__intopen_socket(char *name){ struct sockaddr_un server_address; s32 client_sockfd; s32 server_len; printf("Opening socket %s\n", name); client_sockfd = socket(AF_UNIX, SOCK_STREAM, 0); /* 'destination' socket */ server_address.sun_family = AF_UNIX; strcpy(server_address.sun_path, name); server_len = sizeof(server_address); if (connect(client_sockfd, (struct sockaddr *)&server_address, server_len) < 0) { perror("connect client socket"); D_ERR("Couldn't open socket, sdp will not be used\n"); return -1; } printf("Socket connected to %s\n", server_address.sun_path); return client_sockfd;}#endif /* !__KERNEL__ */void sdp_init(s32 srv){ s32 i; protocol_layer this_layer; DSYS("Initialising SDP\n"); database_query.count = 0; /* Set the confirm and indication functions for the L2CAP-layer */ this_layer.con_ind = sdp_connect_ind; this_layer.con_pnd = sdp_connect_pnd; this_layer.conf_ind = sdp_config_ind; this_layer.disc_ind = sdp_disconnect_ind; this_layer.con_cfm = sdp_connect_cfm; this_layer.conf_cfm = sdp_config_cfm; this_layer.disc_cfm = sdp_disconnect_cfm; this_layer.receive_data = sdp_receive_data; /* Register SDP in the L2AP layer*/ l2cap_register_upper(SDP_LAYER, &this_layer); for (i = 0; i < MAX_NBR_SDP; i++) { sdp_con_list[i].id = i; sdp_con_list[i].l2cap = NULL; sdp_con_list[i].state = SDP_DISCONNECTED; sdp_con_list[i].initiator = 0; sdp_con_list[i].line = 0; } if (srv) { DSYS("Init SDP as server\n"); role = 1;#ifndef __KERNEL__ sdp_sock = open_socket(SDP_SRV_SOCK);#endif } else { DSYS("Init SDP as client\n"); role = 0; }}void sdp_shutdown(void){ s32 i; DSYS("Shutting down SDP\n"); for (i = 0; i < MAX_NBR_SDP; i++) { if (sdp_con_list[i].state != SDP_DISCONNECTED) { sdp_disconnect_req(i); } } #ifdef __KERNEL__ unsubscribe_bt_buf(db_write_tx_buf); db_write_tx_buf = NULL; db_write_recv = 0;#endif}#ifdef __KERNEL__s32sdp_create_proc_file(void){ s32 procfs_status = -ENOENT; /* The database_wq wait queue must be initialised before anyone tries to read from the /proc/sdp_srv file, so we initialise the wait queues here */#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) init_waitqueue_head(&database_wq); init_waitqueue_head(&sdp_disc_wq);#endif /* LINUX_VERSION_CODE */#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) { struct proc_dir_entry *entry; if ((entry = create_proc_entry(sdp_proc_entry.name, sdp_proc_entry.mode, &proc_root))) { /*---------------------------------------------------*/ /* If the proc entry was registered successfully, */ /* then set all the necessary structure information. */ /*---------------------------------------------------*/ entry->proc_iops = sdp_proc_entry.proc_iops; entry->proc_fops = sdp_proc_entry.proc_fops; procfs_status = 0; } }#elif LINUX_VERSION_CODE > KERNEL_VERSION(2,2,0) procfs_status = proc_register(&proc_root, &sdp_proc_entry);#else procfs_status = proc_register_dynamic(&proc_root, &sdp_proc_entry);#endif /* LINUX_VERSION_CODE */ if (procfs_status < 0) { D_ERR("Couldn't register proc file for sdp database %d\n", procfs_status); } return procfs_status;}s32sdp_remove_proc_file(void){#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) remove_proc_entry(sdp_proc_entry.name, &proc_root);#else proc_unregister(&proc_root, sdp_proc_entry.low_ino);#endif return 0;}#endif /* __KERNEL__ */s32 sdp_connect_req(u8* bd_addr, u8 line){ sdp_con *sdp; sdp = get_free_sdp_con(); if (!sdp) { DSYS(__FUNCTION__ " WARNING couldn't find free sdp connection\n"); /* fixme -- use bt_connect_cfm with correct con_id */ return 0; } sdp->state = SDP_CONNECTING; sdp->initiator = TRUE; sdp->line = line; if (l2ca_connect_req(bd_addr, SDP_LAYER)) { D_ERR(__FUNCTION__ " ERROR l2ca_connect_req failed\n"); return -1; } return sdp->id;}/* only client receives connect pnd */void sdp_connect_pnd(l2cap_con *l2cap, s32 status){ printk("sdp_connect_pnd : reason %d\n", status); //PRINTPSM(l2cap);}void sdp_connect_ind(l2cap_con *l2cap) { sdp_con *sdp; D_MISC(__FUNCTION__ " remote cid : %d\n", l2cap->remote_cid); sdp = get_free_sdp_con(); if (!sdp) { DSYS(__FUNCTION__ " WARNING couldn't find free sdp connection\n"); if (l2ca_connect_rsp(l2cap, RES_NOSRC, STAT_NOINFO)) { D_ERR(__FUNCTION__ " l2ca_connect_rsp failed\n"); } } else { if (l2ca_connect_rsp(l2cap, RES_SUCCESS, STAT_NOINFO)) { D_ERR(__FUNCTION__ " l2ca_connect_rsp failed\n"); } sdp->initiator = FALSE; sdp->state = SDP_CONNECTING; sdp->l2cap = l2cap; l2cap->upper_con = (void*) sdp; }}void sdp_connect_cfm(l2cap_con *l2cap, s32 status){ sdp_con *sdp = NULL; s32 i = 0; s32 stop = 0; if (status) { DSYS(__FUNCTION__ " Connection failed\n"); bt_connect_cfm(CREATE_SDP_ID(sdp->line, 0), -1); return; } /* Find the connecting sdp_con */ while ((i < MAX_NBR_SDP) && (!stop)) { if ((sdp_con_list[i].state == SDP_CONNECTING) &&
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -