/* * Get a netgraph control message. * We actually recieve a queue item that has a pointer to the message. * If we free the item, the message will be freed too, unless we remove * it from the item using NGI_GET_MSG(); * The return address is also stored in the item, as an ng_ID_t, * accessible as NGI_RETADDR(item); * Check it is one we understand. If needed, send a response. * We could save the address for an async action later, but don't here. * Always free the message. * The response should be in a malloc'd region that the caller can 'free'. * A response is not required. * Theoretically you could respond defferently to old message types if * the cookie in the header didn't match what we consider to be current * (so that old userland programs could continue to work). */ static int ng_xxx_rcvmsg(node_p node, item_p item, hook_p lasthook) { const xxx_p xxxp = NG_NODE_PRIVATE(node); struct ng_mesg *resp = NULL; int error = 0; struct ng_mesg *msg; NGI_GET_MSG(item, msg); /* Deal with message according to cookie and command */ switch (msg->header.typecookie) { case NGM_XXX_COOKIE: switch (msg->header.cmd) { case NGM_XXX_GET_STATUS: { struct ngxxxstat *stats; NG_MKRESPONSE(resp, msg, sizeof(*stats), M_NOWAIT); if (!resp) { error = ENOMEM; break; } stats = (struct ngxxxstat *) resp->data; stats->packets_in = xxxp->packets_in; stats->packets_out = xxxp->packets_out; break; } case NGM_XXX_SET_FLAG: if (msg->header.arglen != sizeof(u_int32_t)) { error = EINVAL; break; } xxxp->flags = *((u_int32_t *) msg->data); break; default: error = EINVAL; /* unknown command */ break; } break; default: error = EINVAL; /* unknown cookie type */ break; } /* Take care of synchronous response, if any */ NG_RESPOND_MSG(error, node, item, resp); /* Free the message and return */ NG_FREE_MSG(msg); return(error); }
static int ng_vlan_rcvmsg(node_p node, item_p item, hook_p lasthook) { const priv_p priv = NG_NODE_PRIVATE(node); struct ng_mesg *msg, *resp = NULL; struct ng_vlan_filter *vf; hook_p hook; struct ng_vlan_table *t; uintptr_t hook_data; int i, vlan_count; uint16_t vid; int error = 0; NGI_GET_MSG(item, msg); /* Deal with message according to cookie and command. */ switch (msg->header.typecookie) { case NGM_VLAN_COOKIE: switch (msg->header.cmd) { case NGM_VLAN_ADD_FILTER: /* Check that message is long enough. */ if (msg->header.arglen != sizeof(*vf)) { error = EINVAL; break; } vf = (struct ng_vlan_filter *)msg->data; /* Sanity check the VLAN ID value. */ #ifdef NG_VLAN_USE_OLD_VLAN_NAME if (vf->vid == 0 && vf->vid != vf->vlan) { vf->vid = vf->vlan; } else if (vf->vid != 0 && vf->vlan != 0 && vf->vid != vf->vlan) { error = EINVAL; break; } #endif if (vf->vid & ~EVL_VLID_MASK || vf->pcp & ~7 || vf->cfi & ~1) { error = EINVAL; break; } /* Check that a referenced hook exists. */ hook = ng_findhook(node, vf->hook_name); if (hook == NULL) { error = ENOENT; break; } /* And is not one of the special hooks. */ if (hook == priv->downstream_hook || hook == priv->nomatch_hook) { error = EINVAL; break; } /* And is not already in service. */ if (IS_HOOK_VLAN_SET(NG_HOOK_PRIVATE(hook))) { error = EEXIST; break; } /* Check we don't already trap this VLAN. */ if (priv->vlan_hook[vf->vid] != NULL) { error = EEXIST; break; } /* Link vlan and hook together. */ NG_HOOK_SET_PRIVATE(hook, (void *)(HOOK_VLAN_TAG_SET_MASK | EVL_MAKETAG(vf->vid, vf->pcp, vf->cfi))); priv->vlan_hook[vf->vid] = hook; break; case NGM_VLAN_DEL_FILTER: /* Check that message is long enough. */ if (msg->header.arglen != NG_HOOKSIZ) { error = EINVAL; break; } /* Check that hook exists and is active. */ hook = ng_findhook(node, (char *)msg->data); if (hook == NULL) { error = ENOENT; break; } hook_data = (uintptr_t)NG_HOOK_PRIVATE(hook); if (IS_HOOK_VLAN_SET(hook_data) == 0) { error = ENOENT; break; } KASSERT(priv->vlan_hook[EVL_VLANOFTAG(hook_data)] == hook, ("%s: NGM_VLAN_DEL_FILTER: Invalid VID for Hook = %s\n", __func__, (char *)msg->data)); /* Purge a rule that refers to this hook. */ priv->vlan_hook[EVL_VLANOFTAG(hook_data)] = NULL; NG_HOOK_SET_PRIVATE(hook, NULL); break; case NGM_VLAN_DEL_VID_FLT: /* Check that message is long enough. */ if (msg->header.arglen != sizeof(uint16_t)) { error = EINVAL; break; } vid = (*((uint16_t *)msg->data)); /* Sanity check the VLAN ID value. */ if (vid & ~EVL_VLID_MASK) { error = EINVAL; break; } /* Check that hook exists and is active. */ hook = priv->vlan_hook[vid]; if (hook == NULL) { error = ENOENT; break; } hook_data = (uintptr_t)NG_HOOK_PRIVATE(hook); if (IS_HOOK_VLAN_SET(hook_data) == 0) { error = ENOENT; break; } KASSERT(EVL_VLANOFTAG(hook_data) == vid, ("%s: NGM_VLAN_DEL_VID_FLT:" " Invalid VID Hook = %us, must be: %us\n", __func__, (uint16_t )EVL_VLANOFTAG(hook_data), vid)); /* Purge a rule that refers to this hook. */ priv->vlan_hook[vid] = NULL; NG_HOOK_SET_PRIVATE(hook, NULL); break; case NGM_VLAN_GET_TABLE: /* Calculate vlans. */ vlan_count = 0; for (i = 0; i < (EVL_VLID_MASK + 1); i ++) { if (priv->vlan_hook[i] != NULL && NG_HOOK_IS_VALID(priv->vlan_hook[i])) vlan_count ++; } /* Allocate memory for responce. */ NG_MKRESPONSE(resp, msg, sizeof(*t) + vlan_count * sizeof(*t->filter), M_NOWAIT); if (resp == NULL) { error = ENOMEM; break; } /* Pack data to responce. */ t = (struct ng_vlan_table *)resp->data; t->n = 0; vf = &t->filter[0]; for (i = 0; i < (EVL_VLID_MASK + 1); i ++) { hook = priv->vlan_hook[i]; if (hook == NULL || NG_HOOK_NOT_VALID(hook)) continue; hook_data = (uintptr_t)NG_HOOK_PRIVATE(hook); if (IS_HOOK_VLAN_SET(hook_data) == 0) continue; KASSERT(EVL_VLANOFTAG(hook_data) == i, ("%s: NGM_VLAN_GET_TABLE:" " hook %s VID = %us, must be: %i\n", __func__, NG_HOOK_NAME(hook), (uint16_t)EVL_VLANOFTAG(hook_data), i)); #ifdef NG_VLAN_USE_OLD_VLAN_NAME vf->vlan = i; #endif vf->vid = i; vf->pcp = EVL_PRIOFTAG(hook_data); vf->cfi = EVL_CFIOFTAG(hook_data); strncpy(vf->hook_name, NG_HOOK_NAME(hook), NG_HOOKSIZ); vf ++; t->n ++; } break; case NGM_VLAN_GET_DECAP: NG_MKRESPONSE(resp, msg, sizeof(uint32_t), M_NOWAIT); if (resp == NULL) { error = ENOMEM; break; } (*((uint32_t *)resp->data)) = priv->decap_enable; break; case NGM_VLAN_SET_DECAP: if (msg->header.arglen != sizeof(uint32_t)) { error = EINVAL; break; } priv->decap_enable = (*((uint32_t *)msg->data)); break; case NGM_VLAN_GET_ENCAP: NG_MKRESPONSE(resp, msg, sizeof(uint32_t), M_NOWAIT); if (resp == NULL) { error = ENOMEM; break; } (*((uint32_t *)resp->data)) = priv->encap_enable; break; case NGM_VLAN_SET_ENCAP: if (msg->header.arglen != sizeof(uint32_t)) { error = EINVAL; break; } priv->encap_enable = (*((uint32_t *)msg->data)); break; case NGM_VLAN_GET_ENCAP_PROTO: NG_MKRESPONSE(resp, msg, sizeof(uint16_t), M_NOWAIT); if (resp == NULL) { error = ENOMEM; break; } (*((uint16_t *)resp->data)) = ntohs(priv->encap_proto); break; case NGM_VLAN_SET_ENCAP_PROTO: if (msg->header.arglen != sizeof(uint16_t)) { error = EINVAL; break; } priv->encap_proto = htons((*((uint16_t *)msg->data))); break; default: /* Unknown command. */ error = EINVAL; break; } break; case NGM_FLOW_COOKIE: { struct ng_mesg *copy; /* * Flow control messages should come only * from downstream. */ if (lasthook == NULL) break; if (lasthook != priv->downstream_hook) break; /* Broadcast the event to all uplinks. */ for (i = 0; i < (EVL_VLID_MASK + 1); i ++) { if (priv->vlan_hook[i] == NULL) continue; NG_COPYMESSAGE(copy, msg, M_NOWAIT); if (copy == NULL) continue; NG_SEND_MSG_HOOK(error, node, copy, priv->vlan_hook[i], 0); } break; } default: /* Unknown type cookie. */ error = EINVAL; break; } NG_RESPOND_MSG(error, node, item, resp); NG_FREE_MSG(msg); return (error); }
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_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 */
/* * Incoming messages get passed up to the control socket. * Unless they are for us specifically (socket_type) */ static int ngs_rcvmsg(node_p node, item_p item, hook_p lasthook) { struct ngsock *const priv = NG_NODE_PRIVATE(node); struct ngpcb *const pcbp = priv->ctlsock; struct socket *so; struct sockaddr_ng addr; struct ng_mesg *msg; struct mbuf *m; ng_ID_t retaddr = NGI_RETADDR(item); int addrlen; int error = 0; NGI_GET_MSG(item, msg); NG_FREE_ITEM(item); /* * Only allow mesgs to be passed if we have the control socket. * Data sockets can only support the generic messages. */ if (pcbp == NULL) { TRAP_ERROR; NG_FREE_MSG(msg); return (EINVAL); } so = pcbp->ng_socket; #ifdef TRACE_MESSAGES kprintf("[%x]:---------->[socket]: c=<%d>cmd=%x(%s) f=%x #%d\n", retaddr, msg->header.typecookie, msg->header.cmd, msg->header.cmdstr, msg->header.flags, msg->header.token); #endif if (msg->header.typecookie == NGM_SOCKET_COOKIE) { switch (msg->header.cmd) { case NGM_SOCK_CMD_NOLINGER: priv->flags |= NGS_FLAG_NOLINGER; break; case NGM_SOCK_CMD_LINGER: priv->flags &= ~NGS_FLAG_NOLINGER; break; default: error = EINVAL; /* unknown command */ } /* Free the message and return. */ NG_FREE_MSG(msg); return (error); } /* Get the return address into a sockaddr. */ bzero(&addr, sizeof(addr)); addr.sg_len = sizeof(addr); addr.sg_family = AF_NETGRAPH; addrlen = ksnprintf((char *)&addr.sg_data, sizeof(addr.sg_data), "[%x]:", retaddr); if (addrlen < 0 || addrlen > sizeof(addr.sg_data)) { kprintf("%s: ksnprintf([%x]) failed - %d\n", __func__, retaddr, addrlen); NG_FREE_MSG(msg); return (EINVAL); } /* Copy the message itself into an mbuf chain. */ m = m_devget((caddr_t)msg, sizeof(struct ng_mesg) + msg->header.arglen, 0, NULL, NULL); /* * Here we free the message. We need to do that * regardless of whether we got mbufs. */ NG_FREE_MSG(msg); if (m == NULL) { TRAP_ERROR; return (ENOBUFS); } /* Send it up to the socket. */ if (sbappendaddr((struct sockbuf *)&so->so_rcv, (struct sockaddr *)&addr, m, NULL) == 0) { TRAP_ERROR; m_freem(m); return (ENOBUFS); } sorwakeup(so); return (error); }
/* * Receive a control message */ static int ng_ksocket_rcvmsg(node_p node, item_p item, hook_p lasthook) { struct thread *td = curthread; /* XXX broken */ const priv_p priv = NG_NODE_PRIVATE(node); struct socket *const so = priv->so; struct ng_mesg *resp = NULL; int error = 0; struct ng_mesg *msg; ng_ID_t raddr; NGI_GET_MSG(item, msg); switch (msg->header.typecookie) { case NGM_KSOCKET_COOKIE: switch (msg->header.cmd) { case NGM_KSOCKET_BIND: { struct sockaddr *const sa = (struct sockaddr *)msg->data; /* Sanity check */ if (msg->header.arglen < SADATA_OFFSET || msg->header.arglen < sa->sa_len) ERROUT(EINVAL); if (so == NULL) ERROUT(ENXIO); /* Bind */ error = sobind(so, sa, td); break; } case NGM_KSOCKET_LISTEN: { /* Sanity check */ if (msg->header.arglen != sizeof(int32_t)) ERROUT(EINVAL); if (so == NULL) ERROUT(ENXIO); /* Listen */ error = solisten(so, *((int32_t *)msg->data), td); break; } case NGM_KSOCKET_ACCEPT: { /* Sanity check */ if (msg->header.arglen != 0) ERROUT(EINVAL); if (so == NULL) ERROUT(ENXIO); /* Make sure the socket is capable of accepting */ if (!(so->so_options & SO_ACCEPTCONN)) ERROUT(EINVAL); if (priv->flags & KSF_ACCEPTING) ERROUT(EALREADY); error = ng_ksocket_check_accept(priv); if (error != 0 && error != EWOULDBLOCK) ERROUT(error); /* * If a connection is already complete, take it. * Otherwise let the upcall function deal with * the connection when it comes in. */ priv->response_token = msg->header.token; raddr = priv->response_addr = NGI_RETADDR(item); if (error == 0) { ng_ksocket_finish_accept(priv); } else priv->flags |= KSF_ACCEPTING; break; } case NGM_KSOCKET_CONNECT: { struct sockaddr *const sa = (struct sockaddr *)msg->data; /* Sanity check */ if (msg->header.arglen < SADATA_OFFSET || msg->header.arglen < sa->sa_len) ERROUT(EINVAL); if (so == NULL) ERROUT(ENXIO); /* Do connect */ if ((so->so_state & SS_ISCONNECTING) != 0) ERROUT(EALREADY); if ((error = soconnect(so, sa, td)) != 0) { soclrstate(so, SS_ISCONNECTING); ERROUT(error); } if ((so->so_state & SS_ISCONNECTING) != 0) { /* We will notify the sender when we connect */ priv->response_token = msg->header.token; raddr = priv->response_addr = NGI_RETADDR(item); priv->flags |= KSF_CONNECTING; ERROUT(EINPROGRESS); } break; } case NGM_KSOCKET_GETNAME: case NGM_KSOCKET_GETPEERNAME: { int (*func)(struct socket *so, struct sockaddr **nam); struct sockaddr *sa = NULL; int len; /* Sanity check */ if (msg->header.arglen != 0) ERROUT(EINVAL); if (so == NULL) ERROUT(ENXIO); /* Get function */ if (msg->header.cmd == NGM_KSOCKET_GETPEERNAME) { if ((so->so_state & (SS_ISCONNECTED|SS_ISCONFIRMING)) == 0) ERROUT(ENOTCONN); func = so->so_proto->pr_usrreqs->pru_peeraddr; } else func = so->so_proto->pr_usrreqs->pru_sockaddr; /* Get local or peer address */ if ((error = (*func)(so, &sa)) != 0) goto bail; len = (sa == NULL) ? 0 : sa->sa_len; /* Send it back in a response */ NG_MKRESPONSE(resp, msg, len, M_WAITOK | M_NULLOK); if (resp == NULL) { error = ENOMEM; goto bail; } bcopy(sa, resp->data, len); bail: /* Cleanup */ if (sa != NULL) kfree(sa, M_SONAME); break; } case NGM_KSOCKET_GETOPT: { struct ng_ksocket_sockopt *ksopt = (struct ng_ksocket_sockopt *)msg->data; struct sockopt sopt; /* Sanity check */ if (msg->header.arglen != sizeof(*ksopt)) ERROUT(EINVAL); if (so == NULL) ERROUT(ENXIO); /* Get response with room for option value */ NG_MKRESPONSE(resp, msg, sizeof(*ksopt) + NG_KSOCKET_MAX_OPTLEN, M_WAITOK | M_NULLOK); if (resp == NULL) ERROUT(ENOMEM); /* Get socket option, and put value in the response */ sopt.sopt_dir = SOPT_GET; sopt.sopt_level = ksopt->level; sopt.sopt_name = ksopt->name; sopt.sopt_td = NULL; sopt.sopt_valsize = NG_KSOCKET_MAX_OPTLEN; ksopt = (struct ng_ksocket_sockopt *)resp->data; sopt.sopt_val = ksopt->value; if ((error = sogetopt(so, &sopt)) != 0) { NG_FREE_MSG(resp); break; } /* Set actual value length */ resp->header.arglen = sizeof(*ksopt) + sopt.sopt_valsize; break; } case NGM_KSOCKET_SETOPT: { struct ng_ksocket_sockopt *const ksopt = (struct ng_ksocket_sockopt *)msg->data; const int valsize = msg->header.arglen - sizeof(*ksopt); struct sockopt sopt; /* Sanity check */ if (valsize < 0) ERROUT(EINVAL); if (so == NULL) ERROUT(ENXIO); /* Set socket option */ sopt.sopt_dir = SOPT_SET; sopt.sopt_level = ksopt->level; sopt.sopt_name = ksopt->name; sopt.sopt_val = ksopt->value; sopt.sopt_valsize = valsize; sopt.sopt_td = NULL; error = sosetopt(so, &sopt); break; } default: error = EINVAL; break; } break; default: error = EINVAL; break; } done: NG_RESPOND_MSG(error, node, item, resp); NG_FREE_MSG(msg); return (error); }
/* * Receive a control message */ static int ngt_rcvmsg(node_p node, item_p item, hook_p lasthook) { const sc_p sc = NG_NODE_PRIVATE(node); struct ng_mesg *resp = NULL; int error = 0; struct ng_mesg *msg; NGI_GET_MSG(item, msg); switch (msg->header.typecookie) { case NGM_TEE_COOKIE: switch (msg->header.cmd) { case NGM_TEE_GET_STATS: case NGM_TEE_CLR_STATS: case NGM_TEE_GETCLR_STATS: { struct ng_tee_stats *stats; if (msg->header.cmd != NGM_TEE_CLR_STATS) { NG_MKRESPONSE(resp, msg, sizeof(*stats), M_NOWAIT); if (resp == NULL) { error = ENOMEM; goto done; } stats = (struct ng_tee_stats *)resp->data; bcopy(&sc->right.stats, &stats->right, sizeof(stats->right)); bcopy(&sc->left.stats, &stats->left, sizeof(stats->left)); bcopy(&sc->right2left.stats, &stats->right2left, sizeof(stats->right2left)); bcopy(&sc->left2right.stats, &stats->left2right, sizeof(stats->left2right)); } if (msg->header.cmd != NGM_TEE_GET_STATS) { bzero(&sc->right.stats, sizeof(sc->right.stats)); bzero(&sc->left.stats, sizeof(sc->left.stats)); bzero(&sc->right2left.stats, sizeof(sc->right2left.stats)); bzero(&sc->left2right.stats, sizeof(sc->left2right.stats)); } break; } default: error = EINVAL; break; } break; case NGM_FLOW_COOKIE: if (lasthook) { if (lasthook == sc->left.hook) { if (sc->right.hook) { NGI_MSG(item) = msg; NG_FWD_ITEM_HOOK(error, item, sc->right.hook); return (error); } } else { if (sc->left.hook) { NGI_MSG(item) = msg; NG_FWD_ITEM_HOOK(error, item, sc->left.hook); return (error); } } } break; default: error = EINVAL; break; } done: NG_RESPOND_MSG(error, node, item, resp); NG_FREE_MSG(msg); return (error); }
static int ng_bt3c_rcvmsg(node_p node, item_p item, hook_p lasthook) { bt3c_softc_p sc = (bt3c_softc_p) NG_NODE_PRIVATE(node); struct ng_mesg *msg = NULL, *rsp = NULL; int error = 0; if (sc == NULL) { NG_FREE_ITEM(item); return (EHOSTDOWN); } NGI_GET_MSG(item, msg); switch (msg->header.typecookie) { case NGM_GENERIC_COOKIE: switch (msg->header.cmd) { case NGM_TEXT_STATUS: NG_MKRESPONSE(rsp, msg, NG_TEXTRESPONSE, M_NOWAIT); if (rsp == NULL) error = ENOMEM; else snprintf(rsp->data, NG_TEXTRESPONSE, "Hook: %s\n" \ "Flags: %#x\n" \ "Debug: %d\n" \ "State: %d\n" \ "IncmQ: [len:%d,max:%d]\n" \ "OutgQ: [len:%d,max:%d]\n", (sc->hook != NULL)? NG_BT3C_HOOK : "", sc->flags, sc->debug, sc->state, _IF_QLEN(&sc->inq), /* XXX */ sc->inq.ifq_maxlen, /* XXX */ _IF_QLEN(&sc->outq), /* XXX */ sc->outq.ifq_maxlen /* XXX */ ); break; default: error = EINVAL; break; } break; case NGM_BT3C_COOKIE: switch (msg->header.cmd) { case NGM_BT3C_NODE_GET_STATE: NG_MKRESPONSE(rsp, msg, sizeof(ng_bt3c_node_state_ep), M_NOWAIT); if (rsp == NULL) error = ENOMEM; else *((ng_bt3c_node_state_ep *)(rsp->data)) = sc->state; break; case NGM_BT3C_NODE_SET_DEBUG: if (msg->header.arglen != sizeof(ng_bt3c_node_debug_ep)) error = EMSGSIZE; else sc->debug = *((ng_bt3c_node_debug_ep *)(msg->data)); break; case NGM_BT3C_NODE_GET_DEBUG: NG_MKRESPONSE(rsp, msg, sizeof(ng_bt3c_node_debug_ep), M_NOWAIT); if (rsp == NULL) error = ENOMEM; else *((ng_bt3c_node_debug_ep *)(rsp->data)) = sc->debug; break; case NGM_BT3C_NODE_GET_QLEN: NG_MKRESPONSE(rsp, msg, sizeof(ng_bt3c_node_qlen_ep), M_NOWAIT); if (rsp == NULL) { error = ENOMEM; break; } switch (((ng_bt3c_node_qlen_ep *)(msg->data))->queue) { case NGM_BT3C_NODE_IN_QUEUE: ((ng_bt3c_node_qlen_ep *)(rsp->data))->queue = NGM_BT3C_NODE_IN_QUEUE; ((ng_bt3c_node_qlen_ep *)(rsp->data))->qlen = sc->inq.ifq_maxlen; break; case NGM_BT3C_NODE_OUT_QUEUE: ((ng_bt3c_node_qlen_ep *)(rsp->data))->queue = NGM_BT3C_NODE_OUT_QUEUE; ((ng_bt3c_node_qlen_ep *)(rsp->data))->qlen = sc->outq.ifq_maxlen; break; default: NG_FREE_MSG(rsp); error = EINVAL; break; } break; case NGM_BT3C_NODE_SET_QLEN: if (msg->header.arglen != sizeof(ng_bt3c_node_qlen_ep)){ error = EMSGSIZE; break; } if (((ng_bt3c_node_qlen_ep *)(msg->data))->qlen <= 0) { error = EINVAL; break; } switch (((ng_bt3c_node_qlen_ep *)(msg->data))->queue) { case NGM_BT3C_NODE_IN_QUEUE: sc->inq.ifq_maxlen = ((ng_bt3c_node_qlen_ep *) (msg->data))->qlen; /* XXX */ break; case NGM_BT3C_NODE_OUT_QUEUE: sc->outq.ifq_maxlen = ((ng_bt3c_node_qlen_ep *) (msg->data))->qlen; /* XXX */ break; default: error = EINVAL; break; } break; case NGM_BT3C_NODE_GET_STAT: NG_MKRESPONSE(rsp, msg, sizeof(ng_bt3c_node_stat_ep), M_NOWAIT); if (rsp == NULL) error = ENOMEM; else bcopy(&sc->stat, rsp->data, sizeof(ng_bt3c_node_stat_ep)); break; case NGM_BT3C_NODE_RESET_STAT: NG_BT3C_STAT_RESET(sc->stat); break; case NGM_BT3C_NODE_DOWNLOAD_FIRMWARE: if (msg->header.arglen < sizeof(ng_bt3c_firmware_block_ep)) error = EMSGSIZE; else bt3c_download_firmware(sc, msg->data, msg->header.arglen); break; default: error = EINVAL; break; } break; default: error = EINVAL; break; } NG_RESPOND_MSG(error, node, item, rsp); NG_FREE_MSG(msg); return (error); } /* ng_bt3c_rcvmsg */
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 */
static int ng_ubt_rcvmsg(node_p node, item_p item, hook_p lasthook) { struct ubt_softc *sc = NG_NODE_PRIVATE(node); struct ng_mesg *msg, *rsp = NULL; struct ng_bt_mbufq *q; int error = 0, queue, qlen; NGI_GET_MSG(item, msg); switch (msg->header.typecookie) { case NGM_GENERIC_COOKIE: switch (msg->header.cmd) { case NGM_TEXT_STATUS: NG_MKRESPONSE(rsp, msg, NG_TEXTRESPONSE, M_NOWAIT); if (rsp == NULL) { error = ENOMEM; break; } snprintf(rsp->data, NG_TEXTRESPONSE, "Hook: %s\n" \ "Task flags: %#x\n" \ "Debug: %d\n" \ "CMD queue: [have:%d,max:%d]\n" \ "ACL queue: [have:%d,max:%d]\n" \ "SCO queue: [have:%d,max:%d]", (sc->sc_hook != NULL) ? NG_UBT_HOOK : "", sc->sc_task_flags, sc->sc_debug, sc->sc_cmdq.len, sc->sc_cmdq.maxlen, sc->sc_aclq.len, sc->sc_aclq.maxlen, sc->sc_scoq.len, sc->sc_scoq.maxlen); break; default: error = EINVAL; break; } break; case NGM_UBT_COOKIE: switch (msg->header.cmd) { case NGM_UBT_NODE_SET_DEBUG: if (msg->header.arglen != sizeof(ng_ubt_node_debug_ep)){ error = EMSGSIZE; break; } sc->sc_debug = *((ng_ubt_node_debug_ep *) (msg->data)); break; case NGM_UBT_NODE_GET_DEBUG: NG_MKRESPONSE(rsp, msg, sizeof(ng_ubt_node_debug_ep), M_NOWAIT); if (rsp == NULL) { error = ENOMEM; break; } *((ng_ubt_node_debug_ep *) (rsp->data)) = sc->sc_debug; break; case NGM_UBT_NODE_SET_QLEN: if (msg->header.arglen != sizeof(ng_ubt_node_qlen_ep)) { error = EMSGSIZE; break; } queue = ((ng_ubt_node_qlen_ep *) (msg->data))->queue; qlen = ((ng_ubt_node_qlen_ep *) (msg->data))->qlen; switch (queue) { case NGM_UBT_NODE_QUEUE_CMD: q = &sc->sc_cmdq; break; case NGM_UBT_NODE_QUEUE_ACL: q = &sc->sc_aclq; break; case NGM_UBT_NODE_QUEUE_SCO: q = &sc->sc_scoq; break; default: error = EINVAL; goto done; /* NOT REACHED */ } q->maxlen = qlen; break; case NGM_UBT_NODE_GET_QLEN: if (msg->header.arglen != sizeof(ng_ubt_node_qlen_ep)) { error = EMSGSIZE; break; } queue = ((ng_ubt_node_qlen_ep *) (msg->data))->queue; switch (queue) { case NGM_UBT_NODE_QUEUE_CMD: q = &sc->sc_cmdq; break; case NGM_UBT_NODE_QUEUE_ACL: q = &sc->sc_aclq; break; case NGM_UBT_NODE_QUEUE_SCO: q = &sc->sc_scoq; break; default: error = EINVAL; goto done; /* NOT REACHED */ } NG_MKRESPONSE(rsp, msg, sizeof(ng_ubt_node_qlen_ep), M_NOWAIT); if (rsp == NULL) { error = ENOMEM; break; } ((ng_ubt_node_qlen_ep *) (rsp->data))->queue = queue; ((ng_ubt_node_qlen_ep *) (rsp->data))->qlen = q->maxlen; break; case NGM_UBT_NODE_GET_STAT: NG_MKRESPONSE(rsp, msg, sizeof(ng_ubt_node_stat_ep), M_NOWAIT); if (rsp == NULL) { error = ENOMEM; break; } bcopy(&sc->sc_stat, rsp->data, sizeof(ng_ubt_node_stat_ep)); break; case NGM_UBT_NODE_RESET_STAT: UBT_STAT_RESET(sc); break; default: error = EINVAL; break; } break; default: error = EINVAL; break; } done: NG_RESPOND_MSG(error, node, item, rsp); NG_FREE_MSG(msg); return (error); } /* ng_ubt_rcvmsg */
/* * Receive a netgraph control message. */ static int nglmi_rcvmsg(node_p node, item_p item, hook_p lasthook) { sc_p sc = NG_NODE_PRIVATE(node); struct ng_mesg *resp = NULL; int error = 0; struct ng_mesg *msg; NGI_GET_MSG(item, msg); switch (msg->header.typecookie) { case NGM_GENERIC_COOKIE: switch (msg->header.cmd) { case NGM_TEXT_STATUS: { char *arg; int pos, count; NG_MKRESPONSE(resp, msg, NG_TEXTRESPONSE, M_NOWAIT); if (resp == NULL) { error = ENOMEM; break; } arg = resp->data; pos = sprintf(arg, "protocol %s ", sc->protoname); if (sc->flags & SCF_FIXED) pos += sprintf(arg + pos, "fixed\n"); else if (sc->flags & SCF_AUTO) pos += sprintf(arg + pos, "auto-detecting\n"); else pos += sprintf(arg + pos, "auto on dlci %d\n", (sc->lmi_channel == sc->lmi_channel0) ? 0 : 1023); pos += sprintf(arg + pos, "keepalive period: %d seconds\n", sc->liv_rate); pos += sprintf(arg + pos, "unacknowledged keepalives: %ld\n", sc->seq_retries); for (count = 0; ((count <= MAXDLCI) && (pos < (NG_TEXTRESPONSE - 20))); count++) { if (sc->dlci_state[count]) { pos += sprintf(arg + pos, "dlci %d %s\n", count, (sc->dlci_state[count] == DLCI_UP) ? "up" : "down"); } } resp->header.arglen = pos + 1; break; } default: error = EINVAL; break; } break; case NGM_LMI_COOKIE: switch (msg->header.cmd) { case NGM_LMI_GET_STATUS: { struct nglmistat *stat; int k; NG_MKRESPONSE(resp, msg, sizeof(*stat), M_NOWAIT); if (!resp) { error = ENOMEM; break; } stat = (struct nglmistat *) resp->data; strncpy(stat->proto, sc->protoname, sizeof(stat->proto) - 1); strncpy(stat->hook, sc->protoname, sizeof(stat->hook) - 1); stat->autod = !!(sc->flags & SCF_AUTO); stat->fixed = !!(sc->flags & SCF_FIXED); for (k = 0; k <= MAXDLCI; k++) { switch (sc->dlci_state[k]) { case DLCI_UP: stat->up[k / 8] |= (1 << (k % 8)); /* fall through */ case DLCI_DOWN: stat->seen[k / 8] |= (1 << (k % 8)); break; } } break; } default: error = EINVAL; break; } break; default: error = EINVAL; break; } NG_RESPOND_MSG(error, node, item, resp); NG_FREE_MSG(msg); return (error); }
/* * Control message received. */ static int ng_sscop_rcvmsg(node_p node, item_p item, hook_p lasthook) { struct priv *priv = NG_NODE_PRIVATE(node); struct ng_mesg *resp = NULL; struct ng_mesg *msg; int error = 0; NGI_GET_MSG(item, msg); switch (msg->header.typecookie) { case NGM_GENERIC_COOKIE: switch (msg->header.cmd) { case NGM_TEXT_STATUS: NG_MKRESPONSE(resp, msg, NG_TEXTRESPONSE, M_NOWAIT); if (resp == NULL) { error = ENOMEM; break; } resp->header.arglen = text_status(node, priv, (char *)resp->data, resp->header.arglen) + 1; break; default: error = EINVAL; break; } break; case NGM_FLOW_COOKIE: if (priv->enabled && lasthook != NULL) { if (lasthook == priv->upper) error = flow_upper(node, msg); else if (lasthook == priv->lower) error = flow_lower(node, msg); } break; case NGM_SSCOP_COOKIE: switch (msg->header.cmd) { case NGM_SSCOP_GETPARAM: { struct sscop_param *p; NG_MKRESPONSE(resp, msg, sizeof(*p), M_NOWAIT); if (resp == NULL) { error = ENOMEM; break; } p = (struct sscop_param *)resp->data; sscop_getparam(priv->sscop, p); break; } case NGM_SSCOP_SETPARAM: { struct ng_sscop_setparam *arg; struct ng_sscop_setparam_resp *p; if (msg->header.arglen != sizeof(*arg)) { error = EINVAL; break; } if (priv->enabled) { error = EISCONN; break; } arg = (struct ng_sscop_setparam *)msg->data; NG_MKRESPONSE(resp, msg, sizeof(*p), M_NOWAIT); if (resp == NULL) { error = ENOMEM; break; } p = (struct ng_sscop_setparam_resp *)resp->data; p->mask = arg->mask; p->error = sscop_setparam(priv->sscop, &arg->param, &p->mask); break; } case NGM_SSCOP_ENABLE: if (msg->header.arglen != 0) { error = EINVAL; break; } if (priv->enabled) { error = EBUSY; break; } priv->enabled = 1; priv->flow = 1; memset(&priv->stats, 0, sizeof(priv->stats)); break; case NGM_SSCOP_DISABLE: if (msg->header.arglen != 0) { error = EINVAL; break; } if (!priv->enabled) { error = ENOTCONN; break; } priv->enabled = 0; sscop_reset(priv->sscop); break; case NGM_SSCOP_GETDEBUG: if (msg->header.arglen != 0) { error = EINVAL; break; } NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT); if(resp == NULL) { error = ENOMEM; break; } *(u_int32_t *)resp->data = sscop_getdebug(priv->sscop); break; case NGM_SSCOP_SETDEBUG: if (msg->header.arglen != sizeof(u_int32_t)) { error = EINVAL; break; } sscop_setdebug(priv->sscop, *(u_int32_t *)msg->data); break; case NGM_SSCOP_GETSTATE: if (msg->header.arglen != 0) { error = EINVAL; break; } NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT); if(resp == NULL) { error = ENOMEM; break; } *(u_int32_t *)resp->data = priv->enabled ? (sscop_getstate(priv->sscop) + 1) : 0; break; default: error = EINVAL; break; } break; default: error = EINVAL; break; } NG_RESPOND_MSG(error, node, item, resp); NG_FREE_MSG(msg); return (error); }
/* * Receive a control message */ static int ng_vjc_rcvmsg(node_p node, item_p item, hook_p lasthook) { const priv_p priv = NG_NODE_PRIVATE(node); struct ng_mesg *resp = NULL; int error = 0; struct ng_mesg *msg; NGI_GET_MSG(item, msg); /* Check type cookie */ switch (msg->header.typecookie) { case NGM_VJC_COOKIE: switch (msg->header.cmd) { case NGM_VJC_SET_CONFIG: { struct ngm_vjc_config *const c = (struct ngm_vjc_config *) msg->data; if (msg->header.arglen != sizeof(*c)) ERROUT(EINVAL); if ((priv->conf.enableComp || priv->conf.enableDecomp) && (c->enableComp || c->enableDecomp)) ERROUT(EALREADY); if (c->enableComp) { if (c->maxChannel > NG_VJC_MAX_CHANNELS - 1 || c->maxChannel < NG_VJC_MIN_CHANNELS - 1) ERROUT(EINVAL); } else c->maxChannel = NG_VJC_MAX_CHANNELS - 1; if (c->enableComp != 0 || c->enableDecomp != 0) { bzero(&priv->slc, sizeof(priv->slc)); sl_compress_init(&priv->slc, c->maxChannel); } priv->conf = *c; break; } case NGM_VJC_GET_CONFIG: { struct ngm_vjc_config *conf; NG_MKRESPONSE(resp, msg, sizeof(*conf), M_NOWAIT); if (resp == NULL) ERROUT(ENOMEM); conf = (struct ngm_vjc_config *)resp->data; *conf = priv->conf; break; } case NGM_VJC_GET_STATE: { const struct slcompress *const sl0 = &priv->slc; struct slcompress *sl; u_int16_t index; int i; /* Get response structure */ NG_MKRESPONSE(resp, msg, sizeof(*sl), M_NOWAIT); if (resp == NULL) ERROUT(ENOMEM); sl = (struct slcompress *)resp->data; *sl = *sl0; /* Replace pointers with integer indicies */ if (sl->last_cs != NULL) { index = sl0->last_cs - sl0->tstate; bzero(&sl->last_cs, sizeof(sl->last_cs)); *((u_int16_t *)&sl->last_cs) = index; } for (i = 0; i < MAX_STATES; i++) { struct cstate *const cs = &sl->tstate[i]; index = sl0->tstate[i].cs_next - sl0->tstate; bzero(&cs->cs_next, sizeof(cs->cs_next)); *((u_int16_t *)&cs->cs_next) = index; } break; } case NGM_VJC_CLR_STATS: priv->slc.sls_packets = 0; priv->slc.sls_compressed = 0; priv->slc.sls_searches = 0; priv->slc.sls_misses = 0; priv->slc.sls_uncompressedin = 0; priv->slc.sls_compressedin = 0; priv->slc.sls_errorin = 0; priv->slc.sls_tossed = 0; break; case NGM_VJC_RECV_ERROR: sl_uncompress_tcp(NULL, 0, TYPE_ERROR, &priv->slc); break; default: error = EINVAL; break; } break; default: error = EINVAL; break; } done: NG_RESPOND_MSG(error, node, item, resp); NG_FREE_MSG(msg); return (error); }
static int ng_sscfu_rcvmsg(node_p node, item_p item, hook_p lasthook) { struct priv *priv = NG_NODE_PRIVATE(node); struct ng_mesg *resp = NULL; struct ng_mesg *msg; int error = 0; NGI_GET_MSG(item, msg); switch (msg->header.typecookie) { case NGM_GENERIC_COOKIE: switch (msg->header.cmd) { case NGM_TEXT_STATUS: NG_MKRESPONSE(resp, msg, NG_TEXTRESPONSE, M_NOWAIT); if (resp == NULL) { error = ENOMEM; break; } resp->header.arglen = text_status(node, priv, (char *)resp->data, resp->header.arglen) + 1; break; default: error = EINVAL; break; } break; case NGM_SSCFU_COOKIE: switch (msg->header.cmd) { case NGM_SSCFU_GETDEFPARAM: { struct ng_sscfu_getdefparam *p; if (msg->header.arglen != 0) { error = EINVAL; break; } NG_MKRESPONSE(resp, msg, sizeof(*p), M_NOWAIT); if (resp == NULL) { error = ENOMEM; break; } p = (struct ng_sscfu_getdefparam *)resp->data; p->mask = sscfu_getdefparam(&p->param); break; } case NGM_SSCFU_ENABLE: if (msg->header.arglen != 0) { error = EINVAL; break; } if (priv->enabled) { error = EISCONN; break; } priv->enabled = 1; break; case NGM_SSCFU_DISABLE: if (msg->header.arglen != 0) { error = EINVAL; break; } if (!priv->enabled) { error = ENOTCONN; break; } priv->enabled = 0; sscfu_reset(priv->sscf); break; case NGM_SSCFU_GETSTATE: if (msg->header.arglen != 0) { error = EINVAL; break; } NG_MKRESPONSE(resp, msg, sizeof(uint32_t), M_NOWAIT); if(resp == NULL) { error = ENOMEM; break; } *(uint32_t *)resp->data = priv->enabled ? (sscfu_getstate(priv->sscf) + 1) : 0; break; case NGM_SSCFU_GETDEBUG: if (msg->header.arglen != 0) { error = EINVAL; break; } NG_MKRESPONSE(resp, msg, sizeof(uint32_t), M_NOWAIT); if(resp == NULL) { error = ENOMEM; break; } *(uint32_t *)resp->data = sscfu_getdebug(priv->sscf); break; case NGM_SSCFU_SETDEBUG: if (msg->header.arglen != sizeof(uint32_t)) { error = EINVAL; break; } sscfu_setdebug(priv->sscf, *(uint32_t *)msg->data); break; default: error = EINVAL; break; } break; default: error = EINVAL; break; } NG_RESPOND_MSG(error, node, item, resp); NG_FREE_MSG(msg); return (error); }