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

📄 server.c

📁 基于LINUX内核驱动的开发
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * *  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/socket.h>#include <sys/ioctl.h>#include <sys/stat.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 "logging.h"#include "dbus.h"#include "error.h"#include "textfile.h"#include "dbus-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 */	int		attempts;	/* Setup msg received */	guint		watch;		/* BNEP setup watch */	guint		timeout;	/* Max setup time */};/* 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 GSList *setup_sessions = NULL;static const char *prefix = NULL;static gboolean security = TRUE;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 setup_free(struct setup_session *s){	g_free(s->address);	g_free(s);}static int setup_cmp(const struct setup_session *s, const char *addr){	return strcmp(s->address, addr);}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 int create_server_record(sdp_buf_t *buf, 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;	int ret;	memset(&record, 0, sizeof(sdp_record_t));	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 -1;	}	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);	if (sdp_gen_record_pdu(&record, buf) < 0)		ret = -1;	else		ret = 0;	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);	sdp_list_free(record.attrlist, (sdp_free_func_t) sdp_data_free);	sdp_list_free(record.pattern, free);	return ret;}static ssize_t send_bnep_ctrl_rsp(int sk, uint16_t response){	struct bnep_control_rsp rsp;	rsp.type = BNEP_CONTROL;	rsp.ctrl = BNEP_SETUP_CONN_RSP;	rsp.resp = htons(response);	return send(sk, &rsp, sizeof(rsp), 0);}static void cancel_authorization(struct setup_session *s){	DBusMessage *msg;	const char *uuid;	msg = dbus_message_new_method_call("org.bluez", "/org/bluez",						"org.bluez.Database",						"CancelAuthorizationRequest");	if (!msg) {		error("Unable to allocate new method call");		return;	}	uuid = bnep_uuid(s->dst_role);	dbus_message_append_args(msg,			DBUS_TYPE_STRING, &s->address,			DBUS_TYPE_STRING, &uuid,			DBUS_TYPE_INVALID);	send_message_and_unref(connection, msg);}static void authorization_callback(DBusPendingCall *pcall, void *data){	struct setup_session *s = data;	struct network_server *ns = NULL;	DBusMessage *reply = dbus_pending_call_steal_reply(pcall);	char path[MAX_PATH_LENGTH], devname[16];	uint16_t response = BNEP_CONN_NOT_ALLOWED;	DBusError derr;	const char *bridge;	if (!g_slist_find(setup_sessions, s)) {		dbus_message_unref(reply);		return;	}	snprintf(path, MAX_PATH_LENGTH, NETWORK_PATH"/%s", bnep_name(s->dst_role));	dbus_connection_get_object_user_data(connection, path, (void *) &ns);	/* Server can be disabled in the meantime */	if (ns == NULL || ns->enable == FALSE)		goto failed;	dbus_error_init(&derr);	if (dbus_set_error_from_message(&derr, reply)) {		error("Access denied: %s", derr.message);		if (dbus_error_has_name(&derr, DBUS_ERROR_NO_REPLY)) {			debug("Canceling authorization request");			cancel_authorization(s);		}		dbus_error_free(&derr);		goto failed;	}	memset(devname, 0, 16);	strncpy(devname, prefix, strlen(prefix));	if (bnep_connadd(s->nsk, s->dst_role, devname) < 0)		goto failed;	info("Authorization succedded. 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);			goto failed;		}		bnep_if_up(devname, 0);	} else		bnep_if_up(devname, ns->id);	response = BNEP_SUCCESS;	ns->clients = g_slist_append(ns->clients, g_strdup(s->address));failed:	send_bnep_ctrl_rsp(s->nsk, response);	dbus_message_unref(reply);}static void setup_watch_destroy(void *data){	struct setup_session *s;	GSList *l;	/*	 * Remote initiated: socket HUP	 * Authorization: denied/accepted	 */	l = g_slist_find(setup_sessions, data);	if (!l)		return;	s = l->data;	setup_sessions = g_slist_remove(setup_sessions, s);	/* Remove active watches */	if (s->watch)		g_source_remove(s->watch);	if (s->timeout)		g_source_remove(s->timeout);	setup_free(s);}static int authorize_connection(struct setup_session *s){	DBusMessage *msg;	DBusPendingCall *pending;	const char *uuid;	msg = dbus_message_new_method_call("org.bluez", "/org/bluez",				"org.bluez.Database", "RequestAuthorization");	if (!msg) {		error("Unable to allocat new RequestAuthorization method call");		return -ENOMEM;	}	uuid = bnep_uuid(s->dst_role);	debug("Requesting authorization for %s UUID:%s", s->address, uuid);	dbus_message_append_args(msg,			DBUS_TYPE_STRING, &s->address,			DBUS_TYPE_STRING, &uuid,			DBUS_TYPE_INVALID);	if (dbus_connection_send_with_reply(connection,				msg, &pending, -1) == FALSE) {		error("Sending of authorization request failed");		dbus_message_unref(msg);		return -EACCES;	}	dbus_pending_call_set_notify(pending,			authorization_callback, s, setup_watch_destroy);	dbus_pending_call_unref(pending);	dbus_message_unref(msg);	return 0;}static uint16_t inline chk_role(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;

⌨️ 快捷键说明

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