/* $NetBSD: pk_llcsubr.c,v 1.13 2002/10/24 20:54:41 christos Exp $ */ /* * Copyright (c) 1990, 1991, 1992 * Dirk Husemann, Computer Science Department IV, * University of Erlangen-Nuremberg, Germany. * 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.2 (Berkeley) 2/9/95 */ #include __KERNEL_RCSID(0, "$NetBSD: pk_llcsubr.c,v 1.13 2002/10/24 20:54:41 christos Exp $"); #include "opt_llc.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * 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) static int cons_rtrequest_internal __P((int, struct rtentry *, struct rt_addrinfo *)); /* * ifa_rtrequest currently does not check the error from the rtrequest call * so we use a void version of the cons_rtrequest routine. */ void cons_rtrequest(cmd, rt, info) int cmd; struct rtentry *rt; struct rt_addrinfo *info; { cons_rtrequest_internal(cmd, rt, info); } static int cons_rtrequest_internal(cmd, rt, info) int cmd; struct rtentry *rt; struct rt_addrinfo *info; { struct pkcb *pkp; char one_to_one; 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((struct sockaddr_dl *) 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); } } } 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) ((unsigned long)&((struct sockaddr_dl *) 0)->sdl_data[0])); struct rtentry * npaidb_enter(key, value, rt, link) struct sockaddr_dl *key; struct sockaddr *value; struct rtentry *rt; struct llc_linkcb *link; { struct rtentry *nprt; int i; USES_AF_LINK_RTS; if ((nprt = rtalloc1(SA(key), 0)) == 0) { u_int size = sizeof(struct npaidbentry); 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(type, info, sdl) short type; caddr_t info; struct sockaddr_dl *sdl; { struct rtentry *rt; USES_AF_LINK_RTS; if ((rt = rtalloc1((struct sockaddr *) sdl, 0)) != NULL) { 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); } int npaidb_destroy(rt) 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 */ long x25_llcglue(prc, addr) int prc; struct sockaddr *addr; { struct x25_ifaddr *x25ifa; struct dll_ctlinfo ctlinfo; long rv; 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; rv = (long) llc_ctlinput(prc, addr, &ctlinfo); return (rv); } #endif /* LLC */