📄 bnep_core.c
字号:
return 0;}/***************************************************************************/static int bnep_ioctl(struct net_device *dev, struct ifreq *rq, int cmd){ switch (cmd) { //Close a connection case SIOC_DISCONNECT:{ struct bnep_connect_mgnt_struct bnep_connect_mgnt; struct bnep_connection *conn = NULL; copy_from_user(&bnep_connect_mgnt, rq->ifr_data, sizeof(struct bnep_connect_mgnt_struct)); conn = bnep_get_conn_by_bdaddr(dev, &bnep_connect_mgnt.destination_address); if (conn) { BT_DBG("closing connection to %s", batostr(&bnep_connect_mgnt.destination_address)); //Kill session thread stop_kthread(&conn->session); } else { BT_DBG("connection to %s not found", batostr(&bnep_connect_mgnt.destination_address)); return BNEP_ERR_NO_L2CAP; } return 0; } //Create a BNEP or L2CAP connection case SIOC_CONNECT:{ int status = 0; struct bnep_connect_mgnt_struct bnep_connect_mgnt; copy_from_user(&bnep_connect_mgnt, rq->ifr_data, sizeof(struct bnep_connect_mgnt_struct)); switch (bnep_connect_mgnt.protocol) { case CONN_L2CAP_LAYER: status = bnep_l2cap_connect(dev, &bnep_connect_mgnt); break; case CONN_BNEP_LAYER: status = bnep_connect(dev, &bnep_connect_mgnt); break; default: status = BNEP_ERR_CONN_UNKNOWN_LAYER; } return status; } //Set filter on specific link case SIOC_SET_FILTER:{ struct filter_request_struct filter_request; unsigned char *data = NULL; int status; copy_from_user(&filter_request, rq->ifr_data, sizeof(struct filter_request_struct)); if (filter_request.data_length > 0) { data = (unsigned char *) kmalloc(filter_request.data_length, GFP_ATOMIC); copy_from_user(data, filter_request.data, filter_request.data_length); filter_request.data = data; } status = bnep_tx_filter(dev, &filter_request); kfree(data); return status; } //Change role of device case SIOC_SET_ROLE:{ int role_uuid; copy_from_user(&role_uuid, rq->ifr_data, sizeof(int)); return bnep_update_role(dev, role_uuid); } //Test case execution case SIOC_TESTCASE: /* Execute test case */ {#ifdef BNEP_TEST struct bnep_test_ctrl_struct bnep_test_ctrl; copy_from_user(&bnep_test_ctrl, rq->ifr_data, sizeof(struct bnep_test_ctrl_struct)); return test_execute_test(dev, &bnep_test_ctrl);#else BT_DBG("test mode not available. Recompile with -DBNEP_TEST"); return 1;#endif break; } } return -EOPNOTSUPP;}/***************************************************************************/static struct net_device_stats *device_get_stats(struct net_device *dev){ struct bnep_private *priv; priv = (struct bnep_private *) dev->priv; return &(priv->stats);}/***************************************************************************/static int device_open_dev(struct net_device *dev){ netif_start_queue(dev); return 0;}/***************************************************************************/static int device_close_dev(struct net_device *dev){ netif_stop_queue(dev); return 0;}/***************************************************************************/static void device_dev_timeout(struct net_device *dev){ BT_DBG("not implemented");}/***************************************************************************/static int __init bnep_init(struct net_device *dev){ int i; struct bnep_private *priv = (struct bnep_private *) dev->priv; //init dev struct ether_setup(dev); //net device setup dev->hard_start_xmit = &device_tx_data; dev->get_stats = &device_get_stats; dev->do_ioctl = &bnep_ioctl; dev->set_multicast_list = &device_set_multicast_list; dev->open = &device_open_dev; dev->stop = &device_close_dev; dev->tx_timeout = &device_dev_timeout; dev->watchdog_timeo = HZ;#ifdef CONFIG_NET_FASTROUTE dev->accept_fastpath = device_accept_fastpath;#endif //Set device source address from private data BT_DBG("Binding %s <-> %s", batostr(&priv->source_address), dev->name); for (i = 0; i < 6; i++) dev->dev_addr[i] = ((unsigned char *) &priv->source_address)[i]; dev->tx_queue_len = 100; dev->flags &= (IFF_MULTICAST | IFF_BROADCAST); return 0;}/***************************************************************************/struct socket *bnep_sock_accept(struct socket *sk){ struct socket *nsk; int err; nsk = sock_alloc(); if (!nsk) return NULL; nsk->type = sk->type; nsk->ops = sk->ops; err = sk->ops->accept(sk, nsk, 0); BT_DBG("result: %d", err); if (err < 0) { sock_release(nsk); return NULL; } return nsk;}/***************************************************************************/static void bnep_connect_listener(kthread_t * kthread){ struct sockaddr_l2 addr; struct l2cap_options opts; int err, size; struct net_device *dev = (struct net_device *) kthread->arg; struct bnep_private *bnep_priv = bnep_get_priv(dev); BT_DBG("start connect listener"); init_kthread(kthread, "bnep_conn_lsten"); set_fs(KERNEL_DS); // Create socket err = sock_create(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP, &bnep_priv->bnep_sk); if (err < 0) { BT_DBG("Create socket failed %d", err); return; } // Bind socket baswap(&addr.l2_bdaddr, &bnep_priv->source_address); addr.l2_family = AF_BLUETOOTH; addr.l2_psm = htobs(PAN_PSM); err = bnep_priv->bnep_sk->ops->bind(bnep_priv->bnep_sk, (struct sockaddr *) &addr, sizeof(addr)); if (err < 0) { BT_DBG("Bind failed %d", err); return; } // Set L2CAP options size = sizeof(opts); bnep_priv->bnep_sk->ops->getsockopt(bnep_priv->bnep_sk, SOL_L2CAP, L2CAP_OPTIONS, (void *) &opts, &size); opts.imtu = PAN_IMTU; opts.imtu = PAN_OMTU; opts.flush_to = PAN_FLUSH_TO; bnep_priv->bnep_sk->ops->setsockopt(bnep_priv->bnep_sk, SOL_L2CAP, L2CAP_OPTIONS, (void *) &opts, size); // Start listening on the socket err = bnep_priv->bnep_sk->ops->listen(bnep_priv->bnep_sk, 10); if (err) { BT_DBG("Listen failed %d", err); sock_release(bnep_priv->bnep_sk); return; } while (1) { struct socket *nsk; mb(); if (kthread->terminate) { BT_DBG("exiting connect listener"); break; } nsk = bnep_sock_accept(bnep_priv->bnep_sk); if (nsk) { bdaddr_t tmp_addr; baswap(&tmp_addr, &bluez_pi(nsk->sk)->dst); //Check for existing bnep connection if (bnep_get_conn_by_bdaddr(dev, &tmp_addr)) { BT_DBG("connection to %s exists => close new connection", batostr(&tmp_addr)); sock_release(nsk); } else { //Start new thread for this session BT_DBG("starting bnep session on sock %p", nsk); bnep_start_session(nsk, (struct net_device *) kthread->arg); } } } //Kill thread exit_kthread(kthread); return;}/***************************************************************************/static int bnep_read_proc(char *buf, char **start, off_t offset, int count, int *eof, void *priv){ char *ptr = buf; int len; struct list_head *list_ptr; struct bnep_connection *bnep_conn; struct net_device *net_dev = root_dev; int counter; bdaddr_t tmp_addr; struct bnep_private *bnep_priv; ptr += sprintf(ptr, "BNEP device status:\n"); if (net_dev == NULL) { ptr += sprintf(ptr, " No PAN devices loaded\n"); } else { while (net_dev) { bnep_priv = bnep_get_priv(net_dev); ptr += sprintf(ptr, " %s\tBDAddr: %s Role: 0x%.4x\n", net_dev->name, batostr(&bnep_priv->source_address), bnep_priv->role_uuid); for (list_ptr = bnep_priv->bnep_connections.next; list_ptr != &bnep_priv->bnep_connections; list_ptr = list_ptr->next) { bnep_conn = list_entry(list_ptr, struct bnep_connection, list); baswap(&tmp_addr, &bluez_pi(bnep_conn->sk->sk)->dst); ptr += sprintf(ptr, "\t Connection: %s Role 0x%.4x\n", batostr(&tmp_addr), bnep_conn->destination_uuid); if (bnep_conn->filter_info.MulticastFilter) { for (counter = 0; counter < bnep_conn->filter_info.multicast_filter_count; counter++) { int byte_counter; ptr += sprintf(ptr, "\t\tMulticast Filter %d: ", counter); for (byte_counter = 5; byte_counter >= 0; byte_counter--) { ptr += sprintf(ptr, "%.2x%s", ((__u8 *) & bnep_conn-> filter_info. MulticastFilter[counter]. start)[byte_counter], byte_counter == 0 ? "" : ":"); } ptr += sprintf(ptr, " - "); for (byte_counter = 5; byte_counter >= 0; byte_counter--) { ptr += sprintf(ptr, "%.2x%s", ((__u8 *) & bnep_conn-> filter_info. MulticastFilter[counter]. stop)[byte_counter], byte_counter == 0 ? "" : ":"); } ptr += sprintf(ptr, "\n"); } } else { ptr += sprintf(ptr, "\t\tNo Multicast Filter active\n"); } if (bnep_conn->filter_info.NetFilter) { for (counter = 0; counter < bnep_conn->filter_info.net_filter_count; counter++) { ptr += sprintf(ptr, "\t\tProtocol Filter %d: 0x%.4x - 0x%.4x\n", counter, bnep_conn->filter_info. NetFilter[counter].start, bnep_conn->filter_info. NetFilter[counter].stop); } } else { ptr += sprintf(ptr, "\t\tNo Prototocl Filter active\n"); } } net_dev = bnep_priv->next_dev; ptr += sprintf(ptr, "\n"); } } len = ptr - buf; if (len <= count + offset) *eof = 1; *start = buf + offset; len -= offset; if (len > count) len = count; if (len < 0) len = 0; return len;}/******************************************************************************/int bnep_dev_control(struct bnep_dev_ioctl_struct *bnep_dev_ioctl){ int err = 0; if (bnep_dev_ioctl->net_device_command == NET_DEVICE_REMOVE) { //Find device in device list struct net_device *del_dev = NULL; struct net_device *pre_dev = NULL; struct net_device *tmp_dev = root_dev; struct bnep_private *priv = NULL; int status; //Remove device from dev list while (tmp_dev && !del_dev) { if (strcmp(tmp_dev->name, bnep_dev_ioctl->name) == 0) { //Check for active connections if (bnep_get_priv(tmp_dev)->connection_counter != 0) { BT_DBG("can't remove device with active connections"); return BNEP_ERR_DEVICE_CONNECTED; } del_dev = tmp_dev; if (pre_dev) bnep_get_priv(pre_dev)->next_dev = bnep_get_priv(tmp_dev)->next_dev; else root_dev = bnep_get_priv(tmp_dev)->next_dev; } else { pre_dev = tmp_dev; tmp_dev = bnep_get_priv(tmp_dev)->next_dev; } } if (!del_dev) { BT_DBG("device not loaded"); return BNEP_ERR_DEV_NOT_LOADED; } BT_DBG("remove eth net device"); priv = bnep_get_priv(del_dev); //Stop connection listener thread stop_kthread(&priv->listener_thread); //Clean interface to l2cap if (priv->bnep_sk) sock_release(priv->bnep_sk); //Clean interface from kernel unregister_netdev(del_dev); status = netdev_finish_unregister(del_dev); if (status) BT_DBG("can't free net device mem"); bnep_dev_counter--; MOD_DEC_USE_COUNT; } else if (bnep_dev_ioctl->net_device_command == NET_DEVICE_INSERT) { struct bnep_private *priv; struct net_device *new_dev; BT_DBG("insert eth net device"); //Allocate new eth device if (!(new_dev = alloc_etherdev(sizeof(struct bnep_private)))) return -ENOMEM; // Find a name for this unit if (dev_alloc_name(new_dev, bnep_dev_ioctl->name) < 0) { kfree(new_dev); return BNEP_ERR_ALLOC_NAME; } //Init device priv = bnep_get_priv(new_dev); priv->bnep_sk = NULL; priv->role_uuid = bnep_dev_ioctl->role_uuid; new_dev->init = bnep_init; spin_lock_init(&priv->lock); bacpy(&priv
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -