157029Ssklower /*
257029Ssklower * Copyright (C) Dirk Husemann, Computer Science Department IV,
357029Ssklower * University of Erlangen-Nuremberg, Germany, 1990, 1991, 1992
463216Sbostic * Copyright (c) 1992, 1993
563216Sbostic * The Regents of the University of California. All rights reserved.
657029Ssklower *
757029Ssklower * This code is derived from software contributed to Berkeley by
857029Ssklower * Dirk Husemann and the Computer Science Department (IV) of
957029Ssklower * the University of Erlangen-Nuremberg, Germany.
1057029Ssklower *
1157029Ssklower * %sccs.include.redist.c%
1257029Ssklower *
13*68258Scgd * @(#)pk_llcsubr.c 8.2 (Berkeley) 02/09/95
1457029Ssklower */
1557029Ssklower
1657029Ssklower #include <sys/param.h>
1757029Ssklower #include <sys/systm.h>
1857029Ssklower #include <sys/mbuf.h>
1957029Ssklower #include <sys/domain.h>
2057029Ssklower #include <sys/socket.h>
2157029Ssklower #include <sys/socketvar.h>
2257029Ssklower #include <sys/protosw.h>
2357029Ssklower #include <sys/errno.h>
2457029Ssklower #include <sys/time.h>
2557029Ssklower #include <sys/kernel.h>
2657029Ssklower
2757029Ssklower #include <net/if.h>
2857029Ssklower #include <net/if_dl.h>
2957029Ssklower #include <net/if_llc.h>
3057029Ssklower #include <net/if_types.h>
3157029Ssklower #include <net/route.h>
3257029Ssklower
3357029Ssklower #include <netccitt/dll.h>
3457029Ssklower #include <netccitt/x25.h>
3557029Ssklower #include <netccitt/pk.h>
3657029Ssklower #include <netccitt/pk_var.h>
3757029Ssklower #include <netccitt/llc_var.h>
3857029Ssklower
3957029Ssklower
4057029Ssklower /*
4157029Ssklower * Routing support for X.25
4257029Ssklower *
4357029Ssklower * We distinguish between two cases:
4457029Ssklower * RTF_HOST:
4557029Ssklower * rt_key(rt) X.25 address of host
4657029Ssklower * rt_gateway SNPA (MAC+DLSAP) address of host
4757029Ssklower * rt_llinfo pkcb for rt_key(rt)
4857029Ssklower *
4957029Ssklower * RTF_GATEWAY
5057029Ssklower * rt_key(rt) X.25 address of host or suitably masked network
5157029Ssklower * rt_gateway X.25 address of next X.25 gateway (switch)
5257029Ssklower * rt_llinfo rtentry for rt_gateway address
5357029Ssklower * ought to be of type RTF_HOST
5457029Ssklower *
5557029Ssklower *
5657029Ssklower * Mapping of X.121 to pkcbs:
5757029Ssklower *
5857029Ssklower * HDLC uses the DTE-DCE model of X.25, therefore we need a many-to-one
5957029Ssklower * relationship, i.e.:
6057029Ssklower *
6157029Ssklower * {X.121_a, X.121_b, X.121_c, ..., X.121_i} -> pkcb_0
6257029Ssklower *
6357029Ssklower * LLC2 utilizes the DTE-DTE model of X.25, resulting effectively in a
6457029Ssklower * one-to-one relationship, i.e.:
6557029Ssklower *
6657029Ssklower * {X.121_j} -> pkcb_1a
6757029Ssklower * {X.121_k} -> pkcb_1b
6857029Ssklower * ...
6957029Ssklower * {X.121_q} -> pkcb_1q
7057029Ssklower *
7157029Ssklower * It might make sense to allow a many-to-one relation for LLC2 also,
7257029Ssklower *
7357029Ssklower * {X.121_r, X.121_s, X.121_t, X.121_u} -> pkcb_2a
7457029Ssklower *
7557029Ssklower * This would make addresses X.121_[r-u] essentially aliases of one
7657029Ssklower * address ({X.121_[r-u]} would constitute a representative set).
7757029Ssklower *
7857029Ssklower * Each one-to-one relation must obviously be entered individually with
7957029Ssklower * a route add command, whereas a many-to-one relationship can be
8057029Ssklower * either entered individually or generated by using a netmask.
8157029Ssklower *
8257029Ssklower * To facilitate dealings the many-to-one case for LLC2 can only be
8357029Ssklower * established via a netmask.
8457029Ssklower *
8557029Ssklower */
8657029Ssklower
8757029Ssklower #define XTRACTPKP(rt) ((rt)->rt_flags & RTF_GATEWAY ? \
8857029Ssklower ((rt)->rt_llinfo ? \
8957029Ssklower (struct pkcb *) ((struct rtentry *)((rt)->rt_llinfo))->rt_llinfo : \
9057029Ssklower (struct pkcb *) NULL) : \
9157029Ssklower (struct pkcb *)((rt)->rt_llinfo))
9257029Ssklower
9357029Ssklower #define equal(a1, a2) (bcmp((caddr_t)(a1), \
9457029Ssklower (caddr_t)(a2), \
9557029Ssklower (a1)->sa_len) == 0)
9657029Ssklower #define XIFA(rt) ((struct x25_ifaddr *)((rt)->rt_ifa))
9761656Ssklower #define SA(s) ((struct sockaddr *)s)
9857029Ssklower
99*68258Scgd void
cons_rtrequest(int cmd,struct rtentry * rt,struct sockaddr * dst)10057029Ssklower cons_rtrequest(int cmd, struct rtentry *rt, struct sockaddr *dst)
10157029Ssklower {
10257029Ssklower register struct pkcb *pkp;
10357029Ssklower register int i;
10457029Ssklower register char one_to_one;
10557029Ssklower struct pkcb *pk_newlink();
10657029Ssklower struct rtentry *npaidb_enter();
10757029Ssklower
10857029Ssklower pkp = XTRACTPKP(rt);
10957029Ssklower
11057029Ssklower switch(cmd) {
11157029Ssklower case RTM_RESOLVE:
11257029Ssklower case RTM_ADD:
11357029Ssklower if (pkp)
114*68258Scgd return; /* XXX: EEXIST */
11557029Ssklower
11657029Ssklower if (rt->rt_flags & RTF_GATEWAY) {
11757029Ssklower if (rt->rt_llinfo)
11857029Ssklower RTFREE((struct rtentry *)rt->rt_llinfo);
11957029Ssklower rt->rt_llinfo = (caddr_t) rtalloc1(rt->rt_gateway, 1);
120*68258Scgd return; /* XXX: OK */
12157029Ssklower }
12257029Ssklower /*
12357029Ssklower * Assumptions: (1) ifnet structure is filled in
12457029Ssklower * (2) at least the pkcb created via
12557029Ssklower * x25config (ifconfig?) has been
12657029Ssklower * set up already.
12757029Ssklower * (3) HDLC interfaces have an if_type of
12857029Ssklower * IFT_X25{,DDN}, LLC2 interfaces
12957029Ssklower * anything else (any better way to
13057029Ssklower * do this?)
13157029Ssklower *
13257029Ssklower */
13357029Ssklower if (!rt->rt_ifa)
134*68258Scgd return; /* XXX: ENETDOWN */
13557029Ssklower
13657029Ssklower /*
13757029Ssklower * We differentiate between dealing with a many-to-one
13857029Ssklower * (HDLC: DTE-DCE) and a one-to-one (LLC2: DTE-DTE)
13957029Ssklower * relationship (by looking at the if type).
14057029Ssklower *
14157029Ssklower * Only in case of the many-to-one relationship (HDLC)
14257029Ssklower * we set the ia->ia_pkcb pointer to the pkcb allocated
14357029Ssklower * via pk_newlink() as we will use just that one pkcb for
14457029Ssklower * future route additions (the rtentry->rt_llinfo pointer
14557029Ssklower * points to the pkcb allocated for that route).
14657029Ssklower *
14757029Ssklower * In case of the one-to-one relationship (LLC2) we
14857029Ssklower * create a new pkcb (via pk_newlink()) for each new rtentry.
14957029Ssklower *
15057029Ssklower * NOTE: Only in case of HDLC does ia->ia_pkcb point
15157029Ssklower * to a pkcb, in the LLC2 case it doesn't (as we don't
15257029Ssklower * need it here)!
15357029Ssklower */
15457029Ssklower one_to_one = ISISO8802(rt->rt_ifp);
15557029Ssklower
15657029Ssklower if (!(pkp = XIFA(rt)->ia_pkcb) && !one_to_one)
15757029Ssklower XIFA(rt)->ia_pkcb = pkp =
15857029Ssklower pk_newlink(XIFA(rt), (caddr_t) 0);
15957029Ssklower else if (one_to_one &&
16057029Ssklower !equal(rt->rt_gateway, rt->rt_ifa->ifa_addr)) {
16157029Ssklower pkp = pk_newlink(XIFA(rt), (caddr_t) 0);
16257029Ssklower /*
16357029Ssklower * We also need another route entry for mapping
16457029Ssklower * MAC+LSAP->X.25 address
16557029Ssklower */
16657029Ssklower pkp->pk_llrt = npaidb_enter(rt->rt_gateway, rt_key(rt), rt, 0);
16757029Ssklower }
16857029Ssklower if (pkp) {
16957029Ssklower if (!pkp->pk_rt)
17057029Ssklower pkp->pk_rt = rt;
17157029Ssklower pkp->pk_refcount++;
17257029Ssklower }
17357029Ssklower rt->rt_llinfo = (caddr_t) pkp;
17457029Ssklower
175*68258Scgd return; /* XXX: OK */
17657029Ssklower
17757029Ssklower case RTM_DELETE:
17857029Ssklower {
17957029Ssklower /*
18057029Ssklower * The pkp might be empty if we are dealing
18157029Ssklower * with an interface route entry for LLC2, in this
18257029Ssklower * case we don't need to do anything ...
18357029Ssklower */
18457029Ssklower if (pkp) {
18557029Ssklower if ( rt->rt_flags & RTF_GATEWAY ) {
18657029Ssklower if (rt->rt_llinfo)
18757029Ssklower RTFREE((struct rtentry *)rt->rt_llinfo);
188*68258Scgd return; /* XXX: OK */
18957029Ssklower }
19057029Ssklower
19157029Ssklower if (pkp->pk_llrt)
19257029Ssklower npaidb_destroy(pkp->pk_llrt);
19357029Ssklower
19457029Ssklower pk_dellink (pkp);
19557029Ssklower
196*68258Scgd return; /* XXX: OK */
19757029Ssklower }
19857029Ssklower }
19957029Ssklower }
20057029Ssklower }
20157029Ssklower
20258150Sdkhusema /*
20358150Sdkhusema * Network Protocol Addressing Information DataBase (npaidb)
20458150Sdkhusema *
20558150Sdkhusema * To speed up locating the entity dealing with an LLC packet use is made
20658150Sdkhusema * of a routing tree. This npaidb routing tree is handled
20758150Sdkhusema * by the normal rn_*() routines just like (almost) any other routing tree.
20858150Sdkhusema *
20958150Sdkhusema * The mapping being done by the npaidb_*() routines is as follows:
21058150Sdkhusema *
21158150Sdkhusema * Key: MAC,LSAP (enhancing struct sockaddr_dl)
21258150Sdkhusema * Gateway: sockaddr_x25 (i.e. X.25 address - X.121 or NSAP)
21358150Sdkhusema * Llinfo: npaidbentry {
21458150Sdkhusema * struct llc_linkcb *npaidb_linkp;
21558150Sdkhusema * struct rtentry *npaidb_rt;
21658150Sdkhusema * }
21758150Sdkhusema *
21858150Sdkhusema * Using the npaidbentry provided by llinfo we can then access
21958150Sdkhusema *
22058150Sdkhusema * o the pkcb by using (struct pkcb *) (npaidb_rt->rt_llinfo)
22158150Sdkhusema * o the linkcb via npaidb_linkp
22258150Sdkhusema *
22358150Sdkhusema * The following functions are provided
22458150Sdkhusema *
22558150Sdkhusema * o npaidb_enter(struct sockaddr_dl *sdl, struct sockaddr_x25 *sx25,
22658150Sdkhusema * struct struct llc_linkcb *link, struct rtentry *rt)
22758150Sdkhusema *
22858150Sdkhusema * o npaidb_enrich(short type, caddr_t info)
22958150Sdkhusema *
23058150Sdkhusema */
23157029Ssklower
23258150Sdkhusema struct sockaddr_dl npdl_netmask = {
23358150Sdkhusema sizeof(struct sockaddr_dl), /* _len */
23458150Sdkhusema 0, /* _family */
23558150Sdkhusema 0, /* _index */
23658150Sdkhusema 0, /* _type */
23758150Sdkhusema -1, /* _nlen */
23858150Sdkhusema -1, /* _alen */
23958150Sdkhusema -1, /* _slen */
24058150Sdkhusema { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, /* _data */
24158150Sdkhusema };
24258150Sdkhusema struct sockaddr npdl_dummy;
24358150Sdkhusema
24458150Sdkhusema int npdl_datasize = sizeof(struct sockaddr_dl)-
24558150Sdkhusema ((int)((caddr_t)&((struct sockaddr_dl *)0)->sdl_data[0]));
24658150Sdkhusema
24758150Sdkhusema struct rtentry *
npaidb_enter(struct sockaddr_dl * key,struct sockaddr * value,struct rtentry * rt,struct llc_linkcb * link)24858150Sdkhusema npaidb_enter(struct sockaddr_dl *key, struct sockaddr *value,
24958150Sdkhusema struct rtentry *rt, struct llc_linkcb *link)
25058150Sdkhusema {
25158150Sdkhusema struct rtentry *nprt; register int i;
25258150Sdkhusema
25358150Sdkhusema USES_AF_LINK_RTS;
25458150Sdkhusema
25561656Ssklower if ((nprt = rtalloc1(SA(key), 0)) == 0) {
25658150Sdkhusema register u_int size = sizeof(struct npaidbentry);
25758150Sdkhusema register u_char saploc = LLSAPLOC(key, rt->rt_ifp);
25858150Sdkhusema
25958150Sdkhusema /*
26058150Sdkhusema * set up netmask: LLC2 packets have the lowest bit set in
26158150Sdkhusema * response packets (e.g. 0x7e for command packets, 0x7f for
26258150Sdkhusema * response packets), to facilitate the lookup we use a netmask
26358150Sdkhusema * of 11111110 for the SAP position. The remaining positions
26458150Sdkhusema * are zeroed out.
26558150Sdkhusema */
26658150Sdkhusema npdl_netmask.sdl_data[saploc] = NPDL_SAPNETMASK;
26758150Sdkhusema bzero((caddr_t)&npdl_netmask.sdl_data[saploc+1],
26858150Sdkhusema npdl_datasize-saploc-1);
26958150Sdkhusema
27058150Sdkhusema if (value == 0)
27158150Sdkhusema value = &npdl_dummy;
27258150Sdkhusema
27358150Sdkhusema /* now enter it */
27461656Ssklower rtrequest(RTM_ADD, SA(key), SA(value),
27561656Ssklower SA(&npdl_netmask), 0, &nprt);
27658150Sdkhusema
27758150Sdkhusema /* and reset npdl_netmask */
27858150Sdkhusema for (i = saploc; i < npdl_datasize; i++)
27958150Sdkhusema npdl_netmask.sdl_data[i] = -1;
28058150Sdkhusema
28158150Sdkhusema nprt->rt_llinfo = malloc(size , M_PCB, M_WAITOK);
28258150Sdkhusema if (nprt->rt_llinfo) {
28358150Sdkhusema bzero (nprt->rt_llinfo, size);
28458150Sdkhusema ((struct npaidbentry *) (nprt->rt_llinfo))->np_rt = rt;
28558150Sdkhusema }
28658150Sdkhusema } else nprt->rt_refcnt--;
28758150Sdkhusema return nprt;
28858150Sdkhusema }
28958150Sdkhusema
29058150Sdkhusema struct rtentry *
npaidb_enrich(short type,caddr_t info,struct sockaddr_dl * sdl)29158150Sdkhusema npaidb_enrich(short type, caddr_t info, struct sockaddr_dl *sdl)
29258150Sdkhusema {
29358150Sdkhusema struct rtentry *rt;
29458150Sdkhusema
29558150Sdkhusema USES_AF_LINK_RTS;
29658150Sdkhusema
29761656Ssklower if (rt = rtalloc1((struct sockaddr *)sdl, 0)) {
29858150Sdkhusema rt->rt_refcnt--;
29958150Sdkhusema switch (type) {
30058150Sdkhusema case NPAIDB_LINK:
30158150Sdkhusema ((struct npaidbentry *)(rt->rt_llinfo))->np_link =
30258150Sdkhusema (struct llc_linkcb *) info;
30358150Sdkhusema break;
30458150Sdkhusema }
30558150Sdkhusema return rt;
30658150Sdkhusema }
30758150Sdkhusema
30858150Sdkhusema return ((struct rtentry *) 0);
30958150Sdkhusema
31058150Sdkhusema }
31158150Sdkhusema
npaidb_destroy(struct rtentry * rt)31258150Sdkhusema npaidb_destroy(struct rtentry *rt)
31358150Sdkhusema {
31458150Sdkhusema USES_AF_LINK_RTS;
31558150Sdkhusema
31658150Sdkhusema if (rt->rt_llinfo)
31758150Sdkhusema free((caddr_t) rt->rt_llinfo, M_PCB);
31858150Sdkhusema return(rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway, rt_mask(rt),
31958150Sdkhusema 0, 0));
32058150Sdkhusema }
32158150Sdkhusema
32258150Sdkhusema
32358150Sdkhusema #ifdef LLC
32457029Ssklower /*
32557029Ssklower * Glue between X.25 and LLC2
32657029Ssklower */
32757029Ssklower int
x25_llcglue(int prc,struct sockaddr * addr)32857029Ssklower x25_llcglue(int prc, struct sockaddr *addr)
32957029Ssklower {
33057029Ssklower register struct sockaddr_x25 *sx25 = (struct sockaddr_x25 *)addr;
33157029Ssklower register struct x25_ifaddr *x25ifa;
33257029Ssklower struct dll_ctlinfo ctlinfo;
33357029Ssklower
33457029Ssklower if((x25ifa = (struct x25_ifaddr *)ifa_ifwithaddr(addr)) == 0)
33557029Ssklower return 0;
33657029Ssklower
33757029Ssklower ctlinfo.dlcti_cfg =
33857029Ssklower (struct dllconfig *)(((struct sockaddr_x25 *)(&x25ifa->ia_xc))+1);
33957029Ssklower ctlinfo.dlcti_lsap = LLC_X25_LSAP;
34057029Ssklower
34157029Ssklower return ((int)llc_ctlinput(prc, addr, (caddr_t)&ctlinfo));
34257029Ssklower }
34358150Sdkhusema #endif /* LLC */
344