예제 #1
0
/*
 * Receive control message. We just bounce it back as a reply.
 */
static int
ngee_rcvmsg(node_p node, item_p item, hook_p lasthook)
{
	struct ng_mesg *msg;
	int error = 0;

	NGI_GET_MSG(item, msg);
	msg->header.flags |= NGF_RESP;
	NG_RESPOND_MSG(error, node, item, msg);
	return (error);
}
예제 #2
0
/*
 * 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);
}
예제 #3
0
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);
}
예제 #4
0
파일: ng_tee.c 프로젝트: MarginC/kame
/*
 * 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);
}
예제 #5
0
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 */
예제 #6
0
/*
 * 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);
}
예제 #7
0
파일: ng_ubt.c 프로젝트: 2asoft/freebsd
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 */
예제 #8
0
/*
 * 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);
}
예제 #9
0
파일: ng_sscop.c 프로젝트: MarginC/kame
/*
 * 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);
}
예제 #10
0
파일: ng_vjc.c 프로젝트: MarginC/kame
/*
 * 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);
}
예제 #11
0
파일: ng_sscfu.c 프로젝트: MarginC/kame
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);
}