Disable IPSP feature
[platform/upstream/bluez.git] / emulator / vhci.c
1 /*
2  *
3  *  BlueZ - Bluetooth protocol stack for Linux
4  *
5  *  Copyright (C) 2011-2014  Intel Corporation
6  *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
7  *
8  *
9  *  This library is free software; you can redistribute it and/or
10  *  modify it under the terms of the GNU Lesser General Public
11  *  License as published by the Free Software Foundation; either
12  *  version 2.1 of the License, or (at your option) any later version.
13  *
14  *  This library is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  *  Lesser General Public License for more details.
18  *
19  *  You should have received a copy of the GNU Lesser General Public
20  *  License along with this library; if not, write to the Free Software
21  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
22  *
23  */
24
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28
29 #include <stdio.h>
30 #include <errno.h>
31 #include <fcntl.h>
32 #include <unistd.h>
33 #include <stdlib.h>
34 #include <string.h>
35
36 #include "lib/bluetooth.h"
37 #include "lib/hci.h"
38
39 #include "src/shared/mainloop.h"
40 #include "monitor/bt.h"
41 #include "btdev.h"
42 #include "vhci.h"
43
44 #define uninitialized_var(x) x = x
45
46 struct vhci {
47         enum vhci_type type;
48         int fd;
49         struct btdev *btdev;
50 };
51
52 static void vhci_destroy(void *user_data)
53 {
54         struct vhci *vhci = user_data;
55
56         btdev_destroy(vhci->btdev);
57
58         close(vhci->fd);
59
60         free(vhci);
61 }
62
63 static void vhci_write_callback(const struct iovec *iov, int iovlen,
64                                                         void *user_data)
65 {
66         struct vhci *vhci = user_data;
67         ssize_t written;
68
69         written = writev(vhci->fd, iov, iovlen);
70         if (written < 0)
71                 return;
72 }
73
74 static void vhci_read_callback(int fd, uint32_t events, void *user_data)
75 {
76         struct vhci *vhci = user_data;
77         unsigned char buf[4096];
78         ssize_t len;
79
80         if (events & (EPOLLERR | EPOLLHUP))
81                 return;
82
83         len = read(vhci->fd, buf, sizeof(buf));
84         if (len < 1)
85                 return;
86
87         switch (buf[0]) {
88         case BT_H4_CMD_PKT:
89         case BT_H4_ACL_PKT:
90         case BT_H4_SCO_PKT:
91                 btdev_receive_h4(vhci->btdev, buf, len);
92                 break;
93         }
94 }
95
96 struct vhci *vhci_open(enum vhci_type type)
97 {
98         struct vhci *vhci;
99         enum btdev_type uninitialized_var(btdev_type);
100         unsigned char uninitialized_var(ctrl_type);
101         unsigned char setup_cmd[2];
102         static uint8_t id = 0x23;
103
104         switch (type) {
105         case VHCI_TYPE_BREDRLE:
106                 btdev_type = BTDEV_TYPE_BREDRLE;
107                 ctrl_type = HCI_BREDR;
108                 break;
109         case VHCI_TYPE_BREDR:
110                 btdev_type = BTDEV_TYPE_BREDR;
111                 ctrl_type = HCI_BREDR;
112                 break;
113         case VHCI_TYPE_LE:
114                 btdev_type = BTDEV_TYPE_LE;
115                 ctrl_type = HCI_BREDR;
116                 break;
117         case VHCI_TYPE_AMP:
118                 btdev_type = BTDEV_TYPE_AMP;
119                 ctrl_type = HCI_AMP;
120                 break;
121         }
122
123         vhci = malloc(sizeof(*vhci));
124         if (!vhci)
125                 return NULL;
126
127         memset(vhci, 0, sizeof(*vhci));
128         vhci->type = type;
129
130         vhci->fd = open("/dev/vhci", O_RDWR | O_NONBLOCK);
131         if (vhci->fd < 0) {
132                 free(vhci);
133                 return NULL;
134         }
135
136         setup_cmd[0] = HCI_VENDOR_PKT;
137         setup_cmd[1] = ctrl_type;
138
139         if (write(vhci->fd, setup_cmd, sizeof(setup_cmd)) < 0) {
140                 close(vhci->fd);
141                 free(vhci);
142                 return NULL;
143         }
144
145         vhci->btdev = btdev_create(btdev_type, id++);
146         if (!vhci->btdev) {
147                 close(vhci->fd);
148                 free(vhci);
149                 return NULL;
150         }
151
152         btdev_set_send_handler(vhci->btdev, vhci_write_callback, vhci);
153
154         if (mainloop_add_fd(vhci->fd, EPOLLIN, vhci_read_callback,
155                                                 vhci, vhci_destroy) < 0) {
156                 btdev_destroy(vhci->btdev);
157                 close(vhci->fd);
158                 free(vhci);
159                 return NULL;
160         }
161
162         return vhci;
163 }
164
165 void vhci_close(struct vhci *vhci)
166 {
167         if (!vhci)
168                 return;
169
170         mainloop_remove_fd(vhci->fd);
171 }