ng_atmllc.c revision 139823
138032Speter/*-
2111823Sgshapiro * Copyright (c) 2003-2004 Benno Rice <benno@eloquent.com.au>
364562Sgshapiro * All Rights Reserved.
438032Speter *
538032Speter * Redistribution and use in source and binary forms, with or without
638032Speter * modification, are permitted provided that the following conditions
738032Speter * are met:
838032Speter * 1. Redistributions of source code must retain the above copyright
938032Speter *    notice, this list of conditions and the following disclaimer.
1038032Speter * 2. Redistributions in binary form must reproduce the above copyright
1138032Speter *    notice, this list of conditions and the following disclaimer in the
1238032Speter *    documentation and/or other materials provided with the distribution.
1338032Speter *
1464562Sgshapiro * THIS SOFTWARE IS PROVIDED BY THE AUTHOR  ``AS IS'' AND
1538032Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16120256Sgshapiro * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1790792Sgshapiro * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR  BE LIABLE
1890792Sgshapiro * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1964562Sgshapiro * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2064562Sgshapiro * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2164562Sgshapiro * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2294334Sgshapiro * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2364562Sgshapiro * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2494334Sgshapiro * SUCH DAMAGE.
2594334Sgshapiro *
2694334Sgshapiro * $FreeBSD: head/sys/netgraph/ng_atmllc.c 139823 2005-01-07 01:45:51Z imp $
2738032Speter */
2838032Speter
2938032Speter#include <sys/param.h>
3038032Speter#include <sys/systm.h>
3138032Speter#include <sys/kernel.h>
3238032Speter#include <sys/malloc.h>
3338032Speter#include <sys/mbuf.h>
3438032Speter#include <sys/socket.h>
3538032Speter#include <sys/sockio.h>
3638032Speter
3738032Speter#include <netgraph/ng_message.h>
3838032Speter#include <netgraph/netgraph.h>
3938032Speter#include <netgraph/ng_atmllc.h>
4038032Speter
4138032Speter#include <net/if.h>
4238032Speter#include <net/ethernet.h>	/* for M_HASFCS and ETHER_HDR_LEN */
4338032Speter#include <net/if_atm.h>		/* for struct atmllc */
4490792Sgshapiro
4538032Speter#define	NG_ATMLLC_HEADER		"\252\252\3\0\200\302"
4638032Speter#define	NG_ATMLLC_HEADER_LEN		(sizeof(struct atmllc))
4738032Speter#define	NG_ATMLLC_TYPE_ETHERNET_FCS	0x0001
4838032Speter#define	NG_ATMLLC_TYPE_FDDI_FCS		0x0004
4938032Speter#define	NG_ATMLLC_TYPE_ETHERNET_NOFCS	0x0007
5038032Speter#define	NG_ATMLLC_TYPE_FDDI_NOFCS	0x000A
5138032Speter
5290792Sgshapirostruct ng_atmllc_priv {
5390792Sgshapiro	hook_p		atm;
5438032Speter	hook_p		ether;
5538032Speter	hook_p		fddi;
5638032Speter};
5738032Speter
5838032Speter/* Netgraph methods. */
5938032Speterstatic ng_constructor_t		ng_atmllc_constructor;
6038032Speterstatic ng_shutdown_t		ng_atmllc_shutdown;
6190792Sgshapirostatic ng_rcvmsg_t		ng_atmllc_rcvmsg;
6238032Speterstatic ng_newhook_t		ng_atmllc_newhook;
6338032Speterstatic ng_rcvdata_t		ng_atmllc_rcvdata;
6438032Speterstatic ng_disconnect_t		ng_atmllc_disconnect;
6564562Sgshapiro
6638032Speterstatic struct ng_type ng_atmllc_typestruct = {
6738032Speter	.version =	NG_ABI_VERSION,
6890792Sgshapiro	.name =		NG_ATMLLC_NODE_TYPE,
6938032Speter	.constructor =	ng_atmllc_constructor,
7038032Speter	.rcvmsg =	ng_atmllc_rcvmsg,
7138032Speter	.shutdown =	ng_atmllc_shutdown,
7238032Speter	.newhook =	ng_atmllc_newhook,
7338032Speter	.rcvdata =	ng_atmllc_rcvdata,
7438032Speter	.disconnect =	ng_atmllc_disconnect,
7590792Sgshapiro};
7638032SpeterNETGRAPH_INIT(atmllc, &ng_atmllc_typestruct);
7790792Sgshapiro
7838032Speterstatic int
7964562Sgshapirong_atmllc_constructor(node_p node)
8038032Speter{
8138032Speter	struct	ng_atmllc_priv *priv;
8238032Speter
8338032Speter	MALLOC(priv, struct ng_atmllc_priv *, sizeof(*priv), M_NETGRAPH,
8438032Speter	    M_NOWAIT | M_ZERO);
8538032Speter	if (priv == NULL) {
8638032Speter		return (ENOMEM);
8738032Speter	}
8890792Sgshapiro
8938032Speter	NG_NODE_SET_PRIVATE(node, priv);
9038032Speter
9138032Speter	return (0);
9238032Speter}
9338032Speter
9438032Speterstatic int
9538032Speterng_atmllc_rcvmsg(node_p node, item_p item, hook_p lasthook)
9638032Speter{
9790792Sgshapiro	struct	ng_mesg *msg;
9864562Sgshapiro	int	error;
9938032Speter
10038032Speter	error = 0;
10190792Sgshapiro	NGI_GET_MSG(item, msg);
10238032Speter	msg->header.flags |= NGF_RESP;
10338032Speter	NG_RESPOND_MSG(error, node, item, msg);
10490792Sgshapiro	return (error);
10538032Speter}
10638032Speter
10738032Speterstatic int
10838032Speterng_atmllc_shutdown(node_p node)
10938032Speter{
11038032Speter	struct	ng_atmllc_priv *priv;
11138032Speter
11238032Speter	priv = NG_NODE_PRIVATE(node);
11338032Speter
11438032Speter	FREE(priv, M_NETGRAPH);
11538032Speter
11638032Speter	NG_NODE_UNREF(node);
11738032Speter
11838032Speter	return (0);
11938032Speter}
12038032Speter
12138032Speterstatic int
12290792Sgshapirong_atmllc_newhook(node_p node, hook_p hook, const char *name)
12338032Speter{
12438032Speter	struct	ng_atmllc_priv *priv;
12538032Speter
12638032Speter	priv = NG_NODE_PRIVATE(node);
12738032Speter
12838032Speter	if (strcmp(name, NG_ATMLLC_HOOK_ATM) == 0) {
12938032Speter		if (priv->atm != NULL) {
13038032Speter			return (EISCONN);
13138032Speter		}
13290792Sgshapiro		priv->atm = hook;
13390792Sgshapiro	} else if (strcmp(name, NG_ATMLLC_HOOK_ETHER) == 0) {
13490792Sgshapiro		if (priv->ether != NULL) {
13590792Sgshapiro			return (EISCONN);
13690792Sgshapiro		}
13738032Speter		priv->ether = hook;
13838032Speter	} else if (strcmp(name, NG_ATMLLC_HOOK_FDDI) == 0) {
13938032Speter		if (priv->fddi != NULL) {
14038032Speter			return (EISCONN);
14138032Speter		}
14238032Speter		priv->fddi = hook;
14338032Speter	} else {
14494334Sgshapiro		return (EINVAL);
14590792Sgshapiro	}
14690792Sgshapiro
14790792Sgshapiro	return (0);
14894334Sgshapiro}
14994334Sgshapiro
15094334Sgshapirostatic int
15194334Sgshapirong_atmllc_rcvdata(hook_p hook, item_p item)
15294334Sgshapiro{
15394334Sgshapiro	struct	ng_atmllc_priv *priv;
15494334Sgshapiro	struct	mbuf *m;
15594334Sgshapiro	struct	atmllc *hdr;
15690792Sgshapiro	hook_p	outhook;
15790792Sgshapiro	u_int	padding;
15838032Speter	int	error;
15938032Speter
16038032Speter	priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
16138032Speter	m = NGI_M(item);
16238032Speter	outhook = NULL;
16390792Sgshapiro	padding = 0;
16464562Sgshapiro
16594334Sgshapiro	if (hook == priv->atm) {
16694334Sgshapiro		/* Ditch the psuedoheader. */
16794334Sgshapiro		hdr = mtod(m, struct atmllc *);
16838032Speter		/* m_adj(m, sizeof(struct atm_pseudohdr)); */
16994334Sgshapiro
17038032Speter		/*
17138032Speter		 * Make sure we have the LLC and ethernet headers.
17290792Sgshapiro		 * The ethernet header size is slightly larger than the FDDI
17390792Sgshapiro		 * header, which is convenient.
17490792Sgshapiro		 */
17590792Sgshapiro		if (m->m_len < sizeof(struct atmllc) + ETHER_HDR_LEN) {
17690792Sgshapiro			m = m_pullup(m, sizeof(struct atmllc) + ETHER_HDR_LEN);
17790792Sgshapiro			if (m == NULL) {
17890792Sgshapiro				return (ENOMEM);
17990792Sgshapiro			}
18090792Sgshapiro		}
18190792Sgshapiro
18290792Sgshapiro		/* Decode the LLC header. */
18390792Sgshapiro		hdr = mtod(m, struct atmllc *);
18490792Sgshapiro		if (ATM_LLC_TYPE(hdr) == NG_ATMLLC_TYPE_ETHERNET_NOFCS) {
18590792Sgshapiro			m->m_flags &= ~M_HASFCS;
18690792Sgshapiro			outhook = priv->ether;
18790792Sgshapiro			padding = 2;
18890792Sgshapiro		} else if (ATM_LLC_TYPE(hdr) == NG_ATMLLC_TYPE_ETHERNET_FCS) {
18990792Sgshapiro			m->m_flags |= M_HASFCS;
19090792Sgshapiro			outhook = priv->ether;
19190792Sgshapiro			padding = 2;
19290792Sgshapiro		} else if (ATM_LLC_TYPE(hdr) == NG_ATMLLC_TYPE_FDDI_NOFCS) {
19390792Sgshapiro			m->m_flags &= ~M_HASFCS;
19490792Sgshapiro			outhook = priv->fddi;
19590792Sgshapiro			padding = 3;
19690792Sgshapiro		} else if (ATM_LLC_TYPE(hdr) == NG_ATMLLC_TYPE_FDDI_FCS) {
19790792Sgshapiro			m->m_flags |= M_HASFCS;
19890792Sgshapiro			outhook = priv->fddi;
19990792Sgshapiro			padding = 3;
20090792Sgshapiro		} else {
20190792Sgshapiro			printf("ng_atmllc: unknown type: %x\n",
20290792Sgshapiro			    ATM_LLC_TYPE(hdr));
20390792Sgshapiro		}
20490792Sgshapiro
20590792Sgshapiro		/* Remove the LLC header and any padding*/
20638032Speter		m_adj(m, sizeof(struct atmllc) + padding);
20738032Speter	} else if (hook == priv->ether) {
20838032Speter		/* Add the LLC header */
20964562Sgshapiro		M_PREPEND(m, NG_ATMLLC_HEADER_LEN + 2, M_DONTWAIT);
21038032Speter		if (m == NULL) {
21138032Speter			printf("ng_atmllc: M_PREPEND failed\n");
21238032Speter			NG_FREE_ITEM(item);
21338032Speter			return (ENOMEM);
21438032Speter		}
21538032Speter		hdr = mtod(m, struct atmllc *);
21690792Sgshapiro		bzero((void *)hdr, sizeof(struct atmllc) + 2);
21738032Speter		bcopy(NG_ATMLLC_HEADER, hdr->llchdr, 6);
21838032Speter		if ((m->m_flags & M_HASFCS) != 0) {
21990792Sgshapiro			ATM_LLC_SETTYPE(hdr, NG_ATMLLC_TYPE_ETHERNET_FCS);
22064562Sgshapiro		} else {
22138032Speter			ATM_LLC_SETTYPE(hdr, NG_ATMLLC_TYPE_ETHERNET_NOFCS);
22238032Speter		}
22338032Speter		outhook = priv->atm;
22438032Speter	} else if (hook == priv->fddi) {
22538032Speter		/* Add the LLC header */
22638032Speter		M_PREPEND(m, NG_ATMLLC_HEADER_LEN + 3, M_DONTWAIT);
22738032Speter		if (m == NULL) {
22838032Speter			printf("ng_atmllc: M_PREPEND failed\n");
22938032Speter			NG_FREE_ITEM(item);
23090792Sgshapiro			return (ENOMEM);
23190792Sgshapiro		}
23238032Speter		hdr = mtod(m, struct atmllc *);
23338032Speter		bzero((void *)hdr, sizeof(struct atmllc) + 3);
23464562Sgshapiro		bcopy(NG_ATMLLC_HEADER, hdr->llchdr, 6);
23538032Speter		if ((m->m_flags & M_HASFCS) != 0) {
23690792Sgshapiro			ATM_LLC_SETTYPE(hdr, NG_ATMLLC_TYPE_FDDI_FCS);
23790792Sgshapiro		} else {
23838032Speter			ATM_LLC_SETTYPE(hdr, NG_ATMLLC_TYPE_FDDI_NOFCS);
23938032Speter		}
24038032Speter		outhook = priv->atm;
24190792Sgshapiro	}
24290792Sgshapiro
24390792Sgshapiro	if (outhook == NULL) {
24438032Speter		NG_FREE_ITEM(item);
24538032Speter		return (0);
24690792Sgshapiro	}
24790792Sgshapiro
24890792Sgshapiro	NG_FWD_NEW_DATA(error, item, outhook, m);
24938032Speter	return (error);
25038032Speter}
25138032Speter
25290792Sgshapirostatic int
25338032Speterng_atmllc_disconnect(hook_p hook)
25438032Speter{
25590792Sgshapiro	node_p	node;
25638032Speter	struct	ng_atmllc_priv *priv;
25790792Sgshapiro
25838032Speter	node = NG_HOOK_NODE(hook);
25994334Sgshapiro	priv = NG_NODE_PRIVATE(node);
26090792Sgshapiro
26138032Speter	if (hook == priv->atm) {
26238032Speter		priv->atm = NULL;
26338032Speter	} else if (hook == priv->ether) {
26490792Sgshapiro		priv->ether = NULL;
26538032Speter	} else if (hook == priv->fddi) {
26690792Sgshapiro		priv->fddi = NULL;
26790792Sgshapiro	}
26838032Speter
26990792Sgshapiro	if (NG_NODE_NUMHOOKS(node) == 0 && NG_NODE_IS_VALID(node)) {
27038032Speter		ng_rmnode_self(node);
27190792Sgshapiro	}
27290792Sgshapiro
27390792Sgshapiro	return (0);
27490792Sgshapiro}
27594334Sgshapiro