Update of /cvsroot/linux-atm/linux-atm/src/lib In directory usw-pr-cvs1:/tmp/cvs-serv10656/lib Added Files: Tag: V2_4_0 atmres.h qosequal.c ans.c rtf2e164_cc.pl atmequal.c sap2text.c text2atm.c timer.c text2qos.c text2sap.c diag.c common.c Makefile.am kptr.c misc.c text2ip.c qos2text.c unix.c sapequal.c atm2text.c sdu2cell.c Log Message: --- NEW FILE: atmres.h --- /* atmres.h - Common definitions and prototypes for resolver functions */ /* Written 1996,1998 by Werner Almesberger, EPFL-LRC/ICA */ #ifndef _ATMRES_H #define _ATMRES_H #include <arpa/nameser.h> #include <linux/atm.h> /* Some #defines that may be needed if ANS isn't installed on that system */ #ifndef T_ATMA #define T_ATMA 34 #endif #ifndef ATMA_AESA #define ATMA_AESA 0 #endif #ifndef ATMA_E164 #define ATMA_E164 1 #endif /* Return codes for text2atm and atm2text */ #define TRY_OTHER -2 #define FATAL -1 /* must be -1 */ int ans_byname(const char *text,struct sockaddr_atmsvc *addr,int length, int flags); int ans_byaddr(char *buffer,int length,const struct sockaddr_atmsvc *addr, int flags); #endif --- NEW FILE: qosequal.c --- /* qosequal.c - Compares QOS specifications for equality */ /* Written 1996,1999 by Werner Almesberger, EPFL-LRC/ICA */ #if HAVE_CONFIG_H #include <config.h> #endif #include "atm.h" static int tp_equal(int traffic_class,struct atm_trafprm a,struct atm_trafprm b) { switch (traffic_class) { case ATM_NONE: return 1; case ATM_UBR: break; case ATM_CBR: if (a.max_cdv != b.max_cdv) return 0; break; default: return -1; } if (!a.max_pcr && !a.min_pcr) a.max_pcr = ATM_MAX_PCR; if (!b.max_pcr && !b.min_pcr) b.max_pcr = ATM_MAX_PCR; if (a.max_pcr != b.max_pcr || a.pcr != b.pcr || a.min_pcr != b.min_pcr) return 0; return a.max_sdu == b.max_sdu; } int qos_equal(const struct atm_qos *a,const struct atm_qos *b) { if (a->txtp.traffic_class != b->txtp.traffic_class) return 0; if (a->txtp.traffic_class == ATM_NONE) { if (a->rxtp.traffic_class != b->rxtp.traffic_class) return 0; return tp_equal(a->rxtp.traffic_class,a->rxtp,b->rxtp); } else { if (!tp_equal(a->txtp.traffic_class,a->txtp,b->txtp)) return 0; return tp_equal(a->txtp.traffic_class,a->rxtp,b->rxtp); } } --- NEW FILE: ans.c --- /* ans.c - Interface for text2atm and atm2text to ANS */ /* Written 1996-2000 by Werner Almesberger, EPFL-LRC/ICA */ /* * This stuff is a temporary hack to avoid using gethostbyname_nsap and such * without doing the "full upgrade" to getaddrinfo/getnameinfo. This also * serves as an exercise for me to get all the details right before I propose * a patch that would eventually end up in libc (and that should therefore be * as stable as possible). */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdlib.h> #include <stdio.h> #include <string.h> #include <netinet/in.h> #include <arpa/nameser.h> #include <netdb.h> #include <resolv.h> #include "atm.h" #include "atmres.h" #define MAX_ANSWER 2048 #define MAX_NAME 1024 #define MAX_LINE 2048 /* in /etc/e164_cc */ #define E164_CC_DEFAULT_LEN 2 #define E164_CC_FILE "/etc/e164_cc" #define GET16(pos) (((pos)[0] << 8) | (pos)[1]) static int ans(const char *text,int wanted,void *result,int res_len) { unsigned char answer[MAX_ANSWER]; unsigned char name[MAX_NAME]; unsigned char *pos,*data,*found; int answer_len,name_len,data_len,found_len; int questions,answers; found_len = 0; /* gcc wants it */ if ((answer_len = res_search(text,C_IN,wanted,answer,MAX_ANSWER)) < 0) return TRY_OTHER; /* * Response header: id, flags, #queries, #answers, #authority, * #additional (all 16 bits) */ pos = answer+12; if (answer[3] & 15) return TRY_OTHER; /* rcode != 0 */ questions = GET16(answer+4); if (questions != 1) return TRY_OTHER; /* trouble ... */ answers = GET16(answer+6); if (answers < 1) return TRY_OTHER; /* * Query: name, type (16), class (16) */ if ((name_len = dn_expand(answer,answer+answer_len,pos,name,MAX_NAME)) < 0) return TRY_OTHER; pos += name_len; if (GET16(pos) != wanted || GET16(pos+2) != C_IN) return TRY_OTHER; pos += 4; /* * Iterate over answers until we find something we like, giving priority * to ATMA_AESA (until signaling is fixed to work with E.164 too) */ found = NULL; while (answers--) { /* * RR: name, type (16), class (16), TTL (32), resource_len (16), * resource_data ... */ if ((name_len = dn_expand(answer,answer+answer_len,pos,name,MAX_NAME)) < 0) return TRY_OTHER; pos += name_len; data_len = GET16(pos+8); data = pos+10; pos = data+data_len; if (GET16(data-10) != wanted || GET16(data-8) != C_IN || !--data_len) continue; switch (wanted) { case T_NSAP: data_len++; if (data_len != ATM_ESA_LEN) continue; memcpy(((struct sockaddr_atmsvc *) result)-> sas_addr.prv,data,ATM_ESA_LEN); return 0; case T_ATMA: switch (*data++) { case ATMA_AESA: if (data_len != ATM_ESA_LEN) continue; memcpy(((struct sockaddr_atmsvc *) result)-> sas_addr.prv,data,ATM_ESA_LEN); return 0; case ATMA_E164: if (data_len > ATM_E164_LEN) continue; if (!found) { found = data; found_len = data_len; } break; default: continue; } case T_PTR: if (dn_expand(answer,answer+answer_len,data,result, res_len) < 0) return FATAL; return 0; default: continue; } } if (!found) return TRY_OTHER; memcpy(((struct sockaddr_atmsvc *) result)->sas_addr.pub,found, found_len); ((struct sockaddr_atmsvc *) result)->sas_addr.pub[found_len] = 0; return 0; } int ans_byname(const char *text,struct sockaddr_atmsvc *addr,int length, int flags) { if (!(flags & T2A_SVC) || length != sizeof(*addr)) return TRY_OTHER; memset(addr,0,sizeof(*addr)); addr->sas_family = AF_ATMSVC; if (!ans(text,T_ATMA,addr,length)) return 0; return ans(text,T_NSAP,addr,length); } static int encode_nsap(char *buf,const unsigned char *addr) { static int fmt_dcc[] = { 2,12,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 4,2,0 }; static int fmt_e164[] = { 2,12,1,1,1,1,1,1,1,1,16,2,0 }; int *fmt; int pos,i,j; switch (*addr) { case ATM_AFI_DCC: case ATM_AFI_ICD: case ATM_AFI_LOCAL: case ATM_AFI_DCC_GROUP: case ATM_AFI_ICD_GROUP: case ATM_AFI_LOCAL_GROUP: fmt = fmt_dcc; break; case ATM_AFI_E164: case ATM_AFI_E164_GROUP: fmt = fmt_e164; break; default: return TRY_OTHER; } pos = 2*ATM_ESA_LEN; for (i = 0; fmt[i]; i++) { pos -= fmt[i]; for (j = 0; j < fmt[i]; j++) sprintf(buf++,"%x", (addr[(pos+j) >> 1] >> 4*(1-((pos+j) & 1))) & 0xf); *buf++ = '.'; } strcpy(buf,"AESA.ATMA.INT."); return 0; } static int encode_nsap_new(char *buf,const unsigned char *addr) { int i; int digit; for (i = 20; i; ) { i--; digit = addr[i] & 0x0F; *(buf++) = digit + (digit >= 10 ? '7' : '0'); *(buf++) = '.'; digit = ((unsigned char) (addr[i])) >> 4; *(buf++) = digit + (digit >= 10 ? '7' : '0'); *(buf++) = '.'; } strcpy (buf, "NSAP.INT."); return 0; } static int cc_len(int p0,int p1) { static char *cc_table = NULL; FILE *file; char buffer[MAX_LINE]; char *here; int cc; if (!cc_table) { if (!(cc_table = malloc(100))) { perror("malloc"); return E164_CC_DEFAULT_LEN; } memset(cc_table,E164_CC_DEFAULT_LEN,100); if (!(file = fopen(E164_CC_FILE,"r"))) perror(E164_CC_FILE); else { while (fgets(buffer,MAX_LINE,file)) { here = strchr(buffer,'#'); if (here) *here = 0; if (sscanf(buffer,"%d",&cc) == 1) { if (cc < 10) cc_table[cc] = 1; else if (cc < 100) cc_table[cc] = 2; else cc_table[cc/10] = 3; } } fclose(file); } } if (cc_table[p0] == 1) return 1; return cc_table[p0*10+p1]; } static int encode_e164(char *buf,const char *addr) { const char *prefix,*here; prefix = addr+cc_len(addr[0]-48,addr[1]-48); here = strchr(addr,0); while (here > prefix) { *buf++ = *--here; *buf++ = '.'; } while (here > addr) *buf++ = *addr++; strcpy(buf,".E164.ATMA.INT."); return 0; } int ans_byaddr(char *buffer,int length,const struct sockaddr_atmsvc *addr, int flags) { char tmp[MAX_NAME]; /* could be smaller ... */ int res; if (addr->sas_addr.prv) { res = encode_nsap(tmp,addr->sas_addr.prv); if (!res && !ans(tmp,T_PTR,buffer,length)) return 0; res = encode_nsap_new(tmp,addr->sas_addr.prv); if (res < 0) return res; return ans(tmp,T_PTR,buffer,length); } else { res = encode_e164(tmp,addr->sas_addr.pub); if (res < 0) return res; return ans(tmp,T_PTR,buffer,length); } } --- NEW FILE: rtf2e164_cc.pl --- #!/usr/bin/perl # # The E.164 country code listing can be obtained from # http://www.itu.ch/itudoc/itu-t/lists/tf_cc_e_*.rtf # # Usage of this program: # perl rtf2e164_cc.pl <tf_cc_e_xxx.rtf >/etc/e164_cc while (<>) { next unless /{\\fs18\\cf1\s(\d+)}{\\f7\\fs24\s\\tab\s}{\\fs18\\cf1\s([^}]+)}/; last if $1 == 999; } while (<>) { next unless /{\\fs18\\cf1\s(\d+)}{\\f7\\fs24\s\\tab\s}{\\fs18\\cf1\s([^}]+)}/; printf("%-3d %s\n",$1,$2) || die "printf: $!"; } --- NEW FILE: atmequal.c --- /* atmequal.c - Compares ATM addresses for equality */ /* Written 1995-2000 by Werner Almesberger, EPFL-LRC/ICA */ #if HAVE_CONFIG_H #include <config.h> #endif #include <string.h> #include <assert.h> #include <sys/socket.h> #include "atm.h" static int atm_equal_pvc(const struct sockaddr_atmpvc *a, const struct sockaddr_atmpvc *b,int flags) { int wc = flags & AXE_WILDCARD; #define EQ(field,any) \ (a->sap_addr.field == b->sap_addr.field || \ (wc && (a->sap_addr.field == any || b->sap_addr.field == any))) return EQ(itf,ATM_ITF_ANY) && EQ(vpi,ATM_VPI_ANY) && EQ(vci,ATM_VCI_ANY); #undef EQ } static int atm_equal_svc(const struct sockaddr_atmsvc *a, const struct sockaddr_atmsvc *b,int len,int flags) { const unsigned char *a_prv,*b_prv; int len_a,len_b; if (!(flags & AXE_WILDCARD)) len = ATM_ESA_LEN*8; assert(len >= 0 && len <= ATM_ESA_LEN*8); if (*a->sas_addr.prv && *b->sas_addr.prv) { a_prv = a->sas_addr.prv; b_prv = b->sas_addr.prv; if ((flags & AXE_WILDCARD) && len >= 8 && *a_prv == ATM_AFI_E164 && *b_prv == ATM_AFI_E164) { if (len < 68) return 0; /* no comparison possible */ else { int a_pos,b_pos; unsigned char a_val,b_val; for (a_pos = 2; !a_prv[a_pos/2]; a_pos += 2); if (!(a_prv[a_pos/2] & 0xf0)) a_pos++; for (b_pos = 2; !b_prv[b_pos/2]; b_pos += 2); if (!(b_prv[b_pos/2] & 0xf0)) b_pos++; while (1) { a_val = (a_prv[a_pos/2] >> (((~a_pos) & 1)*4)) & 0xf; b_val = (b_prv[b_pos/2] >> (((~b_pos) & 1)*4)) & 0xf; if (a_val == 15 || b_val == 15) break; if (a_val != b_val) return 0; a_pos++; b_pos++; } a_prv += 9; b_prv += 9; if ((len -= 72) < 0) len = 0; } } if (memcmp(a_prv,b_prv,len/8)) return 0; if ((len & 7) && (a_prv[len/8+1]^b_prv[len/8+1]) & (0xff00 >> (len & 7))) return 0; return 1; } if ((*a->sas_addr.prv || *b->sas_addr.prv) && !(flags & AXE_PRVOPT)) return 0; if (!*a->sas_addr.pub || !*b->sas_addr.pub) return 0; len_a = strlen(a->sas_addr.pub); len_b = strlen(b->sas_addr.pub); if (len_a != len_b && !(flags & AXE_WILDCARD)) return 0; return !strncmp(a->sas_addr.pub,b->sas_addr.pub,len_a < len_b ? len_a : len_b); } int atm_equal(const struct sockaddr *a,const struct sockaddr *b,int len, int flags) { assert((a->sa_family == AF_ATMPVC && b->sa_family == AF_ATMPVC) || (a->sa_family == AF_ATMSVC && b->sa_family == AF_ATMSVC)); if (a->sa_family == AF_ATMPVC) return atm_equal_pvc((const struct sockaddr_atmpvc *) a, (const struct sockaddr_atmpvc *) b,flags); return atm_equal_svc((const struct sockaddr_atmsvc *) a, (const struct sockaddr_atmsvc *) b,len,flags); } --- NEW FILE: sap2text.c --- /* sap2text.c - Converts binary encoding of a SAP (Service Access Point; BHLI and BLLI) to textual representation */ /* Written 1997 by Werner Almesberger, EPFL-ICA */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdio.h> #include <stdarg.h> #include <string.h> #include <atmsap.h> #include <linux/atmsap.h> #include "atm.h" /* * <a-b> = a-b bytes * * bhli: * iso=<1-8> * user=<1-8> * hlp=<4> * oui=<3>,id=<4> * blli: * l2=x25_ll | x25_ml | hdlc_arm | hdlc_nrm | hdlc_abm | q922 | iso7776 * l2=user,info=<1> * l2=iso1745 | q291 | lapb | iso8802 | x75 * * etc. */ static int put(char **pos,char **end,int *length,const char *fmt,...) { char scratch[40]; /* we don't put long strings anyway */ va_list ap; int len; va_start(ap,fmt); len = vsprintf(scratch,fmt,ap); va_end(ap); if (!len) return 0; if (!*end) return -1; *length -= *end-*pos; *pos = *end; if (len >= *length) return -1; strcpy(*pos,scratch); *pos += len; *end = *pos; return 0; } static int dump(char **pos,char **end,int *length,const unsigned char *start, int size) { int i; if (!size) return -1; put(pos,end,length,"0x"); for (i = 0; i < size; i++) if (put(pos,end,length,"%02X",start[i]) < 0) return -1; return 0; } static void maybe(char **pos,char **end,int *length,const char *str) { int len; if (!*end) return; len = strlen(str)+*end-*pos; if (len >= *length) { /* okay, but fail on the next PUT */ *end = NULL; return; } strcpy(*end,str); *end = *pos+len; } #define PUT(fmt,arg...) if (put(pos,end,length,fmt,##arg) < 0) return -1 #define DUMP(start,size) if (dump(pos,end,length,start,size) < 0) return -1 #define MAYBE(str) maybe(pos,end,length,str) static int bhli2text(char **pos,char **end,int *length, const struct atm_bhli *bhli) { if (!bhli->hl_type) return 0; PUT("bhli:"); switch (bhli->hl_type) { case ATM_HL_ISO: PUT("iso="); DUMP(bhli->hl_info,bhli->hl_length); break; case ATM_HL_USER: PUT("user="); DUMP(bhli->hl_info,bhli->hl_length); break; #if defined(UNI30) || defined(ALLOW_UNI30) case ATM_HL_HLP: if (bhli->hl_length != 4) return -1; PUT("hlp="); DUMP(bhli->hl_info,bhli->hl_length); break; #endif case ATM_HL_VENDOR: if (bhli->hl_length != 7) return -1; PUT("oui="); DUMP(bhli->hl_info,3); PUT(",id="); DUMP(bhli->hl_info+3,4); break; default: return -1; } MAYBE(","); return 0; } static int l2_proto2text(char **pos,char **end,int *length, const struct atm_blli *blli) { if (!blli->l2_proto) return 0; PUT("l2="); switch (blli->l2_proto) { #define X(u,l) case ATM_L2_##u: PUT(#l); MAYBE(","); return 0 X(ISO1745,iso1745); X(Q291,q291); X(LAPB,lapb); X(ISO8802,iso8802); X(X75,x75); #undef X #define X(u,l) case ATM_L2_##u: PUT(#l); break X(X25_LL,x25_ll); X(X25_ML,x25_ml); X(HDLC_ARM,hdlc_arm); X(HDLC_NRM,hdlc_nrm); X(HDLC_ABM,hdlc_abm); X(Q922,q992); X(ISO7776,iso7776); #undef X case ATM_L2_USER: PUT("user,info=%d",blli->l2.user); MAYBE(","); return 0; default: return -1; } MAYBE(","); if (blli->l2.itu.mode) { PUT("mode="); switch (blli->l2.itu.mode) { case ATM_IMD_NORMAL: PUT("norm"); break; case ATM_IMD_EXTENDED: PUT("ext"); break; default: return -1; } MAYBE(","); } if (blli->l2.itu.window) { PUT("window=%d",blli->l2.itu.window); MAYBE(","); } return 0; } static int mpx_cap(char **pos,char **end,int *length,const char *label, int cap) { if (!cap) return 0; PUT("%s=",label); switch (cap) { case ATM_MC_TS: PUT("ts"); break; case ATM_MC_TS_FEC: PUT("ts_fec"); break; case ATM_MC_PS: PUT("ps"); break; case ATM_MC_PS_FEC: PUT("ps_fec"); break; case ATM_MC_H221: PUT("h221"); break; default: return -1; } MAYBE(","); return 0; } static int l3_proto2text(char **pos,char **end,int *length, const struct atm_blli *blli) { if (!blli->l3_proto) return 0; PUT("l3="); switch (blli->l3_proto) { #define X(u,l) case ATM_L3_##u: PUT(#l); break X(X25,x25); X(ISO8208,iso8208); X(X223,x223); #undef X case ATM_L3_TR9577: PUT("tr9577,ipi="); if (blli->l3.tr9577.ipi != NLPID_IEEE802_1_SNAP) { PUT("0x%x",blli->l3.tr9577.ipi); } else { PUT("snap,oui="); DUMP(blli->l3.tr9577.snap,3); PUT(",pid="); DUMP(blli->l3.tr9577.snap+3,2); } MAYBE(","); return 0; case ATM_L3_USER: PUT("user,info=%d",blli->l3.user); MAYBE(","); return 0; #define X(u,l) case ATM_L3_##u: PUT(#l); MAYBE(","); return 0 X(ISO8473,iso8473); X(T70,t70); X(H321,h321); #undef X case ATM_L3_H310: PUT("h310"); MAYBE(","); switch (blli->l3.h310.term_type) { case ATM_TT_NONE: return 0; case ATM_TT_RX: PUT("term=rx"); break; case ATM_TT_TX: PUT("term=tx"); break; case ATM_TT_RXTX: PUT("term=rxtx"); break; default: return -1; } MAYBE(","); mpx_cap(pos,end,length,"fw_mpx",blli->l3.h310.fw_mpx_cap); mpx_cap(pos,end,length,"bw_mpx",blli->l3.h310.bw_mpx_cap); return 0; default: return -1; } MAYBE(","); if (blli->l3.itu.mode) { PUT("mode="); switch (blli->l3.itu.mode) { case ATM_IMD_NORMAL: PUT("norm"); break; case ATM_IMD_EXTENDED: PUT("ext"); break; default: return -1; } MAYBE(","); } if (blli->l3.itu.def_size) { PUT("size=%d",blli->l3.itu.def_size); MAYBE(","); } if (blli->l3.itu.window) { PUT("window=%d",blli->l3.itu.window); MAYBE(","); } return 0; } static int blli2text(char **pos,char **end,int *length, const struct atm_blli *blli) { MAYBE("blli:"); if (l2_proto2text(pos,end,length,blli)) return -1; return l3_proto2text(pos,end,length,blli); } int sap2text(char *buffer,int length,const struct atm_sap *sap,int flags) { char *pos,*end; int i; pos = end = buffer; if (bhli2text(&pos,&end,&length,&sap->bhli) < 0) return -1; for (i = 0; i < ATM_MAX_BLLI; i++) { if (!blli_in_use(sap->blli[i])) break; if (blli2text(&pos,&end,&length,sap->blli+i) < 0) return -1; } *pos = 0; return pos-buffer; } --- NEW FILE: text2atm.c --- /* text2atm.c - Converts textual representation of ATM address to binary encoding */ /* Written 1995-2000 by Werner Almesberger, EPFL-LRC/ICA */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdio.h> #include <ctype.h> #include <string.h> #include <limits.h> #include "atm.h" #include "atmsap.h" #include "atmres.h" static int try_pvc(const char *text,struct sockaddr_atmpvc *addr,int flags) { int part[3]; int i; part[0] = part[1] = part[2] = 0; i = 0; while (1) { if (!*text) return FATAL; /* empty or ends with a dot */ if (i == 3) return TRY_OTHER; /* too long */ if (isdigit(*text)) { if (*text == '0' && isdigit(text[1])) return TRY_OTHER; /* no leading zeroes */ do { if (part[i] > INT_MAX/10) return TRY_OTHER;/* number too big */ part[i] = part[i]*10+*text++-'0'; } while (isdigit(*text)); i++; if (!*text) break; if (*text++ != '.') return TRY_OTHER; /* non-PVC character */ continue; } if (*text == '*') { if (!(flags & T2A_WILDCARD)) return FATAL; /* not allowed */ part[i++] = ATM_ITF_ANY; /* all *_ANY have the same value */ } else { if (*text != '?') return TRY_OTHER; /* invalid character */ if (!(flags & T2A_UNSPEC)) return FATAL; /* not allowed */ part[i++] = ATM_VPI_UNSPEC; /* all *_UNSPEC have the same value */ } if (!*++text) break; if (*text++ != '.') return FATAL; /* dot required */ } if (i < 2) return TRY_OTHER; /* no dots */ if (i == 2) { part[2] = part[1]; part[1] = part[0]; part[0] = 0; /* default interface */ } if (part[0] > SHRT_MAX || part[2] > ATM_MAX_VCI) return TRY_OTHER; /* too big */ if (part[1] > (flags & T2A_NNI ? ATM_MAX_VPI_NNI : ATM_MAX_VPI)) return TRY_OTHER; /* too big */ if (part[0] == ATM_VPI_UNSPEC) return FATAL; /* bad */ addr->sap_family = AF_ATMPVC; addr->sap_addr.itf = part[0]; addr->sap_addr.vpi = part[1]; addr->sap_addr.vci = part[2]; return 0; } static int do_try_nsap(const char *text,struct sockaddr_atmsvc *addr,int flags) { const char *walk; int count,pos,dot; int offset,len; char value; count = dot = 0; for (walk = text; *walk; walk++) if (isdigit(*walk)) { if (count++ == 15) break; dot = 1; } else if (*text != '.') break; else if (!dot) return FATAL; /* two dots in a row */ else dot = 0; if (*walk != ':') { pos = 0; offset = 0; } else { if (!dot || *text == '0') return FATAL; addr->sas_addr.prv[0] = ATM_AFI_E164; addr->sas_addr.prv[1] = 0; memset(addr->sas_addr.prv+1,0,8); for (pos = 18-count-1; *text; text++) { if (*text == '.') continue; if (*text == ':') break; else { if (pos & 1) addr->sas_addr.prv[pos >> 1] |= *text-'0'; else addr->sas_addr.prv[pos >> 1] = (*text-'0') << 4; pos++; } } addr->sas_addr.prv[8] |= 0xf; text++; pos++; offset = 72; } for (dot = 0; *text; text++) if (isxdigit(*text)) { if (pos == ATM_ESA_LEN*2) return TRY_OTHER; /* too long */ value = isdigit(*text) ? *text-'0' : (islower(*text) ? toupper(*text) : *text)-'A'+10; if (pos & 1) addr->sas_addr.prv[pos >> 1] |= value; else addr->sas_addr.prv[pos >> 1] = value << 4; pos++; dot = 1; } else if (*text == '/' && (flags & T2A_WILDCARD)) break; else if (*text != '.') return TRY_OTHER; else { if (!dot) return FATAL; /* two dots in a row */ dot = 0; } if (!dot) return FATAL; if (pos > 1 && !*addr->sas_addr.prv) return TRY_OTHER; /* no leading zeroes */ if (!*text) return pos != ATM_ESA_LEN*2 ? TRY_OTHER : ATM_ESA_LEN*2; /* handle bad length */ len = 0; while (*++text) { if (!isdigit(*text)) return -1; /* non-digit in length */ if (len >= pos*4) return -1; /* too long */ len = len*10+*text-'0'; } if (len > 7 && addr->sas_addr.prv[0] != ATM_AFI_E164) offset = 72; if (len < offset) return FATAL; return len > pos*4 ? TRY_OTHER : len; } static int try_nsap(const char *text,struct sockaddr_atmsvc *addr,int flags) { int result; result = do_try_nsap(text,addr,flags); if (result < 0) return result; addr->sas_family = AF_ATMSVC; *addr->sas_addr.pub = 0; return result; } static int try_e164(const char *text,struct sockaddr_atmsvc *addr,int flags) { int i,dot,result; if (*text == ':' || *text == '+') text++; for (i = dot = 0; *text; text++) if (isdigit(*text)) { if (i == ATM_E164_LEN) return TRY_OTHER; /* too long */ addr->sas_addr.pub[i++] = *text; dot = 1; } else if (*text != '.') break; else { if (!dot) return TRY_OTHER; /* two dots in a row */ dot = 0; } if (!dot) return TRY_OTHER; addr->sas_addr.pub[i] = 0; *addr->sas_addr.prv = 0; result = 0; if (*text) { if (*text++ != '+') return TRY_OTHER; else { result = do_try_nsap(text,addr,flags); if (result < 0) return FATAL; } } addr->sas_family = AF_ATMSVC; return result; } static int search(FILE *file,const char *text,struct sockaddr *addr,int length, int flags) { char line[MAX_ATM_NAME_LEN+1]; const char *here; int result; while (fgets(line,MAX_ATM_NAME_LEN,file)) { if (!strtok(line,"\t\n ")) continue; while ((here = strtok(NULL,"\t\n "))) if (!strcasecmp(here,text)) { here = strtok(line,"\t\n "); result = text2atm(here,addr,length,flags); if (result >= 0) return result; } } return TRY_OTHER; } static int try_name(const char *text,struct sockaddr *addr,int length, int flags) { FILE *file; int result; if (!(file = fopen(HOSTS_ATM,"r"))) return TRY_OTHER; result = search(file,text,addr,length,flags); (void) fclose(file); return result; } int text2atm(const char *text,struct sockaddr *addr,int length,int flags) { int result; if (!*text) return -1; if (!(flags & (T2A_PVC | T2A_SVC))) flags |= T2A_PVC | T2A_SVC; if (length < sizeof(struct sockaddr_atmpvc)) return -1; if (flags & T2A_PVC) { result = try_pvc(text,(struct sockaddr_atmpvc *) addr,flags); if (result != TRY_OTHER) return result; } if ((flags & T2A_SVC) && length >= sizeof(struct sockaddr_atmsvc)) { result = try_nsap(text,(struct sockaddr_atmsvc *) addr,flags); if (result != TRY_OTHER) return result; result = try_e164(text,(struct sockaddr_atmsvc *) addr,flags); if (result != TRY_OTHER) return result; } if (!(flags & T2A_NAME)) return -1; result = try_name(text,addr,length,flags & ~T2A_NAME); if (result == TRY_OTHER && !(flags & T2A_LOCAL)) result = ans_byname(text,(struct sockaddr_atmsvc *) addr,length,flags); if (result != TRY_OTHER) return result; return -1; } --- NEW FILE: timer.c --- /* timer.c - Timer support */ /* Written 1995-1997 by Werner Almesberger, EPFL-LRC */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdlib.h> #include <stdio.h> #include <string.h> #include <assert.h> #include "atmd.h" static TIMER *timers = NULL; static void dump_list(const char *label) { #ifdef DEBUG_TIMERS TIMER *walk; if (!debug) return; fprintf(stderr,"Timer list %s\n",label); for (walk = timers; walk; walk = walk->next) fprintf(stderr," 0x%p: Timer @0x%p, %ld.%06d (-> 0x%p)\n", walk,walk->callback,(unsigned long) walk->expiration.tv_sec, (int) walk->expiration.tv_usec,walk->next); #endif } TIMER *start_timer(long usec,void (*callback)(void *user),void *user) { TIMER *n,*walk,*last; n = alloc_t(TIMER); n->expiration.tv_usec = now.tv_usec+usec; n->expiration.tv_sec = now.tv_sec; n->callback = callback; n->user = user; while (n->expiration.tv_usec > 1000000) { n->expiration.tv_usec -= 1000000; n->expiration.tv_sec++; } last = NULL; for (walk = timers; walk; walk = walk->next) if (walk->expiration.tv_sec > n->expiration.tv_sec || (walk->expiration.tv_sec == n->expiration.tv_sec && walk->expiration.tv_usec > n->expiration.tv_usec)) break; else last = walk; if (walk) Q_INSERT_BEFORE(timers,n,walk); else Q_INSERT_AFTER(timers,n,last); dump_list("START_TIMER"); return n; } void stop_timer(TIMER *timer) { Q_REMOVE(timers,timer); free(timer); } void (*timer_handler(TIMER *timer))(void *user) { return timer ? timer->callback : NULL; } struct timeval *next_timer(void) { static struct timeval delta; if (!timers) return NULL; delta.tv_sec = timers->expiration.tv_sec-now.tv_sec; delta.tv_usec = timers->expiration.tv_usec-now.tv_usec; while (delta.tv_usec < 0) { delta.tv_usec += 1000000; delta.tv_sec--; } if (delta.tv_sec < 0) delta.tv_sec = delta.tv_usec = 0; return δ } void pop_timer(TIMER *timer) { dump_list("POP_TIMER"); Q_REMOVE(timers,timer); timer->callback(timer->user); free(timer); } void expire_timers(void) { while (timers && (timers->expiration.tv_sec < now.tv_sec || (timers->expiration.tv_sec == now.tv_sec && timers->expiration.tv_usec < now.tv_usec))) pop_timer(timers); } --- NEW FILE: text2qos.c --- /* text2qos.c - Converts textual representation of QOS parameters to binary encoding */ /* Written 1996-2000 by Werner Almesberger, EPFL-LRC/ICA */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdlib.h> #include <stdarg.h> #include <string.h> #include <ctype.h> #include <limits.h> #include "atm.h" #define fetch __atmlib_fetch #define RATE_ERROR -2 int __t2q_get_rate(const char **text,int up) { const char mult[] = "kKmMgGg"; const char *multiplier; char *end; unsigned int rate,fract; int power; if (!strncmp(*text,"max",3)) { *text += 3; return ATM_MAX_PCR; } rate = strtoul(*text,&end,10); power = fract = 0; if (*end == '.') for (end++; *end && isdigit(*end); end++) { fract = fract*10+*end-48; if (--power == -9) break; } multiplier = NULL; if (*end && (multiplier = strchr(mult,*end))) { while (multiplier >= mult) { if (rate > UINT_MAX/1000) return RATE_ERROR; rate *= 1000; power += 3; multiplier -= 2; } end++; } while (power && fract) if (power < 0) { fract /= 10; power++; } else { fract *= 10; power--; } rate += fract; if (strlen(end) < 3) { if (multiplier) return RATE_ERROR; } else if (!strncmp(end,"cps",3)) end += 3; else if (!strncmp(end,"bps",3)) { rate = (rate+(up ? 8*ATM_CELL_PAYLOAD-1 : 0))/8/ ATM_CELL_PAYLOAD; end += 3; } else if (multiplier) return RATE_ERROR; if (rate > INT_MAX) return RATE_ERROR; *text = end; return rate; } static int params(const char **text,struct atm_trafprm *a, struct atm_trafprm *b) { int value; char *end; if (*(*text)++ != ':') return -1; while (1) { if (!**text) return -1; switch (fetch(text,"max_pcr=","pcr=","min_pcr=","max_sdu=","sdu=", NULL)) { case 0: if ((value = __t2q_get_rate(text,0)) == RATE_ERROR) return -1; if (a) a->max_pcr = value; if (b) b->max_pcr = value; break; case 1: if ((value = __t2q_get_rate(text,0)) == RATE_ERROR) return -1; if (a) a->pcr = value; if (b) b->pcr = value; break; case 2: if ((value = __t2q_get_rate(text,1)) == RATE_ERROR) return -1; if (value == ATM_MAX_PCR) return -1; if (a) a->min_pcr = value; if (b) b->min_pcr = value; break; case 3: case 4: value = strtol(*text,&end,10); if (value < 0) return -1; *text = end; if (a) a->max_sdu = value; if (b) b->max_sdu = value; break; default: return 0; } if (!**text) break; if (*(*text)++ != ',') return -1; } return 0; } int text2qos(const char *text,struct atm_qos *qos,int flags) { int traffic_class,aal; traffic_class = ATM_NONE; aal = ATM_NO_AAL; do { static const unsigned char aal_number[] = { ATM_AAL0, ATM_AAL5 }; int item; item = fetch(&text,"!none","ubr","cbr","vbr","abr","aal0","aal5",NULL); switch (item) { case 1: case 2: /* we don't support VBR yet */ case 4: traffic_class = item; break; case 5: case 6: aal = aal_number[item-5]; break; default: return -1; } } while (*text == ',' ? text++ : 0); if (!traffic_class) return -1; if (qos && !(flags & T2Q_DEFAULTS)) memset(qos,0,sizeof(*qos)); if (qos) qos->txtp.traffic_class = qos->rxtp.traffic_class = traffic_class; if (qos && aal) qos->aal = aal; if (!*text) return 0; if (params(&text,qos ? &qos->txtp : NULL,qos ? &qos->rxtp : NULL)) return -1; if (!*text) return 0; switch (fetch(&text,"tx","rx",NULL)) { case 0: if (!fetch(&text,":none",NULL)) { if (qos) qos->txtp.traffic_class = ATM_NONE; if (*text == ',') text++; break; } if (params(&text,qos ? &qos->txtp : NULL,NULL)) return -1; break; case 1: text -= 2; break; default: return -1; } if (!*text) return 0; if (fetch(&text,"rx",NULL)) return -1; if (!fetch(&text,":none",NULL) && qos) qos->rxtp.traffic_class = ATM_NONE; else if (params(&text,qos ? &qos->rxtp : NULL,NULL)) return -1; return *text ? -1 : 0; } --- NEW FILE: text2sap.c --- /* text2sap.c - Converts textual representation of a SAP (Service Access Point; BHLI and BLLI) to binary encoding */ /* Written 1997 by Werner Almesberger, EPFL-ICA */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdlib.h> #include <stdio.h> #include <stdarg.h> #include <string.h> #include <atmsap.h> #include <linux/atmsap.h> #include "atm.h" #define fetch __atmlib_fetch static int bytes(const char **text,unsigned char *buf,int *len,int min,int max) { int num,value; num = 0; if (**text == '0' && ((*text)[1] == 'x' || (*text)[1] == 'X')) *text += 2; while (sscanf(*text,"%2x",&value) == 1) { if (++num > max) return -1; *buf++ = value; *text += 2; } if (num < min) return -1; if (len) *len = num; return 0; } static int text2bhli(const char **text,struct atm_bhli *bhli) { int len; switch (fetch(text,"iso=","user=","hlp=","oui=",NULL)) { case 0: bhli->hl_type = ATM_HL_ISO; if (bytes(text,bhli->hl_info,&len,1,8) < 0) return -1; bhli->hl_length = len; break; case 1: bhli->hl_type = ATM_HL_USER; if (bytes(text,bhli->hl_info,&len,1,8) < 0) return -1; bhli->hl_length = len; break; #if defined(UNI30) || defined(ALLOW_UNI30) case 2: bhli->hl_type = ATM_HL_HLP; if (bytes(text,bhli->hl_info,NULL,4,4) < 0) return -1; bhli->hl_length = 4; break; #endif case 3: bhli->hl_type = ATM_HL_VENDOR; if (bytes(text,bhli->hl_info,NULL,3,3) < 0) return -1; if (fetch(text,",id=",NULL) < 0) return -1; if (bytes(text,bhli->hl_info+3,NULL,4,4) < 0) return -1; bhli->hl_length = 7; break; default: return -1; } return 0; } static int get_int(const char **text,int *value,int min,int max) { char *end; *value = strtoul(*text,&end,0); if (end == *text) return -1; if (*value < min || *value > max) return -1; *text = end; return 0; } static int text2l2_proto(const char **text,struct atm_blli *blli) { static int map[] = { /* No parameters */ ATM_L2_ISO1745, ATM_L2_Q291,ATM_L2_LAPB,ATM_L2_ISO8802,ATM_L2_X75, /* With ITU parameters */ ATM_L2_X25_LL, ATM_L2_X25_ML, ATM_L2_HDLC_ARM, ATM_L2_HDLC_NRM, ATM_L2_HDLC_ABM, ATM_L2_Q922, ATM_L2_ISO7776, /* Other parameter sets */ ATM_L2_USER }; int item,value; item = fetch(text,"iso1745","q291","lapb","iso8802","x75","x25_ll", "x25_ml","hdlc_arm","hdlc_nrm","hdlc_abm","q992","iso7776","user,info=", NULL); if (item < 0) return -1; blli->l2_proto = map[item]; if (blli->l2_proto < ATM_L2_X25_LL) return 0; if (blli->l2_proto == ATM_L2_USER) { if (get_int(text,&value,0,255) < 0) return -1; blli->l2.user = value; return 0; } if (!fetch(text,",mode=",NULL)) { switch (fetch(text,"norm","ext",NULL)) { case 0: blli->l2.itu.mode = ATM_IMD_NORMAL; break; case 1: blli->l2.itu.mode = ATM_IMD_EXTENDED; break; default: return -1; } } if (!fetch(text,",window=",NULL)) { if (get_int(text,&value,1,127) < 0) return -1; blli->l2.itu.window = value; } return 0; } static int text2l3_proto(const char **text,struct atm_blli *blli) { static int map[] = { /* No parameters */ ATM_L3_ISO8473,ATM_L3_T70,ATM_L3_H321, /* With ITU parameters */ ATM_L3_X25,ATM_L3_ISO8208,ATM_L3_X223, /* Other parameter sets */ ATM_L3_TR9577,ATM_L3_USER,ATM_L3_H310 }; int item,value; item = fetch(text,"iso8473","t70","h321","x25","iso8208","x223", "tr9577,ipi=","user,info=","h310",NULL); if (item < 0) return -1; blli->l3_proto = map[item]; if (blli->l3_proto < ATM_L3_X25) return 0; if (blli->l3_proto == ATM_L3_TR9577) { if (!fetch(text,"snap",NULL)) value = NLPID_IEEE802_1_SNAP; else if (get_int(text,&value,0,255) < 0) return -1; blli->l3.tr9577.ipi = value; if (value != NLPID_IEEE802_1_SNAP) return 0; if (fetch(text,",oui=",NULL) < 0) return -1; if (bytes(text,blli->l3.tr9577.snap,NULL,3,3) < 0) return -1; if (fetch(text,",pid=",NULL) < 0) return -1; if (bytes(text,blli->l3.tr9577.snap+3,NULL,2,2) < 0) return -1; return 0; } if (blli->l3_proto == ATM_L3_USER) { if (get_int(text,&value,0,255) < 0) return -1; blli->l3.user = value; return 0; } if (blli->l3_proto == ATM_L3_H310) { if (fetch(text,",term=",NULL)) return 0; item = fetch(text,"!none","rx","tx","rxtx",NULL); if (item == -1) return -1; blli->l3.h310.term_type = item; if (!fetch(text,",fw_mpx=",NULL)) { item = fetch(text,"!none","ts","ts_fec","ps","ps_fec","h221",NULL); if (item == -1) return -1; blli->l3.h310.fw_mpx_cap = item; } if (!fetch(text,",bw_mpx=",NULL)) { item = fetch(text,"!none","ts","ts_fec","ps","ps_fec","h221",NULL); if (item == -1) return -1; blli->l3.h310.bw_mpx_cap = item; } return 0; } if (!fetch(text,",mode=",NULL)) { switch (fetch(text,"norm","ext",NULL)) { case 0: blli->l3.itu.mode = ATM_IMD_NORMAL; break; case 1: blli->l3.itu.mode = ATM_IMD_EXTENDED; break; default: return -1; } } if (!fetch(text,",size=",NULL)) { if (get_int(text,&value,4,12) < 0) return -1; blli->l3.itu.def_size = value; } if (!fetch(text,",window=",NULL)) { if (get_int(text,&value,1,127) < 0) return -1; blli->l3.itu.window = value; } return 0; } static int text2blli(const char **text,struct atm_blli *blli) { switch (fetch(text,"l2=","l3=",NULL)) { case 0: if (text2l2_proto(text,blli) < 0) return -1; break; case 1: return text2l3_proto(text,blli); default: return -1; } if (!**text) return 0; if (fetch(text,",l3=",NULL) < 0) return 0; return text2l3_proto(text,blli); } int text2sap(const char *text,struct atm_sap *sap,int flags) { int bllis; memset(sap,0,sizeof(*sap)); if (!*text) return 0; switch (fetch(&text,"bhli:","blli:",NULL)) { case 0: if (text2bhli(&text,&sap->bhli) < 0) return -1; bllis = 0; break; case 1: if (text2blli(&text,sap->blli) < 0) return -1; bllis = 1; break; default: return -1; } while (1) { if (!*text) return 0; if (fetch(&text,",blli:",NULL) < 0) return -1; if (bllis == ATM_MAX_BLLI) return 0; /* ignore extra BLLIs */ if (text2blli(&text,sap->blli+bllis) < 0) return -1; bllis++; } } --- NEW FILE: diag.c --- /* diag.c - Diagnostic messages */ /* Written 1995-1999 by Werner Almesberger, EPFL-LRC/ICA */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdlib.h> #include <stdarg.h> #include <stdio.h> #include <string.h> #include <syslog.h> #include "atmd.h" #define MAX_DIAG_MSG 8200 #define DUMP_LINE_WIDTH 75 typedef struct _component { const char *name; int verbosity; struct _component *next; } COMPONENT; static int sev2prio[] = { DIAG_DEBUG,LOG_DEBUG, DIAG_INFO,LOG_INFO, DIAG_WARN,LOG_WARNING, DIAG_ERROR,LOG_ERR, DIAG_FATAL,LOG_ALERT, -1,LOG_NOTICE }; static const char *app_name = NULL; static COMPONENT *components = NULL; static int default_verbosity = DIAG_INFO; static FILE *log_to = NULL; static int log_to_initialized = 0; void set_application(const char *name) { app_name = name; } void set_verbosity(const char *component,int level) { COMPONENT *walk; if (!component) { default_verbosity = level; return; } for (walk = components; walk; walk = walk->next) if (!strcmp(walk->name,component)) break; if (!walk) { walk = alloc_t(COMPONENT); walk->name = component; walk->next = components; components = walk; } walk->verbosity = level; } int get_verbosity(const char *component) { COMPONENT *walk; if (!component) { return default_verbosity; } for (walk = components; walk; walk = walk->next) if (!strcmp(walk->name,component)) break; return walk ? walk->verbosity : default_verbosity; } void set_logfile(const char *name) { log_to_initialized = 1; if (log_to && log_to != stderr) { (void) fclose(log_to); log_to = stderr; } if (!name || !strcmp(name,"stderr")) { log_to = stderr; return; } if (!strcmp(name,"syslog")) { if (app_name) openlog(app_name,LOG_CONS,LOG_DAEMON); log_to = NULL; } else if (!(log_to = fopen(name,"w"))) { perror(name); log_to = stderr; } } FILE *get_logfile(void) { if (!log_to_initialized) { log_to = stderr; log_to_initialized = 1; } return log_to; } void diag_fatal_debug_hook(void); /* GCC insists on a prototype */ void diag_fatal_debug_hook(void) { /* * Set a breakpoint here to catch fatal errors before they mess up the * stack. */ } void vdiag(const char *component,int severity,const char *fmt,va_list ap) { COMPONENT *walk; FILE *to; char buffer[MAX_DIAG_MSG+1]; int i; for (walk = components; walk; walk = walk->next) if (!strcmp(walk->name,component)) break; if (severity > (walk ? walk->verbosity : default_verbosity)) return; fflush(stdout); to = get_logfile(); if (!to) { for (i = 0; sev2prio[i] == severity || sev2prio[i] == -1; i += 2); vsprintf(buffer,fmt,ap); syslog(sev2prio[i+1],"%s: %s",component,buffer); } else { if (app_name) fprintf(to,"%s:%s: ",app_name,component); else fprintf(to,"%s: ",component); vfprintf(to,fmt,ap); fputc('\n',to); fflush(to); } if (severity == DIAG_FATAL) { diag_fatal_debug_hook(); fprintf(stderr,"Fatal error - Terminating\n"); exit(1); } } void diag(const char *component,int severity,const char *fmt,...) { va_list ap; va_start(ap,fmt); vdiag(component,severity,fmt,ap); va_end(ap); } void diag_dump(const char *component,int severity,const char *title, const unsigned char *data,int len) { char buffer[DUMP_LINE_WIDTH+1]; char *curr; int data_line,left; if (title) diag(component,severity,"%s (%d bytes)\n",title,len); data_line = DUMP_LINE_WIDTH-(app_name ? strlen(app_name)+1 : 0)- strlen(component)-3; while (len) { left = data_line; curr = buffer; while (len && left >= 3) { sprintf(curr," %02x",*data++); len--; curr += 3; left -= 3; } diag(component,severity,"%s ",buffer); } } --- NEW FILE: common.c --- /* common.c - Common functions */ /* Written 1995-1999 by Werner Almesberger, EPFL-LRC */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdlib.h> #include <stdint.h> #include <sys/types.h> #include "atmd.h" void *alloc(size_t size) { void *n; n = malloc(size); if (n) return n; perror("malloc"); exit(1); } uint32_t read_netl(void *p) { unsigned char *_p = p; return (_p[0] << 24) | (_p[1] << 16) | (_p[2] << 8) | _p[3]; } --- NEW FILE: Makefile.am --- lib_LTLIBRARIES = libatm.la libatmd.la LDFLAGS = -version-info @ATMLIBS_VERSION@ libatm_la_SOURCES = text2atm.c atm2text.c atmequal.c sdu2cell.c text2qos.c \ qos2text.c qosequal.c sap2text.c text2sap.c sapequal.c \ misc.c atmres.h ans.c libatm_la_LIBADD = -lresolv libatm_la_DEPENDENCIES = $(top_builddir)/src/include/atm.h \ $(top_builddir)/src/include/atmsap.h \ $(top_builddir)/src/include/stdint.h libatmd_la_SOURCES = common.c diag.c kptr.c text2ip.c timer.c unix.c libatmd_la_DEPENDENCIES = $(top_builddir)/src/include/atm.h \ $(top_builddir)/src/include/atmd.h \ $(top_builddir)/src/include/stdint.h EXTRA_DIST = rtf2e164_cc.pl --- NEW FILE: kptr.c --- /* kptr.c - Helper functions to use kernel pointer handles */ /* Written 2000 by Werner Almesberger, EPFL ICA */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdlib.h> #include <assert.h> #include <atm.h> #include "atmd.h" int kptr_eq(const atm_kptr_t *a,const atm_kptr_t *b) { unsigned long *_a = (unsigned long *) a,*_b = (unsigned long *) b; assert(sizeof(atm_kptr_t) == 8); switch (sizeof(unsigned long)) { case 2: /* Wow, ATM on ELKS ? :-) */ if (_a[2] != _b[2]) return 0; if (_a[3] != _b[3]) return 0; case 4: if (_a[1] != _b[1]) return 0; case 8: return *_a == *_b; default: abort(); } } const char *kptr_print(const atm_kptr_t *p) { static char buf[KPRT_PRINT_BUFS][sizeof(atm_kptr_t)*2+1]; static int curr_buf = 0; char *result; int i; result = buf[curr_buf]; curr_buf = (curr_buf+1) & (KPRT_PRINT_BUFS-1); for (i = 0; i < sizeof(atm_kptr_t); i++) sprintf(result+2*i,"%02x",((unsigned char *) p)[i]); return result; } --- NEW FILE: misc.c --- /* misc.c - Miscellaneous library functions */ /* Written 1997-2000 by Werner Almesberger, EPFL-ICA/ICA */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdint.h> #include <stdarg.h> #include <string.h> #include <sys/socket.h> #include <sys/ioctl.h> #include <netinet/in.h> /* for htons */ #include <atm.h> #include <atmsap.h> int __atmlib_fetch(const char **pos,...) { const char *value; int ref_len,best_len,len; int i,best; va_list ap; va_start(ap,pos); ref_len = strlen(*pos); best_len = 0; best = -1; for (i = 0; (value = va_arg(ap,const char *)); i++) { len = strlen(value); if (*value != '!' && len <= ref_len && len > best_len && !strncasecmp(*pos,value,len)) { best = i; best_len = len; } } va_end(ap); if (best > -1) (*pos) += best_len; return best; } void atm_tcpip_port_mapping(char *vs_id,uint8_t protocol,uint16_t port) { memcpy(vs_id,ATM_FORUM_OUI "\x01",4); vs_id[4] = protocol; /* e.g. IP_TCP or IP_UDP; from netinet/protocols.h */ vs_id[5] = (htons(port) >> 8) & 255; vs_id[6] = htons(port) & 255; } --- NEW FILE: text2ip.c --- /* text2ip.c - Converts a text string to an IP address. */ /* Written 1998 by Werner Almesberger, EPFL ICA */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdint.h> #include <stdio.h> #include <string.h> #include <netdb.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include "atm.h" #include "atmd.h" static void complain(const char *component,const char *item,const char *msg) { if (!component) fprintf(stderr,"%s: %s\n",item,msg); else diag(component,DIAG_ERROR,"%s: %s",item,msg); } uint32_t text2ip(const char *text,const char *component,int flags) { struct hostent *hostent; uint32_t ip; if (strspn(text,"0123456789.") == strlen(text)) { ip = inet_addr(text); if (ip != INADDR_NONE) return ip; if (flags & T2I_ERROR) complain(component,text,"invalid address"); return INADDR_NONE; } if (!(flags & T2I_NAME)) { if (flags & T2I_ERROR) complain(component,text,"numeric IP address expected"); return INADDR_NONE; } hostent = gethostbyname(text); if (!hostent) { if (flags & T2I_ERROR) complain(component,text,"no such host"); return INADDR_NONE; } if (hostent->h_addrtype != AF_INET) { if (flags & T2I_ERROR) complain(component,text,"unknown address family"); return INADDR_NONE; } memcpy(&ip,hostent->h_addr,hostent->h_length); return ip; } --- NEW FILE: qos2text.c --- /* qos2text.c - Converts binary encoding of QOS parameters to textual representation */ /* Written 1996-2000 by Werner Almesberger, EPFL-LRC */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdio.h> #include <string.h> #include "atm.h" #define FLD(F) \ if (curr->F && ((ref && (ref->F != curr->F || ref->traffic_class == \ ATM_NONE)) || (comp && comp->F == curr->F && comp->traffic_class != \ ATM_NONE))) { \ if (buffer != *pos && !strchr(":,",(*pos)[-1])) *(*pos)++ = ','; \ if (curr->F != ATM_MAX_PCR) *pos += sprintf(*pos,#F "=%d",curr->F); \ else { \ strcat(*pos,#F "=max"); \ *pos += strlen(#F)+4; \ } \ } static void params(char *buffer,char **pos,const struct atm_trafprm *ref, const struct atm_trafprm *curr,const struct atm_trafprm *comp) { FLD(max_pcr); FLD(pcr); FLD(min_pcr); FLD(max_sdu); } static void opt(const char *prefix,char *buffer,char **pos, const struct atm_trafprm *ref,const struct atm_trafprm *curr, const struct atm_trafprm *comp) { char *start; if (curr->traffic_class == ATM_NONE) { if (!comp) *pos += sprintf(*pos,"%snone",prefix); return; } start = *pos; params(buffer,pos,ref,curr,comp); if (start == *pos) return; *pos = start; strcpy(*pos,prefix); *pos += strlen(prefix); params(buffer,pos,ref,curr,comp); } int qos2text(char *buffer,int length,const struct atm_qos *qos,int flags) { char *pos,*start; if (length <= MAX_ATM_QOS_LEN) return -1; *(pos = buffer) = 0; switch (qos->txtp.traffic_class == ATM_NONE ? qos->rxtp.traffic_class : qos->txtp.traffic_class) { case ATM_UBR: strcpy(buffer,"ubr"); pos += 3; break; case ATM_CBR: strcpy(buffer,"cbr"); pos += 3; break; case ATM_ABR: strcpy(buffer,"abr"); pos += 3; break; default: return -1; } if (qos->aal != ATM_NO_AAL) { strcpy(pos,","); pos++; } switch (qos->aal) { case ATM_NO_AAL: break; case ATM_AAL0: strcpy(pos,"aal0"); pos += 4; break; case ATM_AAL5: strcpy(pos,"aal5"); pos += 4; break; default: return -1; } pos++; start = pos; if (qos->txtp.traffic_class != ATM_NONE && qos->rxtp.traffic_class != ATM_NONE) params(buffer,&pos,NULL,&qos->txtp,&qos->rxtp); opt(start == pos ? "tx:" : ",tx:",buffer,&pos,&qos->rxtp,&qos->txtp,NULL); opt(start == pos ? "rx:" : ",rx:",buffer,&pos,&qos->txtp,&qos->rxtp,NULL); if (pos != start) start[-1] = ':'; return 0; } --- NEW FILE: unix.c --- /* unix.c - Unix domain socket communication */ /* Written 1998 by Werner Almesberger, EPFL ICA */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <errno.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/socket.h> #include <sys/un.h> #include "atmd.h" static int mkaddr(const char *path,struct sockaddr_un *addr) { addr->sun_family = AF_UNIX; strcpy(addr->sun_path,path); return (char *) &addr->sun_path[strlen(path)]-(char *) addr; } int un_create(const char *path,mode_t mode) { struct sockaddr_un addr; mode_t old_umask; int size; int s; s = socket(PF_UNIX,SOCK_DGRAM,0); if (s < 0) return s; (void) unlink(path); size = mkaddr(path,&addr); old_umask = umask(~mode); if (bind(s,(struct sockaddr *) &addr,size) < 0) return -1; (void) umask(old_umask); return s; } int un_attach(const char *path) { struct sockaddr_un addr; int size; int s; s = socket(PF_UNIX,SOCK_DGRAM,0); if (s < 0) return s; size = mkaddr("",&addr); if (bind(s,(struct sockaddr *) &addr,size) < 0) return -1; size = mkaddr(path,&addr); if (connect(s,(struct sockaddr *) &addr,size) < 0) return -1; return s; } int un_recv_connect(int s,void *buf,int size) { struct sockaddr_un addr; int addr_size; int len; addr_size = sizeof(addr); len = recvfrom(s,buf,size,0,(struct sockaddr *) &addr,&addr_size); if (len < 0) return len; if (connect(s,(struct sockaddr *) &addr,addr_size) < 0) return -1; return len; } int un_recv(UN_CTX *ctx,int s,void *buf,int size) { ctx->s = s; ctx->size = sizeof(ctx->addr); return recvfrom(s,buf,size,0,(struct sockaddr *) &ctx->addr,&ctx->size); } int un_send(const UN_CTX *ctx,void *buf,int len) { int sent; sent = sendto(ctx->s,buf,len,0,(struct sockaddr *) &ctx->addr,ctx->size); if (sent < 0 || sent == len) return sent; errno = EMSGSIZE; /* ugly */ return -1; } int un_reply(int s,void *buf,int size, int (*handler)(void *buf,int len,void *user),void *user) { UN_CTX ctx; int len; len = un_recv(&ctx,s,buf,size); if (len < 0) return len; len = handler(buf,len,user); if (len <= 0) return len; return un_send(&ctx,buf,len); } --- NEW FILE: sapequal.c --- /* sapequal.c - Compares SAP specifications for compatibility */ /* Written 1998 by Werner Almesberger, EPFL ICA */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdarg.h> #include <string.h> #include "atm.h" #include "atmsap.h" static int bhli_compat(const struct atm_bhli a,const struct atm_bhli b, int flags) { int length; if (!a.hl_type && (flags & SXE_COMPATIBLE)) return 1; if (a.hl_type != b.hl_type) return 0; switch (a.hl_type) { case ATM_HL_ISO: case ATM_HL_USER: length = a.hl_length; if (length != b.hl_length) return 0; break; case ATM_HL_HLP: length = 4; break; case ATM_HL_VENDOR: length = 7; break; default: length = 0; } return !length || !memcmp(a.hl_info,b.hl_info,length); } #define CHECK(FIELD,CONSTRAINT) \ if (res && !res->FIELD) res->FIELD = a.FIELD; \ if (a.FIELD && b.FIELD && a.FIELD != b.FIELD) { \ if (!(flags & SXE_NEGOTIATION)) return 0; \ if (!CONSTRAINT) return 0; \ if (res) res->FIELD = a.FIELD < b.FIELD ? a.FIELD : b.FIELD; \ } static int match_blli(const struct atm_blli a,const struct atm_blli b, int flags,struct atm_blli *res) { if (res) *res = b; if (a.l2_proto != b.l2_proto || a.l3_proto != b.l3_proto) return 0; switch (a.l2_proto) { case ATM_L2_X25_LL: case ATM_L2_X25_ML: case ATM_L2_HDLC_ARM: case ATM_L2_HDLC_NRM: case ATM_L2_HDLC_ABM: case ATM_L2_Q922: case ATM_L2_ISO7776: CHECK(l2.itu.mode,1); CHECK(l2.itu.window,a.l2.itu.window > b.l2.itu.window); break; default: } switch (a.l3_proto) { case ATM_L3_X25: case ATM_L3_ISO8208: case ATM_L3_X223: CHECK(l3.itu.mode,1); CHECK(l3.itu.def_size,a.l3.itu.def_size > b.l3.itu.def_size); CHECK(l3.itu.window,a.l3.itu.window > b.l3.itu.window); break; case ATM_L3_TR9577: if (a.l3.tr9577.ipi != b.l3.tr9577.ipi) return 0; if (a.l3.tr9577.ipi == NLPID_IEEE802_1_SNAP) if (memcmp(a.l3.tr9577.snap,b.l3.tr9577.snap,5)) return 0; break; case ATM_L3_USER: if (a.l3.user != b.l3.user) return 0; break; default: } return 1; } #undef CHECK static int blli_compat(const struct atm_blli *a,const struct atm_blli *b, int flags,struct atm_blli *res) { int i,j; if (!(flags & SXE_COMPATIBLE)) { for (i = 0; i < ATM_MAX_BLLI; i++) if (blli_in_use(a[i])) if (!blli_in_use(b[i])) return 0; else { if (!match_blli(a[i],b[i],0,NULL)) return 0; } else if (blli_in_use(b[i])) return 0; else break; if (res) *res = *a; return 1; } if (!blli_in_use(*a)) { if (res) *res = *b; return 1; } for (i = 0; i < ATM_MAX_BLLI && blli_in_use(a[i]); i++) for (j = 0; j < ATM_MAX_BLLI && blli_in_use(b[j]); j++) if (match_blli(a[i],b[j],flags,res)) return 1; return 0; } int sap_equal(const struct atm_sap *a,const struct atm_sap *b,int flags,...) { va_list ap; struct atm_sap *res; va_start(ap,flags); res = flags & SXE_RESULT ? va_arg(ap,struct atm_sap *) : NULL; va_end(ap); if (!bhli_compat(a->bhli,b->bhli,flags)) return 0; if (!blli_compat(a->blli,b->blli,flags,res ? res->blli : NULL)) return 0; if (res) { res->bhli = b->bhli; memset(res->blli+1,0,sizeof(struct atm_blli)*(ATM_MAX_BLLI-1)); } return 1; } --- NEW FILE: atm2text.c --- /* atm2text.c - Converts binary encoding of ATM address to textual representation */ /* Written 1995-1998 by Werner Almesberger, EPFL-LRC/ICA */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdio.h> #include <string.h> #include "atm.h" #include "atmres.h" static int put_item(char **buffer,int *length,int value) { char *walk,*scan; char tmp; if (!*length) return FATAL; if (value <= 0) { if (!value) *(*buffer)++ = '0'; else if (value == ATM_VCI_ANY) *(*buffer)++ = '*'; else if (value == ATM_VCI_UNSPEC) *(*buffer)++ = '?'; else return FATAL; /* ATM_*_ANY and ATM_*_UNSPEC have all the same value, respectively */ (*length)--; return 0; } for (walk = *buffer; value; value /= 10) { if (!(*length)--) return FATAL; *walk++ = '0'+(value % 10); } for (scan = walk-1; scan > *buffer; (*buffer)++) { tmp = *scan; *scan-- = **buffer; **buffer = tmp; } *buffer = walk; return 0; } static int do_pvc(char *buffer,int length,const struct sockaddr_atmpvc *addr, int flags) { int orig_len; orig_len = length; if (put_item(&buffer,&length,addr->sap_addr.itf)) return FATAL; if (!length--) return FATAL; *buffer++ = '.'; if (put_item(&buffer,&length,addr->sap_addr.vpi)) return FATAL; if (!length--) return FATAL; *buffer++ = '.'; if (put_item(&buffer,&length,addr->sap_addr.vci)) return FATAL; if (!length) return FATAL; *buffer = 0; return orig_len-length; } static int do_svc(char *buffer,int length,const struct sockaddr_atmsvc *addr, int flags) { static int pure[] = { 20 }; static int bin[] = { 1,2,10,6,1 }; static int local[] = { 1,12,6,1 }; static int e164[] = { 4,6,1 }; int orig_len,len,i,left,value; int *fmt; orig_len = length; if (!*addr->sas_addr.pub && !*addr->sas_addr.prv) return FATAL; if (*addr->sas_addr.pub) { len = strlen(addr->sas_addr.pub); if (!*addr->sas_addr.prv && length >= len+2) { *buffer++ = '+'; length--; } if (length < len+1) return FATAL; strcpy(buffer,addr->sas_addr.pub); buffer += len; length -= len; if (*addr->sas_addr.prv) { if (!length--) return FATAL; *buffer++ = '+'; } } if (*addr->sas_addr.prv) { fmt = pure; i = 0; if (flags & A2T_PRETTY) switch (*addr->sas_addr.prv) { case ATM_AFI_DCC: case ATM_AFI_ICD: case ATM_AFI_DCC_GROUP: case ATM_AFI_ICD_GROUP: fmt = bin; break; case ATM_AFI_LOCAL: case ATM_AFI_LOCAL_GROUP: fmt = local; break; case ATM_AFI_E164: case ATM_AFI_E164_GROUP: for (i = 2; i < 17; i++) if (addr->sas_addr.prv[i >> 1] & (0xf0 >> 4*(i & 1))) break; while (i < 17) { value = (addr->sas_addr.prv[i >> 1] >> 4*(1-(i & 1))) & 0xf; if (value > 9) return FATAL; if (!length--) return FATAL; *buffer++ = '0'+value; i++; } if (!length--) return FATAL; *buffer++ = ':'; i = 9; fmt = e164; break; default: break; } for (left = *fmt++; i < ATM_ESA_LEN; i++) { if (!left--) { if (!length--) return FATAL; *buffer++ = '.'; left = *fmt++-1; } if (length < 2) return FATAL; sprintf(buffer,"%02X",addr->sas_addr.prv[i]); length -= 2; buffer += 2; } } if (!length) return FATAL; *buffer = 0; return orig_len-length; } static int search(FILE *file,char *buffer,int length, const struct sockaddr *addr,int flags) { struct sockaddr_atmsvc temp; char line[MAX_ATM_NAME_LEN+1]; const char *here; while (fgets(line,MAX_ATM_NAME_LEN,file)) { if (!(here = strtok(line,"\t\n "))) continue; if (text2atm(here,(struct sockaddr *) &temp,sizeof(temp),flags) < 0) continue; if (temp.sas_family != addr->sa_family) continue; if (temp.sas_family == AF_ATMPVC) { if (((const struct sockaddr_atmpvc *) addr)->sap_addr.itf != ((struct sockaddr_atmpvc *) &temp)->sap_addr.itf || ((const struct sockaddr_atmpvc *) addr)->sap_addr.vpi != ((struct sockaddr_atmpvc *) &temp)->sap_addr.vpi || ((const struct sockaddr_atmpvc *) addr)->sap_addr.vci != ((struct sockaddr_atmpvc *) &temp)->sap_addr.vci) continue; } else if (!atm_equal(addr,(struct sockaddr *) &temp,0,0)) continue; while ((here = strtok(NULL,"\t\n "))) if (strlen(here) < length) { strcpy(buffer,here); return 0; } return FATAL; } return TRY_OTHER; } static int try_name(char *buffer,int length,const struct sockaddr *addr) { FILE *file; int result; if (!(file = fopen(HOSTS_ATM,"r"))) return TRY_OTHER; result = search(file,buffer,length,addr,addr->sa_family == AF_ATMPVC ? T2A_PVC : T2A_SVC); (void) fclose(file); return result; } int atm2text(char *buffer,int length,const struct sockaddr *addr,int flags) { int result; if (addr->sa_family != AF_ATMPVC && addr->sa_family != AF_ATMSVC) return -1; if (!length) return -1; if (flags & A2T_NAME) { result = try_name(buffer,length,addr); if (result == TRY_OTHER && !(flags & A2T_LOCAL)) result = ans_byaddr(buffer,length, (const struct sockaddr_atmsvc *) addr,flags); if (result == FATAL) return FATAL; if (result != TRY_OTHER) return strlen(buffer); } if (addr->sa_family == AF_ATMPVC) return do_pvc(buffer,length,(const struct sockaddr_atmpvc *) addr, flags); else return do_svc(buffer,length,(const struct sockaddr_atmsvc *) addr, flags); return -1; } --- NEW FILE: sdu2cell.c --- /* sdu2cr.c... [truncated message content] |