xref: /f-stack/freebsd/netgraph/ng_atmllc.c (revision 22ce4aff)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2003-2004 Benno Rice <[email protected]>
5  * All Rights Reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR  ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR  BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  *
28  * $FreeBSD$
29  */
30 
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/kernel.h>
34 #include <sys/malloc.h>
35 #include <sys/mbuf.h>
36 #include <sys/socket.h>
37 #include <sys/sockio.h>
38 
39 #include <netgraph/ng_message.h>
40 #include <netgraph/netgraph.h>
41 #include <netgraph/ng_atmllc.h>
42 
43 #include <net/if.h>
44 #include <net/ethernet.h>	/* for M_HASFCS and ETHER_HDR_LEN */
45 
46 #define	NG_ATMLLC_HEADER		"\252\252\3\0\200\302"
47 #define	NG_ATMLLC_HEADER_LEN		(sizeof(struct atmllc))
48 #define	NG_ATMLLC_TYPE_ETHERNET_FCS	0x0001
49 #define	NG_ATMLLC_TYPE_FDDI_FCS		0x0004
50 #define	NG_ATMLLC_TYPE_ETHERNET_NOFCS	0x0007
51 #define	NG_ATMLLC_TYPE_FDDI_NOFCS	0x000A
52 
53 struct ng_atmllc_priv {
54 	hook_p		atm;
55 	hook_p		ether;
56 	hook_p		fddi;
57 };
58 
59 struct atmllc {
60 	uint8_t		llchdr[6];	/* aa.aa.03.00.00.00 */
61 	uint8_t		type[2];	/* "ethernet" type */
62 };
63 
64 /* ATM_LLC macros: note type code in host byte order */
65 #define	ATM_LLC_TYPE(X) (((X)->type[0] << 8) | ((X)->type[1]))
66 #define	ATM_LLC_SETTYPE(X, V) do {		\
67 	(X)->type[0] = ((V) >> 8) & 0xff;	\
68 	(X)->type[1] = ((V) & 0xff);		\
69     } while (0)
70 
71 /* Netgraph methods. */
72 static ng_constructor_t		ng_atmllc_constructor;
73 static ng_shutdown_t		ng_atmllc_shutdown;
74 static ng_rcvmsg_t		ng_atmllc_rcvmsg;
75 static ng_newhook_t		ng_atmllc_newhook;
76 static ng_rcvdata_t		ng_atmllc_rcvdata;
77 static ng_disconnect_t		ng_atmllc_disconnect;
78 
79 static struct ng_type ng_atmllc_typestruct = {
80 	.version =	NG_ABI_VERSION,
81 	.name =		NG_ATMLLC_NODE_TYPE,
82 	.constructor =	ng_atmllc_constructor,
83 	.rcvmsg =	ng_atmllc_rcvmsg,
84 	.shutdown =	ng_atmllc_shutdown,
85 	.newhook =	ng_atmllc_newhook,
86 	.rcvdata =	ng_atmllc_rcvdata,
87 	.disconnect =	ng_atmllc_disconnect,
88 };
89 NETGRAPH_INIT(atmllc, &ng_atmllc_typestruct);
90 
91 static int
ng_atmllc_constructor(node_p node)92 ng_atmllc_constructor(node_p node)
93 {
94 	struct	ng_atmllc_priv *priv;
95 
96 	priv = malloc(sizeof(*priv), M_NETGRAPH, M_WAITOK | M_ZERO);
97 	NG_NODE_SET_PRIVATE(node, priv);
98 
99 	return (0);
100 }
101 
102 static int
ng_atmllc_rcvmsg(node_p node,item_p item,hook_p lasthook)103 ng_atmllc_rcvmsg(node_p node, item_p item, hook_p lasthook)
104 {
105 	struct	ng_mesg *msg;
106 	int	error;
107 
108 	error = 0;
109 	NGI_GET_MSG(item, msg);
110 	msg->header.flags |= NGF_RESP;
111 	NG_RESPOND_MSG(error, node, item, msg);
112 	return (error);
113 }
114 
115 static int
ng_atmllc_shutdown(node_p node)116 ng_atmllc_shutdown(node_p node)
117 {
118 	struct	ng_atmllc_priv *priv;
119 
120 	priv = NG_NODE_PRIVATE(node);
121 
122 	free(priv, M_NETGRAPH);
123 
124 	NG_NODE_UNREF(node);
125 
126 	return (0);
127 }
128 
129 static int
ng_atmllc_newhook(node_p node,hook_p hook,const char * name)130 ng_atmllc_newhook(node_p node, hook_p hook, const char *name)
131 {
132 	struct	ng_atmllc_priv *priv;
133 
134 	priv = NG_NODE_PRIVATE(node);
135 
136 	if (strcmp(name, NG_ATMLLC_HOOK_ATM) == 0) {
137 		if (priv->atm != NULL) {
138 			return (EISCONN);
139 		}
140 		priv->atm = hook;
141 	} else if (strcmp(name, NG_ATMLLC_HOOK_ETHER) == 0) {
142 		if (priv->ether != NULL) {
143 			return (EISCONN);
144 		}
145 		priv->ether = hook;
146 	} else if (strcmp(name, NG_ATMLLC_HOOK_FDDI) == 0) {
147 		if (priv->fddi != NULL) {
148 			return (EISCONN);
149 		}
150 		priv->fddi = hook;
151 	} else {
152 		return (EINVAL);
153 	}
154 
155 	return (0);
156 }
157 
158 static int
ng_atmllc_rcvdata(hook_p hook,item_p item)159 ng_atmllc_rcvdata(hook_p hook, item_p item)
160 {
161 	struct	ng_atmllc_priv *priv;
162 	struct	mbuf *m;
163 	struct	atmllc *hdr;
164 	hook_p	outhook;
165 	u_int	padding;
166 	int	error;
167 
168 	priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
169 	NGI_GET_M(item, m);
170 	outhook = NULL;
171 	padding = 0;
172 
173 	if (hook == priv->atm) {
174 		/* Ditch the pseudoheader. */
175 		hdr = mtod(m, struct atmllc *);
176 		/* m_adj(m, sizeof(struct atm_pseudohdr)); */
177 
178 		/*
179 		 * Make sure we have the LLC and ethernet headers.
180 		 * The ethernet header size is slightly larger than the FDDI
181 		 * header, which is convenient.
182 		 */
183 		if (m->m_len < sizeof(struct atmllc) + ETHER_HDR_LEN) {
184 			m = m_pullup(m, sizeof(struct atmllc) + ETHER_HDR_LEN);
185 			if (m == NULL) {
186 				NG_FREE_ITEM(item);
187 				return (ENOMEM);
188 			}
189 		}
190 
191 		/* Decode the LLC header. */
192 		hdr = mtod(m, struct atmllc *);
193 		if (ATM_LLC_TYPE(hdr) == NG_ATMLLC_TYPE_ETHERNET_NOFCS) {
194 			m->m_flags &= ~M_HASFCS;
195 			outhook = priv->ether;
196 			padding = 2;
197 		} else if (ATM_LLC_TYPE(hdr) == NG_ATMLLC_TYPE_ETHERNET_FCS) {
198 			m->m_flags |= M_HASFCS;
199 			outhook = priv->ether;
200 			padding = 2;
201 		} else if (ATM_LLC_TYPE(hdr) == NG_ATMLLC_TYPE_FDDI_NOFCS) {
202 			m->m_flags &= ~M_HASFCS;
203 			outhook = priv->fddi;
204 			padding = 3;
205 		} else if (ATM_LLC_TYPE(hdr) == NG_ATMLLC_TYPE_FDDI_FCS) {
206 			m->m_flags |= M_HASFCS;
207 			outhook = priv->fddi;
208 			padding = 3;
209 		} else {
210 			printf("ng_atmllc: unknown type: %x\n",
211 			    ATM_LLC_TYPE(hdr));
212 		}
213 
214 		/* Remove the LLC header and any padding*/
215 		m_adj(m, sizeof(struct atmllc) + padding);
216 	} else if (hook == priv->ether) {
217 		/* Add the LLC header */
218 		M_PREPEND(m, NG_ATMLLC_HEADER_LEN + 2, M_NOWAIT);
219 		if (m == NULL) {
220 			printf("ng_atmllc: M_PREPEND failed\n");
221 			NG_FREE_ITEM(item);
222 			return (ENOMEM);
223 		}
224 		hdr = mtod(m, struct atmllc *);
225 		bzero((void *)hdr, sizeof(struct atmllc) + 2);
226 		bcopy(NG_ATMLLC_HEADER, hdr->llchdr, 6);
227 		if ((m->m_flags & M_HASFCS) != 0) {
228 			ATM_LLC_SETTYPE(hdr, NG_ATMLLC_TYPE_ETHERNET_FCS);
229 		} else {
230 			ATM_LLC_SETTYPE(hdr, NG_ATMLLC_TYPE_ETHERNET_NOFCS);
231 		}
232 		outhook = priv->atm;
233 	} else if (hook == priv->fddi) {
234 		/* Add the LLC header */
235 		M_PREPEND(m, NG_ATMLLC_HEADER_LEN + 3, M_NOWAIT);
236 		if (m == NULL) {
237 			printf("ng_atmllc: M_PREPEND failed\n");
238 			NG_FREE_ITEM(item);
239 			return (ENOMEM);
240 		}
241 		hdr = mtod(m, struct atmllc *);
242 		bzero((void *)hdr, sizeof(struct atmllc) + 3);
243 		bcopy(NG_ATMLLC_HEADER, hdr->llchdr, 6);
244 		if ((m->m_flags & M_HASFCS) != 0) {
245 			ATM_LLC_SETTYPE(hdr, NG_ATMLLC_TYPE_FDDI_FCS);
246 		} else {
247 			ATM_LLC_SETTYPE(hdr, NG_ATMLLC_TYPE_FDDI_NOFCS);
248 		}
249 		outhook = priv->atm;
250 	}
251 
252 	if (outhook == NULL) {
253 		NG_FREE_M(m);
254 		NG_FREE_ITEM(item);
255 		return (0);
256 	}
257 
258 	NG_FWD_NEW_DATA(error, item, outhook, m);
259 	return (error);
260 }
261 
262 static int
ng_atmllc_disconnect(hook_p hook)263 ng_atmllc_disconnect(hook_p hook)
264 {
265 	node_p	node;
266 	struct	ng_atmllc_priv *priv;
267 
268 	node = NG_HOOK_NODE(hook);
269 	priv = NG_NODE_PRIVATE(node);
270 
271 	if (hook == priv->atm) {
272 		priv->atm = NULL;
273 	} else if (hook == priv->ether) {
274 		priv->ether = NULL;
275 	} else if (hook == priv->fddi) {
276 		priv->fddi = NULL;
277 	}
278 
279 	if (NG_NODE_NUMHOOKS(node) == 0 && NG_NODE_IS_VALID(node)) {
280 		ng_rmnode_self(node);
281 	}
282 
283 	return (0);
284 }
285