xref: /original-bsd/sys/netccitt/pk_llcsubr.c (revision e8c4bdd9)
1 /*
2  * Copyright (C) Dirk Husemann, Computer Science Department IV,
3  * 		 University of Erlangen-Nuremberg, Germany, 1990, 1991, 1992
4  * Copyright (c) 1992   Regents of the University of California.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * Dirk Husemann and the Computer Science Department (IV) of
9  * the University of Erlangen-Nuremberg, Germany.
10  *
11  * %sccs.include.redist.c%
12  *
13  *	@(#)pk_llcsubr.c	7.2 (Berkeley) 02/23/93
14  */
15 
16 #include <sys/param.h>
17 #include <sys/systm.h>
18 #include <sys/mbuf.h>
19 #include <sys/domain.h>
20 #include <sys/socket.h>
21 #include <sys/socketvar.h>
22 #include <sys/protosw.h>
23 #include <sys/errno.h>
24 #include <sys/time.h>
25 #include <sys/kernel.h>
26 
27 #include <net/if.h>
28 #include <net/if_dl.h>
29 #include <net/if_llc.h>
30 #include <net/if_types.h>
31 #include <net/route.h>
32 
33 #include <netccitt/dll.h>
34 #include <netccitt/x25.h>
35 #include <netccitt/pk.h>
36 #include <netccitt/pk_var.h>
37 #include <netccitt/llc_var.h>
38 
39 
40 /*
41  * Routing support for X.25
42  *
43  * We distinguish between two cases:
44  * RTF_HOST:
45  * 	rt_key(rt)	X.25 address of host
46  *	rt_gateway	SNPA (MAC+DLSAP) address of host
47  *	rt_llinfo	pkcb for rt_key(rt)
48  *
49  * RTF_GATEWAY
50  *	rt_key(rt)	X.25 address of host or suitably masked network
51  *	rt_gateway	X.25 address of next X.25 gateway (switch)
52  *	rt_llinfo	rtentry for rt_gateway address
53  *			ought to be of type RTF_HOST
54  *
55  *
56  * Mapping of X.121 to pkcbs:
57  *
58  * HDLC uses the DTE-DCE model of X.25, therefore we need a many-to-one
59  * relationship, i.e.:
60  *
61  * 	{X.121_a, X.121_b, X.121_c, ..., X.121_i} -> pkcb_0
62  *
63  * LLC2 utilizes the DTE-DTE model of X.25, resulting effectively in a
64  * one-to-one relationship, i.e.:
65  *
66  *	{X.121_j} 	->	pkcb_1a
67  *	{X.121_k}	->	pkcb_1b
68  *	...
69  *	{X.121_q}	->	pkcb_1q
70  *
71  * It might make sense to allow a many-to-one relation for LLC2 also,
72  *
73  *	{X.121_r, X.121_s, X.121_t, X.121_u} -> pkcb_2a
74  *
75  * This would make addresses X.121_[r-u] essentially aliases of one
76  * address ({X.121_[r-u]} would constitute a representative set).
77  *
78  * Each one-to-one relation must obviously be entered individually with
79  * a route add command, whereas a many-to-one relationship can be
80  * either entered individually or generated by using a netmask.
81  *
82  * To facilitate dealings the many-to-one case for LLC2 can only be
83  * established via a netmask.
84  *
85  */
86 
87 #define XTRACTPKP(rt)	((rt)->rt_flags & RTF_GATEWAY ? \
88 			 ((rt)->rt_llinfo ? \
89 			  (struct pkcb *) ((struct rtentry *)((rt)->rt_llinfo))->rt_llinfo : \
90 			  (struct pkcb *) NULL) : \
91 			 (struct pkcb *)((rt)->rt_llinfo))
92 
93 #define equal(a1, a2) (bcmp((caddr_t)(a1), \
94 			       (caddr_t)(a2), \
95 			       (a1)->sa_len) == 0)
96 #define XIFA(rt) ((struct x25_ifaddr *)((rt)->rt_ifa))
97 
98 int
99 cons_rtrequest(int cmd, struct rtentry *rt, struct sockaddr *dst)
100 {
101 	register struct pkcb *pkp;
102 	register int i;
103 	register char one_to_one;
104 	struct pkcb *pk_newlink();
105 	struct rtentry *npaidb_enter();
106 
107 	pkp = XTRACTPKP(rt);
108 
109 	switch(cmd) {
110 	case RTM_RESOLVE:
111 	case RTM_ADD:
112 		if (pkp)
113 			return(EEXIST);
114 
115 		if (rt->rt_flags & RTF_GATEWAY) {
116 			if (rt->rt_llinfo)
117 				RTFREE((struct rtentry *)rt->rt_llinfo);
118 			rt->rt_llinfo = (caddr_t) rtalloc1(rt->rt_gateway, 1);
119 			return(0);
120 		}
121 		/*
122 		 * Assumptions:	(1) ifnet structure is filled in
123 		 *		(2) at least the pkcb created via
124 		 *		    x25config (ifconfig?) has been
125 		 *		    set up already.
126 		 *		(3) HDLC interfaces have an if_type of
127 		 *		    IFT_X25{,DDN}, LLC2 interfaces
128 		 *		    anything else (any better way to
129 		 *		    do this?)
130 		 *
131 		 */
132 		if (!rt->rt_ifa)
133 			return (ENETDOWN);
134 
135 		/*
136 		 * We differentiate between dealing with a many-to-one
137 		 * (HDLC: DTE-DCE) and a one-to-one (LLC2: DTE-DTE)
138 		 * relationship (by looking at the if type).
139 		 *
140 		 * Only in case of the many-to-one relationship (HDLC)
141 		 * we set the ia->ia_pkcb pointer to the pkcb allocated
142 		 * via pk_newlink() as we will use just that one pkcb for
143 		 * future route additions (the rtentry->rt_llinfo pointer
144 		 * points to the pkcb allocated for that route).
145 		 *
146 		 * In case of the one-to-one relationship (LLC2) we
147 		 * create a new pkcb (via pk_newlink()) for each new rtentry.
148 		 *
149 		 * NOTE: Only in case of HDLC does ia->ia_pkcb point
150 		 * to a pkcb, in the LLC2 case it doesn't (as we don't
151 		 * need it here)!
152 		 */
153 		one_to_one = ISISO8802(rt->rt_ifp);
154 
155 		if (!(pkp = XIFA(rt)->ia_pkcb) && !one_to_one)
156 			XIFA(rt)->ia_pkcb = pkp =
157 				pk_newlink(XIFA(rt), (caddr_t) 0);
158 		else if (one_to_one &&
159 			 !equal(rt->rt_gateway, rt->rt_ifa->ifa_addr)) {
160 			pkp = pk_newlink(XIFA(rt), (caddr_t) 0);
161 			/*
162 			 * We also need another route entry for mapping
163 			 * MAC+LSAP->X.25 address
164 			 */
165 			pkp->pk_llrt = npaidb_enter(rt->rt_gateway, rt_key(rt), rt, 0);
166 		}
167 		if (pkp) {
168 			if (!pkp->pk_rt)
169 				pkp->pk_rt = rt;
170 			pkp->pk_refcount++;
171 		}
172 		rt->rt_llinfo = (caddr_t) pkp;
173 
174 		return(0);
175 
176 	case RTM_DELETE:
177 	{
178 		/*
179 		 * The pkp might be empty if we are dealing
180 		 * with an interface route entry for LLC2, in this
181 		 * case we don't need to do anything ...
182 		 */
183 		if (pkp) {
184 			if ( rt->rt_flags & RTF_GATEWAY ) {
185 				if (rt->rt_llinfo)
186 					RTFREE((struct rtentry *)rt->rt_llinfo);
187 				return(0);
188 			}
189 
190 			if (pkp->pk_llrt)
191 				npaidb_destroy(pkp->pk_llrt);
192 
193 			pk_dellink (pkp);
194 
195 			return(0);
196 		}
197 	}
198 	}
199 }
200 
201 /*
202  * Network Protocol Addressing Information DataBase (npaidb)
203  *
204  * To speed up locating the entity dealing with an LLC packet use is made
205  * of a routing tree. This npaidb routing tree is handled
206  * by the normal rn_*() routines just like (almost) any other routing tree.
207  *
208  * The mapping being done by the npaidb_*() routines is as follows:
209  *
210  *     Key:       MAC,LSAP (enhancing struct sockaddr_dl)
211  *     Gateway:   sockaddr_x25 (i.e. X.25 address - X.121 or NSAP)
212  *     Llinfo:    npaidbentry {
213  *                         struct llc_linkcb *npaidb_linkp;
214  *                         struct rtentry *npaidb_rt;
215  *                }
216  *
217  * Using the npaidbentry provided by llinfo we can then access
218  *
219  *       o the pkcb by using (struct pkcb *) (npaidb_rt->rt_llinfo)
220  *       o the linkcb via npaidb_linkp
221  *
222  * The following functions are provided
223  *
224  *       o npaidb_enter(struct sockaddr_dl *sdl, struct sockaddr_x25 *sx25,
225  *                      struct struct llc_linkcb *link, struct rtentry *rt)
226  *
227  *       o npaidb_enrich(short type, caddr_t info)
228  *
229  */
230 
231 struct sockaddr_dl npdl_netmask = {
232  sizeof(struct sockaddr_dl),					/* _len */
233  0,								/* _family */
234  0,								/* _index */
235  0,								/* _type */
236  -1,								/* _nlen */
237  -1,								/* _alen */
238  -1,								/* _slen */
239  { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},		/* _data */
240 };
241 struct sockaddr npdl_dummy;
242 
243 int npdl_datasize = sizeof(struct sockaddr_dl)-
244 		((int)((caddr_t)&((struct sockaddr_dl *)0)->sdl_data[0]));
245 
246 struct rtentry *
247 npaidb_enter(struct sockaddr_dl *key, struct sockaddr *value,
248 	     struct rtentry *rt, struct llc_linkcb *link)
249 {
250 	struct rtentry *nprt; register int i;
251 
252 	USES_AF_LINK_RTS;
253 
254 	if ((nprt = rtalloc1(key, 0)) == 0) {
255 		register u_int size = sizeof(struct npaidbentry);
256 		register u_char saploc = LLSAPLOC(key, rt->rt_ifp);
257 
258 		/*
259 		 * set up netmask: LLC2 packets have the lowest bit set in
260 		 * response packets (e.g. 0x7e for command packets, 0x7f for
261 		 * response packets), to facilitate the lookup we use a netmask
262 		 * of 11111110 for the SAP position. The remaining positions
263 		 * are zeroed out.
264 		 */
265 		npdl_netmask.sdl_data[saploc] = NPDL_SAPNETMASK;
266 		bzero((caddr_t)&npdl_netmask.sdl_data[saploc+1],
267 		      npdl_datasize-saploc-1);
268 
269 		if (value == 0)
270 			value = &npdl_dummy;
271 
272 		/* now enter it */
273 		rtrequest(RTM_ADD, key, value, &npdl_netmask, 0, &nprt);
274 
275 		/* and reset npdl_netmask */
276 		for (i = saploc; i < npdl_datasize; i++)
277 			npdl_netmask.sdl_data[i] = -1;
278 
279 		nprt->rt_llinfo = malloc(size , M_PCB, M_WAITOK);
280 		if (nprt->rt_llinfo) {
281 			bzero (nprt->rt_llinfo, size);
282 			((struct npaidbentry *) (nprt->rt_llinfo))->np_rt = rt;
283 		}
284 	} else nprt->rt_refcnt--;
285 	return nprt;
286 }
287 
288 struct rtentry *
289 npaidb_enrich(short type, caddr_t info, struct sockaddr_dl *sdl)
290 {
291 	struct rtentry *rt;
292 
293 	USES_AF_LINK_RTS;
294 
295 	if (rt = rtalloc1(sdl, 0)) {
296 		rt->rt_refcnt--;
297 		switch (type) {
298 		case NPAIDB_LINK:
299 			((struct npaidbentry *)(rt->rt_llinfo))->np_link =
300 				(struct llc_linkcb *) info;
301 			break;
302 		}
303 		return rt;
304 	}
305 
306 	return ((struct rtentry *) 0);
307 
308 }
309 
310 npaidb_destroy(struct rtentry *rt)
311 {
312 	USES_AF_LINK_RTS;
313 
314 	if (rt->rt_llinfo)
315 		free((caddr_t) rt->rt_llinfo, M_PCB);
316 	return(rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway, rt_mask(rt),
317 			 0, 0));
318 }
319 
320 
321 #ifdef LLC
322 /*
323  * Glue between X.25 and LLC2
324  */
325 int
326 x25_llcglue(int prc, struct sockaddr *addr)
327 {
328 	register struct sockaddr_x25 *sx25 = (struct sockaddr_x25 *)addr;
329 	register struct x25_ifaddr *x25ifa;
330 	struct dll_ctlinfo ctlinfo;
331 
332 	if((x25ifa = (struct x25_ifaddr *)ifa_ifwithaddr(addr)) == 0)
333 		return 0;
334 
335 	ctlinfo.dlcti_cfg  =
336 	    (struct dllconfig *)(((struct sockaddr_x25 *)(&x25ifa->ia_xc))+1);
337 	ctlinfo.dlcti_lsap = LLC_X25_LSAP;
338 
339 	return ((int)llc_ctlinput(prc, addr, (caddr_t)&ctlinfo));
340 }
341 #endif /* LLC */
342