/* * get/set socket options */ int sco_ctloutput(int req, struct socket *so, struct sockopt *sopt) { struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb; int err = 0; DPRINTFN(2, "req %s\n", prcorequests[req]); if (pcb == NULL) return EINVAL; if (sopt->sopt_level != BTPROTO_SCO) return ENOPROTOOPT; switch(req) { case PRCO_GETOPT: err = sco_getopt(pcb, sopt); break; case PRCO_SETOPT: err = sco_setopt(pcb, sopt); break; default: err = ENOPROTOOPT; break; } return err; }
static int btsco_open(void *hdl, int flags) { struct sockaddr_bt sa; struct btsco_softc *sc = hdl; struct sockopt sopt; int err, timo; DPRINTF("%s flags 0x%x\n", sc->sc_name, flags); /* flags FREAD & FWRITE? */ if (sc->sc_sco != NULL || sc->sc_sco_l != NULL) return EIO; KASSERT(mutex_owned(bt_lock)); memset(&sa, 0, sizeof(sa)); sa.bt_len = sizeof(sa); sa.bt_family = AF_BLUETOOTH; bdaddr_copy(&sa.bt_bdaddr, &sc->sc_laddr); if (sc->sc_flags & BTSCO_LISTEN) { err = sco_attach_pcb(&sc->sc_sco_l, &btsco_sco_proto, sc); if (err) goto done; err = sco_bind_pcb(sc->sc_sco_l, &sa); if (err) { sco_detach_pcb(&sc->sc_sco_l); goto done; } err = sco_listen_pcb(sc->sc_sco_l); if (err) { sco_detach_pcb(&sc->sc_sco_l); goto done; } timo = 0; /* no timeout */ } else { err = sco_attach_pcb(&sc->sc_sco, &btsco_sco_proto, sc); if (err) goto done; err = sco_bind_pcb(sc->sc_sco, &sa); if (err) { sco_detach_pcb(&sc->sc_sco); goto done; } bdaddr_copy(&sa.bt_bdaddr, &sc->sc_raddr); err = sco_connect_pcb(sc->sc_sco, &sa); if (err) { sco_detach_pcb(&sc->sc_sco); goto done; } timo = BTSCO_TIMEOUT; } sc->sc_state = BTSCO_WAIT_CONNECT; while (err == 0 && sc->sc_state == BTSCO_WAIT_CONNECT) err = cv_timedwait_sig(&sc->sc_connect, bt_lock, timo); switch (sc->sc_state) { case BTSCO_CLOSED: /* disconnected */ err = sc->sc_err; /* fall through to */ case BTSCO_WAIT_CONNECT: /* error */ if (sc->sc_sco != NULL) sco_detach_pcb(&sc->sc_sco); if (sc->sc_sco_l != NULL) sco_detach_pcb(&sc->sc_sco_l); break; case BTSCO_OPEN: /* hurrah */ sockopt_init(&sopt, BTPROTO_SCO, SO_SCO_MTU, 0); (void)sco_getopt(sc->sc_sco, &sopt); (void)sockopt_get(&sopt, &sc->sc_mtu, sizeof(sc->sc_mtu)); sockopt_destroy(&sopt); break; default: UNKNOWN(sc->sc_state); break; } done: DPRINTF("done err=%d, sc_state=%d, sc_mtu=%d\n", err, sc->sc_state, sc->sc_mtu); return err; }