371 lines
11 KiB
C
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 */
|