157029Ssklower /* 257029Ssklower * Copyright (C) Dirk Husemann, Computer Science Department IV, 357029Ssklower * University of Erlangen-Nuremberg, Germany, 1990, 1991, 1992 4*63216Sbostic * Copyright (c) 1992, 1993 5*63216Sbostic * 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*63216Sbostic * @(#)pk_llcsubr.c 8.1 (Berkeley) 06/10/93 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 9957029Ssklower int 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) 11457029Ssklower return(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); 12057029Ssklower return(0); 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) 13457029Ssklower return (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 17557029Ssklower return(0); 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); 18857029Ssklower return(0); 18957029Ssklower } 19057029Ssklower 19157029Ssklower if (pkp->pk_llrt) 19257029Ssklower npaidb_destroy(pkp->pk_llrt); 19357029Ssklower 19457029Ssklower pk_dellink (pkp); 19557029Ssklower 19657029Ssklower return(0); 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 * 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 * 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 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 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