NetBSD/sys/netccitt/pk_llcsubr.c
2002-10-24 20:54:41 +00:00

410 lines
11 KiB
C

/* $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 <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: pk_llcsubr.c,v 1.13 2002/10/24 20:54:41 christos Exp $");
#include "opt_llc.h"
#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/pk_extern.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)
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 */