xref: /csrg-svn/sys/netccitt/pk_llcsubr.c (revision 68258)
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