diff options
Diffstat (limited to 'sys/netccitt/pk_llcsubr.c')
-rw-r--r-- | sys/netccitt/pk_llcsubr.c | 370 |
1 files changed, 370 insertions, 0 deletions
diff --git a/sys/netccitt/pk_llcsubr.c b/sys/netccitt/pk_llcsubr.c new file mode 100644 index 0000000..7269fb2 --- /dev/null +++ b/sys/netccitt/pk_llcsubr.c @@ -0,0 +1,370 @@ +/* + * Copyright (C) Dirk Husemann, Computer Science Department IV, + * University of Erlangen-Nuremberg, Germany, 1990, 1991, 1992 + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Dirk Husemann and the Computer Science Department (IV) of + * the University of Erlangen-Nuremberg, Germany. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)pk_llcsubr.c 8.1 (Berkeley) 6/10/93 + * $Id$ + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/domain.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/protosw.h> +#include <sys/errno.h> +#include <sys/time.h> +#include <sys/kernel.h> + +#include <net/if.h> +#include <net/if_dl.h> +#include <net/if_llc.h> +#include <net/if_types.h> +#include <net/route.h> + +#include <netccitt/dll.h> +#include <netccitt/x25.h> +#include <netccitt/pk.h> +#include <netccitt/pk_var.h> +#include <netccitt/llc_var.h> + + +/* + * Routing support for X.25 + * + * We distinguish between two cases: + * RTF_HOST: + * rt_key(rt) X.25 address of host + * rt_gateway SNPA (MAC+DLSAP) address of host + * rt_llinfo pkcb for rt_key(rt) + * + * RTF_GATEWAY + * rt_key(rt) X.25 address of host or suitably masked network + * rt_gateway X.25 address of next X.25 gateway (switch) + * rt_llinfo rtentry for rt_gateway address + * ought to be of type RTF_HOST + * + * + * Mapping of X.121 to pkcbs: + * + * HDLC uses the DTE-DCE model of X.25, therefore we need a many-to-one + * relationship, i.e.: + * + * {X.121_a, X.121_b, X.121_c, ..., X.121_i} -> pkcb_0 + * + * LLC2 utilizes the DTE-DTE model of X.25, resulting effectively in a + * one-to-one relationship, i.e.: + * + * {X.121_j} -> pkcb_1a + * {X.121_k} -> pkcb_1b + * ... + * {X.121_q} -> pkcb_1q + * + * It might make sense to allow a many-to-one relation for LLC2 also, + * + * {X.121_r, X.121_s, X.121_t, X.121_u} -> pkcb_2a + * + * This would make addresses X.121_[r-u] essentially aliases of one + * address ({X.121_[r-u]} would constitute a representative set). + * + * Each one-to-one relation must obviously be entered individually with + * a route add command, whereas a many-to-one relationship can be + * either entered individually or generated by using a netmask. + * + * To facilitate dealings the many-to-one case for LLC2 can only be + * established via a netmask. + * + */ + +#define XTRACTPKP(rt) ((rt)->rt_flags & RTF_GATEWAY ? \ + ((rt)->rt_llinfo ? \ + (struct pkcb *) ((struct rtentry *)((rt)->rt_llinfo))->rt_llinfo : \ + (struct pkcb *) NULL) : \ + (struct pkcb *)((rt)->rt_llinfo)) + +#define equal(a1, a2) (bcmp((caddr_t)(a1), \ + (caddr_t)(a2), \ + (a1)->sa_len) == 0) +#define XIFA(rt) ((struct x25_ifaddr *)((rt)->rt_ifa)) +#define SA(s) ((struct sockaddr *)s) + +int +cons_rtrequest(int cmd, struct rtentry *rt, struct sockaddr *dst) +{ + register struct pkcb *pkp; + register int i; + register char one_to_one; + struct pkcb *pk_newlink(); + struct rtentry *npaidb_enter(); + + pkp = XTRACTPKP(rt); + + switch(cmd) { + case RTM_RESOLVE: + case RTM_ADD: + if (pkp) + return(EEXIST); + + if (rt->rt_flags & RTF_GATEWAY) { + if (rt->rt_llinfo) + RTFREE((struct rtentry *)rt->rt_llinfo); + rt->rt_llinfo = (caddr_t) rtalloc1(rt->rt_gateway, 1); + return(0); + } + /* + * Assumptions: (1) ifnet structure is filled in + * (2) at least the pkcb created via + * x25config (ifconfig?) has been + * set up already. + * (3) HDLC interfaces have an if_type of + * IFT_X25{,DDN}, LLC2 interfaces + * anything else (any better way to + * do this?) + * + */ + if (!rt->rt_ifa) + return (ENETDOWN); + + /* + * We differentiate between dealing with a many-to-one + * (HDLC: DTE-DCE) and a one-to-one (LLC2: DTE-DTE) + * relationship (by looking at the if type). + * + * Only in case of the many-to-one relationship (HDLC) + * we set the ia->ia_pkcb pointer to the pkcb allocated + * via pk_newlink() as we will use just that one pkcb for + * future route additions (the rtentry->rt_llinfo pointer + * points to the pkcb allocated for that route). + * + * In case of the one-to-one relationship (LLC2) we + * create a new pkcb (via pk_newlink()) for each new rtentry. + * + * NOTE: Only in case of HDLC does ia->ia_pkcb point + * to a pkcb, in the LLC2 case it doesn't (as we don't + * need it here)! + */ + one_to_one = ISISO8802(rt->rt_ifp); + + if (!(pkp = XIFA(rt)->ia_pkcb) && !one_to_one) + XIFA(rt)->ia_pkcb = pkp = + pk_newlink(XIFA(rt), (caddr_t) 0); + else if (one_to_one && + !equal(rt->rt_gateway, rt->rt_ifa->ifa_addr)) { + pkp = pk_newlink(XIFA(rt), (caddr_t) 0); + /* + * We also need another route entry for mapping + * MAC+LSAP->X.25 address + */ + pkp->pk_llrt = npaidb_enter(rt->rt_gateway, rt_key(rt), rt, 0); + } + if (pkp) { + if (!pkp->pk_rt) + pkp->pk_rt = rt; + pkp->pk_refcount++; + } + rt->rt_llinfo = (caddr_t) pkp; + + return(0); + + case RTM_DELETE: + { + /* + * The pkp might be empty if we are dealing + * with an interface route entry for LLC2, in this + * case we don't need to do anything ... + */ + if (pkp) { + if ( rt->rt_flags & RTF_GATEWAY ) { + if (rt->rt_llinfo) + RTFREE((struct rtentry *)rt->rt_llinfo); + return(0); + } + + if (pkp->pk_llrt) + npaidb_destroy(pkp->pk_llrt); + + pk_dellink (pkp); + + return(0); + } + } + } +} + +/* + * Network Protocol Addressing Information DataBase (npaidb) + * + * To speed up locating the entity dealing with an LLC packet use is made + * of a routing tree. This npaidb routing tree is handled + * by the normal rn_*() routines just like (almost) any other routing tree. + * + * The mapping being done by the npaidb_*() routines is as follows: + * + * Key: MAC,LSAP (enhancing struct sockaddr_dl) + * Gateway: sockaddr_x25 (i.e. X.25 address - X.121 or NSAP) + * Llinfo: npaidbentry { + * struct llc_linkcb *npaidb_linkp; + * struct rtentry *npaidb_rt; + * } + * + * Using the npaidbentry provided by llinfo we can then access + * + * o the pkcb by using (struct pkcb *) (npaidb_rt->rt_llinfo) + * o the linkcb via npaidb_linkp + * + * The following functions are provided + * + * o npaidb_enter(struct sockaddr_dl *sdl, struct sockaddr_x25 *sx25, + * struct struct llc_linkcb *link, struct rtentry *rt) + * + * o npaidb_enrich(short type, caddr_t info) + * + */ + +struct sockaddr_dl npdl_netmask = { + sizeof(struct sockaddr_dl), /* _len */ + 0, /* _family */ + 0, /* _index */ + 0, /* _type */ + -1, /* _nlen */ + -1, /* _alen */ + -1, /* _slen */ + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, /* _data */ +}; +struct sockaddr npdl_dummy; + +int npdl_datasize = sizeof(struct sockaddr_dl)- + ((int)((caddr_t)&((struct sockaddr_dl *)0)->sdl_data[0])); + +struct rtentry * +npaidb_enter(struct sockaddr_dl *key, struct sockaddr *value, + struct rtentry *rt, struct llc_linkcb *link) +{ + struct rtentry *nprt; register int i; + + USES_AF_LINK_RTS; + + if ((nprt = rtalloc1(SA(key), 0)) == 0) { + register u_int size = sizeof(struct npaidbentry); + register u_char saploc = LLSAPLOC(key, rt->rt_ifp); + + /* + * set up netmask: LLC2 packets have the lowest bit set in + * response packets (e.g. 0x7e for command packets, 0x7f for + * response packets), to facilitate the lookup we use a netmask + * of 11111110 for the SAP position. The remaining positions + * are zeroed out. + */ + npdl_netmask.sdl_data[saploc] = NPDL_SAPNETMASK; + bzero((caddr_t)&npdl_netmask.sdl_data[saploc+1], + npdl_datasize-saploc-1); + + if (value == 0) + value = &npdl_dummy; + + /* now enter it */ + rtrequest(RTM_ADD, SA(key), SA(value), + SA(&npdl_netmask), 0, &nprt); + + /* and reset npdl_netmask */ + for (i = saploc; i < npdl_datasize; i++) + npdl_netmask.sdl_data[i] = -1; + + nprt->rt_llinfo = malloc(size , M_PCB, M_WAITOK); + if (nprt->rt_llinfo) { + bzero (nprt->rt_llinfo, size); + ((struct npaidbentry *) (nprt->rt_llinfo))->np_rt = rt; + } + } else nprt->rt_refcnt--; + return nprt; +} + +struct rtentry * +npaidb_enrich(short type, caddr_t info, struct sockaddr_dl *sdl) +{ + struct rtentry *rt; + + USES_AF_LINK_RTS; + + if (rt = rtalloc1((struct sockaddr *)sdl, 0)) { + rt->rt_refcnt--; + switch (type) { + case NPAIDB_LINK: + ((struct npaidbentry *)(rt->rt_llinfo))->np_link = + (struct llc_linkcb *) info; + break; + } + return rt; + } + + return ((struct rtentry *) 0); + +} + +npaidb_destroy(struct rtentry *rt) +{ + USES_AF_LINK_RTS; + + if (rt->rt_llinfo) + free((caddr_t) rt->rt_llinfo, M_PCB); + return(rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway, rt_mask(rt), + 0, 0)); +} + + +#ifdef LLC +/* + * Glue between X.25 and LLC2 + */ +int +x25_llcglue(int prc, struct sockaddr *addr) +{ + register struct sockaddr_x25 *sx25 = (struct sockaddr_x25 *)addr; + register struct x25_ifaddr *x25ifa; + struct dll_ctlinfo ctlinfo; + + if((x25ifa = (struct x25_ifaddr *)ifa_ifwithaddr(addr)) == 0) + return 0; + + ctlinfo.dlcti_cfg = + (struct dllconfig *)(((struct sockaddr_x25 *)(&x25ifa->ia_xc))+1); + ctlinfo.dlcti_lsap = LLC_X25_LSAP; + + return ((int)llc_ctlinput(prc, addr, (caddr_t)&ctlinfo)); +} +#endif /* LLC */ |