407 lines
11 KiB
C
407 lines
11 KiB
C
/* $NetBSD: pk_llcsubr.c,v 1.11 2001/01/17 04:05:43 itojun 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 "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) ((caddr_t) & ((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 */
|