示例#1
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);
}
示例#2
0
static void
ngd_send(netmsg_t msg)
{
	struct socket *so = msg->send.base.nm_so;
	struct mbuf *m = msg->send.nm_m;
	struct sockaddr *addr = msg->send.nm_addr;
	struct mbuf *control = msg->send.nm_control;
	struct ngpcb *const pcbp = sotongpcb(so);
	struct sockaddr_ng *const sap = (struct sockaddr_ng *) addr;
	int	len, error;
	hook_p  hook = NULL;
	char	hookname[NG_HOOKSIZ];

	if ((pcbp == NULL) || (control != NULL)) {
		error = EINVAL;
		goto release;
	}
	if (pcbp->sockdata == NULL) {
		error = ENOTCONN;
		goto release;
	}

	if (sap == NULL)
		len = 0;		/* Make compiler happy. */
	else
		len = sap->sg_len - 2;

	/*
	 * If the user used any of these ways to not specify an address
	 * then handle specially.
	 */
	if ((sap == NULL) || (len <= 0) || (*sap->sg_data == '\0')) {
		if (NG_NODE_NUMHOOKS(pcbp->sockdata->node) != 1) {
			error = EDESTADDRREQ;
			goto release;
		}
		/*
		 * If exactly one hook exists, just use it.
		 * Special case to allow write(2) to work on an ng_socket.
		 */
		hook = LIST_FIRST(&pcbp->sockdata->node->nd_hooks);
	} else {
		if (len >= NG_HOOKSIZ) {
			error = EINVAL;
			goto release;
		}

		/*
		 * chop off the sockaddr header, and make sure it's NUL
		 * terminated
		 */
		bcopy(sap->sg_data, hookname, len);
		hookname[len] = '\0';

		/* Find the correct hook from 'hookname' */
		hook = ng_findhook(pcbp->sockdata->node, hookname);
		if (hook == NULL) {
			error = EHOSTUNREACH;
			goto release;
		}
	}

	/* Send data. */
	NG_SEND_DATA_FLAGS(error, hook, m, NG_WAITOK);

release:
	if (control != NULL)
		m_freem(control);
	if (m != NULL)
		m_freem(m);
	lwkt_replymsg(&msg->send.base.lmsg, error);
}