⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 server.c

📁 这是Linux环境下的蓝牙源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * *  BlueZ - Bluetooth protocol stack for Linux * *  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 <unistd.h>#include <stdlib.h>#include <errno.h>#include <sys/stat.h>#include <sys/param.h>#include <net/if.h>#include <bluetooth/bluetooth.h>#include <bluetooth/hci.h>#include <bluetooth/hci_lib.h>#include <bluetooth/bnep.h>#include <bluetooth/l2cap.h>#include <bluetooth/sdp.h>#include <bluetooth/sdp_lib.h>#include <netinet/in.h>#include <glib.h>#include <gdbus.h>#include "../src/dbus-common.h"#include "logging.h"#include "error.h"#include "textfile.h"#include "dbus-service.h"#include "sdpd.h"#include "glib-helper.h"#define NETWORK_SERVER_INTERFACE "org.bluez.network.Server"#define SETUP_TIMEOUT		1000#define MAX_SETUP_ATTEMPTS	3#include "bridge.h"#include "common.h"#include "manager.h"/* Pending Authorization */struct setup_session {	char		*address;	/* Remote Bluetooth Address */	uint16_t	dst_role;	/* Destination role */	uint16_t	src_role;	/* Source role */	int		nsk;		/* L2CAP socket */	guint		watch;		/* BNEP socket watch */};struct timeout {	guint	id;		/* Timeout id */	guint	watch;		/* BNEP socket watch */};/* Main server structure */struct network_server {	bdaddr_t	src;		/* Bluetooth Local Address */	char		*iface;		/* Routing interface */	char		*name;		/* Server service name */	char		*range;		/* IP Address range */	char		*path;		/* D-Bus path */	gboolean	enable;		/* Enable flag */	uint32_t	record_id;	/* Service record id */	uint16_t	id;		/* Service class identifier */	GSList		*clients;	/* Active connections */};static GIOChannel *bnep_io = NULL;static DBusConnection *connection = NULL;static struct setup_session *setup = NULL;static GSList *servers = NULL;static const char *prefix = NULL;static gboolean security = TRUE;gint find_server(gconstpointer a, gconstpointer b){	const struct network_server *ns = a;	const char *path = b;	return strcmp(ns->path, path);}static struct setup_session *setup_session_new(gchar *address,		uint16_t dst_role, uint16_t src_role, int nsk, guint watch){	struct setup_session *setup;	setup = g_new0(struct setup_session, 1);	setup->address = g_strdup(address);	setup->dst_role = dst_role;	setup->src_role = src_role;	setup->nsk = nsk;	setup->watch = watch;	return setup;}static void setup_session_free(struct setup_session *setup){	g_source_remove(setup->watch);	g_free(setup->address);	g_free(setup);}static struct network_server *server_find(bdaddr_t *src, uint16_t role){	struct network_server *ns;	GSList *l;	for (l = servers; l; l = l->next) {		ns = l->data;		if (bacmp(&ns->src, src) != 0)			continue;		if (ns->id == role)			return ns;	}	return NULL;}static int store_property(bdaddr_t *src, uint16_t id,			const char *key, const char *value){	char filename[PATH_MAX + 1];	char addr[18];	ba2str(src, addr);	if (id == BNEP_SVC_NAP)		create_name(filename, PATH_MAX, STORAGEDIR, addr, "nap");	else if (id == BNEP_SVC_GN)		create_name(filename, PATH_MAX, STORAGEDIR, addr, "gn");	else if (id == BNEP_SVC_PANU)		create_name(filename, PATH_MAX, STORAGEDIR, addr, "panu");	return textfile_put(filename, key, value);}static void add_lang_attr(sdp_record_t *r){	sdp_lang_attr_t base_lang;	sdp_list_t *langs = 0;	/* UTF-8 MIBenum (http://www.iana.org/assignments/character-sets) */	base_lang.code_ISO639 = (0x65 << 8) | 0x6e;	base_lang.encoding = 106;	base_lang.base_offset = SDP_PRIMARY_LANG_BASE;	langs = sdp_list_append(0, &base_lang);	sdp_set_lang_attr(r, langs);	sdp_list_free(langs, 0);}static sdp_record_t *server_record_new(const char *name, uint16_t id){	sdp_list_t *svclass, *pfseq, *apseq, *root, *aproto;	uuid_t root_uuid, pan, l2cap, bnep;	sdp_profile_desc_t profile[1];	sdp_list_t *proto[2];	sdp_data_t *v, *p;	uint16_t psm = BNEP_PSM, version = 0x0100;	uint16_t security_desc = (security ? 0x0001 : 0x0000);	uint16_t net_access_type = 0xfffe;	uint32_t max_net_access_rate = 0;	const char *desc = "BlueZ PAN service";	sdp_record_t *record;	record = sdp_record_alloc();	if (!record)		return NULL;	record->attrlist = NULL;	record->pattern = NULL;	switch (id) {	case BNEP_SVC_NAP:		sdp_uuid16_create(&pan, NAP_SVCLASS_ID);		svclass = sdp_list_append(NULL, &pan);		sdp_set_service_classes(record, svclass);		sdp_uuid16_create(&profile[0].uuid, NAP_PROFILE_ID);		profile[0].version = 0x0100;		pfseq = sdp_list_append(NULL, &profile[0]);		sdp_set_profile_descs(record, pfseq);		sdp_set_info_attr(record, name, NULL, desc);		sdp_attr_add_new(record, SDP_ATTR_NET_ACCESS_TYPE,					SDP_UINT16, &net_access_type);		sdp_attr_add_new(record, SDP_ATTR_MAX_NET_ACCESSRATE,					SDP_UINT32, &max_net_access_rate);		break;	case BNEP_SVC_GN:		sdp_uuid16_create(&pan, GN_SVCLASS_ID);		svclass = sdp_list_append(NULL, &pan);		sdp_set_service_classes(record, svclass);		sdp_uuid16_create(&profile[0].uuid, GN_PROFILE_ID);		profile[0].version = 0x0100;		pfseq = sdp_list_append(NULL, &profile[0]);		sdp_set_profile_descs(record, pfseq);		sdp_set_info_attr(record, name, NULL, desc);		break;	case BNEP_SVC_PANU:		sdp_uuid16_create(&pan, PANU_SVCLASS_ID);		svclass = sdp_list_append(NULL, &pan);		sdp_set_service_classes(record, svclass);		sdp_uuid16_create(&profile[0].uuid, PANU_PROFILE_ID);		profile[0].version = 0x0100;		pfseq = sdp_list_append(NULL, &profile[0]);		sdp_set_profile_descs(record, pfseq);		sdp_set_info_attr(record, name, NULL, desc);		break;	default:		return NULL;	}	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);	root = sdp_list_append(NULL, &root_uuid);	sdp_set_browse_groups(record, root);	sdp_uuid16_create(&l2cap, L2CAP_UUID);	proto[0] = sdp_list_append(NULL, &l2cap);	p = sdp_data_alloc(SDP_UINT16, &psm);	proto[0] = sdp_list_append(proto[0], p);	apseq    = sdp_list_append(NULL, proto[0]);	sdp_uuid16_create(&bnep, BNEP_UUID);	proto[1] = sdp_list_append(NULL, &bnep);	v = sdp_data_alloc(SDP_UINT16, &version);	proto[1] = sdp_list_append(proto[1], v);	/* Supported protocols */	{		uint16_t ptype[] = {			0x0800,  /* IPv4 */			0x0806,  /* ARP */		};		sdp_data_t *head, *pseq;		int p;		for (p = 0, head = NULL; p < 2; p++) {			sdp_data_t *data = sdp_data_alloc(SDP_UINT16, &ptype[p]);			if (head)				sdp_seq_append(head, data);			else				head = data;		}		pseq = sdp_data_alloc(SDP_SEQ16, head);		proto[1] = sdp_list_append(proto[1], pseq);	}	apseq = sdp_list_append(apseq, proto[1]);	aproto = sdp_list_append(NULL, apseq);	sdp_set_access_protos(record, aproto);	add_lang_attr(record);	sdp_attr_add_new(record, SDP_ATTR_SECURITY_DESC,				SDP_UINT16, &security_desc);	sdp_data_free(p);	sdp_data_free(v);	sdp_list_free(apseq, NULL);	sdp_list_free(root, NULL);	sdp_list_free(aproto, NULL);	sdp_list_free(proto[0], NULL);	sdp_list_free(proto[1], NULL);	sdp_list_free(svclass, NULL);	sdp_list_free(pfseq, NULL);	return record;}static ssize_t send_bnep_ctrl_rsp(int sk, uint16_t val){	struct bnep_control_rsp rsp;	rsp.type = BNEP_CONTROL;	rsp.ctrl = BNEP_SETUP_CONN_RSP;	rsp.resp = htons(val);	return send(sk, &rsp, sizeof(rsp), 0);}static int server_connadd(struct network_server *ns, int nsk,			const gchar *address, uint16_t dst_role){	char devname[16];	const char *bridge;	int err;	/* Server can be disabled in the meantime */	if (ns->enable == FALSE)		return -EPERM;	memset(devname, 0, 16);	strncpy(devname, prefix, strlen(prefix));	err = bnep_connadd(nsk, dst_role, devname);	if (err < 0)		return err;	info("Added new connection: %s", devname);	bridge = bridge_get_name(ns->id);	if (bridge) {		if (bridge_add_interface(ns->id, devname) < 0) {			error("Can't add %s to the bridge %s: %s(%d)",					devname, bridge, strerror(errno),					errno);			return -EPERM;		}		bnep_if_up(devname, 0);	} else		bnep_if_up(devname, ns->id);	ns->clients = g_slist_append(ns->clients, g_strdup(address));	return 0;}static void req_auth_cb(DBusError *derr, void *user_data){	struct network_server *ns = user_data;	uint16_t val;	if (!setup) {		info("Authorization cancelled: Client exited");		return;	}	if (derr) {		error("Access denied: %s", derr->message);		if (dbus_error_has_name(derr, DBUS_ERROR_NO_REPLY)) {			bdaddr_t dst;			str2ba(setup->address, &dst);			service_cancel_auth(&ns->src, &dst);		}		val = BNEP_CONN_NOT_ALLOWED;		goto done;	}	if (server_connadd(ns, setup->nsk,			setup->address, setup->dst_role) < 0)		val = BNEP_CONN_NOT_ALLOWED;	else		val = BNEP_SUCCESS;done:	send_bnep_ctrl_rsp(setup->nsk, val);	setup_session_free(setup);	setup = NULL;}static int authorize_connection(struct network_server *ns, const char *address){	const char *uuid;	bdaddr_t dst;	int ret_val;	uuid =  bnep_uuid(ns->id);	str2ba(address, &dst);	ret_val = service_req_auth(&ns->src, &dst, uuid, req_auth_cb, ns);	return ret_val;}static uint16_t inline bnep_setup_chk(uint16_t dst_role, uint16_t src_role){	/* Allowed PAN Profile scenarios */	switch (dst_role) {	case BNEP_SVC_NAP:	case BNEP_SVC_GN:		if (src_role == BNEP_SVC_PANU)			return 0;		return BNEP_CONN_INVALID_SRC;	case BNEP_SVC_PANU:		if (src_role == BNEP_SVC_PANU ||			src_role == BNEP_SVC_GN ||			src_role == BNEP_SVC_NAP)			return 0;		return BNEP_CONN_INVALID_SRC;	}	return BNEP_CONN_INVALID_DST;}static uint16_t bnep_setup_decode(struct bnep_setup_conn_req *req,				uint16_t *dst_role, uint16_t *src_role){	uint8_t *dest, *source;	dest = req->service;	source = req->service + req->uuid_size;	switch (req->uuid_size) {	case 2: /* UUID16 */		*dst_role = ntohs(bt_get_unaligned((uint16_t *) dest));		*src_role = ntohs(bt_get_unaligned((uint16_t *) source));		break;	case 4: /* UUID32 */	case 16: /* UUID128 */		*dst_role = ntohl(bt_get_unaligned((uint32_t *) dest));		*src_role = ntohl(bt_get_unaligned((uint32_t *) source));		break;	default:		return BNEP_CONN_INVALID_SVC;	}	return 0;}static gboolean bnep_setup(GIOChannel *chan,			GIOCondition cond, gpointer user_data){	struct timeout *to = user_data;	struct network_server *ns;	uint8_t packet[BNEP_MTU];	struct bnep_setup_conn_req *req = (void *) packet;	struct sockaddr_l2 sa;	socklen_t size;	char address[18];	uint16_t rsp, src_role, dst_role;	int n, sk;	if (cond & G_IO_NVAL)		return FALSE;	if (cond & (G_IO_ERR | G_IO_HUP)) {		error("Hangup or error on BNEP socket");		return FALSE;	}	sk = g_io_channel_unix_get_fd(chan);	/* Reading BNEP_SETUP_CONNECTION_REQUEST_MSG */	n = read(sk, packet, sizeof(packet));	if (n < 0) {		error("read(): %s(%d)", strerror(errno), errno);		return FALSE;	}	if (req->type != BNEP_CONTROL || req->ctrl != BNEP_SETUP_CONN_REQ)		return FALSE;	rsp = bnep_setup_decode(req, &dst_role, &src_role);	if (rsp)		goto reply;	rsp = bnep_setup_chk(dst_role, src_role);	if (rsp)		goto reply;	size = sizeof(sa);	if (getsockname(sk, (struct sockaddr *) &sa, &size) < 0) {		rsp = BNEP_CONN_NOT_ALLOWED;		goto reply;	}	ba2str(&sa.l2_bdaddr, address);	ns = server_find(&sa.l2_bdaddr, dst_role);	if (!ns || ns->enable == FALSE) {		error("Server unavailable: %s (0x%x)", address, dst_role);		rsp = BNEP_CONN_NOT_ALLOWED;		goto reply;	}	if (getpeername(sk, (struct sockaddr *) &sa, &size) < 0) {		rsp = BNEP_CONN_NOT_ALLOWED;		goto reply;	}	ba2str(&sa.l2_bdaddr, address);	if (setup) {		error("Connection rejected: Pending authorization");		rsp = BNEP_CONN_NOT_ALLOWED;		goto reply;	}	setup = setup_session_new(address, dst_role, src_role, sk, to->watch);	/* Wait authorization before reply success */	if (authorize_connection(ns, address) < 0) {		setup_session_free(setup);		setup = NULL;		rsp = BNEP_CONN_NOT_ALLOWED;		goto reply;	}	g_source_remove(to->id);	to->id = 0;	return TRUE;reply:	send_bnep_ctrl_rsp(sk, rsp);	return FALSE;}static void setup_destroy(void *user_data){	struct timeout *to = user_data;	if (to->id)		g_source_remove(to->id);	g_free(to);}static gboolean timeout_cb(void *user_data){	struct timeout *to = user_data;	to->id = 0;	g_source_remove(to->watch);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -