freebsd-skq/sys/netccitt/pk_llcsubr.c
David Greenman 3c4dd3568f Added $Id$
1994-08-02 07:55:43 +00:00

371 lines
11 KiB
C

/*
* 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 */