Beispiel #1
0
int
bthidev_detach(struct device *self, int flags)
{
	struct bthidev_softc *sc = (struct bthidev_softc *)self;
	struct bthidev *hidev;

	mutex_enter(&bt_lock);
	sc->sc_flags = 0;	/* disable reconnecting */

	/* release interrupt listen */
	if (sc->sc_int_l != NULL) {
		l2cap_detach(&sc->sc_int_l);
		sc->sc_int_l = NULL;
	}

	/* release control listen */
	if (sc->sc_ctl_l != NULL) {
		l2cap_detach(&sc->sc_ctl_l);
		sc->sc_ctl_l = NULL;
	}

	/* close interrupt channel */
	if (sc->sc_int != NULL) {
		l2cap_disconnect(sc->sc_int, 0);
		l2cap_detach(&sc->sc_int);
		sc->sc_int = NULL;
	}

	/* close control channel */
	if (sc->sc_ctl != NULL) {
		l2cap_disconnect(sc->sc_ctl, 0);
		l2cap_detach(&sc->sc_ctl);
		sc->sc_ctl = NULL;
	}

	/* remove timeout */
	timeout_del(&sc->sc_reconnect);

	mutex_exit(&bt_lock);

	/* detach children */
	while ((hidev = LIST_FIRST(&sc->sc_list)) != NULL) {
		LIST_REMOVE(hidev, sc_next);
		config_detach(&hidev->sc_dev, flags);
	}

	/* release descriptor */
	if (sc->sc_desc != NULL) {
		free(sc->sc_desc, M_BTHIDEV);
		sc->sc_desc = NULL;
	}
	return 0;
}
Beispiel #2
0
static int
bthidev_detach(device_t self, int flags)
{
	struct bthidev_softc *sc = device_private(self);
	struct bthidev *hidev;

	mutex_enter(bt_lock);
	sc->sc_flags = 0;	/* disable reconnecting */

	/* release interrupt listen */
	if (sc->sc_int_l != NULL) {
		l2cap_detach(&sc->sc_int_l);
		sc->sc_int_l = NULL;
	}

	/* release control listen */
	if (sc->sc_ctl_l != NULL) {
		l2cap_detach(&sc->sc_ctl_l);
		sc->sc_ctl_l = NULL;
	}

	/* close interrupt channel */
	if (sc->sc_int != NULL) {
		l2cap_disconnect(sc->sc_int, 0);
		l2cap_detach(&sc->sc_int);
		sc->sc_int = NULL;
	}

	/* close control channel */
	if (sc->sc_ctl != NULL) {
		l2cap_disconnect(sc->sc_ctl, 0);
		l2cap_detach(&sc->sc_ctl);
		sc->sc_ctl = NULL;
	}

	callout_halt(&sc->sc_reconnect, bt_lock);
	callout_destroy(&sc->sc_reconnect);

	mutex_exit(bt_lock);

	/* detach children */
	while ((hidev = LIST_FIRST(&sc->sc_list)) != NULL) {
		LIST_REMOVE(hidev, sc_next);
		config_detach(hidev->sc_dev, flags);
	}

	sockopt_destroy(&sc->sc_mode);

	return 0;
}
Beispiel #3
0
static void stdin_process(btstack_data_source_t *ds, btstack_data_source_callback_type_t callback_type){
    char buffer;
    read(ds->fd, &buffer, 1);
    switch (buffer){
        case 'c':
            printf("Creating L2CAP Connection to %s, PSM SDP\n", bd_addr_to_str(remote));
            l2cap_create_channel(packet_handler, remote, PSM_SDP, 100, NULL);
            break;
        case 's':
            printf("Send L2CAP Data\n");
            l2cap_send(local_cid, (uint8_t *) "0123456789", 10);
            break;
        case 'e':
            printf("Send L2CAP ECHO Request\n");
            l2cap_send_echo_request(handle, (uint8_t *)  "Hello World!", 13);
            break;
        case 'd':
            printf("L2CAP Channel Closed\n");
            l2cap_disconnect(local_cid, 0);
            break;
        case '\n':
        case '\r':
            break;
        default:
            show_usage();
            break;

    }
}
Beispiel #4
0
static void stdin_process(char buffer){
    switch (buffer){
        case 'c':
            printf("Creating L2CAP Connection to %s, PSM SDP\n", bd_addr_to_str(remote));
            if (l2cap_ertm){
                l2cap_create_ertm_channel(packet_handler, remote, BLUETOOTH_PROTOCOL_SDP, &ertm_config, ertm_buffer, sizeof(ertm_buffer), &local_cid);
            } else {
                l2cap_create_channel(packet_handler, remote, BLUETOOTH_PROTOCOL_SDP, 100, &local_cid);
            }
            break;
        case 'b':
            printf("Set channel busy\n");
            l2cap_ertm_set_busy(local_cid);
            break;
        case 'B':
            printf("Set channel ready\n");
            l2cap_ertm_set_ready(local_cid);
            break;
        case 's':
            printf("Send some L2CAP Data\n");
            l2cap_send(local_cid, (uint8_t *) "0123456789", 10);
            break;
        case 'S':
            printf("Send more L2CAP Data\n");
            l2cap_send(local_cid, (uint8_t *) "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789", 100);
            break;
        case 'd':
            printf("L2CAP Channel Closed\n");
            l2cap_disconnect(local_cid, 0);
            break;
        case 'e':
            printf("L2CAP Enhanced Retransmission Mode (ERTM) optional\n");
            l2cap_ertm = 1;
            ertm_config.ertm_mandatory = 0;
            break;
        case 'E':
            printf("L2CAP Enhanced Retransmission Mode (ERTM) mandatory\n");
            l2cap_ertm = 1;
            ertm_config.ertm_mandatory = 1;
            break;
        case 'p':
            printf("Send L2CAP ECHO Request\n");
            l2cap_send_echo_request(handle, (uint8_t *)  "Hello World!", 13);
            break;
        case 't':
            printf("Disconnect ACL handle\n");
            gap_disconnect(handle);
            break;
        case '\n':
        case '\r':
            break;
        default:
            show_usage();
            break;

    }
}
Beispiel #5
0
/*
 * callouts are scheduled after connections have been lost, in order
 * to clean up and reconnect.
 */
static void
bthidev_timeout(void *arg)
{
	struct bthidev_softc *sc = arg;

	mutex_enter(bt_lock);
	callout_ack(&sc->sc_reconnect);

	switch (sc->sc_state) {
	case BTHID_CLOSED:
		if (sc->sc_int != NULL) {
			l2cap_disconnect(sc->sc_int, 0);
			break;
		}

		if (sc->sc_ctl != NULL) {
			l2cap_disconnect(sc->sc_ctl, 0);
			break;
		}

		if (sc->sc_flags & BTHID_RECONNECT) {
			sc->sc_flags |= BTHID_CONNECTING;
			bthidev_connect(sc);
			break;
		}

		break;

	case BTHID_WAIT_CTL:
		break;

	case BTHID_WAIT_INT:
		break;

	case BTHID_OPEN:
		break;

	default:
		break;
	}
	mutex_exit(bt_lock);
}
Beispiel #6
0
/*
 * User Request.
 * up is socket
 * m is either
 *	optional mbuf chain containing message
 *	ioctl command (PRU_CONTROL)
 * nam is either
 *	optional mbuf chain containing an address
 *	ioctl data (PRU_CONTROL)
 *	optionally protocol number (PRU_ATTACH)
 *	message flags (PRU_RCVD)
 * ctl is either
 *	optional mbuf chain containing socket options
 *	optional interface pointer (PRU_CONTROL, PRU_PURGEIF)
 * l is pointer to process requesting action (if any)
 *
 * we are responsible for disposing of m and ctl if
 * they are mbuf chains
 */
int
l2cap_usrreq(struct socket *up, int req, struct mbuf *m,
    struct mbuf *nam, struct mbuf *ctl, struct proc *p)
{
	struct l2cap_channel *pcb = up->so_pcb;
	struct sockaddr_bt *sa;
	struct mbuf *m0;
	int err = 0;

#ifdef notyet			/* XXX */
	DPRINTFN(2, "%s\n", prurequests[req]);
#endif

	switch (req) {
	case PRU_CONTROL:
		return EPASSTHROUGH;

#ifdef notyet			/* XXX */
	case PRU_PURGEIF:
		return EOPNOTSUPP;
#endif

	case PRU_ATTACH:
		/* XXX solock() and bt_lock fiddling in NetBSD */
		if (pcb != NULL)
			return EINVAL;
		/*
		 * For L2CAP socket PCB we just use an l2cap_channel structure
		 * since we have nothing to add..
		 */
		err = soreserve(up, l2cap_sendspace, l2cap_recvspace);
		if (err)
			return err;

		return l2cap_attach((struct l2cap_channel **)&up->so_pcb,
					&l2cap_proto, up);
	}

	if (pcb == NULL) {
		err = EINVAL;
		goto release;
	}

	switch(req) {
	case PRU_DISCONNECT:
		soisdisconnecting(up);
		return l2cap_disconnect(pcb, up->so_linger);

	case PRU_ABORT:
		l2cap_disconnect(pcb, 0);
		soisdisconnected(up);
		/* fall through to */
	case PRU_DETACH:
		return l2cap_detach((struct l2cap_channel **)&up->so_pcb);

	case PRU_BIND:
		KASSERT(nam != NULL);
		sa = mtod(nam, struct sockaddr_bt *);

		if (sa->bt_len != sizeof(struct sockaddr_bt))
			return EINVAL;

		if (sa->bt_family != AF_BLUETOOTH)
			return EAFNOSUPPORT;

		return l2cap_bind(pcb, sa);

	case PRU_CONNECT:
		KASSERT(nam != NULL);
		sa = mtod(nam, struct sockaddr_bt *);

		if (sa->bt_len != sizeof(struct sockaddr_bt))
			return EINVAL;

		if (sa->bt_family != AF_BLUETOOTH)
			return EAFNOSUPPORT;

		soisconnecting(up);
		return l2cap_connect(pcb, sa);

	case PRU_PEERADDR:
		KASSERT(nam != NULL);
		sa = mtod(nam, struct sockaddr_bt *);
		nam->m_len = sizeof(struct sockaddr_bt);
		return l2cap_peeraddr(pcb, sa);

	case PRU_SOCKADDR:
		KASSERT(nam != NULL);
		sa = mtod(nam, struct sockaddr_bt *);
		nam->m_len = sizeof(struct sockaddr_bt);
		return l2cap_sockaddr(pcb, sa);

	case PRU_SHUTDOWN:
		socantsendmore(up);
		break;

	case PRU_SEND:
		KASSERT(m != NULL);
		if (m->m_pkthdr.len == 0)
			break;

		if (m->m_pkthdr.len > pcb->lc_omtu) {
			err = EMSGSIZE;
			break;
		}

		m0 = m_copym(m, 0, M_COPYALL, M_DONTWAIT);
		if (m0 == NULL) {
			err = ENOMEM;
			break;
		}

		if (ctl)	/* no use for that */
			m_freem(ctl);

		sbappendrecord(&up->so_snd, m);
		return l2cap_send(pcb, m0);

	case PRU_SENSE:
		return 0;		/* (no release) */

	case PRU_RCVD:
	case PRU_RCVOOB:
		return EOPNOTSUPP;	/* (no release) */

	case PRU_LISTEN:
		return l2cap_listen(pcb);

	case PRU_ACCEPT:
		KASSERT(nam != NULL);
		sa = mtod(nam, struct sockaddr_bt *);
		nam->m_len = sizeof(struct sockaddr_bt);
		return l2cap_peeraddr(pcb, sa);

	case PRU_CONNECT2:
	case PRU_SENDOOB:
	case PRU_FASTTIMO:
	case PRU_SLOWTIMO:
	case PRU_PROTORCV:
	case PRU_PROTOSEND:
		err = EOPNOTSUPP;
		break;

	default:
		UNKNOWN(req);
		err = EOPNOTSUPP;
		break;
	}

release:
	if (m) m_freem(m);
	if (ctl) m_freem(ctl);
	return err;
}
Beispiel #7
0
void sdp_client_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
    UNUSED(size);
    
    // uint16_t handle;
    if (packet_type == L2CAP_DATA_PACKET){
        uint16_t responseTransactionID = big_endian_read_16(packet,1);
        if (responseTransactionID != transactionID){
            log_error("Mismatching transaction ID, expected %u, found %u.", transactionID, responseTransactionID);
            return;
        } 
        
        if (packet[0] == SDP_ErrorResponse){
            log_error("Received error response with code %u, disconnecting", packet[2]);
            l2cap_disconnect(sdp_cid, 0);
            return;
        }

        if (packet[0] != SDP_ServiceSearchAttributeResponse 
         && packet[0] != SDP_ServiceSearchResponse
         && packet[0] != SDP_ServiceAttributeResponse){
            log_error("Not a valid PDU ID, expected %u, %u or %u, found %u.", SDP_ServiceSearchResponse, 
                                    SDP_ServiceAttributeResponse, SDP_ServiceSearchAttributeResponse, packet[0]);
            return;
        }

        PDU_ID = (SDP_PDU_ID_t)packet[0];
        log_debug("SDP Client :: PDU ID. %u ,%u", PDU_ID, packet[0]);
        switch (PDU_ID){
#ifdef ENABLE_SDP_EXTRA_QUERIES
            case SDP_ServiceSearchResponse:
                sdp_client_parse_service_search_response(packet);
                break;
            case SDP_ServiceAttributeResponse:
                sdp_client_parse_service_attribute_response(packet);
                break;
#endif
            case SDP_ServiceSearchAttributeResponse:
                sdp_client_parse_service_search_attribute_response(packet);
                break;
            default:
                log_error("SDP Client :: PDU ID invalid. %u ,%u", PDU_ID, packet[0]);
                return;
        }

        // continuation set or DONE?
        if (continuationStateLen == 0){
            log_debug("SDP Client Query DONE! ");
            sdp_client_state = QUERY_COMPLETE;
            l2cap_disconnect(sdp_cid, 0);
            return;
        }
        // prepare next request and send
        sdp_client_state = W2_SEND;
        l2cap_request_can_send_now_event(sdp_cid);
        return;
    }
    
    if (packet_type != HCI_EVENT_PACKET) return;
    
    switch(hci_event_packet_get_type(packet)){
        case L2CAP_EVENT_CHANNEL_OPENED:
            if (sdp_client_state != W4_CONNECT) break;
            // data: event (8), len(8), status (8), address(48), handle (16), psm (16), local_cid(16), remote_cid (16), local_mtu(16), remote_mtu(16) 
            if (packet[2]) {
                log_info("SDP Client Connection failed, status 0x%02x.", packet[2]);
                sdp_client_state = INIT;
                sdp_parser_handle_done(packet[2]);
                break;
            }
            sdp_cid = channel;
            mtu = little_endian_read_16(packet, 17);
            // handle = little_endian_read_16(packet, 9);
            log_debug("SDP Client Connected, cid %x, mtu %u.", sdp_cid, mtu);

            sdp_client_state = W2_SEND;
            l2cap_request_can_send_now_event(sdp_cid);
            break;

        case L2CAP_EVENT_CAN_SEND_NOW:
            if(l2cap_event_can_send_now_get_local_cid(packet) == sdp_cid){
                sdp_client_send_request(sdp_cid);
            }
            break;
        case L2CAP_EVENT_CHANNEL_CLOSED: {
            if (sdp_cid != little_endian_read_16(packet, 2)) {
                // log_info("Received L2CAP_EVENT_CHANNEL_CLOSED for cid %x, current cid %x\n",  little_endian_read_16(packet, 2),sdp_cid);
                break;
            }
            log_info("SDP Client disconnected.");
            uint8_t status = sdp_client_state == QUERY_COMPLETE ? 0 : SDP_QUERY_INCOMPLETE;
            sdp_client_state = INIT;
            sdp_parser_handle_done(status);
            break;
        }
        default:
            break;
    }
}