int ng_l2cap_l2ca_qos_ind(ng_l2cap_chan_p ch) { ng_l2cap_p l2cap = ch->con->l2cap; struct ng_mesg *msg = NULL; ng_l2cap_l2ca_qos_ind_ip *ip = NULL; int error = 0; /* Check if upstream hook is connected and valid */ if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { NG_L2CAP_ERR( "%s: %s - unable to send L2CA_QoSViolationInd message. " \ "Hook is not connected or valid, psm=%d\n", __func__, NG_NODE_NAME(l2cap->node), ch->psm); return (ENOTCONN); } /* Create and send L2CA_QoSViolationInd message */ NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_QOS_IND, sizeof(*ip), M_NOWAIT); if (msg == NULL) error = ENOMEM; else { ip = (ng_l2cap_l2ca_qos_ind_ip *)(msg->data); bcopy(&ch->con->remote, &ip->bdaddr, sizeof(ip->bdaddr)); NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0); } return (error); } /* ng_l2cap_l2ca_qos_ind */
int ng_hci_lp_enc_change(ng_hci_unit_con_p con, int status) { ng_hci_unit_p unit = con->unit; struct ng_mesg *msg = NULL; ng_hci_lp_enc_change_ep *ep = NULL; int error; if (con->link_type != NG_HCI_LINK_SCO) { if (unit->acl != NULL && NG_HOOK_IS_VALID(unit->acl)) { NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_ENC_CHG, sizeof(*ep), M_NOWAIT); if (msg != NULL) { ep = (ng_hci_lp_enc_change_ep *) msg->data; ep->status = status; ep->link_type = con->link_type; ep->con_handle = con->con_handle; NG_SEND_MSG_HOOK(error, unit->node, msg, unit->acl, 0); } } else NG_HCI_INFO( "%s: %s - ACL hook not valid, hook=%p\n", __func__, NG_NODE_NAME(unit->node), unit->acl); } return (0); } /* ng_hci_lp_con_cfm */
int ng_l2cap_l2ca_cfg_rsp_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result) { ng_l2cap_p l2cap = ch->con->l2cap; struct ng_mesg *msg = NULL; ng_l2cap_l2ca_cfg_rsp_op *op = NULL; int error = 0; /* Check if upstream hook is connected and valid */ if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { NG_L2CAP_ERR( "%s: %s - unable to send L2CA_ConfigRsp response message. " \ "Hook is not connected or valid, psm=%d\n", __func__, NG_NODE_NAME(l2cap->node), ch->psm); return (ENOTCONN); } /* Create and send L2CA_ConfigRsp response message */ NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CFG_RSP, sizeof(*op), M_NOWAIT); if (msg == NULL) error = ENOMEM; else { msg->header.token = token; msg->header.flags |= NGF_RESP; op = (ng_l2cap_l2ca_cfg_rsp_op *)(msg->data); op->result = result; NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0); } return (error); } /* ng_l2cap_l2ca_cfg_rsp_rsp */
int ng_l2cap_l2ca_cfg_ind(ng_l2cap_chan_p ch) { ng_l2cap_p l2cap = ch->con->l2cap; struct ng_mesg *msg = NULL; ng_l2cap_l2ca_cfg_ind_ip *ip = NULL; int error = 0; /* Check if upstream hook is connected and valid */ if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { NG_L2CAP_ERR( "%s: %s - Unable to send L2CA_ConfigInd message. " \ "Hook is not connected or valid, psm=%d\n", __func__, NG_NODE_NAME(l2cap->node), ch->psm); return (ENOTCONN); } /* Create and send L2CA_ConnectInd message */ NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CFG_IND, sizeof(*ip), M_NOWAIT); if (msg == NULL) error = ENOMEM; else { ip = (ng_l2cap_l2ca_cfg_ind_ip *)(msg->data); ip->lcid = ch->scid; ip->omtu = ch->omtu; bcopy(&ch->iflow, &ip->iflow, sizeof(ip->iflow)); ip->flush_timo = ch->flush_timo; NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0); } return (error); } /* ng_l2cap_l2ca_cfg_ind */
int ng_l2cap_lp_qos_req(ng_l2cap_p l2cap, u_int16_t con_handle, ng_l2cap_flow_p flow) { struct ng_mesg *msg = NULL; ng_hci_lp_qos_req_ep *ep = NULL; ng_l2cap_con_p con = NULL; int error = 0; /* Verify that we have this connection */ con = ng_l2cap_con_by_handle(l2cap, con_handle); if (con == NULL) { NG_L2CAP_ERR( "%s: %s - unexpected LP_QoSSetupReq event. " \ "Connection does not exist, con_handle=%d\n", __func__, NG_NODE_NAME(l2cap->node), con_handle); return (ENOENT); } /* Verify connection state */ if (con->state != NG_L2CAP_CON_OPEN) { NG_L2CAP_ERR( "%s: %s - unexpected LP_QoSSetupReq event. " \ "Invalid connection state, state=%d, con_handle=%d\n", __func__, NG_NODE_NAME(l2cap->node), con->state, con->con_handle); return (EINVAL); } /* Check if lower layer protocol is still connected */ if (l2cap->hci == NULL || NG_HOOK_NOT_VALID(l2cap->hci)) { NG_L2CAP_ERR( "%s: %s - hook \"%s\" is not connected or valid", __func__, NG_NODE_NAME(l2cap->node), NG_L2CAP_HOOK_HCI); return (ENOTCONN); } /* Create and send LP_QoSSetupReq event */ NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_QOS_REQ, sizeof(*ep), M_NOWAIT); if (msg == NULL) return (ENOMEM); ep = (ng_hci_lp_qos_req_ep *) (msg->data); ep->con_handle = con_handle; ep->flags = flow->flags; ep->service_type = flow->service_type; ep->token_rate = flow->token_rate; ep->peak_bandwidth = flow->peak_bandwidth; ep->latency = flow->latency; ep->delay_variation = flow->delay_variation; NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->hci, 0); return (error); } /* ng_l2cap_lp_con_req */
int ng_l2cap_lp_con_req(ng_l2cap_p l2cap, bdaddr_p bdaddr) { struct ng_mesg *msg = NULL; ng_hci_lp_con_req_ep *ep = NULL; ng_l2cap_con_p con = NULL; int error = 0; /* Verify that we DO NOT have connection to the remote unit */ con = ng_l2cap_con_by_addr(l2cap, bdaddr); if (con != NULL) { NG_L2CAP_ALERT( "%s: %s - unexpected LP_ConnectReq event. " \ "Connection already exists, state=%d, con_handle=%d\n", __func__, NG_NODE_NAME(l2cap->node), con->state, con->con_handle); return (EEXIST); } /* Check if lower layer protocol is still connected */ if (l2cap->hci == NULL || NG_HOOK_NOT_VALID(l2cap->hci)) { NG_L2CAP_ERR( "%s: %s - hook \"%s\" is not connected or valid\n", __func__, NG_NODE_NAME(l2cap->node), NG_L2CAP_HOOK_HCI); return (ENOTCONN); } /* Create and intialize new connection descriptor */ con = ng_l2cap_new_con(l2cap, bdaddr); if (con == NULL) return (ENOMEM); /* Create and send LP_ConnectReq event */ NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_CON_REQ, sizeof(*ep), M_NOWAIT); if (msg == NULL) { ng_l2cap_free_con(con); return (ENOMEM); } ep = (ng_hci_lp_con_req_ep *) (msg->data); bcopy(bdaddr, &ep->bdaddr, sizeof(ep->bdaddr)); ep->link_type = NG_HCI_LINK_ACL; con->state = NG_L2CAP_W4_LP_CON_CFM; ng_l2cap_lp_timeout(con); NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->hci, NULL); if (error != 0) ng_l2cap_free_con(con); /* will remove timeout */ return (error); } /* ng_l2cap_lp_con_req */
int ng_l2cap_l2ca_con_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result, u_int16_t status) { ng_l2cap_p l2cap = ch->con->l2cap; struct ng_mesg *msg = NULL; ng_l2cap_l2ca_con_op *op = NULL; int error = 0; /* Check if upstream hook is connected and valid */ if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { NG_L2CAP_ERR( "%s: %s - unable to send L2CA_Connect response message. " \ "Hook is not connected or valid, psm=%d\n", __func__, NG_NODE_NAME(l2cap->node), ch->psm); return (ENOTCONN); } /* Create and send L2CA_Connect response message */ NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CON, sizeof(*op), M_NOWAIT); if (msg == NULL) error = ENOMEM; else { msg->header.token = token; msg->header.flags |= NGF_RESP; op = (ng_l2cap_l2ca_con_op *)(msg->data); /* * XXX Spec. says we should only populate LCID when result == 0 * What about PENDING? What the heck, for now always populate * LCID :) */ if(ch->scid == NG_L2CAP_ATT_CID){ op->idtype = NG_L2CAP_L2CA_IDTYPE_ATT; op->lcid = ch->con->con_handle; }else if(ch->scid == NG_L2CAP_SMP_CID){ op->idtype = NG_L2CAP_L2CA_IDTYPE_SMP; op->lcid = ch->con->con_handle; }else{ op->idtype = (ch->con->linktype == NG_HCI_LINK_ACL)? NG_L2CAP_L2CA_IDTYPE_BREDR : NG_L2CAP_L2CA_IDTYPE_LE; op->lcid = ch->scid; } op->encryption = ch->con->encryption; op->result = result; op->status = status; NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0); } return (error); } /* ng_l2cap_l2ca_con_rsp */
int ng_l2cap_l2ca_write_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result, u_int16_t length) { ng_l2cap_p l2cap = ch->con->l2cap; struct ng_mesg *msg = NULL; ng_l2cap_l2ca_write_op *op = NULL; int error = 0; /* Check if upstream hook is connected and valid */ if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { NG_L2CAP_ERR( "%s: %s - unable to send L2CA_WriteRsp message. " \ "Hook is not connected or valid, psm=%d\n", __func__, NG_NODE_NAME(l2cap->node), ch->psm); return (ENOTCONN); } /* Create and send L2CA_WriteRsp message */ NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_WRITE, sizeof(*op), M_NOWAIT); if (msg == NULL) error = ENOMEM; else { msg->header.token = token; msg->header.flags |= NGF_RESP; op = (ng_l2cap_l2ca_write_op *)(msg->data); op->result = result; op->length = length; if(ch->scid == NG_L2CAP_ATT_CID){ op->idtype = NG_L2CAP_L2CA_IDTYPE_ATT; op->lcid = ch->con->con_handle; }else if(ch->scid == NG_L2CAP_SMP_CID){ op->idtype = NG_L2CAP_L2CA_IDTYPE_SMP; op->lcid = ch->con->con_handle; }else{ op->idtype = (ch->con->linktype == NG_HCI_LINK_ACL)? NG_L2CAP_L2CA_IDTYPE_BREDR : NG_L2CAP_L2CA_IDTYPE_LE; op->lcid = ch->scid; } NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0); } return (error); } /* ng_l2cap_l2ca_write_rsp */
int ng_l2cap_l2ca_ping_rsp(ng_l2cap_con_p con, u_int32_t token, u_int16_t result, struct mbuf *data) { ng_l2cap_p l2cap = con->l2cap; struct ng_mesg *msg = NULL; ng_l2cap_l2ca_ping_op *op = NULL; int error = 0, size = 0; /* Check if control hook is connected and valid */ if (l2cap->ctl == NULL || NG_HOOK_NOT_VALID(l2cap->ctl)) { NG_L2CAP_WARN( "%s: %s - unable to send L2CA_Ping response message. " \ "Hook is not connected or valid\n", __func__, NG_NODE_NAME(l2cap->node)); error = ENOTCONN; goto out; } size = (data == NULL)? 0 : data->m_pkthdr.len; /* Create and send L2CA_Ping response message */ NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_PING, sizeof(*op) + size, M_NOWAIT); if (msg == NULL) error = ENOMEM; else { msg->header.token = token; msg->header.flags |= NGF_RESP; op = (ng_l2cap_l2ca_ping_op *)(msg->data); op->result = result; bcopy(&con->remote, &op->bdaddr, sizeof(op->bdaddr)); if (data != NULL && size > 0) { op->echo_size = size; m_copydata(data, 0, size, (caddr_t) op + sizeof(*op)); } NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->ctl, 0); } out: NG_FREE_M(data); return (error); } /* ng_l2cap_l2ca_ping_rsp */
void ng_hci_node_is_up(node_p node, hook_p hook, void *arg1, int arg2) { ng_hci_unit_p unit = NULL; struct ng_mesg *msg = NULL; ng_hci_node_up_ep *ep = NULL; int error; if (node == NULL || NG_NODE_NOT_VALID(node) || hook == NULL || NG_HOOK_NOT_VALID(hook)) return; unit = (ng_hci_unit_p) NG_NODE_PRIVATE(node); if ((unit->state & NG_HCI_UNIT_READY) != NG_HCI_UNIT_READY) return; if (hook != unit->acl && hook != unit->sco) return; NG_MKMESSAGE(msg,NGM_HCI_COOKIE,NGM_HCI_NODE_UP,sizeof(*ep),M_NOWAIT); if (msg != NULL) { ep = (ng_hci_node_up_ep *)(msg->data); if (hook == unit->acl) { NG_HCI_BUFF_ACL_SIZE(unit->buffer, ep->pkt_size); NG_HCI_BUFF_ACL_TOTAL(unit->buffer, ep->num_pkts); } else { NG_HCI_BUFF_SCO_SIZE(unit->buffer, ep->pkt_size); NG_HCI_BUFF_SCO_TOTAL(unit->buffer, ep->num_pkts); } bcopy(&unit->bdaddr, &ep->bdaddr, sizeof(ep->bdaddr)); NG_SEND_MSG_HOOK(error, node, msg, hook, 0); } else error = ENOMEM; if (error != 0) NG_HCI_INFO( "%s: %s - failed to send NODE_UP message to hook \"%s\", error=%d\n", __func__, NG_NODE_NAME(unit->node), NG_HOOK_NAME(hook), error); } /* ng_hci_node_is_up */
int ng_hci_lp_con_ind(ng_hci_unit_con_p con, u_int8_t *uclass) { ng_hci_unit_p unit = con->unit; struct ng_mesg *msg = NULL; ng_hci_lp_con_ind_ep *ep = NULL; hook_p hook = NULL; int error = 0; /* * Connection_Request event is generated for specific link type. * Use link_type to select upstream hook. */ if (con->link_type == NG_HCI_LINK_ACL) hook = unit->acl; else hook = unit->sco; if (hook != NULL && NG_HOOK_IS_VALID(hook)) { NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_CON_IND, sizeof(*ep), M_NOWAIT); if (msg == NULL) return (ENOMEM); ep = (ng_hci_lp_con_ind_ep *)(msg->data); ep->link_type = con->link_type; bcopy(uclass, ep->uclass, sizeof(ep->uclass)); bcopy(&con->bdaddr, &ep->bdaddr, sizeof(ep->bdaddr)); NG_SEND_MSG_HOOK(error, unit->node, msg, hook, 0); } else { NG_HCI_WARN( "%s: %s - Upstream hook is not connected or not valid, hook=%p\n", __func__, NG_NODE_NAME(unit->node), hook); error = ENOTCONN; } return (error); } /* ng_hci_lp_con_ind */
int ng_l2cap_l2ca_discon_ind(ng_l2cap_chan_p ch) { ng_l2cap_p l2cap = ch->con->l2cap; struct ng_mesg *msg = NULL; ng_l2cap_l2ca_discon_ind_ip *ip = NULL; int error = 0; /* Check if upstream hook is connected and valid */ if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { NG_L2CAP_ERR( "%s: %s - unable to send L2CA_DisconnectInd message. " \ "Hook is not connected or valid, psm=%d\n", __func__, NG_NODE_NAME(l2cap->node), ch->psm); return (ENOTCONN); } /* Create and send L2CA_DisconnectInd message */ NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_DISCON_IND, sizeof(*ip), M_NOWAIT); if (msg == NULL) error = ENOMEM; else { ip = (ng_l2cap_l2ca_discon_ind_ip *)(msg->data); ip->idtype = ch->idtype; if(ch->idtype == NG_L2CAP_L2CA_IDTYPE_ATT|| ch->idtype == NG_L2CAP_L2CA_IDTYPE_SMP) ip->lcid = ch->con->con_handle; else ip->lcid = ch->scid; NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0); } return (error); } /* ng_l2cap_l2ca_discon_ind */
/* * When incoming data is appended to the socket, we get notified here. * This is also called whenever a significant event occurs for the socket. * Our original caller may have queued this even some time ago and * we cannot trust that he even still exists. The node however is being * held with a reference by the queueing code and guarantied to be valid. */ static void ng_ksocket_incoming2(node_p node, hook_p hook, void *arg1, int arg2) { struct socket *so = arg1; const priv_p priv = NG_NODE_PRIVATE(node); struct ng_mesg *response; struct uio auio; int flags, error; KASSERT(so == priv->so, ("%s: wrong socket", __func__)); /* Allow next incoming event to be queued. */ atomic_store_rel_int(&priv->fn_sent, 0); /* Check whether a pending connect operation has completed */ if (priv->flags & KSF_CONNECTING) { if ((error = so->so_error) != 0) { so->so_error = 0; so->so_state &= ~SS_ISCONNECTING; } if (!(so->so_state & SS_ISCONNECTING)) { NG_MKMESSAGE(response, NGM_KSOCKET_COOKIE, NGM_KSOCKET_CONNECT, sizeof(int32_t), M_NOWAIT); if (response != NULL) { response->header.flags |= NGF_RESP; response->header.token = priv->response_token; *(int32_t *)response->data = error; /* * send an async "response" message * to the node that set us up * (if it still exists) */ NG_SEND_MSG_ID(error, node, response, priv->response_addr, 0); } priv->flags &= ~KSF_CONNECTING; } } /* Check whether a pending accept operation has completed */ if (priv->flags & KSF_ACCEPTING) { error = ng_ksocket_check_accept(priv); if (error != EWOULDBLOCK) priv->flags &= ~KSF_ACCEPTING; if (error == 0) ng_ksocket_finish_accept(priv); } /* * If we don't have a hook, we must handle data events later. When * the hook gets created and is connected, this upcall function * will be called again. */ if (priv->hook == NULL) return; /* Read and forward available mbuf's */ auio.uio_td = NULL; auio.uio_resid = MJUMPAGESIZE; /* XXXGL: sane limit? */ flags = MSG_DONTWAIT; while (1) { struct sockaddr *sa = NULL; struct mbuf *m; /* Try to get next packet from socket */ if ((error = soreceive(so, (so->so_state & SS_ISCONNECTED) ? NULL : &sa, &auio, &m, NULL, &flags)) != 0) break; /* See if we got anything */ if (m == NULL) { if (sa != NULL) free(sa, M_SONAME); break; } KASSERT(m->m_nextpkt == NULL, ("%s: nextpkt", __func__)); /* * Stream sockets do not have packet boundaries, so * we have to allocate a header mbuf and attach the * stream of data to it. */ if (so->so_type == SOCK_STREAM) { struct mbuf *mh; mh = m_gethdr(M_NOWAIT, MT_DATA); if (mh == NULL) { m_freem(m); if (sa != NULL) free(sa, M_SONAME); break; } mh->m_next = m; for (; m; m = m->m_next) mh->m_pkthdr.len += m->m_len; m = mh; } /* Put peer's socket address (if any) into a tag */ if (sa != NULL) { struct sa_tag *stag; stag = (struct sa_tag *)m_tag_alloc(NGM_KSOCKET_COOKIE, NG_KSOCKET_TAG_SOCKADDR, sizeof(ng_ID_t) + sa->sa_len, M_NOWAIT); if (stag == NULL) { free(sa, M_SONAME); goto sendit; } bcopy(sa, &stag->sa, sa->sa_len); free(sa, M_SONAME); stag->id = NG_NODE_ID(node); m_tag_prepend(m, &stag->tag); } sendit: /* Forward data with optional peer sockaddr as packet tag */ NG_SEND_DATA_ONLY(error, priv->hook, m); } /* * If the peer has closed the connection, forward a 0-length mbuf * to indicate end-of-file. */ if (so->so_rcv.sb_state & SBS_CANTRCVMORE && !(priv->flags & KSF_EOFSEEN)) { struct mbuf *m; m = m_gethdr(M_NOWAIT, MT_DATA); if (m != NULL) NG_SEND_DATA_ONLY(error, priv->hook, m); priv->flags |= KSF_EOFSEEN; } }
int ng_l2cap_l2ca_enable_clt(ng_l2cap_p l2cap, struct ng_mesg *msg) { ng_l2cap_l2ca_enable_clt_ip *ip = NULL; int error = 0; #if 0 * ng_l2cap_l2ca_enable_clt_op *op = NULL; * u_int16_t result; * u_int32_t token; #endif /* Check message */ if (msg->header.arglen != sizeof(*ip)) { NG_L2CAP_ALERT( "%s: %s - invalid L2CA_EnableCLT message size, size=%d\n", __func__, NG_NODE_NAME(l2cap->node), msg->header.arglen); return (EMSGSIZE); } /* Process request */ ip = (ng_l2cap_l2ca_enable_clt_ip *) (msg->data); #if 0 * result = NG_L2CAP_SUCCESS; #endif switch (ip->psm) { case 0: /* Special case: disable/enable all PSM */ if (ip->enable) l2cap->flags &= ~(NG_L2CAP_CLT_SDP_DISABLED | NG_L2CAP_CLT_RFCOMM_DISABLED | NG_L2CAP_CLT_TCP_DISABLED); else l2cap->flags |= (NG_L2CAP_CLT_SDP_DISABLED | NG_L2CAP_CLT_RFCOMM_DISABLED | NG_L2CAP_CLT_TCP_DISABLED); break; case NG_L2CAP_PSM_SDP: if (ip->enable) l2cap->flags &= ~NG_L2CAP_CLT_SDP_DISABLED; else l2cap->flags |= NG_L2CAP_CLT_SDP_DISABLED; break; case NG_L2CAP_PSM_RFCOMM: if (ip->enable) l2cap->flags &= ~NG_L2CAP_CLT_RFCOMM_DISABLED; else l2cap->flags |= NG_L2CAP_CLT_RFCOMM_DISABLED; break; case NG_L2CAP_PSM_TCP: if (ip->enable) l2cap->flags &= ~NG_L2CAP_CLT_TCP_DISABLED; else l2cap->flags |= NG_L2CAP_CLT_TCP_DISABLED; break; default: NG_L2CAP_ERR( "%s: %s - unsupported PSM=%d\n", __func__, NG_NODE_NAME(l2cap->node), ip->psm); #if 0 * result = NG_L2CAP_PSM_NOT_SUPPORTED; #endif error = ENOTSUP; break; } #if 0 * /* Create and send response message */ * token = msg->header.token; * NG_FREE_MSG(msg); * NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_ENABLE_CLT, * sizeof(*op), M_NOWAIT); * if (msg == NULL) * error = ENOMEM; * else { * msg->header.token = token; * msg->header.flags |= NGF_RESP; * * op = (ng_l2cap_l2ca_enable_clt_op *)(msg->data); * op->result = result; * } * * /* Send response to control hook */ * if (l2cap->ctl != NULL && NG_HOOK_IS_VALID(l2cap->ctl)) * NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->ctl, 0); #endif return (error); } /* ng_l2cap_l2ca_enable_clt */
static int ng_hci_lp_le_con_req(ng_hci_unit_p unit, item_p item, hook_p hook, int link_type) { struct acl_con_req { ng_hci_cmd_pkt_t hdr; ng_hci_le_create_connection_cp cp; } __attribute__ ((packed)) *req = NULL; ng_hci_lp_con_req_ep *ep = NULL; ng_hci_unit_con_p con = NULL; struct mbuf *m = NULL; int error = 0; ep = (ng_hci_lp_con_req_ep *)(NGI_MSG(item)->data); if((link_type != NG_HCI_LINK_LE_PUBLIC)&& (link_type != NG_HCI_LINK_LE_RANDOM)){ printf("%s: Link type %d Cannot be here \n", __func__, link_type); } /* * Only one ACL connection can exist between each pair of units. * So try to find ACL connection descriptor (in any state) that * has requested remote BD_ADDR. * * Two cases: * * 1) We do not have connection to the remote unit. This is simple. * Just create new connection descriptor and send HCI command to * create new connection. * * 2) We do have connection descriptor. We need to check connection * state: * * 2.1) NG_HCI_CON_W4_LP_CON_RSP means that we are in the middle of * accepting connection from the remote unit. This is a race * condition. We will ignore this message. * * 2.2) NG_HCI_CON_W4_CONN_COMPLETE means that upper layer already * requested connection or we just accepted it. In any case * all we need to do here is set appropriate notification bit * and wait. * * 2.3) NG_HCI_CON_OPEN means connection is open. Just reply back * and let upper layer know that we have connection already. */ con = ng_hci_con_by_bdaddr(unit, &ep->bdaddr, link_type); if (con != NULL) { switch (con->state) { case NG_HCI_CON_W4_LP_CON_RSP: /* XXX */ error = EALREADY; break; case NG_HCI_CON_W4_CONN_COMPLETE: if (hook != unit->sco) con->flags |= NG_HCI_CON_NOTIFY_ACL; else con->flags |= NG_HCI_CON_NOTIFY_SCO; break; case NG_HCI_CON_OPEN: { struct ng_mesg *msg = NULL; ng_hci_lp_con_cfm_ep *cfm = NULL; if (hook != NULL && NG_HOOK_IS_VALID(hook)) { NGI_GET_MSG(item, msg); NG_FREE_MSG(msg); NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_CON_CFM, sizeof(*cfm), M_NOWAIT); if (msg != NULL) { cfm = (ng_hci_lp_con_cfm_ep *)msg->data; cfm->status = 0; cfm->link_type = con->link_type; cfm->con_handle = con->con_handle; bcopy(&con->bdaddr, &cfm->bdaddr, sizeof(cfm->bdaddr)); /* * This will forward item back to * sender and set item to NULL */ _NGI_MSG(item) = msg; NG_FWD_ITEM_HOOK(error, item, hook); } else error = ENOMEM; } else NG_HCI_INFO( "%s: %s - Source hook is not valid, hook=%p\n", __func__, NG_NODE_NAME(unit->node), hook); } break; default: panic( "%s: %s - Invalid connection state=%d\n", __func__, NG_NODE_NAME(unit->node), con->state); break; } goto out; } /* * If we got here then we need to create new ACL connection descriptor * and submit HCI command. First create new connection desriptor, set * bdaddr and notification flags. */ con = ng_hci_new_con(unit, link_type); if (con == NULL) { error = ENOMEM; goto out; } bcopy(&ep->bdaddr, &con->bdaddr, sizeof(con->bdaddr)); /* * Create HCI command */ MGETHDR(m, M_NOWAIT, MT_DATA); if (m == NULL) { ng_hci_free_con(con); error = ENOBUFS; goto out; } m->m_pkthdr.len = m->m_len = sizeof(*req); req = mtod(m, struct acl_con_req *); req->hdr.type = NG_HCI_CMD_PKT; req->hdr.length = sizeof(req->cp); req->hdr.opcode = htole16(NG_HCI_OPCODE(NG_HCI_OGF_LE, NG_HCI_OCF_LE_CREATE_CONNECTION)); bcopy(&ep->bdaddr, &req->cp.peer_addr, sizeof(req->cp.peer_addr)); req->cp.own_address_type = 0; req->cp.peer_addr_type = (link_type == NG_HCI_LINK_LE_RANDOM)? 1:0; req->cp.scan_interval = htole16(4); req->cp.scan_window = htole16(4); req->cp.filter_policy = 0; req->cp.conn_interval_min = htole16(0xf); req->cp.conn_interval_max = htole16(0xf); req->cp.conn_latency = htole16(0); req->cp.supervision_timeout = htole16(0xc80); req->cp.min_ce_length = htole16(1); req->cp.max_ce_length = htole16(1); /* * Adust connection state */ if (hook != unit->sco) con->flags |= NG_HCI_CON_NOTIFY_ACL; else con->flags |= NG_HCI_CON_NOTIFY_SCO; con->state = NG_HCI_CON_W4_CONN_COMPLETE; ng_hci_con_timeout(con); /* * Queue and send HCI command */ NG_BT_MBUFQ_ENQUEUE(&unit->cmdq, m); if (!(unit->state & NG_HCI_UNIT_COMMAND_PENDING)) error = ng_hci_send_command(unit); out: if (item != NULL) NG_FREE_ITEM(item); return (error); } /* ng_hci_lp_acl_con_req */
int ng_hci_lp_con_cfm(ng_hci_unit_con_p con, int status) { ng_hci_unit_p unit = con->unit; struct ng_mesg *msg = NULL; ng_hci_lp_con_cfm_ep *ep = NULL; int error; /* * Check who wants to be notified. For ACL links both ACL and SCO * upstream hooks will be notified (if required). For SCO links * only SCO upstream hook will receive notification */ if (con->link_type == NG_HCI_LINK_ACL && con->flags & NG_HCI_CON_NOTIFY_ACL) { if (unit->acl != NULL && NG_HOOK_IS_VALID(unit->acl)) { NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_CON_CFM, sizeof(*ep), M_NOWAIT); if (msg != NULL) { ep = (ng_hci_lp_con_cfm_ep *) msg->data; ep->status = status; ep->link_type = con->link_type; ep->con_handle = con->con_handle; bcopy(&con->bdaddr, &ep->bdaddr, sizeof(ep->bdaddr)); NG_SEND_MSG_HOOK(error, unit->node, msg, unit->acl, 0); } } else NG_HCI_INFO( "%s: %s - ACL hook not valid, hook=%p\n", __func__, NG_NODE_NAME(unit->node), unit->acl); con->flags &= ~NG_HCI_CON_NOTIFY_ACL; } if (con->flags & NG_HCI_CON_NOTIFY_SCO) { if (unit->sco != NULL && NG_HOOK_IS_VALID(unit->sco)) { NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_CON_CFM, sizeof(*ep), M_NOWAIT); if (msg != NULL) { ep = (ng_hci_lp_con_cfm_ep *) msg->data; ep->status = status; ep->link_type = con->link_type; ep->con_handle = con->con_handle; bcopy(&con->bdaddr, &ep->bdaddr, sizeof(ep->bdaddr)); NG_SEND_MSG_HOOK(error, unit->node, msg, unit->sco, 0); } } else NG_HCI_INFO( "%s: %s - SCO hook not valid, hook=%p\n", __func__, NG_NODE_NAME(unit->node), unit->acl); con->flags &= ~NG_HCI_CON_NOTIFY_SCO; } return (0); } /* ng_hci_lp_con_cfm */
static int ng_hci_lp_acl_con_req(ng_hci_unit_p unit, item_p item, hook_p hook) { struct acl_con_req { ng_hci_cmd_pkt_t hdr; ng_hci_create_con_cp cp; } __attribute__ ((packed)) *req = NULL; ng_hci_lp_con_req_ep *ep = NULL; ng_hci_unit_con_p con = NULL; ng_hci_neighbor_t *n = NULL; struct mbuf *m = NULL; int error = 0; ep = (ng_hci_lp_con_req_ep *)(NGI_MSG(item)->data); /* * Only one ACL connection can exist between each pair of units. * So try to find ACL connection descriptor (in any state) that * has requested remote BD_ADDR. * * Two cases: * * 1) We do not have connection to the remote unit. This is simple. * Just create new connection descriptor and send HCI command to * create new connection. * * 2) We do have connection descriptor. We need to check connection * state: * * 2.1) NG_HCI_CON_W4_LP_CON_RSP means that we are in the middle of * accepting connection from the remote unit. This is a race * condition. We will ignore this message. * * 2.2) NG_HCI_CON_W4_CONN_COMPLETE means that upper layer already * requested connection or we just accepted it. In any case * all we need to do here is set appropriate notification bit * and wait. * * 2.3) NG_HCI_CON_OPEN means connection is open. Just reply back * and let upper layer know that we have connection already. */ con = ng_hci_con_by_bdaddr(unit, &ep->bdaddr, NG_HCI_LINK_ACL); if (con != NULL) { switch (con->state) { case NG_HCI_CON_W4_LP_CON_RSP: /* XXX */ error = EALREADY; break; case NG_HCI_CON_W4_CONN_COMPLETE: if (hook == unit->acl) con->flags |= NG_HCI_CON_NOTIFY_ACL; else con->flags |= NG_HCI_CON_NOTIFY_SCO; break; case NG_HCI_CON_OPEN: { struct ng_mesg *msg = NULL; ng_hci_lp_con_cfm_ep *cfm = NULL; if (hook != NULL && NG_HOOK_IS_VALID(hook)) { NGI_GET_MSG(item, msg); NG_FREE_MSG(msg); NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_CON_CFM, sizeof(*cfm), M_NOWAIT); if (msg != NULL) { cfm = (ng_hci_lp_con_cfm_ep *)msg->data; cfm->status = 0; cfm->link_type = con->link_type; cfm->con_handle = con->con_handle; bcopy(&con->bdaddr, &cfm->bdaddr, sizeof(cfm->bdaddr)); /* * This will forward item back to * sender and set item to NULL */ _NGI_MSG(item) = msg; NG_FWD_ITEM_HOOK(error, item, hook); } else error = ENOMEM; } else NG_HCI_INFO( "%s: %s - Source hook is not valid, hook=%p\n", __func__, NG_NODE_NAME(unit->node), hook); } break; default: panic( "%s: %s - Invalid connection state=%d\n", __func__, NG_NODE_NAME(unit->node), con->state); break; } goto out; } /* * If we got here then we need to create new ACL connection descriptor * and submit HCI command. First create new connection desriptor, set * bdaddr and notification flags. */ con = ng_hci_new_con(unit, NG_HCI_LINK_ACL); if (con == NULL) { error = ENOMEM; goto out; } bcopy(&ep->bdaddr, &con->bdaddr, sizeof(con->bdaddr)); /* * Create HCI command */ MGETHDR(m, M_DONTWAIT, MT_DATA); if (m == NULL) { ng_hci_free_con(con); error = ENOBUFS; goto out; } m->m_pkthdr.len = m->m_len = sizeof(*req); req = mtod(m, struct acl_con_req *); req->hdr.type = NG_HCI_CMD_PKT; req->hdr.length = sizeof(req->cp); req->hdr.opcode = htole16(NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL, NG_HCI_OCF_CREATE_CON)); bcopy(&ep->bdaddr, &req->cp.bdaddr, sizeof(req->cp.bdaddr)); req->cp.pkt_type = (NG_HCI_PKT_DM1|NG_HCI_PKT_DH1); if (unit->features[0] & NG_HCI_LMP_3SLOT) req->cp.pkt_type |= (NG_HCI_PKT_DM3|NG_HCI_PKT_DH3); if (unit->features[0] & NG_HCI_LMP_5SLOT) req->cp.pkt_type |= (NG_HCI_PKT_DM5|NG_HCI_PKT_DH5); req->cp.pkt_type &= unit->packet_mask; if ((req->cp.pkt_type & (NG_HCI_PKT_DM1|NG_HCI_PKT_DH1| NG_HCI_PKT_DM3|NG_HCI_PKT_DH3| NG_HCI_PKT_DM5|NG_HCI_PKT_DH5)) == 0) req->cp.pkt_type = (NG_HCI_PKT_DM1|NG_HCI_PKT_DH1); req->cp.pkt_type = htole16(req->cp.pkt_type); if ((unit->features[0] & NG_HCI_LMP_SWITCH) && unit->role_switch) req->cp.accept_role_switch = 1; else req->cp.accept_role_switch = 0; /* * We may speed up connect by specifying valid parameters. * So check the neighbor cache. */ n = ng_hci_get_neighbor(unit, &ep->bdaddr); if (n == NULL) { req->cp.page_scan_rep_mode = 0; req->cp.page_scan_mode = 0; req->cp.clock_offset = 0; } else { req->cp.page_scan_rep_mode = n->page_scan_rep_mode; req->cp.page_scan_mode = n->page_scan_mode; req->cp.clock_offset = htole16(n->clock_offset); } /* * Adust connection state */ if (hook == unit->acl) con->flags |= NG_HCI_CON_NOTIFY_ACL; else con->flags |= NG_HCI_CON_NOTIFY_SCO; con->state = NG_HCI_CON_W4_CONN_COMPLETE; ng_hci_con_timeout(con); /* * Queue and send HCI command */ NG_BT_MBUFQ_ENQUEUE(&unit->cmdq, m); if (!(unit->state & NG_HCI_UNIT_COMMAND_PENDING)) error = ng_hci_send_command(unit); out: if (item != NULL) NG_FREE_ITEM(item); return (error); } /* ng_hci_lp_acl_con_req */
void vboxNetFltPortOsSetActive(PVBOXNETFLTINS pThis, bool fActive) { struct ifnet *ifp; struct ifreq ifreq; int error; node_p node; struct ng_mesg *msg; struct ngm_connect *con; struct ngm_rmhook *rm; char path[NG_PATHSIZ]; Log(("%s: fActive:%d\n", __func__, fActive)); ifp = ASMAtomicUoReadPtrT(&pThis->u.s.ifp, struct ifnet *); VBOXCURVNET_SET(ifp->if_vnet); node = ASMAtomicUoReadPtrT(&pThis->u.s.node, node_p); memset(&ifreq, 0, sizeof(struct ifreq)); /* Activate interface */ if (fActive) { pThis->u.s.flags = ifp->if_flags; ifpromisc(ifp, 1); /* ng_ether nodes are named after the interface name */ snprintf(path, sizeof(path), "%s:", ifp->if_xname); /* * Send a netgraph connect message to the ng_ether node * assigned to the bridged interface. Connecting * the hooks 'lower' (ng_ether) to out 'input'. */ NG_MKMESSAGE(msg, NGM_GENERIC_COOKIE, NGM_CONNECT, sizeof(struct ngm_connect), M_NOWAIT); if (msg == NULL) return; con = (struct ngm_connect *)msg->data; snprintf(con->path, NG_PATHSIZ, "vboxnetflt_%s:", ifp->if_xname); strlcpy(con->ourhook, "lower", NG_HOOKSIZ); strlcpy(con->peerhook, "input", NG_HOOKSIZ); NG_SEND_MSG_PATH(error, node, msg, path, 0); /* * Do the same for the hooks 'upper' (ng_ether) and our * 'output' hook. */ NG_MKMESSAGE(msg, NGM_GENERIC_COOKIE, NGM_CONNECT, sizeof(struct ngm_connect), M_NOWAIT); if (msg == NULL) return; con = (struct ngm_connect *)msg->data; snprintf(con->path, NG_PATHSIZ, "vboxnetflt_%s:", ifp->if_xname); strlcpy(con->ourhook, "upper", sizeof(con->ourhook)); strlcpy(con->peerhook, "output", sizeof(con->peerhook)); NG_SEND_MSG_PATH(error, node, msg, path, 0); } else { /* De-activate interface */ pThis->u.s.flags = 0; ifpromisc(ifp, 0); /* Disconnect msgs are addressed to ourself */ snprintf(path, sizeof(path), "vboxnetflt_%s:", ifp->if_xname); /* * Send a netgraph message to disconnect our 'input' hook */ NG_MKMESSAGE(msg, NGM_GENERIC_COOKIE, NGM_RMHOOK, sizeof(struct ngm_rmhook), M_NOWAIT); if (msg == NULL) return; rm = (struct ngm_rmhook *)msg->data; strlcpy(rm->ourhook, "input", NG_HOOKSIZ); NG_SEND_MSG_PATH(error, node, msg, path, 0); /* * Send a netgraph message to disconnect our 'output' hook */ NG_MKMESSAGE(msg, NGM_GENERIC_COOKIE, NGM_RMHOOK, sizeof(struct ngm_rmhook), M_NOWAIT); if (msg == NULL) return; rm = (struct ngm_rmhook *)msg->data; strlcpy(rm->ourhook, "output", NG_HOOKSIZ); NG_SEND_MSG_PATH(error, node, msg, path, 0); } VBOXCURVNET_RESTORE(); }
int ng_l2cap_lp_con_ind(ng_l2cap_p l2cap, struct ng_mesg *msg) { ng_hci_lp_con_ind_ep *ep = NULL; ng_hci_lp_con_rsp_ep *rp = NULL; struct ng_mesg *rsp = NULL; ng_l2cap_con_p con = NULL; int error = 0; /* Check message */ if (msg->header.arglen != sizeof(*ep)) { NG_L2CAP_ALERT( "%s: %s - invalid LP_ConnectInd message size\n", __func__, NG_NODE_NAME(l2cap->node)); return (EMSGSIZE); } ep = (ng_hci_lp_con_ind_ep *) (msg->data); /* Make sure we have only one connection to the remote unit */ con = ng_l2cap_con_by_addr(l2cap, &ep->bdaddr); if (con != NULL) { NG_L2CAP_ALERT( "%s: %s - unexpected LP_ConnectInd event. " \ "Connection already exists, state=%d, con_handle=%d\n", __func__, NG_NODE_NAME(l2cap->node), con->state, con->con_handle); return (EEXIST); } /* Check if lower layer protocol is still connected */ if (l2cap->hci == NULL || NG_HOOK_NOT_VALID(l2cap->hci)) { NG_L2CAP_ERR( "%s: %s - hook \"%s\" is not connected or valid", __func__, NG_NODE_NAME(l2cap->node), NG_L2CAP_HOOK_HCI); return (ENOTCONN); } /* Create and intialize new connection descriptor */ con = ng_l2cap_new_con(l2cap, &ep->bdaddr); if (con == NULL) return (ENOMEM); /* Create and send LP_ConnectRsp event */ NG_MKMESSAGE(rsp, NGM_HCI_COOKIE, NGM_HCI_LP_CON_RSP, sizeof(*rp), M_NOWAIT); if (rsp == NULL) { ng_l2cap_free_con(con); return (ENOMEM); } rp = (ng_hci_lp_con_rsp_ep *)(rsp->data); rp->status = 0x00; /* accept connection */ rp->link_type = NG_HCI_LINK_ACL; bcopy(&ep->bdaddr, &rp->bdaddr, sizeof(rp->bdaddr)); con->state = NG_L2CAP_W4_LP_CON_CFM; ng_l2cap_lp_timeout(con); NG_SEND_MSG_HOOK(error, l2cap->node, rsp, l2cap->hci, 0); if (error != 0) { if (ng_l2cap_lp_untimeout(con) == 0) ng_l2cap_free_con(con); /* * Do not free connection if ng_l2cap_lp_untimeout() failed * let timeout handler deal with it. Always return error to * the caller. */ } return (error); } /* ng_l2cap_lp_con_ind */
/* * Handle the first completed incoming connection, assumed to be already * on the socket's so_comp queue. */ static void ng_ksocket_finish_accept(priv_p priv) { struct socket *const head = priv->so; struct socket *so; struct sockaddr *sa = NULL; struct ng_mesg *resp; struct ng_ksocket_accept *resp_data; node_p node; priv_p priv2; int len; int error; ACCEPT_LOCK(); so = TAILQ_FIRST(&head->so_comp); if (so == NULL) { /* Should never happen */ ACCEPT_UNLOCK(); return; } TAILQ_REMOVE(&head->so_comp, so, so_list); head->so_qlen--; so->so_qstate &= ~SQ_COMP; so->so_head = NULL; SOCK_LOCK(so); soref(so); sosetstate(so, SS_NBIO); SOCK_UNLOCK(so); ACCEPT_UNLOCK(); /* XXX KNOTE(&head->so_rcv.sb_sel.si_note, 0); */ soaccept(so, &sa); len = OFFSETOF(struct ng_ksocket_accept, addr); if (sa != NULL) len += sa->sa_len; NG_MKMESSAGE(resp, NGM_KSOCKET_COOKIE, NGM_KSOCKET_ACCEPT, len, M_WAITOK | M_NULLOK); if (resp == NULL) { soclose(so); goto out; } resp->header.flags |= NGF_RESP; resp->header.token = priv->response_token; /* Clone a ksocket node to wrap the new socket */ error = ng_make_node_common(&ng_ksocket_typestruct, &node); if (error) { kfree(resp, M_NETGRAPH); soclose(so); goto out; } if (ng_ksocket_constructor(node) != 0) { NG_NODE_UNREF(node); kfree(resp, M_NETGRAPH); soclose(so); goto out; } priv2 = NG_NODE_PRIVATE(node); priv2->so = so; priv2->flags |= KSF_CLONED | KSF_EMBRYONIC; /* * Insert the cloned node into a list of embryonic children * on the parent node. When a hook is created on the cloned * node it will be removed from this list. When the parent * is destroyed it will destroy any embryonic children it has. */ LIST_INSERT_HEAD(&priv->embryos, priv2, siblings); so->so_upcallarg = (caddr_t)node; so->so_upcall = ng_ksocket_incoming; SOCKBUF_LOCK(&so->so_rcv); so->so_rcv.sb_flags |= SB_UPCALL; SOCKBUF_UNLOCK(&so->so_rcv); SOCKBUF_LOCK(&so->so_snd); so->so_snd.sb_flags |= SB_UPCALL; SOCKBUF_UNLOCK(&so->so_snd); /* Fill in the response data and send it or return it to the caller */ resp_data = (struct ng_ksocket_accept *)resp->data; resp_data->nodeid = NG_NODE_ID(node); if (sa != NULL) bcopy(sa, &resp_data->addr, sa->sa_len); NG_SEND_MSG_ID(error, node, resp, priv->response_addr, 0); out: if (sa != NULL) kfree(sa, M_SONAME); }
/* * When incoming data is appended to the socket, we get notified here. * This is also called whenever a significant event occurs for the socket. * Our original caller may have queued this even some time ago and * we cannot trust that he even still exists. The node however is being * held with a reference by the queueing code and guarantied to be valid. */ static void ng_ksocket_incoming2(node_p node, hook_p hook, void *arg1, int arg2) { struct socket *so = arg1; const priv_p priv = NG_NODE_PRIVATE(node); struct mbuf *m; struct ng_mesg *response; struct uio auio; int s, flags, error; s = splnet(); /* so = priv->so; *//* XXX could have derived this like so */ KASSERT(so == priv->so, ("%s: wrong socket", __func__)); /* Allow next incoming event to be queued. */ atomic_store_rel_int(&priv->fn_sent, 0); /* Check whether a pending connect operation has completed */ if (priv->flags & KSF_CONNECTING) { if ((error = so->so_error) != 0) { so->so_error = 0; soclrstate(so, SS_ISCONNECTING); } if (!(so->so_state & SS_ISCONNECTING)) { NG_MKMESSAGE(response, NGM_KSOCKET_COOKIE, NGM_KSOCKET_CONNECT, sizeof(int32_t), M_WAITOK | M_NULLOK); if (response != NULL) { response->header.flags |= NGF_RESP; response->header.token = priv->response_token; *(int32_t *)response->data = error; /* * send an async "response" message * to the node that set us up * (if it still exists) */ NG_SEND_MSG_ID(error, node, response, priv->response_addr, 0); } priv->flags &= ~KSF_CONNECTING; } } /* Check whether a pending accept operation has completed */ if (priv->flags & KSF_ACCEPTING) { error = ng_ksocket_check_accept(priv); if (error != EWOULDBLOCK) priv->flags &= ~KSF_ACCEPTING; if (error == 0) ng_ksocket_finish_accept(priv); } /* * If we don't have a hook, we must handle data events later. When * the hook gets created and is connected, this upcall function * will be called again. */ if (priv->hook == NULL) { splx(s); return; } /* Read and forward available mbuf's */ auio.uio_td = NULL; auio.uio_resid = 1000000000; flags = MSG_DONTWAIT; while (1) { struct sockaddr *sa = NULL; struct mbuf *n; /* Try to get next packet from socket */ if ((error = soreceive(so, (so->so_state & SS_ISCONNECTED) ? NULL : &sa, &auio, &m, NULL, &flags)) != 0) break; /* See if we got anything */ if (m == NULL) { if (sa != NULL) kfree(sa, M_SONAME); break; } /* * Don't trust the various socket layers to get the * packet header and length correct (e.g. kern/15175). * * Also, do not trust that soreceive() will clear m_nextpkt * for us (e.g. kern/84952, kern/82413). */ m->m_pkthdr.csum_flags = 0; for (n = m, m->m_pkthdr.len = 0; n != NULL; n = n->m_next) { m->m_pkthdr.len += n->m_len; n->m_nextpkt = NULL; } /* Put peer's socket address (if any) into a tag */ if (sa != NULL) { struct sa_tag *stag; stag = (struct sa_tag *)m_tag_alloc(NGM_KSOCKET_COOKIE, NG_KSOCKET_TAG_SOCKADDR, sizeof(ng_ID_t) + sa->sa_len, MB_DONTWAIT); if (stag == NULL) { kfree(sa, M_SONAME); goto sendit; } bcopy(sa, &stag->sa, sa->sa_len); kfree(sa, M_SONAME); stag->id = NG_NODE_ID(node); m_tag_prepend(m, &stag->tag); } sendit: /* Forward data with optional peer sockaddr as packet tag */ NG_SEND_DATA_ONLY(error, priv->hook, m); } /* * If the peer has closed the connection, forward a 0-length mbuf * to indicate end-of-file. */ if (so->so_rcv.sb_state & SBS_CANTRCVMORE && !(priv->flags & KSF_EOFSEEN)) { MGETHDR(m, MB_DONTWAIT, MT_DATA); if (m != NULL) { m->m_len = m->m_pkthdr.len = 0; NG_SEND_DATA_ONLY(error, priv->hook, m); } priv->flags |= KSF_EOFSEEN; } splx(s); }