xref: /btstack/example/pan_lwip_http_server.c (revision 97dc5e692c7d94a280158af58036a0efee5b0e56)
1*97dc5e69SMatthias Ringwald /*
2*97dc5e69SMatthias Ringwald  * Copyright (C) 2014 BlueKitchen GmbH
3*97dc5e69SMatthias Ringwald  *
4*97dc5e69SMatthias Ringwald  * Redistribution and use in source and binary forms, with or without
5*97dc5e69SMatthias Ringwald  * modification, are permitted provided that the following conditions
6*97dc5e69SMatthias Ringwald  * are met:
7*97dc5e69SMatthias Ringwald  *
8*97dc5e69SMatthias Ringwald  * 1. Redistributions of source code must retain the above copyright
9*97dc5e69SMatthias Ringwald  *    notice, this list of conditions and the following disclaimer.
10*97dc5e69SMatthias Ringwald  * 2. Redistributions in binary form must reproduce the above copyright
11*97dc5e69SMatthias Ringwald  *    notice, this list of conditions and the following disclaimer in the
12*97dc5e69SMatthias Ringwald  *    documentation and/or other materials provided with the distribution.
13*97dc5e69SMatthias Ringwald  * 3. Neither the name of the copyright holders nor the names of
14*97dc5e69SMatthias Ringwald  *    contributors may be used to endorse or promote products derived
15*97dc5e69SMatthias Ringwald  *    from this software without specific prior written permission.
16*97dc5e69SMatthias Ringwald  * 4. Any redistribution, use, or modification is done solely for
17*97dc5e69SMatthias Ringwald  *    personal benefit and not for any commercial purpose or for
18*97dc5e69SMatthias Ringwald  *    monetary gain.
19*97dc5e69SMatthias Ringwald  *
20*97dc5e69SMatthias Ringwald  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21*97dc5e69SMatthias Ringwald  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22*97dc5e69SMatthias Ringwald  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23*97dc5e69SMatthias Ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
24*97dc5e69SMatthias Ringwald  * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25*97dc5e69SMatthias Ringwald  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26*97dc5e69SMatthias Ringwald  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27*97dc5e69SMatthias Ringwald  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28*97dc5e69SMatthias Ringwald  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29*97dc5e69SMatthias Ringwald  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30*97dc5e69SMatthias Ringwald  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31*97dc5e69SMatthias Ringwald  * SUCH DAMAGE.
32*97dc5e69SMatthias Ringwald  *
33*97dc5e69SMatthias Ringwald  * Please inquire about commercial licensing options at
34*97dc5e69SMatthias Ringwald  * [email protected]
35*97dc5e69SMatthias Ringwald  *
36*97dc5e69SMatthias Ringwald  */
37*97dc5e69SMatthias Ringwald 
38*97dc5e69SMatthias Ringwald #define __BTSTACK_FILE__ "pan_lwip_http_server.c"
39*97dc5e69SMatthias Ringwald 
40*97dc5e69SMatthias Ringwald // *****************************************************************************
41*97dc5e69SMatthias Ringwald /* EXAMPLE_START(pan_lwip_http_server): PAN - HTTP Server using lwIP
42*97dc5e69SMatthias Ringwald  *
43*97dc5e69SMatthias Ringwald  * @text Bluetooth PAN is mainly used for Internet Tethering, where e.g. a mobile
44*97dc5e69SMatthias Ringwald  * phone provides internet connection to a laptop or a tablet.
45*97dc5e69SMatthias Ringwald  *
46*97dc5e69SMatthias Ringwald  * Instead of regular internet access, it's also possible to provide a Web app on a
47*97dc5e69SMatthias Ringwald  * Bluetooth device, e.g. for configuration or maintenance. For some device,
48*97dc5e69SMatthias Ringwald  * this can be a more effective way to provide an interface compared to dedicated
49*97dc5e69SMatthias Ringwald  * smartphone applications (for Android and iOS).
50*97dc5e69SMatthias Ringwald  *
51*97dc5e69SMatthias Ringwald  * Before iOS 11, accessing an HTTP server via Bluetooth PAN was not supported on
52*97dc5e69SMatthias Ringwald  * the iPhone, but on iPod and iPad. With iOS 11, this works as expected.
53*97dc5e69SMatthias Ringwald  *
54*97dc5e69SMatthias Ringwald  * After pairing your device, please open the URL http://192.168.7.1 in your web
55*97dc5e69SMatthias Ringwald  * browser.
56*97dc5e69SMatthias Ringwald 
57*97dc5e69SMatthias Ringwald  */
58*97dc5e69SMatthias Ringwald  // *****************************************************************************
59*97dc5e69SMatthias Ringwald 
60*97dc5e69SMatthias Ringwald #include <stdio.h>
61*97dc5e69SMatthias Ringwald 
62*97dc5e69SMatthias Ringwald #include "btstack_config.h"
63*97dc5e69SMatthias Ringwald #include "bnep_lwip.h"
64*97dc5e69SMatthias Ringwald #include "btstack.h"
65*97dc5e69SMatthias Ringwald 
66*97dc5e69SMatthias Ringwald #include "lwip/init.h"
67*97dc5e69SMatthias Ringwald #include "lwip/opt.h"
68*97dc5e69SMatthias Ringwald #include "lwip/tcpip.h"
69*97dc5e69SMatthias Ringwald #include "lwip/apps/httpd.h"
70*97dc5e69SMatthias Ringwald #include "dhserver.h"
71*97dc5e69SMatthias Ringwald 
72*97dc5e69SMatthias Ringwald // network types
73*97dc5e69SMatthias Ringwald #define NETWORK_TYPE_IPv4       0x0800
74*97dc5e69SMatthias Ringwald #define NETWORK_TYPE_ARP        0x0806
75*97dc5e69SMatthias Ringwald #define NETWORK_TYPE_IPv6       0x86DD
76*97dc5e69SMatthias Ringwald 
77*97dc5e69SMatthias Ringwald static uint8_t pan_sdp_record[220];
78*97dc5e69SMatthias Ringwald 
79*97dc5e69SMatthias Ringwald static btstack_packet_callback_registration_t hci_event_callback_registration;
80*97dc5e69SMatthias Ringwald 
81*97dc5e69SMatthias Ringwald /*
82*97dc5e69SMatthias Ringwald  * @section Packet Handler
83*97dc5e69SMatthias Ringwald  *
84*97dc5e69SMatthias Ringwald  * @text All BNEP events are handled in the platform/bnep_lwip.c BNEP-LWIP Adapter.
85*97dc5e69SMatthias Ringwald  *       Here, we only print status information and handle pairing requests.
86*97dc5e69SMatthias Ringwald  */
87*97dc5e69SMatthias Ringwald 
88*97dc5e69SMatthias Ringwald /* LISTING_START(packetHandler): Packet Handler */
89*97dc5e69SMatthias Ringwald static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
90*97dc5e69SMatthias Ringwald     /* LISTING_PAUSE */
91*97dc5e69SMatthias Ringwald     UNUSED(channel);
92*97dc5e69SMatthias Ringwald     UNUSED(size);
93*97dc5e69SMatthias Ringwald 
94*97dc5e69SMatthias Ringwald     bd_addr_t event_addr;
95*97dc5e69SMatthias Ringwald 
96*97dc5e69SMatthias Ringwald     switch (packet_type) {
97*97dc5e69SMatthias Ringwald         case HCI_EVENT_PACKET:
98*97dc5e69SMatthias Ringwald             switch (hci_event_packet_get_type(packet)) {
99*97dc5e69SMatthias Ringwald 
100*97dc5e69SMatthias Ringwald                 case HCI_EVENT_PIN_CODE_REQUEST:
101*97dc5e69SMatthias Ringwald                     // inform about pin code request
102*97dc5e69SMatthias Ringwald                     printf("Pin code request - using '0000'\n");
103*97dc5e69SMatthias Ringwald                     hci_event_pin_code_request_get_bd_addr(packet, event_addr);
104*97dc5e69SMatthias Ringwald                     gap_pin_code_response(event_addr, "0000");
105*97dc5e69SMatthias Ringwald                     break;
106*97dc5e69SMatthias Ringwald 
107*97dc5e69SMatthias Ringwald                 case HCI_EVENT_USER_CONFIRMATION_REQUEST:
108*97dc5e69SMatthias Ringwald                     // inform about user confirmation request
109*97dc5e69SMatthias Ringwald                     printf("SSP User Confirmation Auto accept\n");
110*97dc5e69SMatthias Ringwald                     hci_event_user_confirmation_request_get_bd_addr(packet, event_addr);
111*97dc5e69SMatthias Ringwald                     break;
112*97dc5e69SMatthias Ringwald 
113*97dc5e69SMatthias Ringwald                 /* @text BNEP_EVENT_CHANNEL_OPENED is received after a BNEP connection was established or
114*97dc5e69SMatthias Ringwald                  * or when the connection fails. The status field returns the error code.
115*97dc5e69SMatthias Ringwald                  */
116*97dc5e69SMatthias Ringwald                 case BNEP_EVENT_CHANNEL_OPENED:
117*97dc5e69SMatthias Ringwald                     if (bnep_event_channel_opened_get_status(packet)) {
118*97dc5e69SMatthias Ringwald                         printf("BNEP channel open failed, status %02x\n", bnep_event_channel_opened_get_status(packet));
119*97dc5e69SMatthias Ringwald                     } else {
120*97dc5e69SMatthias Ringwald                         uint16_t uuid_source = bnep_event_channel_opened_get_source_uuid(packet);
121*97dc5e69SMatthias Ringwald                         uint16_t uuid_dest   = bnep_event_channel_opened_get_destination_uuid(packet);
122*97dc5e69SMatthias Ringwald                         uint16_t mtu         = bnep_event_channel_opened_get_mtu(packet);
123*97dc5e69SMatthias Ringwald                         bnep_event_channel_opened_get_remote_address(packet, event_addr);
124*97dc5e69SMatthias Ringwald                         printf("BNEP connection open succeeded to %s source UUID 0x%04x dest UUID: 0x%04x, max frame size %u\n", bd_addr_to_str(event_addr), uuid_source, uuid_dest, mtu);
125*97dc5e69SMatthias Ringwald                         printf("Please open 'http://192.168.7.1' in your web browser: \n");
126*97dc5e69SMatthias Ringwald                     }
127*97dc5e69SMatthias Ringwald                     break;
128*97dc5e69SMatthias Ringwald 
129*97dc5e69SMatthias Ringwald                 /* @text BNEP_EVENT_CHANNEL_CLOSED is received when the connection gets closed.
130*97dc5e69SMatthias Ringwald                  */
131*97dc5e69SMatthias Ringwald                 case BNEP_EVENT_CHANNEL_CLOSED:
132*97dc5e69SMatthias Ringwald                     printf("BNEP channel closed\n");
133*97dc5e69SMatthias Ringwald                     break;
134*97dc5e69SMatthias Ringwald 
135*97dc5e69SMatthias Ringwald                 default:
136*97dc5e69SMatthias Ringwald                     break;
137*97dc5e69SMatthias Ringwald             }
138*97dc5e69SMatthias Ringwald             break;
139*97dc5e69SMatthias Ringwald         default:
140*97dc5e69SMatthias Ringwald             break;
141*97dc5e69SMatthias Ringwald     }
142*97dc5e69SMatthias Ringwald }
143*97dc5e69SMatthias Ringwald /* LISTING_END */
144*97dc5e69SMatthias Ringwald 
145*97dc5e69SMatthias Ringwald /* @section PAN BNEP Setup
146*97dc5e69SMatthias Ringwald  *
147*97dc5e69SMatthias Ringwald  * @text Listing PanBnepSetup shows the setup of the PAN setup
148*97dc5e69SMatthias Ringwald  */
149*97dc5e69SMatthias Ringwald 
150*97dc5e69SMatthias Ringwald /* LISTING_START(PanBnepSetup): Configure GAP, register PAN NAP servier, register PAN NA SDP record. */
151*97dc5e69SMatthias Ringwald static void pan_bnep_setup(void){
152*97dc5e69SMatthias Ringwald 
153*97dc5e69SMatthias Ringwald     // Discoverable
154*97dc5e69SMatthias Ringwald     // Set local name with a template Bluetooth address, that will be automatically
155*97dc5e69SMatthias Ringwald     // replaced with a actual address once it is available, i.e. when BTstack boots
156*97dc5e69SMatthias Ringwald     // up and starts talking to a Bluetooth module.
157*97dc5e69SMatthias Ringwald     gap_set_local_name("PAN HTTP 00:00:00:00:00:00");
158*97dc5e69SMatthias Ringwald     gap_discoverable_control(1);
159*97dc5e69SMatthias Ringwald 
160*97dc5e69SMatthias Ringwald     // register for HCI events
161*97dc5e69SMatthias Ringwald     hci_event_callback_registration.callback = &packet_handler;
162*97dc5e69SMatthias Ringwald     hci_add_event_handler(&hci_event_callback_registration);
163*97dc5e69SMatthias Ringwald 
164*97dc5e69SMatthias Ringwald     // Initialize L2CAP
165*97dc5e69SMatthias Ringwald     l2cap_init();
166*97dc5e69SMatthias Ringwald 
167*97dc5e69SMatthias Ringwald     // Initialize BNEP
168*97dc5e69SMatthias Ringwald     bnep_init();
169*97dc5e69SMatthias Ringwald 
170*97dc5e69SMatthias Ringwald     // Init SDP
171*97dc5e69SMatthias Ringwald     sdp_init();
172*97dc5e69SMatthias Ringwald     memset(pan_sdp_record, 0, sizeof(pan_sdp_record));
173*97dc5e69SMatthias Ringwald     uint16_t network_packet_types[] = { NETWORK_TYPE_IPv4, NETWORK_TYPE_ARP, 0};    // 0 as end of list
174*97dc5e69SMatthias Ringwald 
175*97dc5e69SMatthias Ringwald     // NAP Network Access Type: Other, 1 MB/s
176*97dc5e69SMatthias Ringwald     pan_create_nap_sdp_record(pan_sdp_record, sdp_create_service_record_handle(), network_packet_types, NULL, NULL, BNEP_SECURITY_NONE, PAN_NET_ACCESS_TYPE_OTHER, 1000000, NULL, NULL);
177*97dc5e69SMatthias Ringwald     sdp_register_service(pan_sdp_record);
178*97dc5e69SMatthias Ringwald     printf("SDP service record size: %u\n", de_get_len((uint8_t*) pan_sdp_record));
179*97dc5e69SMatthias Ringwald 
180*97dc5e69SMatthias Ringwald     // Init BNEP lwIP Adapter
181*97dc5e69SMatthias Ringwald     bnep_lwip_init();
182*97dc5e69SMatthias Ringwald 
183*97dc5e69SMatthias Ringwald     // Setup NAP Service via BENP lwIP adapter
184*97dc5e69SMatthias Ringwald     bnep_lwip_register_service(BLUETOOTH_SERVICE_CLASS_NAP, 1691);
185*97dc5e69SMatthias Ringwald 
186*97dc5e69SMatthias Ringwald     // register callback - to print state
187*97dc5e69SMatthias Ringwald     bnep_lwip_register_packet_handler(packet_handler);
188*97dc5e69SMatthias Ringwald }
189*97dc5e69SMatthias Ringwald /* LISTING_END */
190*97dc5e69SMatthias Ringwald 
191*97dc5e69SMatthias Ringwald 
192*97dc5e69SMatthias Ringwald /* @section DHCP Server Configuration
193*97dc5e69SMatthias Ringwald  *
194*97dc5e69SMatthias Ringwald  * @text Listing DhcpSetup shows the DHCP Server configuration for network 192.168.7.0/8
195*97dc5e69SMatthias Ringwald  */
196*97dc5e69SMatthias Ringwald 
197*97dc5e69SMatthias Ringwald /* LISTING_START(DhcpSetup): Setup DHCP Server with 3 entries for 192.168.7.0/8. */
198*97dc5e69SMatthias Ringwald 
199*97dc5e69SMatthias Ringwald #define NUM_DHCP_ENTRY 3
200*97dc5e69SMatthias Ringwald 
201*97dc5e69SMatthias Ringwald static dhcp_entry_t entries[NUM_DHCP_ENTRY] =
202*97dc5e69SMatthias Ringwald {
203*97dc5e69SMatthias Ringwald     /* mac    ip address        subnet mask        lease time */
204*97dc5e69SMatthias Ringwald     { {0}, {192, 168, 7, 2}, {255, 255, 255, 0}, 24 * 60 * 60 },
205*97dc5e69SMatthias Ringwald     { {0}, {192, 168, 7, 3}, {255, 255, 255, 0}, 24 * 60 * 60 },
206*97dc5e69SMatthias Ringwald     { {0}, {192, 168, 7, 4}, {255, 255, 255, 0}, 24 * 60 * 60 }
207*97dc5e69SMatthias Ringwald };
208*97dc5e69SMatthias Ringwald 
209*97dc5e69SMatthias Ringwald static dhcp_config_t dhcp_config =
210*97dc5e69SMatthias Ringwald {
211*97dc5e69SMatthias Ringwald     {192, 168, 7, 1}, 67, /* server address, port */
212*97dc5e69SMatthias Ringwald     {0, 0, 0, 0},         /* dns server */
213*97dc5e69SMatthias Ringwald     NULL,                /* dns suffix */
214*97dc5e69SMatthias Ringwald     NUM_DHCP_ENTRY,       /* num entry */
215*97dc5e69SMatthias Ringwald     entries               /* entries */
216*97dc5e69SMatthias Ringwald };
217*97dc5e69SMatthias Ringwald /* LISTING_END */
218*97dc5e69SMatthias Ringwald 
219*97dc5e69SMatthias Ringwald 
220*97dc5e69SMatthias Ringwald /* @section DHCP Server Setup
221*97dc5e69SMatthias Ringwald  *
222*97dc5e69SMatthias Ringwald  * @text Listing LwipSetup shows the setup of the lwIP network stack and starts the DHCP Server
223*97dc5e69SMatthias Ringwald  */
224*97dc5e69SMatthias Ringwald 
225*97dc5e69SMatthias Ringwald /* LISTING_START(LwipSetup): Report lwIP version, init lwIP, start DHCP Serverr */
226*97dc5e69SMatthias Ringwald 
227*97dc5e69SMatthias Ringwald static void network_setup(void){
228*97dc5e69SMatthias Ringwald     printf("lwIP version: " LWIP_VERSION_STRING "\n");
229*97dc5e69SMatthias Ringwald 
230*97dc5e69SMatthias Ringwald #if BYTE_ORDER == LITTLE_ENDIAN
231*97dc5e69SMatthias Ringwald     // big endian detection not supported by build configuration
232*97dc5e69SMatthias Ringwald     if (btstack_is_big_endian()){
233*97dc5e69SMatthias Ringwald         printf("lwIP configured for little endian, but running on big endian. Please set BYTE_ORDER to BIG_ENDIAN in lwiopts.h\n");
234*97dc5e69SMatthias Ringwald         while (1);
235*97dc5e69SMatthias Ringwald     }
236*97dc5e69SMatthias Ringwald #endif
237*97dc5e69SMatthias Ringwald 
238*97dc5e69SMatthias Ringwald     // init lwIP stack
239*97dc5e69SMatthias Ringwald     lwip_init();
240*97dc5e69SMatthias Ringwald 
241*97dc5e69SMatthias Ringwald     // start DHCP Server
242*97dc5e69SMatthias Ringwald     dhserv_init(&dhcp_config);
243*97dc5e69SMatthias Ringwald 
244*97dc5e69SMatthias Ringwald     // start HTTP Server
245*97dc5e69SMatthias Ringwald     httpd_init();
246*97dc5e69SMatthias Ringwald }
247*97dc5e69SMatthias Ringwald /* LISTING_END */
248*97dc5e69SMatthias Ringwald 
249*97dc5e69SMatthias Ringwald 
250*97dc5e69SMatthias Ringwald /* @section Main
251*97dc5e69SMatthias Ringwald  *
252*97dc5e69SMatthias Ringwald  * @text Setup the lwIP network and PAN NAP
253*97dc5e69SMatthias Ringwald  */
254*97dc5e69SMatthias Ringwald 
255*97dc5e69SMatthias Ringwald /* LISTING_START(Main): Setup lwIP network and PAN NAP */
256*97dc5e69SMatthias Ringwald int btstack_main(int argc, const char * argv[]);
257*97dc5e69SMatthias Ringwald int btstack_main(int argc, const char * argv[]){
258*97dc5e69SMatthias Ringwald 
259*97dc5e69SMatthias Ringwald     (void)argc;
260*97dc5e69SMatthias Ringwald     (void)argv;
261*97dc5e69SMatthias Ringwald 
262*97dc5e69SMatthias Ringwald     // setup lwIP, HTTP, DHCP
263*97dc5e69SMatthias Ringwald     network_setup();
264*97dc5e69SMatthias Ringwald 
265*97dc5e69SMatthias Ringwald     // setup Classic PAN NAP Service
266*97dc5e69SMatthias Ringwald     pan_bnep_setup();
267*97dc5e69SMatthias Ringwald 
268*97dc5e69SMatthias Ringwald     // Turn on the device
269*97dc5e69SMatthias Ringwald     hci_power_control(HCI_POWER_ON);
270*97dc5e69SMatthias Ringwald     return 0;
271*97dc5e69SMatthias Ringwald }
272*97dc5e69SMatthias Ringwald /* LISTING_END */
273*97dc5e69SMatthias Ringwald 
274*97dc5e69SMatthias Ringwald /* EXAMPLE_END */
275