/* * listen for our device */ static int bthidev_listen(struct bthidev_softc *sc) { struct sockaddr_bt sa; int err; memset(&sa, 0, sizeof(sa)); sa.bt_len = sizeof(sa); sa.bt_family = AF_BLUETOOTH; bdaddr_copy(&sa.bt_bdaddr, &sc->sc_laddr); /* * Listen on control PSM */ err = l2cap_attach(&sc->sc_ctl_l, &bthidev_ctl_proto, sc); if (err) return err; err = l2cap_setopt(sc->sc_ctl_l, &sc->sc_mode); if (err) return err; sa.bt_psm = sc->sc_ctlpsm; err = l2cap_bind(sc->sc_ctl_l, &sa); if (err) return err; err = l2cap_listen(sc->sc_ctl_l); if (err) return err; /* * Listen on interrupt PSM */ err = l2cap_attach(&sc->sc_int_l, &bthidev_int_proto, sc); if (err) return err; err = l2cap_setopt(sc->sc_int_l, &sc->sc_mode); if (err) return err; sa.bt_psm = sc->sc_intpsm; err = l2cap_bind(sc->sc_int_l, &sa); if (err) return err; err = l2cap_listen(sc->sc_int_l); if (err) return err; sc->sc_state = BTHID_WAIT_CTL; return 0; }
static void bthidev_ctl_connected(void *arg) { struct sockaddr_bt sa; struct bthidev_softc *sc = arg; int err; if (sc->sc_state != BTHID_WAIT_CTL) return; KASSERT(sc->sc_ctl != NULL); KASSERT(sc->sc_int == NULL); if (sc->sc_flags & BTHID_CONNECTING) { /* initiate connect on interrupt PSM */ err = l2cap_attach(&sc->sc_int, &bthidev_int_proto, sc); if (err) goto fail; err = l2cap_setopt(sc->sc_int, &sc->sc_mode); if (err) goto fail; memset(&sa, 0, sizeof(sa)); sa.bt_len = sizeof(sa); sa.bt_family = AF_BLUETOOTH; bdaddr_copy(&sa.bt_bdaddr, &sc->sc_laddr); err = l2cap_bind(sc->sc_int, &sa); if (err) goto fail; sa.bt_psm = sc->sc_intpsm; bdaddr_copy(&sa.bt_bdaddr, &sc->sc_raddr); err = l2cap_connect(sc->sc_int, &sa); if (err) goto fail; } sc->sc_state = BTHID_WAIT_INT; return; fail: l2cap_detach(&sc->sc_ctl); sc->sc_ctl = NULL; aprint_error_dev(sc->sc_dev, "connect failed (%d)\n", err); }
/* * start connecting to our device */ int bthidev_connect(struct bthidev_softc *sc) { struct sockaddr_bt sa; int err; if (sc->sc_attempts++ > 0) printf("%s: connect (#%d)\n", sc->sc_btdev.sc_dev.dv_xname, sc->sc_attempts); memset(&sa, 0, sizeof(sa)); sa.bt_len = sizeof(sa); sa.bt_family = AF_BLUETOOTH; err = l2cap_attach(&sc->sc_ctl, &bthidev_ctl_proto, sc); if (err) { printf("%s: l2cap_attach failed (%d)\n", sc->sc_btdev.sc_dev.dv_xname, err); return err; } err = l2cap_setlinkmode(sc->sc_ctl, sc->sc_mode); if (err) return err; bdaddr_copy(&sa.bt_bdaddr, &sc->sc_laddr); err = l2cap_bind(sc->sc_ctl, &sa); if (err) { printf("%s: l2cap_bind failed (%d)\n", sc->sc_btdev.sc_dev.dv_xname, err); return err; } sa.bt_psm = sc->sc_ctlpsm; bdaddr_copy(&sa.bt_bdaddr, &sc->sc_raddr); err = l2cap_connect(sc->sc_ctl, &sa); if (err) { printf("%s: l2cap_connect failed (%d)\n", sc->sc_btdev.sc_dev.dv_xname, err); return err; } sc->sc_state = BTHID_WAIT_CTL; return 0; }
/* * start connecting to our device */ static int bthidev_connect(struct bthidev_softc *sc) { struct sockaddr_bt sa; int err; if (sc->sc_attempts++ > 0) aprint_verbose_dev(sc->sc_dev, "connect (#%d)\n", sc->sc_attempts); memset(&sa, 0, sizeof(sa)); sa.bt_len = sizeof(sa); sa.bt_family = AF_BLUETOOTH; err = l2cap_attach(&sc->sc_ctl, &bthidev_ctl_proto, sc); if (err) { aprint_error_dev(sc->sc_dev, "l2cap_attach failed (%d)\n", err); return err; } err = l2cap_setopt(sc->sc_ctl, &sc->sc_mode); if (err) return err; bdaddr_copy(&sa.bt_bdaddr, &sc->sc_laddr); err = l2cap_bind(sc->sc_ctl, &sa); if (err) { aprint_error_dev(sc->sc_dev, "l2cap_bind failed (%d)\n", err); return err; } sa.bt_psm = sc->sc_ctlpsm; bdaddr_copy(&sa.bt_bdaddr, &sc->sc_raddr); err = l2cap_connect(sc->sc_ctl, &sa); if (err) { aprint_error_dev(sc->sc_dev, "l2cap_connect failed (%d)\n", err); return err; } sc->sc_state = BTHID_WAIT_CTL; return 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; }