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