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 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 * 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 * 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 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 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