1 /*
2 * Copyright (C) Dirk Husemann, Computer Science Department IV,
3 * University of Erlangen-Nuremberg, Germany, 1990, 1991, 1992
4 * Copyright (c) 1992, 1993
5 * The Regents of the University of California. 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 8.2 (Berkeley) 02/09/95
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 #define SA(s) ((struct sockaddr *)s)
98
99 void
cons_rtrequest(int cmd,struct rtentry * rt,struct sockaddr * dst)100 cons_rtrequest(int cmd, struct rtentry *rt, struct sockaddr *dst)
101 {
102 register struct pkcb *pkp;
103 register int i;
104 register char one_to_one;
105 struct pkcb *pk_newlink();
106 struct rtentry *npaidb_enter();
107
108 pkp = XTRACTPKP(rt);
109
110 switch(cmd) {
111 case RTM_RESOLVE:
112 case RTM_ADD:
113 if (pkp)
114 return; /* XXX: EEXIST */
115
116 if (rt->rt_flags & RTF_GATEWAY) {
117 if (rt->rt_llinfo)
118 RTFREE((struct rtentry *)rt->rt_llinfo);
119 rt->rt_llinfo = (caddr_t) rtalloc1(rt->rt_gateway, 1);
120 return; /* XXX: OK */
121 }
122 /*
123 * Assumptions: (1) ifnet structure is filled in
124 * (2) at least the pkcb created via
125 * x25config (ifconfig?) has been
126 * set up already.
127 * (3) HDLC interfaces have an if_type of
128 * IFT_X25{,DDN}, LLC2 interfaces
129 * anything else (any better way to
130 * do this?)
131 *
132 */
133 if (!rt->rt_ifa)
134 return; /* XXX: ENETDOWN */
135
136 /*
137 * We differentiate between dealing with a many-to-one
138 * (HDLC: DTE-DCE) and a one-to-one (LLC2: DTE-DTE)
139 * relationship (by looking at the if type).
140 *
141 * Only in case of the many-to-one relationship (HDLC)
142 * we set the ia->ia_pkcb pointer to the pkcb allocated
143 * via pk_newlink() as we will use just that one pkcb for
144 * future route additions (the rtentry->rt_llinfo pointer
145 * points to the pkcb allocated for that route).
146 *
147 * In case of the one-to-one relationship (LLC2) we
148 * create a new pkcb (via pk_newlink()) for each new rtentry.
149 *
150 * NOTE: Only in case of HDLC does ia->ia_pkcb point
151 * to a pkcb, in the LLC2 case it doesn't (as we don't
152 * need it here)!
153 */
154 one_to_one = ISISO8802(rt->rt_ifp);
155
156 if (!(pkp = XIFA(rt)->ia_pkcb) && !one_to_one)
157 XIFA(rt)->ia_pkcb = pkp =
158 pk_newlink(XIFA(rt), (caddr_t) 0);
159 else if (one_to_one &&
160 !equal(rt->rt_gateway, rt->rt_ifa->ifa_addr)) {
161 pkp = pk_newlink(XIFA(rt), (caddr_t) 0);
162 /*
163 * We also need another route entry for mapping
164 * MAC+LSAP->X.25 address
165 */
166 pkp->pk_llrt = npaidb_enter(rt->rt_gateway, rt_key(rt), rt, 0);
167 }
168 if (pkp) {
169 if (!pkp->pk_rt)
170 pkp->pk_rt = rt;
171 pkp->pk_refcount++;
172 }
173 rt->rt_llinfo = (caddr_t) pkp;
174
175 return; /* XXX: OK */
176
177 case RTM_DELETE:
178 {
179 /*
180 * The pkp might be empty if we are dealing
181 * with an interface route entry for LLC2, in this
182 * case we don't need to do anything ...
183 */
184 if (pkp) {
185 if ( rt->rt_flags & RTF_GATEWAY ) {
186 if (rt->rt_llinfo)
187 RTFREE((struct rtentry *)rt->rt_llinfo);
188 return; /* XXX: OK */
189 }
190
191 if (pkp->pk_llrt)
192 npaidb_destroy(pkp->pk_llrt);
193
194 pk_dellink (pkp);
195
196 return; /* XXX: OK */
197 }
198 }
199 }
200 }
201
202 /*
203 * Network Protocol Addressing Information DataBase (npaidb)
204 *
205 * To speed up locating the entity dealing with an LLC packet use is made
206 * of a routing tree. This npaidb routing tree is handled
207 * by the normal rn_*() routines just like (almost) any other routing tree.
208 *
209 * The mapping being done by the npaidb_*() routines is as follows:
210 *
211 * Key: MAC,LSAP (enhancing struct sockaddr_dl)
212 * Gateway: sockaddr_x25 (i.e. X.25 address - X.121 or NSAP)
213 * Llinfo: npaidbentry {
214 * struct llc_linkcb *npaidb_linkp;
215 * struct rtentry *npaidb_rt;
216 * }
217 *
218 * Using the npaidbentry provided by llinfo we can then access
219 *
220 * o the pkcb by using (struct pkcb *) (npaidb_rt->rt_llinfo)
221 * o the linkcb via npaidb_linkp
222 *
223 * The following functions are provided
224 *
225 * o npaidb_enter(struct sockaddr_dl *sdl, struct sockaddr_x25 *sx25,
226 * struct struct llc_linkcb *link, struct rtentry *rt)
227 *
228 * o npaidb_enrich(short type, caddr_t info)
229 *
230 */
231
232 struct sockaddr_dl npdl_netmask = {
233 sizeof(struct sockaddr_dl), /* _len */
234 0, /* _family */
235 0, /* _index */
236 0, /* _type */
237 -1, /* _nlen */
238 -1, /* _alen */
239 -1, /* _slen */
240 { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, /* _data */
241 };
242 struct sockaddr npdl_dummy;
243
244 int npdl_datasize = sizeof(struct sockaddr_dl)-
245 ((int)((caddr_t)&((struct sockaddr_dl *)0)->sdl_data[0]));
246
247 struct rtentry *
npaidb_enter(struct sockaddr_dl * key,struct sockaddr * value,struct rtentry * rt,struct llc_linkcb * link)248 npaidb_enter(struct sockaddr_dl *key, struct sockaddr *value,
249 struct rtentry *rt, struct llc_linkcb *link)
250 {
251 struct rtentry *nprt; register int i;
252
253 USES_AF_LINK_RTS;
254
255 if ((nprt = rtalloc1(SA(key), 0)) == 0) {
256 register u_int size = sizeof(struct npaidbentry);
257 register u_char saploc = LLSAPLOC(key, rt->rt_ifp);
258
259 /*
260 * set up netmask: LLC2 packets have the lowest bit set in
261 * response packets (e.g. 0x7e for command packets, 0x7f for
262 * response packets), to facilitate the lookup we use a netmask
263 * of 11111110 for the SAP position. The remaining positions
264 * are zeroed out.
265 */
266 npdl_netmask.sdl_data[saploc] = NPDL_SAPNETMASK;
267 bzero((caddr_t)&npdl_netmask.sdl_data[saploc+1],
268 npdl_datasize-saploc-1);
269
270 if (value == 0)
271 value = &npdl_dummy;
272
273 /* now enter it */
274 rtrequest(RTM_ADD, SA(key), SA(value),
275 SA(&npdl_netmask), 0, &nprt);
276
277 /* and reset npdl_netmask */
278 for (i = saploc; i < npdl_datasize; i++)
279 npdl_netmask.sdl_data[i] = -1;
280
281 nprt->rt_llinfo = malloc(size , M_PCB, M_WAITOK);
282 if (nprt->rt_llinfo) {
283 bzero (nprt->rt_llinfo, size);
284 ((struct npaidbentry *) (nprt->rt_llinfo))->np_rt = rt;
285 }
286 } else nprt->rt_refcnt--;
287 return nprt;
288 }
289
290 struct rtentry *
npaidb_enrich(short type,caddr_t info,struct sockaddr_dl * sdl)291 npaidb_enrich(short type, caddr_t info, struct sockaddr_dl *sdl)
292 {
293 struct rtentry *rt;
294
295 USES_AF_LINK_RTS;
296
297 if (rt = rtalloc1((struct sockaddr *)sdl, 0)) {
298 rt->rt_refcnt--;
299 switch (type) {
300 case NPAIDB_LINK:
301 ((struct npaidbentry *)(rt->rt_llinfo))->np_link =
302 (struct llc_linkcb *) info;
303 break;
304 }
305 return rt;
306 }
307
308 return ((struct rtentry *) 0);
309
310 }
311
npaidb_destroy(struct rtentry * rt)312 npaidb_destroy(struct rtentry *rt)
313 {
314 USES_AF_LINK_RTS;
315
316 if (rt->rt_llinfo)
317 free((caddr_t) rt->rt_llinfo, M_PCB);
318 return(rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway, rt_mask(rt),
319 0, 0));
320 }
321
322
323 #ifdef LLC
324 /*
325 * Glue between X.25 and LLC2
326 */
327 int
x25_llcglue(int prc,struct sockaddr * addr)328 x25_llcglue(int prc, struct sockaddr *addr)
329 {
330 register struct sockaddr_x25 *sx25 = (struct sockaddr_x25 *)addr;
331 register struct x25_ifaddr *x25ifa;
332 struct dll_ctlinfo ctlinfo;
333
334 if((x25ifa = (struct x25_ifaddr *)ifa_ifwithaddr(addr)) == 0)
335 return 0;
336
337 ctlinfo.dlcti_cfg =
338 (struct dllconfig *)(((struct sockaddr_x25 *)(&x25ifa->ia_xc))+1);
339 ctlinfo.dlcti_lsap = LLC_X25_LSAP;
340
341 return ((int)llc_ctlinput(prc, addr, (caddr_t)&ctlinfo));
342 }
343 #endif /* LLC */
344