You can subscribe to this list here.
2001 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
(2) |
Sep
(164) |
Oct
(104) |
Nov
|
Dec
|
---|---|---|---|---|---|---|---|---|---|---|---|---|
2003 |
Jan
|
Feb
|
Mar
|
Apr
(3) |
May
(17) |
Jun
|
Jul
(11) |
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
2004 |
Jan
|
Feb
(8) |
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
(4) |
Oct
(1) |
Nov
|
Dec
(6) |
2005 |
Jan
(1) |
Feb
(2) |
Mar
|
Apr
(13) |
May
|
Jun
|
Jul
|
Aug
|
Sep
(7) |
Oct
(2) |
Nov
(6) |
Dec
|
2007 |
Jan
|
Feb
(3) |
Mar
|
Apr
(2) |
May
|
Jun
|
Jul
(6) |
Aug
(36) |
Sep
(3) |
Oct
(1) |
Nov
|
Dec
(23) |
2008 |
Jan
(33) |
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
2009 |
Jan
|
Feb
|
Mar
(13) |
Apr
|
May
|
Jun
|
Jul
|
Aug
(32) |
Sep
|
Oct
|
Nov
(14) |
Dec
|
2010 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
(2) |
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
(13) |
2011 |
Jan
(16) |
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
2013 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
(1) |
Nov
|
Dec
|
From: Paul B. S. <pa...@us...> - 2001-10-03 17:47:34
|
Update of /cvsroot/linux-atm/linux-atm In directory usw-pr-cvs1:/tmp/cvs-serv6071 Modified Files: Tag: V2_4_0 configure.in Log Message: Updated configure.in and src/Makefile.am to include src/extra... Index: configure.in =================================================================== RCS file: /cvsroot/linux-atm/linux-atm/Attic/configure.in,v retrieving revision 1.1.2.1 retrieving revision 1.1.2.2 diff -C2 -d -r1.1.2.1 -r1.1.2.2 *** configure.in 2001/09/03 10:56:35 1.1.2.1 --- configure.in 2001/10/03 17:47:31 1.1.2.2 *************** *** 165,169 **** src/switch/Makefile \ src/switch/debug/Makefile \ ! src/switch/tcp/Makefile ) --- 165,170 ---- src/switch/Makefile \ src/switch/debug/Makefile \ ! src/switch/tcp/Makefile \ ! src/extra/Makefile ) |
From: Paul B. S. <pa...@us...> - 2001-10-03 17:47:34
|
Update of /cvsroot/linux-atm/linux-atm/src In directory usw-pr-cvs1:/tmp/cvs-serv6071/src Modified Files: Tag: V2_4_0 Makefile.am Log Message: Updated configure.in and src/Makefile.am to include src/extra... Index: Makefile.am =================================================================== RCS file: /cvsroot/linux-atm/linux-atm/src/Attic/Makefile.am,v retrieving revision 1.1.2.1 retrieving revision 1.1.2.2 diff -C2 -d -r1.1.2.1 -r1.1.2.2 *** Makefile.am 2001/09/03 11:02:53 1.1.2.1 --- Makefile.am 2001/10/03 17:47:31 1.1.2.2 *************** *** 1,3 **** SUBDIRS = include lib test debug qgen saal sigd maint arpd ilmid man led lane \ ! mpoad switch # extra --- 1,3 ---- SUBDIRS = include lib test debug qgen saal sigd maint arpd ilmid man led lane \ ! mpoad switch extra |
From: Paul B. S. <pa...@us...> - 2001-10-03 17:45:56
|
Update of /cvsroot/linux-atm/linux-atm/src/extra In directory usw-pr-cvs1:/tmp/cvs-serv3891/src/extra Added Files: Tag: V2_4_0 Makefile.am Log Message: Here is the ANS stuff coalesced(sp?) into a single directory now... Updated the bind patch so that it applies against the latest BIND 4... For the record, I have not tested this... I don't know if anybody is even using this... --- NEW FILE: Makefile.am --- EXTRA_DIST = ANS |
From: Paul B. S. <pa...@us...> - 2001-10-03 17:45:56
|
Update of /cvsroot/linux-atm/linux-atm/src/extra/ANS In directory usw-pr-cvs1:/tmp/cvs-serv3891/src/extra/ANS Added Files: Tag: V2_4_0 127.0.0 192.168.27 atm atm-reverse bind-498-REL.patch e164_cc hosts2ans.pl named.conf pdf2e164_cc.pl README README.DNS resolv.conf Log Message: Here is the ANS stuff coalesced(sp?) into a single directory now... Updated the bind patch so that it applies against the latest BIND 4... For the record, I have not tested this... I don't know if anybody is even using this... --- NEW FILE: 127.0.0 --- @ IN SOA ns.atm. hostmaster.atm. ( 1999102501 ; Serial 8H ; Refresh 2H ; Retry 1W ; Expire 1D ) ; Minimum TTL NS ns.atm. 1 PTR localhost. --- NEW FILE: 192.168.27 --- @ IN SOA obelix-atm.atm. hostmaster.obelix-atm.atm. ( 1999102201 ; serial, YYYYMMDDnn 8H ; refresh, seconds 2H ; retry, seconds 1W ; expire, seconds 1D ) ; minimum, seconds NS obelix-atm.atm. ; ; Hosts ; 72 PTR obelix-atm.atm. 96 PTR pong-atm.atm. 81 PTR osteolito-atm.atm. --- NEW FILE: atm --- @ IN SOA obelix-atm.atm. hostmaster.obelix-atm.atm. ( 1999102201 ; serial, YYYYMMDDnn 8H ; refresh, seconds 2H ; retry, seconds 1W ; expire, seconds 1D ) ; minimum, seconds NS obelix-atm MX 10 mail.my.domain. TXT "My organisation's ATM network" localhost A 127.0.0.1 atm. A 192.168.27.72 ; ; Hosts on 192.168.27.0 CLIP network ; obelix-atm A 192.168.27.72 pong-atm A 192.168.27.96 osteolito-atm A 192.168.27.81 ; ; NSAPs - ATM addresses ; obelix-atm IN NSAP 47000580FFE1000000F20F400F0020480E306E00 pong-atm IN NSAP 47000580FFE1000000F21A2F5C0020480E042f00 osteolito-atm IN NSAP 47000580FFE1000000F21A2F5C002048089A9200 --- NEW FILE: atm-reverse --- @ IN SOA obelix-atm.atm. rprior.obelix-atm.atm. ( 1999102201 ; serial, YYYYMMDDnn 8H ; refresh, seconds 2H ; retry, seconds 1W ; expire, seconds 1D ) ; minimum, seconds NS obelix-atm.atm. ; ; Hosts ; 0.0.E.6.0.3.E.0.8.4.0.2.0.0.F.0.0.4.F.0.2.F IN PTR obelix-atm.atm. 0.0.F.2.4.0.E.0.8.4.0.2.0.0.C.5.F.2.A.1.2.F IN PTR pong-atm.atm. 0.0.2.9.A.9.8.0.8.4.0.2.0.0.C.5.F.2.A.1.2.F IN PTR osteolito-atm.atm. --- NEW FILE: bind-498-REL.patch --- diff -urN bind-498-REL.orig/Makefile bind-498-REL/Makefile --- bind-498-REL.orig/Makefile Sat Jan 27 17:29:22 2001 +++ bind-498-REL/Makefile Tue Oct 2 17:21:47 2001 @@ -107,20 +107,20 @@ #(Linux - on modern systems, all you need to do is rename or remove # compat/include/sys/cdefs.h. See doc/info/Linux for more information.) -#CC = gcc $(CPPFLAGS) -#CDEBUG = -g -#CPPFLAGS = -DSYSV -#LEX=flex -8 -I -#INSTALL_COMPAT = install-compat -#LIBS = -lfl -#DESTEXEC = /usr/sbin -#DESTMAN = /usr/man -#MANDIR = man -#MANROFF = cat -#DESTHELP = /usr/lib -#CATEXT = $$$$N [...2014 lines suppressed...] + cp++; + break; + } +#endif + case T_AAAA: { char t[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"]; diff -urN bind-498-REL.orig/tools/nslookup/nslookup.help bind-498-REL/tools/nslookup/nslookup.help --- bind-498-REL.orig/tools/nslookup/nslookup.help Mon Oct 7 23:51:08 1996 +++ bind-498-REL/tools/nslookup/nslookup.help Tue Oct 2 17:21:56 2001 @@ -16,7 +16,7 @@ root=NAME - set root server to NAME retry=X - set number of retries to X timeout=X - set initial time-out interval to X seconds - querytype=X - set query type, e.g., A,ANY,CNAME,HINFO,MX,PX,NS,PTR,SOA,TXT,WKS,SRV,NAPTR + querytype=X - set query type, e.g., A,ANY,CNAME,HINFO,MX,PX,NS,PTR,SOA,TXT,WKS,SRV,NAPTR,ATMA port=X - set port number to send query on type=X - synonym for querytype class=X - set query class to one of IN (Internet), CHAOS, HESIOD or ANY --- NEW FILE: e164_cc --- 93 Afghanistan (Islamic State of) 355 Albania (Republic of) 213 Algeria (People's Democratic Republic of) 684 American Samoa 376 Andorra (Principality of) 244 Angola (Republic of) 1 Anguilla 1 Antigua and Barbuda 54 Argentine Republic 374 Armenia (Republic of) 297 Aruba 247 Ascension 61 Australia 672 Australian External Territories 43 Austria 994 Azerbaijani Republic 1 Bahamas (Commonwealth of the) 973 Bahrain (State of) 880 Bangladesh (People's Republic of) 1 Barbados 375 Belarus (Republic of) 32 Belgium 501 Belize 229 Benin (Republic of) 1 Bermuda 975 Bhutan (Kingdom of) 591 Bolivia (Republic of) 387 Bosnia and Herzegovina 267 Botswana (Republic of) 55 Brazil (Federative Republic of) 1 British Virgin Islands 673 Brunei Darussalam 359 Bulgaria (Republic of) 226 Burkina Faso 257 Burundi (Republic of) 855 Cambodia (Kingdom of) 237 Cameroon (Republic of) 1 Canada 238 Cape Verde (Republic of) 1 Cayman Islands 236 Central African Republic 235 Chad (Republic of) 56 Chile 86 China (People's Republic of) 57 Colombia (Republic of) 269 Comoros (Islamic Federal Republic of the) 242 Congo (Republic of the) 682 Cook Islands 506 Costa Rica 225 Côte d'Ivoire (Republic of) 385 Croatia (Republic of) 53 Cuba 357 Cyprus (Republic of) 420 Czech Republic 850 Democratic People's Republic of Korea 243 Democratic Republic of the Congo 45 Denmark 246 Diego Garcia 253 Djibouti (Republic of) 1 Dominica (Commonwealth of) 1 Dominican Republic 670 East Timor 593 Ecuador 20 Egypt (Arab Republic of) 503 El Salvador (Republic of) 240 Equatorial Guinea (Republic of) 291 Eritrea 372 Estonia (Republic of) 251 Ethiopia (Federal Democratic Republic of) 500 Falkland Islands (Malvinas) 298 Faroe Islands 679 Fiji (Republic of) 358 Finland 33 France 594 French Guiana (French Department of) 689 French Polynesia (Territoire français d'outre-mer) 241 Gabonese Republic 220 Gambia (Republic of the) 995 Georgia 49 Germany (Federal Republic of) 233 Ghana 350 Gibraltar 881 Global Mobile Satellite System (GMSS), shared code 30 Greece 299 Greenland (Denmark) 1 Grenada 388 Group of countries, shared code 590 Guadeloupe (French Department of) 1 Guam 502 Guatemala (Republic of) 224 Guinea (Republic of) 245 Guinea-Bissau (Republic of) 592 Guyana 509 Haiti (Republic of) 504 Honduras (Republic of) 852 Hongkong 36 Hungary (Republic of) 354 Iceland 91 India (Republic of) 62 Indonesia (Republic of) 871 Inmarsat (Atlantic Ocean-East) 874 Inmarsat (Atlantic Ocean-West) 873 Inmarsat (Indian Ocean) 872 Inmarsat (Pacific Ocean) 870 Inmarsat SNAC 800 International Freephone Service 882 International Networks, shared code 98 Iran (Islamic Republic of) 964 Iraq (Republic of) 353 Ireland 972 Israel (State of) 39 Italy 1 Jamaica 81 Japan 962 Jordan (Hashemite Kingdom of) 7 Kazakstan (Republic of) 254 Kenya (Republic of) 686 Kiribati (Republic of) 82 Korea (Republic of) 965 Kuwait (State of) 996 Kyrgyz Republic 856 Lao People's Democratic Republic 371 Latvia (Republic of) 961 Lebanon 266 Lesotho (Kingdom of) 231 Liberia (Republic of) 218 Libya (Socialist People's Libyan Arab Jamahiriya) 423 Liechtenstein (Principality of) 370 Lithuania (Republic of) 352 Luxembourg 853 Macau 261 Madagascar (Republic of) 265 Malawi 60 Malaysia 960 Maldives (Republic of) 223 Mali (Republic of) 356 Malta 692 Marshall Islands (Republic of the) 596 Martinique (French Department of) 222 Mauritania (Islamic Republic of) 230 Mauritius (Republic of) 269 Mayotte (Collectivité territoriale de la République française) 52 Mexico 691 Micronesia (Federated States of) 373 Moldova (Republic of) 377 Monaco (Principality of) 976 Mongolia 1 Montserrat 212 Morocco (Kingdom of) 258 Mozambique (Republic of) 95 Myanmar (Union of) 264 Namibia (Republic of) 674 Nauru (Republic of) 977 Nepal 31 Netherlands (Kingdom of the) 599 Netherlands Antilles 687 New Caledonia (Territoire français d'outre-mer) 64 New Zealand 505 Nicaragua 227 Niger (Republic of the) 234 Nigeria (Federal Republic of) 683 Niue 1 Northern Mariana Islands (Commonwealth of the) 47 Norway 968 Oman (Sultanate of) 92 Pakistan (Islamic Republic of) 680 Palau (Republic of) 507 Panama (Republic of) 675 Papua New Guinea 595 Paraguay (Republic of) 51 Peru 63 Philippines (Republic of the) 48 Poland (Republic of) 351 Portugal 1 Puerto Rico 974 Qatar (State of) 262 Reunion (French Department of) 40 Romania 7 Russian Federation 250 Rwandese Republic 290 Saint Helena 1 Saint Kitts and Nevis 1 Saint Lucia 508 Saint Pierre and Miquelon (Collectivité territoriale de la République 1 Saint Vincent and the Grenadines 685 Samoa (Independent State of) 378 San Marino (Republic of) 239 Sao Tome and Principe (Democratic Republic of) 966 Saudi Arabia (Kingdom of) 221 Senegal (Republic of) 248 Seychelles (Republic of) 232 Sierra Leone 65 Singapore (Republic of) 421 Slovak Republic 386 Slovenia (Republic of) 677 Solomon Islands 252 Somali Democratic Republic 27 South Africa (Republic of) 34 Spain 94 Sri Lanka (Democratic Socialist Republic of) 249 Sudan (Republic of the) 597 Suriname (Republic of) 268 Swaziland (Kingdom of) 46 Sweden 41 Switzerland (Confederation of) 963 Syrian Arab Republic 992 Tajikistan (Republic of) 255 Tanzania (United Republic of) 66 Thailand 389 The Former Yugoslav Republic of Macedonia 228 Togolese Republic 690 Tokelau 676 Tonga (Kingdom of) 991 Trial of a proposed new international telecommunication public 1 Trinidad and Tobago 216 Tunisia 90 Turkey 993 Turkmenistan 1 Turks and Caicos Islands 688 Tuvalu 256 Uganda (Republic of) 380 Ukraine 971 United Arab Emirates 44 United Kingdom of Great Britain and Northern Ireland 1 United States of America 1 United States Virgin Islands 598 Uruguay (Eastern Republic of) 998 Uzbekistan (Republic of) 678 Vanuatu (Republic of) 379 Vatican City State 39 Vatican City State 58 Venezuela (Bolivarian Republic of) 84 Viet Nam (Socialist Republic of) 681 Wallis and Futuna (Territoire français d'outre-mer) 967 Yemen (Republic of) 381 Yugoslavia (Federal Republic of) 260 Zambia (Republic of) 263 Zimbabwe (Republic of) 0 Reserved 886 Reserved 970 Reserved 875 Reserved - Maritime Mobile Service Applications 876 Reserved - Maritime Mobile Service Applications 877 Reserved - Maritime Mobile Service Applications 969 Reserved - reservation currently under investigation 878 Reserved - Universal Personal Telecommunication Service (UPT) 888 Reserved for future global service 808 Reserved for International Shared Cost Service (ISCS) 879 Reserved for national non-commercial purposes 979 Reserved for the International Premium Rate Service (IPRS) 210 Spare code 211 Spare code 214 Spare code 215 Spare code 217 Spare code 219 Spare code 259 Spare code 280 Spare code 281 Spare code 282 Spare code 283 Spare code 284 Spare code 285 Spare code 286 Spare code 287 Spare code 288 Spare code 289 Spare code 292 Spare code 293 Spare code 294 Spare code 295 Spare code 296 Spare code 382 Spare code 383 Spare code 384 Spare code 422 Spare code 424 Spare code 425 Spare code 426 Spare code 427 Spare code 428 Spare code 429 Spare code 671 Spare code 693 Spare code 694 Spare code 695 Spare code 696 Spare code 697 Spare code 698 Spare code 699 Spare code 801 Spare code 802 Spare code 803 Spare code 804 Spare code 805 Spare code 806 Spare code 807 Spare code 809 Spare code 830 Spare code 831 Spare code 832 Spare code 833 Spare code 834 Spare code 835 Spare code 836 Spare code 837 Spare code 838 Spare code 839 Spare code 851 Spare code 854 Spare code 857 Spare code 858 Spare code 859 Spare code 883 Spare code 884 Spare code 885 Spare code 887 Spare code 889 Spare code 890 Spare code 891 Spare code 892 Spare code 893 Spare code 894 Spare code 895 Spare code 896 Spare code 897 Spare code 898 Spare code 899 Spare code 978 Spare code 990 Spare code 997 Spare code 999 Spare code --- NEW FILE: hosts2ans.pl --- #!/usr/bin/perl # # Usage: # # hosts2ans.pl [-r] [ domain [ host [ email ] ] ] </etc/hosts.atm >zonefile # # Where domain is the name of the domain to create, e.g. lrc.epfl.ch (if # omitted, hostname -d is used) # host is the name of the primary DNS server of that domain, e.g. # lrcpcs.epfl.ch (if omitted, hostname -f is used) # email is the e-mail address of the DNS administrator of that # domain, e.g. ro...@lr... (if omitted, root@host is used) # zonefile is the name of the output file, e.g. lrc.zone # # Trailing dots in domain, host, and email are silently removed. # # With -r, the reverse mapping (PTR) is created. Otherwise, the forward mapping # (ATMA) is created. # # Example: host2ans.pl lrc.epfl.ch </etc/hosts.atm >/etc/named/lrc.zone if ($ARGV[0] eq "-r") { shift(@ARGV); $rev = 1; } $master = $tmp = `hostname -f` unless defined($master = $ARGV[1]); $master =~ s/\n//; $master =~ s/\.$//; ($domain = $master) =~ s/^[^.]*\.// unless defined($domain = $ARGV[0]); $domain =~ s/\.$//; $email = "root\@$master" unless defined($email = $ARGV[2]); $email =~ s/@/\./; $email =~ s/\.$//; print "; ".($rev ? "Reverse mapping" : "Authoritative data")." for $domain". "\n\n"; print "@\t\tIN\tSOA\t$master. $email. (\n"; @t = localtime(time); $t[5] += 1900 if $t[5] < 100; # Perl bug ? printf("\t\t\t\t%04d%02d%02d%02d\t; Serial\n",$t[5],$t[4],$t[3],$t[2]); print "\t\t\t\t10800\t\t; Refresh (3h)\n"; print "\t\t\t\t3600\t\t; Retry (1h)\n"; print "\t\t\t\t3600000\t\t; Expire (1000h)\n"; print "\t\t\t\t86400 )\t\t; Minimum (24h)\n"; print "\t\tIN\tNS\t$master.\n"; print "localhost\tIN\tA\t127.0.0.1\n" unless $rev; while (<STDIN>) { chop; s/#.*//; s/\s+$//; s/^\s+//; next if /^$/; ($addr,$host) = split(/\s+/); $addr =~ s/\.//g; $host =~ s/\..*//; $host =~ s/\.$//; if ($rev) { $pfx = substr($addr,0,26); $tail = substr($addr,26,14); if ($pfx ne $origin) { $origin = $pfx; $single = substr($pfx,6,20); print "\$ORIGIN ".join(".",reverse split("",substr($pfx,6,20))). ".".substr($pfx,2,4).".".substr($pfx,0,2).".AESA.ATMA.INT.\n"; } print substr($tail,12,2).".".substr($tail,0,12)."\tIN\tPTR\t$host.". $domain.".\n"; } else { print $host.(length($host) < 8 ? "\t" : "")."\tIN\tATMA\t$addr\n"; } } --- NEW FILE: named.conf --- options { directory "/var/named"; }; zone "0.0.127.in-addr.arpa" { type master; file "zone/127.0.0"; }; zone "atm" { notify no; type master; file "zone/atm"; }; zone "27.168.192.in-addr.arpa" { notify no; type master; file "zone/192.168.27"; }; zone "0.0.0.0.0.0.1.E.F.F.0.8.5.0.0.0.7.4.nsap.int" { notify no; type master; file "zone/atm-reverse"; }; --- NEW FILE: pdf2e164_cc.pl --- #!/usr/bin/perl # # The E.164 country code listing "List of ITU-T Recommendation E.164 Assigned # Country Codes" can be obtained from # The International Telecommunications Union (ITU) http://www.itu.org/ # at http://www.itu.int/itudoc/itu-t/ob-lists/icc/e164_717.html # # Usage of this program: # perl pdf2e164_cc.pl e164_xxx.pdf >/etc/e164_cc # open(PDF2TXT, "pdftotext -raw $ARGV[0] - |"); while(<PDF2TXT>) { next unless /^(\d+)\s+(.+)\s+/; last if $1 == 999; } while(<PDF2TXT>) { next unless /^(\d+)\s+(.+)\s+/; ($country, $junk) = split(/\s{2,}/, $2, 2); printf("%-3d %s\n", $1, $country) || die "printf: $!"; last if $1 == 999; } close(PDF2TXT); --- NEW FILE: README --- E.164 Country Codes ------------------- The file e164_cc is provided for those performing reverse lookups with the ATM Name Service (ANS). It can be installed via: cp e164_cc /etc The latest "List of ITU-T Recommendation E.164 Assigned Country Codes" can be obtained from the International Telecommunications Union (ITU) (http://www.itu.org/) in PDF or Word format (http://www.itu.int/itudoc/itu-t/ob-lists/icc/e164_717.html). The pdf2e164_cc.pl script, which is included in this directory, can be used to convert this file into the proper text format: perl pdf2e164_cc.pl >/etc/e164_cc Installing BIND --------------- BIND 4.9.8 can be gotten from the Internet Software Consortium (ISC) (http://www.isc.org/products/BIND/). The patch included in this directory (bind-498-REL.patch) is based upon version 4 (http://www.isc.org/products/BIND/bind4.html). After downloading BIND, unbundle it like so: mkdir /usr/src/bind-498-REL tar xzvf bind-498-REL.tar.gz -C /usr/src/bind-498-REL Apply the patch with: cp bind-498-REL.patch /usr/src cd /usr/src patch -p0 <bind-498-REL.patch or: cp bind-498-REL.patch /usr/src/bind-498-REL cd /usr/src/bind-498-REL patch -p1 <bind-498-REL.patch Then follow the instructions as outlined in the INSTALL file provided with the distribution. If you followed the instructions as outlined above, that will be /usr/src/bind-498-REL/INSTALL. See the README.DNS file in this directory for further instructions. --- NEW FILE: README.DNS --- **************************** * * * DNS access for linux-atm * (by Rui Prior) * * **************************** This package is meant for using the NSAP mapping capability of standard DNS servers (bind-8.2) for the direct and reverse translation of private ATM addresses. It doesn't break compatibility with ANS service. In fact, the resolution functions try to use the ANS service first, and only if it fails DNS is attempted. INSTALLATION: ------------- Install the bind package. I provide some examples of configuration files for you to modify as needed. These files assume you're currently in a domain named "my.domain" and are going to create a dummy domain named "atm". Your newly configured DNS server is going to act as a root server for this domain. The files are in subdirectory "bind-files". "named.conf" and "resolv.conf" should go in "/etc", and all other files should go in "/var/named/zone". "127.0.0" is for mapping localhost, and you may copy is as is. "192.168.27" is for reverse lookup of IP hosts on the ATM network (in my case, the network is the experimental 192.168.27.0). "atm" contains direct IP and NSAP mapping for hosts on the dummy domain "atm". "atm-reverse" contains reverse NSAP mapping. Please notice how the order of the nibbles is inverted, and each nibble is separated by one dot. After you install all the files, don't forget to do "ndc restart" in order to inform named of the updates. You should do this every time you modify the configuration files. After having all this installed (and, just in case, rebooting :-) you may test the setup using the provided test program. Go to the "debug" subdirectory and type "make dnstest". Now test the setup using "dnstest <host>", where <host> is one of the hosts in your bind configuration files. IMPORTANT NOTICE: ----------------- I strongly advise you to keep the arpserver on "/etc/hosts.atm". --- NEW FILE: resolv.conf --- search my.domain atm ; The host where we're running the nameserver: nameserver 192.168.27.72 ; The nameservers for my.domain nameserver xxx.xxx.xxx.xxx nameserver yyy.yyy.yyy.yyy |
From: Paul B. S. <pa...@us...> - 2001-10-03 17:41:54
|
Update of /cvsroot/linux-atm/linux-atm/src/extra/ANS In directory usw-pr-cvs1:/tmp/cvs-serv3347/src/extra/ANS Log Message: Directory /cvsroot/linux-atm/linux-atm/src/extra/ANS added to the repository --> Using per-directory sticky tag `V2_4_0' |
From: Paul B. S. <pa...@us...> - 2001-10-03 17:41:36
|
Update of /cvsroot/linux-atm/linux-atm/src/extra In directory usw-pr-cvs1:/tmp/cvs-serv3135/src/extra Log Message: Directory /cvsroot/linux-atm/linux-atm/src/extra added to the repository --> Using per-directory sticky tag `V2_4_0' |
From: Paul B. S. <pa...@us...> - 2001-10-03 16:25:40
|
Update of /cvsroot/linux-atm/linux-atm/doc In directory usw-pr-cvs1:/tmp/cvs-serv19376/doc Modified Files: Tag: V2_4_0 atm-linux-howto.sgml Log Message: Some minor updates to the HOWTO to keep sgmltools-lite from complaining so much... Also remove pdf2e164_cc.pl... It doesn't belong here.. We'll put it in src/extra... Index: atm-linux-howto.sgml =================================================================== RCS file: /cvsroot/linux-atm/linux-atm/doc/Attic/atm-linux-howto.sgml,v retrieving revision 1.1.2.1 retrieving revision 1.1.2.2 diff -C2 -d -r1.1.2.1 -r1.1.2.2 *** atm-linux-howto.sgml 2001/09/28 20:18:42 1.1.2.1 --- atm-linux-howto.sgml 2001/10/03 16:25:35 1.1.2.2 *************** *** 663,667 **** The file <filename>/proc/net/atm/arp</filename> contains information specific to Classical IP over ATM, see section ! <link linkend=IP_Over_ATM_CLIP endterm="IP_Over_ATM_CLIP.title"></link>. </para> --- 663,667 ---- The file <filename>/proc/net/atm/arp</filename> contains information specific to Classical IP over ATM, see section ! <link linkend="IP_Over_ATM_CLIP" endterm="IP_Over_ATM_CLIP.title"></link>. </para> *************** *** 1324,1328 **** in the normal way. Now you (should) have a working ATM set-up. To get IP over ATM working, just follow the instructions in ! section <link linkend=IP_Over_ATM endterm="IP_Over_ATM.title"></link>. </para> --- 1324,1328 ---- in the normal way. Now you (should) have a working ATM set-up. To get IP over ATM working, just follow the instructions in ! section <link linkend="IP_Over_ATM" endterm="IP_Over_ATM.title"></link>. </para> *************** *** 1581,1585 **** LECS, accepts the MTU size as defined by the LES and will not act as an proxy LEC. These parameters can be tailored with command line ! options which are defined in <filename>zeppelin.8</filename>. </para> --- 1581,1586 ---- LECS, accepts the MTU size as defined by the LES and will not act as an proxy LEC. These parameters can be tailored with command line ! options which are defined in ! <citerefentry><refentrytitle>zeppelin</refentrytitle><manvolnum>8</manvolnum></citerefentry>. </para> *************** *** 1601,1606 **** <para> ! The LANE service (<filename>lecs.8</filename>, <filename>les.8</filename> ! and <filename>bus.8</filename>) is configured using configuration files. The configuration file syntax is listed on the respective manual pages. --- 1602,1610 ---- <para> ! The LANE service ( ! <citerefentry><refentrytitle>lecs</refentrytitle><manvolnum>8</manvolnum></citerefentry>, ! <citerefentry><refentrytitle>les</refentrytitle><manvolnum>8</manvolnum></citerefentry>, and ! <citerefentry><refentrytitle>bus</refentrytitle><manvolnum>8</manvolnum></citerefentry>) ! is configured using configuration files. The configuration file syntax is listed on the respective manual pages. *************** *** 1650,1654 **** <para> Below is the example from Section ! <link linkend=IP_Over_ATM_LAN_Emulation endterm="IP_Over_ATM_LAN_Emulation.title"></link> which starts two LANE clients. The configuration has been augmented with two MPOA clients --- 1654,1658 ---- <para> Below is the example from Section ! <link linkend="IP_Over_ATM_LAN_Emulation" endterm="IP_Over_ATM_LAN_Emulation.title"></link> which starts two LANE clients. The configuration has been augmented with two MPOA clients |
From: Paul B. S. <pa...@us...> - 2001-10-03 16:25:40
|
Update of /cvsroot/linux-atm/linux-atm/src/lib In directory usw-pr-cvs1:/tmp/cvs-serv19376/src/lib Removed Files: Tag: V2_4_0 pdf2e164_cc.pl Log Message: Some minor updates to the HOWTO to keep sgmltools-lite from complaining so much... Also remove pdf2e164_cc.pl... It doesn't belong here.. We'll put it in src/extra... --- pdf2e164_cc.pl DELETED --- |
From: Paul B. S. <pa...@us...> - 2001-09-28 20:18:46
|
Update of /cvsroot/linux-atm/linux-atm/doc In directory usw-pr-cvs1:/tmp/cvs-serv24976/doc Added Files: Tag: V2_4_0 atm-linux-howto.sgml Log Message: Here is our first crack at an ATM on Linux HOWTO... It is essentially a conversion of Werner's usage.tex document into DocBook format with a few minor changes by me... More to come though... I want to begin to address the fact that we have zero documentation available in an on-line format.. The ATM API is next in line for a conversion... We'll make sure it's complete for the 2.4.0 release... --- NEW FILE: atm-linux-howto.sgml --- <!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook V4.1//EN"> <article ID="ATM-Linux-HOWTO"> <articleinfo> <title>ATM on Linux HOWTO</title> <author> <firstname>Paul</firstname> <surname>Schroeder</surname> <othername role=mi>B</othername> <affiliation> <orgname>IBM Corporation</orgname> <address><email>pa...@us...</email></address> </affiliation> </author> <author> <firstname>Werner</firstname> <surname>Almesberger</surname> [...1766 lines suppressed...] </biblioentry> <biblioentry ID="kiis" XREFLABEL="kiis"> <title>Implementation of LAN Emulation Over ATM in Linux</title> <author> <firstname>Marko</firstname> <surname>Kiiskilä</surname> </author> <releaseinfo> <ulink URL="ftp://sunsite.tut.fi/pub/Local/linux-atm/misc/">ftp://sunsite.tut.fi/pub/Local/linux-atm/misc/</ulink> </releaseinfo> <pubdate>October 1996</pubdate> </biblioentry> </bibliodiv> </bibliography> </article> |
From: Paul B. S. <pa...@us...> - 2001-09-28 20:15:44
|
Update of /cvsroot/linux-atm/linux-atm/src/lib In directory usw-pr-cvs1:/tmp/cvs-serv24655/src/lib Modified Files: Tag: V2_4_0 Makefile.am Removed Files: Tag: V2_4_0 rtf2e164_cc.pl Log Message: Remove old RTF to E.164 conversion script. The ITU no longer provides this format. Also update Makefile.am to include the new PDF conversion script instead... Index: Makefile.am =================================================================== RCS file: /cvsroot/linux-atm/linux-atm/src/lib/Attic/Makefile.am,v retrieving revision 1.1.2.1 retrieving revision 1.1.2.2 diff -C2 -d -r1.1.2.1 -r1.1.2.2 *** Makefile.am 2001/09/03 18:41:05 1.1.2.1 --- Makefile.am 2001/09/28 20:15:41 1.1.2.2 *************** *** 16,19 **** $(top_builddir)/src/include/stdint.h ! EXTRA_DIST = rtf2e164_cc.pl --- 16,19 ---- $(top_builddir)/src/include/stdint.h ! EXTRA_DIST = pdf2e164_cc.pl --- rtf2e164_cc.pl DELETED --- |
From: Paul B. S. <pa...@us...> - 2001-09-28 20:14:38
|
Update of /cvsroot/linux-atm/linux-atm/src/lib In directory usw-pr-cvs1:/tmp/cvs-serv24317/src/lib Added Files: Tag: V2_4_0 pdf2e164_cc.pl Log Message: This script converts the PDF version of the E.164 Country Code document for the ATM Naming Service (ANS) en leu of the old RTF conversion script. --- NEW FILE: pdf2e164_cc.pl --- #!/usr/bin/perl # # The E.164 country code listing "List of ITU-T Recommendation E.164 Assigned # Country Codes" can be obtained from # The International Telecommunications Union (ITU) http://www.itu.org/ # at http://www.itu.int/itudoc/itu-t/ob-lists/icc/e164_717.html # # Usage of this program: # perl pdf2e164_cc.pl e164_xxx.pdf >/etc/e164_cc # open(PDF2TXT, "pdftotext -raw $ARGV[0] - |"); while(<PDF2TXT>) { next unless /^(\d+)\s+(.+)\s+/; last if $1 == 999; } while(<PDF2TXT>) { next unless /^(\d+)\s+(.+)\s+/; ($country, $junk) = split(/\s{2,}/, $2, 2); printf("%-3d %s\n", $1, $country) || die "printf: $!"; last if $1 == 999; } close(PDF2TXT); |
From: Paul B. S. <pa...@us...> - 2001-09-18 18:51:13
|
Update of /cvsroot/linux-atm/linux-atm In directory usw-pr-cvs1:/tmp/cvs-serv32119 Modified Files: Tag: V2_4_0 linux-atm.spec Log Message: added missing man pages for lecs, bus, and les to RPM spec file.. Index: linux-atm.spec =================================================================== RCS file: /cvsroot/linux-atm/linux-atm/Attic/linux-atm.spec,v retrieving revision 1.1.2.1 retrieving revision 1.1.2.2 diff -C2 -d -r1.1.2.1 -r1.1.2.2 *** linux-atm.spec 2001/09/14 23:55:01 1.1.2.1 --- linux-atm.spec 2001/09/18 18:51:10 1.1.2.2 *************** *** 79,84 **** --- 79,87 ---- install -c -m 644 src/led/zeppelin.8 $RPM_BUILD_ROOT/usr/local/man/man8 install -c -m 755 src/lane/les $RPM_BUILD_ROOT/usr/local/sbin + install -c -m 644 src/lane/les.8 $RPM_BUILD_ROOT/usr/local/man/man8 install -c -m 755 src/lane/bus $RPM_BUILD_ROOT/usr/local/sbin + install -c -m 644 src/lane/bus.8 $RPM_BUILD_ROOT/usr/local/man/man8 install -c -m 755 src/lane/lecs $RPM_BUILD_ROOT/usr/local/sbin + install -c -m 644 src/lane/lecs.8 $RPM_BUILD_ROOT/usr/local/man/man8 install -c -m 755 src/mpoad/mpcd $RPM_BUILD_ROOT/usr/local/sbin install -c -m 644 src/mpoad/mpcd.8 $RPM_BUILD_ROOT/usr/local/man/man8 *************** *** 132,135 **** --- 135,141 ---- /usr/local/sbin/bus /usr/local/sbin/lecs + /usr/local/man/man8/les.8 + /usr/local/man/man8/bus.8 + /usr/local/man/man8/lecs.8 /usr/local/sbin/mpcd /usr/local/man/man8/mpcd.8 |
From: Paul B. S. <pa...@us...> - 2001-09-14 23:55:04
|
Update of /cvsroot/linux-atm/linux-atm In directory usw-pr-cvs1:/tmp/cvs-serv1346 Added Files: Tag: V2_4_0 linux-atm.spec mkrpm Log Message: Our first crack at an RPM spec file... Run ./mkrpm to build the RPM.. The binary RPM will go into the RPMS directory and the source RPM will go into SRPMS... --- NEW FILE: linux-atm.spec --- Summary: linux-atm - Tools to support ATM networking under Linux. Name: linux-atm %define linux_atm_version 2.4.0 Version: %{linux_atm_version} %define includedir /usr/include Release: 1 License: BSD License, GNU General Public License (GPL), GNU Lesser General Public License (LGPL) Group: System Environment/Daemons ExclusiveOS: Linux BuildRoot: /var/tmp/%{name}-buildroot %define _sourcedir %(pwd) %define _specdir %(pwd) %define _rpmdir %(pwd)/RPMS %define _srcrpmdir %(pwd)/SRPMS Source: linux-atm-%{linux_atm_version}.tar.gz %description Tools to support ATM networking under Linux. Eventually this will also include support for some types of DSL modems. %prep %setup -q %build ./configure --disable-shared make %install rm -rf $RPM_BUILD_ROOT mkdir -p $RPM_BUILD_ROOT/usr/local/include install -c -m 644 src/include/atm.h $RPM_BUILD_ROOT/usr/local/include install -c -m 644 src/include/atmd.h $RPM_BUILD_ROOT/usr/local/include install -c -m 644 src/include/atmsap.h $RPM_BUILD_ROOT/usr/local/include mkdir -p $RPM_BUILD_ROOT/usr/local/lib install -c -m 755 src/lib/.libs/libatm.lai $RPM_BUILD_ROOT/usr/local/lib/libatm.la install -c -m 644 src/lib/.libs/libatm.a $RPM_BUILD_ROOT/usr/local/lib ranlib $RPM_BUILD_ROOT/usr/local/lib/libatm.a install -c -m 755 src/lib/.libs/libatmd.lai $RPM_BUILD_ROOT/usr/local/lib/libatmd.la install -c -m 644 src/lib/.libs/libatmd.a $RPM_BUILD_ROOT/usr/local/lib ranlib $RPM_BUILD_ROOT/usr/local/lib/libatmd.a mkdir -p $RPM_BUILD_ROOT/usr/local/bin install -c -m 755 src/test/aread $RPM_BUILD_ROOT/usr/local/bin install -c -m 755 src/test/awrite $RPM_BUILD_ROOT/usr/local/bin install -c -m 755 src/test/ttcp_atm $RPM_BUILD_ROOT/usr/local/bin mkdir -p $RPM_BUILD_ROOT/usr/local/sbin install -c -m 755 src/sigd/atmsigd $RPM_BUILD_ROOT/usr/local/sbin mkdir -p $RPM_BUILD_ROOT/usr/local/etc install -c -m 644 src/sigd/atmsigd.conf $RPM_BUILD_ROOT/usr/local/etc mkdir -p $RPM_BUILD_ROOT/usr/local/man/man4 install -c -m 644 src/sigd/atmsigd.conf.4 $RPM_BUILD_ROOT/usr/local/man/man4 mkdir -p $RPM_BUILD_ROOT/usr/local/man/man8 install -c -m 644 src/sigd/atmsigd.8 $RPM_BUILD_ROOT/usr/local/man/man8 install -c -m 755 src/maint/atmdiag $RPM_BUILD_ROOT/usr/local/bin install -c -m 755 src/maint/atmdump $RPM_BUILD_ROOT/usr/local/bin install -c -m 755 src/maint/sonetdiag $RPM_BUILD_ROOT/usr/local/bin install -c -m 755 src/maint/saaldump $RPM_BUILD_ROOT/usr/local/bin install -c -m 755 src/maint/atmaddr $RPM_BUILD_ROOT/usr/local/sbin install -c -m 755 src/maint/esi $RPM_BUILD_ROOT/usr/local/sbin install -c -m 755 src/maint/atmloop $RPM_BUILD_ROOT/usr/local/sbin install -c -m 755 src/maint/atmtcp $RPM_BUILD_ROOT/usr/local/sbin install -c -m 755 src/maint/enitune $RPM_BUILD_ROOT/usr/local/sbin install -c -m 755 src/maint/zntune $RPM_BUILD_ROOT/usr/local/sbin install -c -m 644 src/maint/atmaddr.8 $RPM_BUILD_ROOT/usr/local/man/man8 install -c -m 644 src/maint/atmdiag.8 $RPM_BUILD_ROOT/usr/local/man/man8 install -c -m 644 src/maint/atmdump.8 $RPM_BUILD_ROOT/usr/local/man/man8 install -c -m 644 src/maint/atmloop.8 $RPM_BUILD_ROOT/usr/local/man/man8 install -c -m 644 src/maint/atmtcp.8 $RPM_BUILD_ROOT/usr/local/man/man8 install -c -m 644 src/maint/esi.8 $RPM_BUILD_ROOT/usr/local/man/man8 install -c -m 755 src/arpd/atmarp $RPM_BUILD_ROOT/usr/local/sbin install -c -m 755 src/arpd/atmarpd $RPM_BUILD_ROOT/usr/local/sbin install -c -m 644 src/arpd/atmarp.8 $RPM_BUILD_ROOT/usr/local/man/man8 install -c -m 644 src/arpd/atmarpd.8 $RPM_BUILD_ROOT/usr/local/man/man8 install -c -m 755 src/ilmid/ilmid $RPM_BUILD_ROOT/usr/local/sbin mkdir -p $RPM_BUILD_ROOT/usr/local/man/man7 install -c -m 644 src/man/qos.7 $RPM_BUILD_ROOT/usr/local/man/man7 install -c -m 644 src/man/sap.7 $RPM_BUILD_ROOT/usr/local/man/man7 install -c -m 755 src/led/zeppelin $RPM_BUILD_ROOT/usr/local/sbin install -c -m 644 src/led/zeppelin.8 $RPM_BUILD_ROOT/usr/local/man/man8 install -c -m 755 src/lane/les $RPM_BUILD_ROOT/usr/local/sbin install -c -m 755 src/lane/bus $RPM_BUILD_ROOT/usr/local/sbin install -c -m 755 src/lane/lecs $RPM_BUILD_ROOT/usr/local/sbin install -c -m 755 src/mpoad/mpcd $RPM_BUILD_ROOT/usr/local/sbin install -c -m 644 src/mpoad/mpcd.8 $RPM_BUILD_ROOT/usr/local/man/man8 %clean rm -rf $RPM_BUILD_ROOT %files %defattr(-, root, root) %doc AUTHORS BUGS ChangeLog COPYING COPYING.GPL COPYING.LGPL INSTALL NEWS README THANKS /usr/local/include/atm.h /usr/local/include/atmd.h /usr/local/include/atmsap.h /usr/local/lib/libatm.la /usr/local/lib/libatm.a /usr/local/lib/libatmd.la /usr/local/lib/libatmd.a /usr/local/bin/aread /usr/local/bin/awrite /usr/local/bin/ttcp_atm /usr/local/sbin/atmsigd %config /usr/local/etc/atmsigd.conf /usr/local/man/man4/atmsigd.conf.4 /usr/local/man/man8/atmsigd.8 /usr/local/bin/atmdiag /usr/local/bin/atmdump /usr/local/bin/sonetdiag /usr/local/bin/saaldump /usr/local/sbin/atmaddr /usr/local/sbin/esi /usr/local/sbin/atmloop /usr/local/sbin/atmtcp /usr/local/sbin/enitune /usr/local/sbin/zntune /usr/local/man/man8/atmaddr.8 /usr/local/man/man8/atmdiag.8 /usr/local/man/man8/atmdump.8 /usr/local/man/man8/atmloop.8 /usr/local/man/man8/atmtcp.8 /usr/local/man/man8/esi.8 /usr/local/sbin/atmarp /usr/local/sbin/atmarpd /usr/local/man/man8/atmarp.8 /usr/local/man/man8/atmarpd.8 /usr/local/sbin/ilmid /usr/local/man/man7/qos.7 /usr/local/man/man7/sap.7 /usr/local/sbin/zeppelin /usr/local/man/man8/zeppelin.8 /usr/local/sbin/les /usr/local/sbin/bus /usr/local/sbin/lecs /usr/local/sbin/mpcd /usr/local/man/man8/mpcd.8 %post ldconfig -n /usr/local/lib %postun ldconfig -n /usr/local/lib %changelog * Fri Sep 14 2001 Paul Schroeder <paulsch@@us.ibm.com> - First build of linux-atm RPM. --- NEW FILE: mkrpm --- #!/bin/sh mkdir -p RPMS mkdir -p SRPMS rpm -ba linux-atm.spec |
From: Paul B. S. <pa...@us...> - 2001-09-14 23:53:12
|
Update of /cvsroot/linux-atm/linux-atm/src/sigd In directory usw-pr-cvs1:/tmp/cvs-serv1215/src/sigd Modified Files: Tag: V2_4_0 Makefile.am Log Message: Add atmsigd.conf to EXTRA_DIST in src/sigd/Makefile.am Index: Makefile.am =================================================================== RCS file: /cvsroot/linux-atm/linux-atm/src/sigd/Attic/Makefile.am,v retrieving revision 1.1.2.1 retrieving revision 1.1.2.2 diff -C2 -d -r1.1.2.1 -r1.1.2.2 *** Makefile.am 2001/09/03 18:41:05 1.1.2.1 --- Makefile.am 2001/09/14 23:53:09 1.1.2.2 *************** *** 18,22 **** man_MANS = atmsigd.conf.4 atmsigd.8 ! EXTRA_DIST = cfg_y.h $(man_MANS) mkmess.pl README mess.c: $(top_builddir)/src/qgen/uni.h mkmess.pl --- 18,22 ---- man_MANS = atmsigd.conf.4 atmsigd.8 ! EXTRA_DIST = cfg_y.h $(man_MANS) $(sysconf_DATA) mkmess.pl README mess.c: $(top_builddir)/src/qgen/uni.h mkmess.pl |
From: Paul B. S. <pa...@us...> - 2001-09-14 21:18:01
|
Update of /cvsroot/linux-atm/linux-atm In directory usw-pr-cvs1:/tmp/cvs-serv5287 Modified Files: Tag: V2_4_0 config.h.in Log Message: Chas Williams' ia64 build fixes... Index: config.h.in =================================================================== RCS file: /cvsroot/linux-atm/linux-atm/Attic/config.h.in,v retrieving revision 1.1.2.1 retrieving revision 1.1.2.2 diff -C2 -d -r1.1.2.1 -r1.1.2.2 *** config.h.in 2001/09/03 10:56:35 1.1.2.1 --- config.h.in 2001/09/14 21:17:58 1.1.2.2 *************** *** 1,2 **** ! /* config.h.in */ --- 1,84 ---- ! /* config.h.in. Generated automatically from configure.in by autoheader. */ ! #ifndef _ATM_CONFIG_H ! #define _ATM_CONFIG_H ! ! ! /* Define if lex declares yytext as a char * by default, not a char[]. */ ! #undef YYTEXT_POINTER ! ! /* ! Default config file location for atmsigd ! */ ! #define ATMSIGD_CONF "/usr/local/etc/atmsigd.conf" ! ! #undef YY_USE_CONST ! ! /* ! The UNI version can be configured at run time. Dynamic is the default. Use the ! explicit version selections only in case of problems. ! */ ! #undef DYNAMIC_UNI ! ! #undef UNI30 ! ! /* ! Note: some UNI 3.0 switches will show really strange behaviour if confronted ! with using 3.1 signaling, so be sure to test your network *very* ! carefully before permanently configuring machines to use UNI 3.1. ! */ ! #undef UNI31 ! #undef ALLOW_UNI30 ! ! /* ! Some partial support for UNI 4.0 can be enabled by using UNI40 ! */ ! #undef UNI40 ! ! /* ! If using UNI40, you can also enable peak cell rate modification as ! specified in Q.2963.1 ! */ ! #undef Q2963_1 ! ! /* ! If you're using a Cisco LS100 or LS7010 switch, you should add the following ! line to work around a bug in their point-to-multipoint signaling (it got ! confused when receiving a CALL PROCEEDING, so we don't send it, which of ! course makes our clearing procedure slightly non-conformant): ! */ ! #undef CISCO ! ! /* ! Some versions of the Thomson Thomflex 5000 won't do any signaling before they ! get a RESTART. Uncomment the next line to enable sending of a RESTART ! whenever SAAL comes up. Note that the RESTART ACKNOWLEDGE sent in response to ! the RESTART will yield a warning, because we don't implement the full RESTART ! state machine. ! */ ! #undef THOMFLEX ! ! /* ! Use select() instead of poll() with MPOA ! */ ! #undef BROKEN_POLL ! ! /* ! Use proposed MPOA 1.1 features ! */ ! #undef MPOA_1_1 ! ! /* Define if you have the mpr library (-lmpr). */ ! #undef HAVE_LIBMPR ! ! /* Define if you have the resolv library (-lresolv). */ ! #undef HAVE_LIBRESOLV ! ! /* Name of package */ ! #undef PACKAGE ! ! /* Version number of package */ ! #undef VERSION ! ! ! #endif |
From: Paul B. S. <pa...@us...> - 2001-09-14 21:18:01
|
Update of /cvsroot/linux-atm/linux-atm/src/ilmid/asn1 In directory usw-pr-cvs1:/tmp/cvs-serv5287/src/ilmid/asn1 Modified Files: Tag: V2_4_0 asn_int.c asn_tag.h Log Message: Chas Williams' ia64 build fixes... Index: asn_int.c =================================================================== RCS file: /cvsroot/linux-atm/linux-atm/src/ilmid/asn1/Attic/asn_int.c,v retrieving revision 1.1.2.1 retrieving revision 1.1.2.2 diff -C2 -d -r1.1.2.1 -r1.1.2.2 *** asn_int.c 2001/09/03 18:41:06 1.1.2.1 --- asn_int.c 2001/09/14 21:17:58 1.1.2.2 *************** *** 85,89 **** unsigned long int dataCpy; ! #define INT_MASK (0x7f80 << ((sizeof(AsnInt) - 2) * 8)) dataCpy = *data; --- 85,89 ---- unsigned long int dataCpy; ! #define INT_MASK (0x7f80L << ((sizeof(AsnInt) - 2) * 8)) dataCpy = *data; Index: asn_tag.h =================================================================== RCS file: /cvsroot/linux-atm/linux-atm/src/ilmid/asn1/Attic/asn_tag.h,v retrieving revision 1.1.2.1 retrieving revision 1.1.2.2 diff -C2 -d -r1.1.2.1 -r1.1.2.2 *** asn_tag.h 2001/09/03 18:41:06 1.1.2.1 --- asn_tag.h 2001/09/14 21:17:58 1.1.2.2 *************** *** 70,73 **** --- 70,74 ---- } BER_CLASS; + #ifdef notdef typedef enum { *************** *** 77,80 **** --- 78,87 ---- CONS = (1 << 5) } BER_FORM; + #else + #define ANY_FORM -2 + #define NULL_FORM -1 + #define PRIM 0 + #define CONS (1L << 5) + #endif |
From: Paul B. S. <pa...@us...> - 2001-09-03 18:51:21
|
Update of /cvsroot/linux-atm/linux-atm In directory usw-pr-cvs1:/tmp/cvs-serv12691 Removed Files: Tag: V2_4_0 .kernel Log Message: --- .kernel DELETED --- |
Update of /cvsroot/linux-atm/linux-atm/src/mpoad In directory usw-pr-cvs1:/tmp/cvs-serv10656/mpoad Added Files: Tag: V2_4_0 TODO io.c io.h CHANGELOG Makefile.am k_interf.c k_interf.h get_vars.c get_vars.h lecs.c lecs.h main.c mpcd.8 tag_list.c README.mpoa packets.h p_factory.c p_recogn.c poll2select.c poll2select.h id_list.c Log Message: --- NEW FILE: TODO --- Check that closing unused SVCs does not create synchronization problems Get configuration information from LECS MPOA spec, A.1.4, IP Options, check them Support more MPOA/NHRP CIE error codes Check CBR vs UBR SVCs before using them as return channel Decide what to do when a new MPS is detected --- NEW FILE: io.c --- #if HAVE_CONFIG_H #include <config.h> #endif #include <stdio.h> #include <unistd.h> #include <time.h> /* for time() */ #include <fcntl.h> #include <string.h> /* for strerror() */ #include <errno.h> #include <sys/ioctl.h> #include <sys/param.h> /* for OPEN_MAX */ #if __GLIBC__ >= 2 #include <sys/poll.h> #else /* ugly hack to make it compile on RH 4.2 - WA */ #include <syscall.h> #include <linux/poll.h> #define SYS_poll 168 _syscall3(int,poll,struct pollfd *,ufds,unsigned int,nfds,int,timeout); #endif #include <atm.h> #include <linux/atmioc.h> #include <linux/atmmpc.h> #include <sys/types.h> #include <sys/socket.h> #include <atm.h> #include <netinet/in.h> /* for ntohl() */ #include "packets.h" #include "k_interf.h" #include "io.h" #include "get_vars.h" #ifdef BROKEN_POLL #include "poll2select.h" #endif #ifndef OPEN_MAX /* Fixme: there's got to be a better way to fix this */ #define OPEN_MAX 256 #endif #define POLL_TIMEOUT 5000 /* poll() timeout, 5 seconds */ #if 1 #define dprintf printf #else #define dprintf(format,args...) #endif #if 0 #define ddprintf printf #else #define ddprintf(format,args...) #endif extern struct mpc_control mpc_control; /* from main.c */ int keep_alive_sm_running = 0; struct outgoing_shortcut { int fd; uint32_t ipaddr; /* in network byte order */ int state; /* see io.h for states */ }; static struct llc_snap_hdr llc_snap_mpoa_ctrl = { 0xaa, 0xaa, 0x03, {0x00, 0x00, 0x5e}, {0x00, 0x03} }; static time_t stay_alive; /* Next Keep-Alive should come before we hit this time */ static struct pollfd fds[OPEN_MAX]; static int first_empty; /* first non-reserved slot in fds[] */ static int fds_used; /* first non-occupied slot in fds[], => also # of used fds */ static short socket_type[OPEN_MAX]; /* type and state info for fds[], see "io.h" for types */ static struct outgoing_shortcut ingress_shortcuts[OPEN_MAX]; /* array of shortcuts we made */ static int update_ingress_entry(uint32_t *addr, int fd, int new_state); static int msg_from_mps(int slot); static int accept_conn(int slot); static int add_shortcut(int slot, int type); static int check_connection(int slot); static int complete_connection(int slot); static int create_shortcut(char *atm_addr,struct atm_qos qos); static void wait_for_mps_ctrl_addr(void); static int connect_to_MPS(void); void main_loop(int listen_socket) { int i, changed_fds; int kernel_ok, mps_ok, new_ctrl, new_shortcut; int poll_timeout = POLL_TIMEOUT; time_t now, previous_now; for (i = 0; i < OPEN_MAX; i++) fds[i].fd = -1; fds[0].fd = mpc_control.kernel_socket; /* mpcd <--> kernel socket */ fds[0].events = POLLIN; socket_type[0]= KERNEL; if(!mpc_control.mps_ctrl_addr_set) /* Can't do much without the MPS control ATM addr */ wait_for_mps_ctrl_addr(); connect_to_MPS(); fds[1].fd = mpc_control.MPS_socket; /* we opened this to MPS */ fds[1].events = POLLIN; socket_type[1]= (OUTGOING_CTRL | CONNECTED); fds[2].fd = mpc_control.MPS_listen_socket; /* for incoming control calls */ fds[2].events = POLLIN; socket_type[2]= LISTENING_CTRL; fds[3].fd = listen_socket; /* for incoming shortcuts */ fds[3].events = POLLIN; socket_type[3]= LISTENING_DATA; fds_used = first_empty = 4; now = previous_now = time(NULL); while (1) { kernel_ok = mps_ok = new_ctrl = new_shortcut = 1; fflush(stdout); #ifdef BROKEN_POLL changed_fds = poll2select(fds, fds_used, poll_timeout); #else changed_fds = poll(fds, fds_used, poll_timeout); #endif #if 0 printf("\nio.c: main_loop() poll returns %d\n", changed_fds); for (i = 0; i < OPEN_MAX; i++) { if (fds[i].fd < 0 ) continue; /* slot not in use */ if ( fds[i].revents == 0) { printf("check1: fd %d slot %d not changed\n", fds[i].fd, i); } else printf("check1: fd %d slot %d changed\n", fds[i].fd, i); } #endif switch(changed_fds) { case -1: printf("mpcd: io.c: main_loop: poll error: %s\n", strerror(errno)); if(errno == EINTR) continue; goto out; /* return to main() */ break; /* not reached */ case 0: keep_alive_sm(0, -1); /* (keepalive_liftime, seq_num) */ clear_expired(); /* id_list.c */ poll_timeout = POLL_TIMEOUT; previous_now = time(NULL); continue; break; /* not reached */ } /* It was not a timeout. Adjust poll_timeout */ now = time(NULL); poll_timeout -= now - previous_now; if (poll_timeout < 0) poll_timeout = 0; /* Since we are here something happened to the fds */ if (fds[0].revents) { dprintf("mpcd: io.c: main_loop() msg_from_kernel\n"); kernel_ok = msg_from_kernel(fds[0].fd); changed_fds--; } if (fds[1].revents) { ddprintf("mpcd: io.c: main_loop() msg_from_mps1\n"); mps_ok = msg_from_mps(1); changed_fds--; } if (fds[2].revents) { new_ctrl = accept_conn(2); changed_fds--; if( new_ctrl < 0 ) break; socket_type[new_ctrl] = INCOMING_CTRL | CONNECTED; dprintf("mpcd: io.c main_loop() accepted INCOMING_CTRL slot %d\n", new_ctrl); } if (fds[3].revents) { new_shortcut = accept_conn(3); dprintf("mpcd: io.c main_loop() accepted INCOMING_SHORTCUT slot %d\n", new_shortcut); changed_fds--; if( new_shortcut < 0 ) break; socket_type[new_shortcut] = INCOMING_SHORTCUT; if (add_shortcut(new_shortcut, MPC_SOCKET_EGRESS) < 0) break; } #if 0 if (changed_fds == 0) /* see if we can already go back to poll() */ continue; #endif for (i = first_empty; i < fds_used; i++) { if (fds[i].fd < 0 ) continue; /* slot not in use */ if ( fds[i].revents == 0) { ddprintf("fd %d slot %d not changed\n", fds[i].fd, i); continue; } ddprintf("about to process fd %d slot %d\n", fds[i].fd, i); if (socket_type[i] & INCOMING_CTRL) { ddprintf("mpcd: io.c: main_loop() msg_from_mps2\n"); mps_ok = msg_from_mps(i); } else { ddprintf("mpcd: io.c: main_loop() checking connection fd %d\n", fds[i].fd); if (check_connection(i) < 0) { printf("mpcd: io.c: main_loop: check_connection returned < 0\n"); break; /* this will cause break from while(1) too */ } } if (--changed_fds == 0) break; /* no more changed fds, leave for() */ } if (changed_fds != 0){ printf("mpcd: changed_fds = %d\n", changed_fds); /* break; */ /* leave while(1) */ } if (kernel_ok && mps_ok >= 0 && new_ctrl >= 0 && new_shortcut >= 0) continue; /* back to poll() */ else break; /* leave main_loop */ } out: /* clean up, close the sockets */ for (i = 0; i < fds_used; i++) { if (fds[i].fd < 0) continue; close(fds[i].fd); socket_type[i] = NOT_USED; } printf("mpcd: io.c: exiting main_loop()\n"); return; } /* * If MPS control ATM address is not given as an argument this func waits until * kernel has found one from a TLV in le_arp and tells us what it is. */ static void wait_for_mps_ctrl_addr(){ while(!mpc_control.mps_ctrl_addr_set){ #ifdef BROKEN_POLL if(poll2select(fds, 1, -1)) #else if(poll(fds, 1, -1)) #endif msg_from_kernel(fds[0].fd); } return; } /* * Sends a packet to MPS. Adds LLC/SNAP encapsulation * in the beginning of the buffer. */ int send_to_mps(char *buff, int length) { char tmp[MAX_PACKET_LENGTH + sizeof(struct llc_snap_hdr)]; int bytes_written; char *pos = tmp; if(mpc_control.MPS_socket<0){ connect_to_MPS(); fds[1].fd = mpc_control.MPS_socket; fds[1].events = POLLIN; fds[1].revents = 0; socket_type[1] = (OUTGOING_CTRL | CONNECTED); } memcpy(pos, &llc_snap_mpoa_ctrl, sizeof(struct llc_snap_hdr)); pos += sizeof(struct llc_snap_hdr); memcpy(pos, buff, length); length += sizeof(struct llc_snap_hdr); bytes_written = write(mpc_control.MPS_socket, tmp, length); while(bytes_written != 0){ bytes_written = write(mpc_control.MPS_socket, tmp+bytes_written, length-bytes_written); if( bytes_written < 0 ){ printf("mpcd: io.c: send_to_mps() write failed\n"); return -1; } } return 1; } /* * Sends a control packet over a shortcut. Used in a dataplane purge. */ int send_to_dataplane(char *buff, int length, int shortcut_fd) { char tmp[MAX_PACKET_LENGTH + sizeof(struct llc_snap_hdr)]; int bytes_written; char *pos = tmp; memcpy(pos, &llc_snap_mpoa_ctrl, sizeof(struct llc_snap_hdr)); pos += sizeof(struct llc_snap_hdr); memcpy(pos, buff, length); length += sizeof(struct llc_snap_hdr); bytes_written = write(shortcut_fd, tmp, length); while(bytes_written != 0){ bytes_written = write(shortcut_fd, tmp+bytes_written, length-bytes_written); if( bytes_written < 0 ){ printf("mpcd: io.c: write to dataplane failed\n"); return -1; } } return 1; } /* * Keep alive state machine. Sequence number less than * and keep_alive_lifetime equal to zero is used * when checking wheter the MPS is still alive. * */ void keep_alive_sm(unsigned keep_alive_lifetime, int sequence_number){ struct k_message msg; static unsigned previous_sequence_number = 0; static int start_keep_alive_sm = 0; time_t now = time(NULL); memset(&msg,0,sizeof(struct k_message)); if(!keep_alive_sm_running){ start_keep_alive_sm = 0; return; } if(!start_keep_alive_sm){ dprintf("mpcd: io.c: starting keep_alive_sm.\n"); stay_alive = time(NULL) + MPC_C2; start_keep_alive_sm = 1; return; } if( now > stay_alive ){ dprintf("mpcd: io.c: MPS death!"); msg.type = MPS_DEATH; memcpy(msg.MPS_ctrl,mpc_control.MPS_CTRL_ATM_ADDR,ATM_ESA_LEN); send_to_kernel(&msg); previous_sequence_number = 0; stay_alive = now + MPC_C2; return; } if( sequence_number < 0 ) return; if( sequence_number < previous_sequence_number ){ dprintf("mpcd: io.c: MPS death!"); msg.type = MPS_DEATH; memcpy(msg.MPS_ctrl,mpc_control.MPS_CTRL_ATM_ADDR,ATM_ESA_LEN); send_to_kernel(&msg); previous_sequence_number = 0; stay_alive = now + MPC_C2; return; } stay_alive = now + keep_alive_lifetime; previous_sequence_number = sequence_number; return; } /* * Creates a socket, sets traffic and sap parameters * and binds the socket with given address. * * returns < 0 for error, socket for ok */ int get_socket(struct sockaddr_atmsvc *address) { struct atm_qos qos; struct atm_sap sap; int socket_fd; socket_fd = socket(PF_ATMSVC, SOCK_DGRAM, 0); if( socket_fd < 0 ){ printf("mpcd: io.c: socket creation failure: %s \n",strerror(errno)); return -1; } memset(&qos, 0, sizeof(qos)); memset(&sap, 0, sizeof(sap)); qos.aal = ATM_AAL5; qos.txtp.traffic_class = ATM_UBR; qos.rxtp.traffic_class = ATM_UBR; qos.txtp.max_sdu = 1536; qos.rxtp.max_sdu = 1536; sap.blli[0].l2_proto = ATM_L2_ISO8802; if (setsockopt(socket_fd, SOL_ATM,SO_ATMQOS, &qos, sizeof(qos)) < 0){ printf("mpcd: io.c: setsockopt SO_ATMQOS failed: %s \n",strerror(errno)); close(socket_fd); return -1; } if (setsockopt(socket_fd,SOL_ATM,SO_ATMSAP,&sap,sizeof(sap)) < 0) { printf("mpcd: io.c: setsockop SO_ATMSAP failed\n"); close (socket_fd); return -1; } if (address == NULL) return socket_fd; if (bind(socket_fd, (struct sockaddr *)address, sizeof(struct sockaddr_atmsvc)) < 0){ printf("mpcd: io.c: bind failure: %s \n",strerror(errno)); close(socket_fd); return -1; } return socket_fd; } /* * Creates an ATM_ANYCLASS traffic class socket, sets traffic and sap * parameters and binds the socket with given address. * * returns < 0 for error, socket for ok */ int get_listen_socket(struct sockaddr_atmsvc *address) { int s; struct atm_qos qos; s = get_socket(NULL); if (s < 0) { printf("mpcd: io.c: get_listen_socket() get socket failed\n"); return s; } memset(&qos, 0, sizeof(qos)); qos.aal = ATM_AAL5; qos.txtp.traffic_class = ATM_ANYCLASS; qos.rxtp.traffic_class = ATM_ANYCLASS; if (setsockopt(s, SOL_ATM,SO_ATMQOS, &qos, sizeof(qos)) < 0){ printf("mpcd: io.c: get_listen_socket() setsockopt SO_ATMQOS: %s\n", strerror(errno)); close(s); return -1; } if (bind(s, (struct sockaddr *)address, sizeof(struct sockaddr_atmsvc)) < 0){ printf("mpcd: io.c: get_listen_socket() bind: %s\n", strerror(errno)); close(s); return -1; } if (listen(s, 5) < 0) { printf("mpcd: io.c: get_lilsten_socket() listen: %s\n", strerror(errno)); close(s); return -1; } return s; } /* * If addr != NULL searches by addr. If addr == NULL searches by fd. * Returns ipaddr. * */ static int update_ingress_entry(uint32_t *addr, int fd, int new_state) { int i; if (addr != NULL) { dprintf("mpcd: io.c update_ingress_entry() updating ip 0x%x\n", *addr); for (i = 0; i < OPEN_MAX; i++) if (ingress_shortcuts[i].ipaddr == *addr) break; } else { dprintf("mpcd: io.c update_ingress_entry() updating fd %d\n", fd); for (i = 0; i < OPEN_MAX; i++) if (ingress_shortcuts[i].fd == fd) break; } if (i == OPEN_MAX) { printf("mpcd: io.c: update_ingress_entry: entry not found\n"); return 0; } ingress_shortcuts[i].fd = fd; ingress_shortcuts[i].state = new_state; if (new_state == INGRESS_NOT_USED) memset(&ingress_shortcuts[i], 0 , sizeof(ingress_shortcuts[i])); return ingress_shortcuts[i].ipaddr; } /* * returns < 0 for error * */ static int msg_from_mps(int slot) { int bytes_read, fd; char buff[MAX_PACKET_LENGTH]; fd = fds[slot].fd; bytes_read = read(fd, buff, sizeof(buff)); if (bytes_read < 0) { printf("mpcd: io.c: read failed from MPS: %s\n", strerror(errno)); close(fd); fds[slot].fd = -1; socket_type[slot] = NOT_USED; return -1; } if (bytes_read == 0) { dprintf("mpcd: io.c: EOF from MPS\n"); close(fd); fds[slot].fd = -1; if (slot == 1) mpc_control.MPS_socket = -1; socket_type[slot] = NOT_USED; return 1; /* See spec 4.6. Might be normal */ } if ( memcmp(buff, &llc_snap_mpoa_ctrl, sizeof(llc_snap_mpoa_ctrl)) != 0 ) { printf("mpcd: io.c: msg_from_mps: MPS is pushing us garbage\n"); return -1; } (void)recognize_packet(buff + sizeof(struct llc_snap_hdr)); return 0; } /* * returns < 0 for error, slot of the new socket for ok * */ static int accept_conn(int slot) { struct sockaddr_atmsvc sa; int i, new_fd, sa_len; sa_len = sizeof(sa); new_fd = accept(fds[slot].fd, (struct sockaddr *)&sa, &sa_len); if (new_fd < 0) { printf("mpcd: io.c: accept_conn: %s\n", strerror(errno)); return -1; } for (i = first_empty; i < OPEN_MAX; i++) { if (fds[i].fd >= 0) /* slot in use ? */ continue; fds[i].fd = new_fd; fds[i].events = POLLIN; fds[i].revents = 0; break; } if (i == OPEN_MAX) { printf("mpcd: io.c: accept_conn: no room for new connection\n"); return -1; } if (i >= fds_used) fds_used = i + 1; return i; } /* * returns < 0 for error, slot of the new socket for ok * */ static int add_shortcut(int slot, int type) { struct atmmpc_ioc ioc_data; int ipaddr = 0; if (type == MPC_SOCKET_INGRESS) ipaddr = update_ingress_entry(NULL, fds[slot].fd, INGRESS_CONNECTED); ioc_data.dev_num = mpc_control.INTERFACE_NUMBER; ioc_data.ipaddr = ipaddr; ioc_data.type = type; if (ioctl(fds[slot].fd, ATMMPC_DATA, &ioc_data) < 0) { printf("mpcd: io.c: add_shortcut: %s\n", strerror(errno)); close(fds[slot].fd); fds[slot].fd = -1; socket_type[slot] = NOT_USED; return -1; } return slot; } /* * ECONNRESET == RST in TCP world. Check what equivalent * events can happen in ATM world. * * Returns < 0 for error */ static int check_connection(int slot) { char buff[MAX_PACKET_LENGTH]; struct k_message *msg; struct pollfd *pfd; int bytes_read; dprintf("mpcd: io.c: check_connection() event in fd %d, type %d\n", fds[slot].fd, socket_type[slot]); if (socket_type[slot] & CONNECTING) { /* connect() completed (maybe) */ complete_connection(slot); /* ignore return value */ return 0; } pfd = &fds[slot]; bytes_read = read(pfd->fd, buff, sizeof(buff)); if (bytes_read < 0) { if (errno == ECONNRESET || errno == EPIPE) { /* conn reset by the other end or kernel (EPIPE) */ if (socket_type[slot] & OUTGOING_SHORTCUT) update_ingress_entry(NULL, pfd->fd, INGRESS_NOT_USED); close(pfd->fd); pfd->fd = -1; socket_type[slot] = NOT_USED; return 1; } printf("mpcd: io.c: check_connection() bytes_read=%d, errno='%s'\n", bytes_read, strerror(errno)); return -1; } if (bytes_read == 0) { /* conn closed by the other end */ if (socket_type[slot] & OUTGOING_SHORTCUT) update_ingress_entry(NULL, pfd->fd, INGRESS_NOT_USED); dprintf("mpcd: io.c: check_connection() fd %d type %d; connection closed'\n", pfd->fd, socket_type[slot]); close(pfd->fd); pfd->fd = -1; socket_type[slot] = NOT_USED; return 1; } /* See if this is a MPOA control packet */ if ( memcmp(buff, &llc_snap_mpoa_ctrl, sizeof(llc_snap_mpoa_ctrl)) == 0 ) if ( recognize_packet(buff + sizeof(llc_snap_mpoa_ctrl)) >= 0) return 1; dprintf("mpcd: io.c check_connection(): msg from kernel\n"); msg = (struct k_message *)buff; if(msg->type == DATA_PLANE_PURGE){ send_purge_request(msg->content.eg_info.mps_ip,32, get_own_ip_addr(mpc_control.INTERFACE_NUMBER),pfd->fd); return 1; } printf("mpcd: io.c check_connection(): unknown msg %d from kernel, ignoring", msg->type); return 1; } /* * returns < 0 for unsuccessful connect, fd for ok * */ static int complete_connection(int slot) { int retval; struct sockaddr_atmsvc dummy; dprintf("mpcd: io.c: complete_connection() completing fd %d slot %d\n", fds[slot].fd, slot); /* this seems to be common method in Linux-ATM * making sure that nonblocking connect was * completed successfully */ retval = connect(fds[slot].fd,(struct sockaddr *)&dummy, sizeof(dummy)); if (retval < 0) { printf("mpcd: io.c: complete_connection(): '%s'\n", strerror(errno)); socket_type[slot] = NOT_USED; update_ingress_entry(NULL, fds[slot].fd, INGRESS_NOT_USED); close(fds[slot].fd); fds[slot].fd = -1; fds[slot].revents = 0; return 0; } socket_type[slot] &= ~CONNECTING; socket_type[slot] |= CONNECTED; fds[slot].events = POLLIN; /* We left POLLOUT accidentally in. Hope you never do the same */ fds[slot].revents = 0; if(socket_type[slot] & OUTGOING_SHORTCUT) return add_shortcut(slot, MPC_SOCKET_INGRESS); return fds[slot].fd; } /* * Called if kernel wants us to create a shortcut */ void create_ingress_svc(uint32_t ipaddr, char *atm_addr, struct atm_qos qos) { int i, new_socket; new_socket = create_shortcut(atm_addr,qos); if (new_socket < 0) { printf("mpcd: io.c: create_ingress_svc: create_shortcut failed\n"); return; } for (i = first_empty; i < OPEN_MAX; i++) { if (fds[i].fd >= 0) /* slot in use ? */ continue; fds[i].fd = new_socket; fds[i].events = POLLIN | POLLOUT; fds[i].revents = 0; break; } if (i == OPEN_MAX) { printf("mpcd: io.c: create_ingress_svc: create_shortcut: no room for new connection\n"); return; } socket_type[i] = (OUTGOING_SHORTCUT | CONNECTING); if (i >= fds_used) fds_used = i + 1; /* Store the IP address we are creating this shortcut for */ dprintf("mpcd: io.c: create_ingress_svc: adding ip 0x%x\n", ipaddr); for(i = 0; i < OPEN_MAX; i++) if (ingress_shortcuts[i].state == INGRESS_NOT_USED) break; if (i == OPEN_MAX) { printf("mpcd: io.c: create_ingress_svc: ingress no more entries\n"); return; } ingress_shortcuts[i].fd = new_socket; ingress_shortcuts[i].ipaddr = ipaddr; ingress_shortcuts[i].state = INGRESS_CONNECTING; } /* * returns < 0 for error, socket for ok * */ static int create_shortcut(char *atm_addr, struct atm_qos qos) { int s, flags, retval; struct sockaddr_atmsvc addr; dprintf("mpcd: io.c: create_shortcut() addr = 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", atm_addr[0], atm_addr[1], atm_addr[2], atm_addr[3], atm_addr[4]); memset(&addr, 0, sizeof(addr)); addr.sas_family = AF_ATMSVC; memcpy(addr.sas_addr.prv, atm_addr, ATM_ESA_LEN); s = get_socket(&mpc_control.data_listen_addr); if(qos.txtp.traffic_class > ATM_UBR || qos.rxtp.traffic_class > ATM_UBR){ printf("mpcd: io.c: create_shortcut() setting qos params (cbr)\n"); if (setsockopt(s, SOL_ATM,SO_ATMQOS, &qos, sizeof(qos)) < 0){ printf("mpcd: io.c: setsockopt SO_ATMQOS failed: %s \n",strerror(errno)); close(s); return -1; } } dprintf("mpcd: create_shortcut() got fd %d \n", s); if ( (flags = fcntl(s, F_GETFL)) < 0) { printf("mpcd: io.c: fcntl(F_GETFL) failed: %s\n", strerror(errno)); close(s); return -1; } if (fcntl(s, F_SETFL, flags | O_NONBLOCK) < 0) { printf("mpcd: io.c: fcntl(F_SETFL) failed: %s\n", strerror(errno)); close(s); return -1; } retval = connect(s, (struct sockaddr *)&addr, sizeof(addr)); if (retval < 0 && errno != EINPROGRESS) { printf("mpcd: io.c: create_shortcut: connect failed: %s\n", strerror(errno)); return -1; } return s; } /* * Creates an active connection to MPS * * returns < 0 for error */ static int connect_to_MPS(){ int c; struct sockaddr_atmsvc mps_ctrl_addr; struct sockaddr_atmsvc ctrl_listen_addr; memset(&mps_ctrl_addr,0,sizeof(struct sockaddr_atmsvc)); memset(&ctrl_listen_addr,0,sizeof(struct sockaddr_atmsvc)); memcpy(mps_ctrl_addr.sas_addr.prv,mpc_control.MPS_CTRL_ATM_ADDR,ATM_ESA_LEN); memcpy(ctrl_listen_addr.sas_addr.prv,mpc_control.OWN_ATM_ADDRESS,ATM_ESA_LEN); mps_ctrl_addr.sas_family = AF_ATMSVC; ctrl_listen_addr.sas_family = AF_ATMSVC; mpc_control.MPS_socket = get_socket(&ctrl_listen_addr); if (mpc_control.MPS_socket < 0) return -1; c = connect(mpc_control.MPS_socket, (struct sockaddr *)&(mps_ctrl_addr), sizeof(struct sockaddr_atmsvc)); if( c < 0 ){ printf("mpcd: io.c: connect to MPS failed: %s \n",strerror(errno)); close(mpc_control.MPS_socket); return -1; } return 0; } --- NEW FILE: io.h --- #ifndef _MPOA_IO_H #define _MPOA_IO_H #include<atm.h> #define MAX_PACKET_LENGTH 4096 /* max size of MPOA ctrl or data packet */ void main_loop(int listen_socket); int send_to_mps(char *buff, int length); int send_to_dataplane(char *buff, int length, int fd); void keep_alive_sm(unsigned keep_alive_lifetime, int sequence_number); int get_socket(struct sockaddr_atmsvc *address); int get_listen_socket(struct sockaddr_atmsvc *address); void create_ingress_svc(uint32_t ipaddr, char *atm_addr, struct atm_qos qos); /* Socket types and states */ #define NOT_USED 0x0000 #define KERNEL 0x0001 #define OUTGOING_CTRL 0x0002 #define INCOMING_CTRL 0x0004 #define LISTENING_DATA 0x0010 #define LISTENING_CTRL 0x0020 #define OUTGOING_SHORTCUT 0x0100 #define INCOMING_SHORTCUT 0x0200 #define CONNECTING 0x1000 /* For outgoing sockets */ #define CONNECTED 0x2000 /* For outgoing sockets */ /* states for outgoing ingress shortcuts */ #define INGRESS_NOT_USED 0 #define INGRESS_REQUEST_SEND 400 #define INGRESS_CONNECTING 401 #define INGRESS_CONNECTED 402 #endif /* _MPOA_IO_H */ --- NEW FILE: CHANGELOG --- Changes from version 0.55 ========================= o mpoa_proc.c: CDV is no more requred for CBR entries o mpc.c: two small skb_buff leaks fixed o kernel: number of debug messages reduced o k_interf.c: mpcd could not be killed if MPS's address was not known Changes from version 0.52 ========================= o mpoa_proc.c: when setting QoS values for shortcuts, receive values can now be specified with just "... rx=tx" Changes from version 0.50 ========================= o lecs.c: new file. mpcd can now ask LECS for configuration info if it is given correct command line arguments o p_recogn.c: added more sanity checks for incoming packets, fixed possible dereferences of uninitialized variables o p_recogn.c: receiving MPOA Triggers now works o k_interf.c: added missing ntohl() o mpc.c: If MPS does not advertise its MAC address with MPOA Device Discover we take it from LE_ARP packet. This should remove the need for -m commandline option. o both kernel & daemon: killing mpcd with SIGHUP now makes it restart itself closing all connections and flushing both ingress and egress cache o mpcd.8: updated, example added o README.mpoa: updated Changes from version 0.46 ========================= o io.c: fixed a misuse of a buffer in set_mps_ctrl_addr() o p_recogn: If service category extension present in MPOA resolution reply, appropriate information is included in to message to kernel. New func service_category_to_traff_class(). o poll2select.[ch]: new files to circumvent bugs in poll() o io.c: poll2select() is now used instead of poll() o k_interf.c: mpcd now does nothing before MPS's atm addr is known o README.mpoa: CBR example updated and changed o mpc.c: res_reply_rcvd(): a check that CBR is supported by the other end before attempting to create a CBR shortcut was added. o mpc.c: res_reply_rcvd(): pcr-value of egress shortcut in tx-direction is checked before using the same svc as an ingress shortcut. o mpc.c: if MPS's ATM address is known to kernel when mpcd comes up, kernel sends it to mpcd. Old version waited for the next LE_ARP o mpc.c: when adding a QoS entry for a shortcut the old entry is overwritten instead. Old version just added another IP o mpoa_proc.c: CBR QoS now only wants max_pcr, max_cdv, and max_sdu values Changes from version 0.43 ============================== o io.c: poll() seems to have problems returning correct values fixed it with a workaround o mpcd: put all the global variables in one global struct o io.c: listen sockets are now created with ATM_ANYCLASS traffic class o p_recogn.c: calculation of ip-address mask from a prefix-length in a CIE o io.c: mpoad no more exits when something really bad happens to it's sockets. Instead it does a soft boot and tries again o mpc.c: now correct pointer is kfree()ed in atm_mpoa_delete_qos() o mpc.c: while purging ingress entries ip-masks are taken into consideration o mpoa_caches.[ch]: new function in_cache_search_with_mask() o mpc.h: struct mpoa_client contains a new struct mpc_parameters o mpc.c: lane_assoc_ind() handles also MPC configuration TLVs o mpc.c: mpc->number_of_mps_macs is now updated correctly Changes from version pre0.43-0 ============================== o p_recogn.c: fixed a bug in extension parsing o io.c: fixed handling of the pollfd array indexing o p_recogn.c: chechksum checking for incoming control packets o main.c: default values for local listen ATM-adresses o getvars.[ch]: removed stupid set_own_atm_address function --- NEW FILE: Makefile.am --- sbin_PROGRAMS = mpcd LDADD = $(top_builddir)/src/lib/libatm.la mpcd_SOURCES = get_vars.c get_vars.h io.c io.h k_interf.c k_interf.h main.c \ p_factory.c p_recogn.c id_list.c tag_list.c \ poll2select.c poll2select.h lecs.c lecs.h packets.h man_MANS = mpcd.8 EXTRA_DIST = $(man_MANS) CHANGELOG README.mpoa TODO --- NEW FILE: k_interf.c --- #if HAVE_CONFIG_H #include <config.h> #endif #include <stdio.h> #include <unistd.h> #include <string.h> #include <errno.h> #include <sys/param.h> /* for OPEN_MAX */ #include <stdint.h> #include <netinet/in.h> /* for ntohl() */ #include <linux/atmmpc.h> #include <atm.h> #include "k_interf.h" #include "packets.h" #include "io.h" #include "get_vars.h" #if 0 #define dprintf printf #else #define dprintf(format,args...) #endif extern int keep_alive_sm_running; /* from io.c */ extern struct mpc_control mpc_control; /* from main.c */ static void snd_mpoa_res_rqst(struct k_message *msg); static void snd_mpoa_res_rtry(struct k_message *msg); static void set_mps_ctrl_addr(struct k_message *msg); static void stop_keep_alive_sm(void); static uint32_t traff_class_to_service_category(uint8_t traffic_class); /* * returns < 0 for error * */ int send_to_kernel(struct k_message *msg) { if (write(mpc_control.kernel_socket, msg, sizeof(struct k_message)) != sizeof(struct k_message) ) { printf("mpcd: k_interf.c: write to kernel failed!\n"); return -1; } return 1; } /* * returns 0 for error * */ int msg_from_kernel(int fd) { ssize_t bytes_read; struct k_message msg; memset(&msg,0,sizeof(struct k_message)); bytes_read = read(fd, (void *)&msg, sizeof(msg)); if (bytes_read < 0) { printf("mpcd: k_interf.c: read failed from kernel: %s\n", strerror(errno)); return 0; } if (bytes_read == 0) { printf("mpcd: k_interf.c:EOF from kernel\n"); return 0; } if (bytes_read != sizeof(msg)) { printf("mpcd: k_interf.c: msg from kernel wrong size\n"); return 0; } dprintf("mpcd: k_interf.c: message from kernel: "); if (msg.type == DIE) { dprintf(" die\n"); exit(0); } /* do nothing if MPS's control ATM address is not known */ if (msg.type != SET_MPS_CTRL_ADDR && !mpc_control.mps_ctrl_addr_set) return 0; switch(msg.type) { case SND_MPOA_RES_RQST: dprintf("snd_mpoa_res_rqst.\n"); snd_mpoa_res_rqst(&msg); return 1; break; /* not reached */ case SND_MPOA_RES_RTRY: dprintf("snd_mpoa_res_rtry.\n"); snd_mpoa_res_rtry(&msg); return 1; break; /* not reached */ case SET_MPS_CTRL_ADDR: dprintf("set_mps_ctrl_addr.\n"); set_mps_ctrl_addr(&msg); return 1; break; /* not reached */ case STOP_KEEP_ALIVE_SM: dprintf("stop_keep_alive_sm.\n"); stop_keep_alive_sm(); return 1; break; /* not reached */ case EGRESS_ENTRY_REMOVED: dprintf("egress_entry_removed.\n"); remove_tag(msg.content.eg_info.tag); return 1; break; /* not reached */ case SND_EGRESS_PURGE: dprintf("snd_egress_purge,cache_id = %u.\n",msg.content.eg_info.cache_id); send_egress_cache_purge_request(0, /* 1 == no reply, 0 == reply requested */ ntohl(msg.content.eg_info.mps_ip), 32, get_own_ip_addr(mpc_control.INTERFACE_NUMBER), msg.content.eg_info.cache_id); return 1; break; case OPEN_INGRESS_SVC: dprintf(" open_ingress_svc\n"); create_ingress_svc(msg.content.in_info.in_dst_ip, msg.content.in_info.eg_MPC_ATM_addr, msg.qos); return 1; break; case RELOAD: printf(" reload\n"); return 0; break; default: dprintf("unknown message %d\n", msg.type); return 0; break; /* not reached */ } return 0; /* not reached */ } static void snd_mpoa_res_rqst(struct k_message *msg){ send_resolution_request(0, 1, /* Source ip present */ msg->content.in_info.in_dst_ip, 0, /* prefix length */ traff_class_to_service_category(msg->qos.txtp.traffic_class)); return; } static void snd_mpoa_res_rtry(struct k_message *msg){ uint32_t rqst_id = search_by_type(MPOA_RESOLUTION_REQUEST, msg->content.in_info.in_dst_ip); send_resolution_request(rqst_id, 1, msg->content.in_info.in_dst_ip, 0, traff_class_to_service_category(msg->qos.txtp.traffic_class)); return; } static void set_mps_ctrl_addr(struct k_message *msg) { char buffer[ATM_ESA_LEN]; int i; struct sockaddr_atmsvc mps_ctrl_addr; char *buff = buffer; memcpy(mps_ctrl_addr.sas_addr.prv, msg->MPS_ctrl, ATM_ESA_LEN); mps_ctrl_addr.sas_family = AF_ATMSVC; if(mpc_control.mps_ctrl_addr_set && !memcmp(msg->MPS_ctrl,mpc_control.MPS_CTRL_ATM_ADDR,ATM_ESA_LEN)) return; if(mpc_control.mps_ctrl_addr_set && memcmp(msg->MPS_ctrl,mpc_control.MPS_CTRL_ATM_ADDR,ATM_ESA_LEN)){ printf("mpcd: k_interf.c: new MPS "); for (i = 0; i < ATM_ESA_LEN; i++) printf("%02x", msg->MPS_ctrl[i]); printf("\n"); return; } memcpy(mpc_control.MPS_CTRL_ATM_ADDR, msg->MPS_ctrl, ATM_ESA_LEN); printf("mpcd: k_interf.c: setting MPS control ATM address to "); if(atm2text(buff,ATM_ESA_LEN, (struct sockaddr*)&mps_ctrl_addr, T2A_SVC)<0) { for (i = 0; i < ATM_ESA_LEN; i++) printf("%02x", mpc_control.MPS_CTRL_ATM_ADDR[i]); printf("\n"); } else printf("%s\n", buff); mpc_control.mps_ctrl_addr_set = 1; return; } static void stop_keep_alive_sm(){ keep_alive_sm_running = 0; return; } /* * Converts linux-ATM traffic descriptions to those used in MPOA ATM service * category extension. Only UBR and CBR supported. */ static uint32_t traff_class_to_service_category(uint8_t traffic_class){ switch(traffic_class){ case ATM_NONE: return 0; break; case ATM_UBR: return 0; break; case ATM_CBR: return CBR; break; default: return 0; } } --- NEW FILE: k_interf.h --- #ifndef K_INTERF_H #define K_INTERF_H int send_to_kernel( struct k_message *msg); int msg_from_kernel(int fd); #endif /* K_INTERF_H */ --- NEW FILE: get_vars.c --- #if HAVE_CONFIG_H #include <config.h> #endif #include <stdio.h> #include <string.h> #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <stdint.h> #include <atm.h> #include <linux/atmdev.h> #include <sys/ioctl.h> #include <netinet/in.h> #include <netdb.h> #include <unistd.h> #include <net/if.h> #include <arpa/inet.h> #include <errno.h> #include "packets.h" #include "get_vars.h" #include "io.h" extern struct mpc_control mpc_control; /* From main.c */ /* Returns the Time To Live value. */ int get_ttl(){ int optvalue = 1; unsigned optlength = sizeof(optvalue); int sockfd = socket( AF_INET, SOCK_STREAM, IPPROTO_IP ); getsockopt( sockfd, IPPROTO_IP, IP_TTL, &optvalue, &optlength ); close(sockfd); return optvalue; } /* * Returns clients own IP-address. According to interface number. * */ uint32_t get_own_ip_addr(int iface_nmbr ){ struct ifreq req; int fd; char * addr; uint32_t address; char name[6]; sprintf(name, "lec%d", iface_nmbr ); memcpy(req.ifr_ifrn.ifrn_name,name,sizeof(name)); fd = socket( AF_INET, SOCK_STREAM, IPPROTO_IP ); if(fd < 0){ printf("mpcd: get_vars.c: socket creation failed.\n"); exit(1); } if(ioctl(fd,SIOCGIFADDR,&req)<0){ printf("mpcd: get_vars.c: ioctl failed: %s\n", strerror(errno)); exit(1); } addr = req.ifr_ifru.ifru_addr.sa_data; address = ((unsigned char)addr[2] << 24) | ((unsigned char)addr[3] << 16) | ((unsigned char)addr[4] << 8 ) | (unsigned char)addr[5] ; close(fd); return address; } int get_own_atm_addr(unsigned char * address){ memcpy(address,mpc_control.data_listen_addr.sas_addr.prv,ATM_ESA_LEN); return 1; } --- NEW FILE: get_vars.h --- #ifndef GET_VARS_H #define GET_VARS_H #include <linux/types.h> int get_ttl(void); uint32_t get_own_ip_addr(int iface_nmbr); int get_own_atm_addr(unsigned char *address ); #endif /* GET_VARS_H */ --- NEW FILE: lecs.c --- /* lecs.c, get MPOA configuration info from LECS */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdio.h> #include <string.h> #include <netinet/in.h> /* htons() and friends */ #include <unistd.h> #include <errno.h> #include <atm.h> #include <atmsap.h> #include <linux/atmmpc.h> /* for MPOA Device type TLV */ #include "lecs.h" #include "k_interf.h" #define MAXFRAME 1024 static int get_lecs_socket(struct sockaddr_atmsvc *sa); static int send_request(int fd, char *buff, char *lec_addr, char *elan_name); static int get_reply(int fd, char *buff, struct mpc_parameters *params); void get_mpc_config(struct sockaddr_atmsvc *sa, char *lec_addr, char *elan_name) { int s; char buff[MAXFRAME]; struct k_message msg; s = get_lecs_socket(sa); if (s < 0) return; memset(buff, 0, sizeof(buff)); if (send_request(s, buff, lec_addr, elan_name) < 0) { printf("mpcd: lecs.c: send_request failed, using defaults\n"); return; } msg.content.params.mpc_p1 = MPC_P1; msg.content.params.mpc_p2 = MPC_P2; msg.content.params.mpc_p4 = MPC_P4; msg.content.params.mpc_p5 = MPC_P5; msg.content.params.mpc_p6 = MPC_P6; if (get_reply(s, buff, &msg.content.params) < 0) { printf("mpcd: lecs.c: get_config failed, using defaults\n"); return; } msg.type = SET_MPC_PARAMS; send_to_kernel(&msg); printf("mpcd: lecs.c: get_config: about to return\n"); return; } static int send_request(int fd, char *buff, char *lec_addr, char *elan_name) { char *tmp; int retval; struct le_config_frame *frame; frame = (struct le_config_frame *)buff; frame->marker = htons(0xff00); frame->protocol = 0x01; frame->version = 0x01; frame->opcode = htons(0x0001); frame->tran_id = htonl(42); frame->flags = htons(0x002); memcpy(frame->src_atm_addr, lec_addr, ATM_ESA_LEN); frame->num_tlvs = 1; if (elan_name != NULL) { strcpy(frame->elan_name, elan_name); frame->elan_name_size = strlen(elan_name); } /* add the MPOA device type TLV */ tmp = buff + sizeof(struct le_config_frame); *(uint32_t *)tmp = htonl(TLV_MPOA_DEVICE_TYPE); tmp += 4; *tmp++ = 22; /* device type field + MPC's ATM address */ *tmp++ = MPC; *tmp++ = 0; memcpy(tmp, lec_addr, ATM_ESA_LEN); tmp += ATM_ESA_LEN; retval = write(fd, buff, tmp - buff); if (retval < 0 || retval != (tmp - buff)) return -1; return 0; } static int get_reply(int fd, char *buff, struct mpc_parameters *params) { int retval; uint32_t type; uint8_t length, *tlvs, *end_of_tlvs; struct le_config_frame *frame; retval = read(fd, buff, MAXFRAME); if (retval < 0) return -1; frame = (struct le_config_frame *)buff; if (frame->status != 0) { printf("mpcd: lecs.c: get_reply: config status %d\n", frame->status); return -1; } if (frame->num_tlvs == 0) { printf("mpcd: lecs.c: get_reply: no TLVS\n"); return -1; } tlvs = buff + sizeof(struct le_config_frame); end_of_tlvs = buff + retval; while (end_of_tlvs - tlvs >= 5 && frame->num_tlvs-- > 0) { type = (tlvs[0] << 24) | (tlvs[1] << 16) | (tlvs[2] << 8) | tlvs[3]; length = tlvs[4]; tlvs += 5; /* Sampo-Add: start */ switch(type){ case TLV_SC_SETUP_FRAME_COUNT: params->mpc_p1 = (*(tlvs+1)<<8) | (*tlvs); params->mpc_p1 = htons(params->mpc_p1); printf("mpcd: lecs.c: get_reply: MPC_p1 = %d\n",params->mpc_p1); break; case TLV_SC_SETUP_FRAME_TIME: params->mpc_p2 = (*(tlvs+1)<<8) | (*tlvs); params->mpc_p2 = htons(params->mpc_p2); printf("mpcd: lecs.c: get_reply: MPC_p2 = %d\n",params->mpc_p2); break; case TLV_FLOW_DETECTION_PROTOCOLS: memcpy(params->mpc_p3, tlvs, length); printf("mpcd: lecs.c: get_reply: MPC_p3 = %s\n",params->mpc_p3); break; case TLV_MPC_ININTIAL_RETRY_TIME: params->mpc_p4 = (*(tlvs+1)<<8) | (*tlvs); params->mpc_p4 = htons(params->mpc_p4); printf("mpcd: lecs.c: get_reply: MPC_p4 = %d\n",params->mpc_p4); break; case TLV_MPC_RETRY_TIME_MAXIMUM: params->mpc_p5 = (*(tlvs+1)<<8) | (*tlvs); params->mpc_p5 = htons(params->mpc_p5); printf("mpcd: lecs.c: get_reply: MPC_p5 = %d\n",params->mpc_p5); break; case TLV_HOLD_DOWN_TIME: params->mpc_p6 = (*(tlvs+1)<<8) | (*tlvs); params->mpc_p6 = htons(params->mpc_p6); printf("mpcd: lecs.c: get_reply: MPC_p6 = %d\n",params->mpc_p6); break; default: printf("mpcd: lecs.c: get_reply: TLV type 0x%x\n", type); break; } tlvs += length; /* Sampo-Add: end */ } if (end_of_tlvs - tlvs != 0) printf("mpcd: lecs.c: get_reply: ignoring %d bytes of trailing TLV carbage\n", end_of_tlvs - tlvs); return 1; } static int get_lecs_socket(struct sockaddr_atmsvc *sa) { int s, retval; struct atm_qos qos; struct atm_sap sap; s = socket(PF_ATMSVC, SOCK_DGRAM, 0); if (s < 0){ printf("mpcd: lecs.c: socket failed: %s\n", strerror(errno)); return -1; } memset(&qos, 0, sizeof(qos)); memset(&sap, 0, sizeof(sap)); qos.aal = ATM_AAL5; qos.txtp.traffic_class = ATM_UBR; qos.rxtp.traffic_class = ATM_UBR; qos.txtp.max_sdu = 1516; qos.rxtp.max_sdu = 1516; if (setsockopt(s, SOL_ATM,SO_ATMQOS, &qos, sizeof(qos)) < 0){ printf("mpcd: lecs.c: setsockopt SO_ATMQOS failed: %s\n", strerror(errno)); close(s); return -1; } sap.blli[0].l2_proto = ATM_L2_NONE; sap.blli[0].l3_proto = ATM_L3_TR9577; sap.blli[0].l3.tr9577.ipi = NLPID_IEEE802_1_SNAP; sap.blli[0].l3.tr9577.snap[0] = 0x00; sap.blli[0].l3.tr9577.snap[1] = 0xa0; sap.blli[0].l3.tr9577.snap[2] = 0x3e; sap.blli[0].l3.tr9577.snap[3] = 0x00; sap.blli[0].l3.tr9577.snap[4] = 0x01; if (setsockopt(s, SOL_ATM,SO_ATMSAP, &sap, sizeof(sap)) < 0) { printf("mpcd: lecs.c: setsockop SO_ATMSAP failed: %s\n", strerror(errno)); close (s); return -1; } retval = connect(s, (struct sockaddr *)sa, sizeof(struct sockaddr_atmsvc)); if (retval < 0) { printf("mpcd: lecs.c: connect failed: %s\n", strerror(errno)); close (s); return -1; } return s; } --- NEW FILE: lecs.h --- #ifndef LECS_H #define LECS_H void get_mpc_config(struct sockaddr_atmsvc *sa, char *lec_addr, char *elan_name); struct le_config_frame { uint16_t marker; uint8_t protocol; uint8_t version; uint16_t opcode; uint16_t status; uint32_t tran_id; uint16_t lecid; uint16_t flags; uint8_t src_lan[8]; uint8_t target_lan[8]; uint8_t src_atm_addr[ATM_ESA_LEN]; uint8_t lan_type; uint8_t max_frame_size; uint8_t num_tlvs; uint8_t elan_name_size; uint8_t target_atm_addr[ATM_ESA_LEN]; uint8_t elan_name[32]; /* TLVs if any */ } __attribute__ ((packed)); /* MPOA Configuration TLVs */ #define TLV_SC_SETUP_FRAME_COUNT 0x00a03e24 /* MPC_p1 */ #define TLV_SC_SETUP_FRAME_TIME 0x00a03e25 /* MPC_p2 */ #define TLV_FLOW_DETECTION_PROTOCOLS 0x00a03e26 /* MPC_p3 */ #define TLV_MPC_ININTIAL_RETRY_TIME 0x00a03e27 /* MPC_p4 */ #define TLV_MPC_RETRY_TIME_MAXIMUM 0x00a03e28 /* MPC_p5 */ #define TLV_HOLD_DOWN_TIME 0x00a03e29 /* MPC_p6 */ #endif /* LECS_H */ --- NEW FILE: main.c --- #if HAVE_CONFIG_H #include <config.h> #endif #include <stdio.h> #include <stdlib.h> #include <sys/utsname.h> #include <getopt.h> #include <time.h> #include <sys/ioctl.h> #include <atm.h> #include <linux/atmdev.h> #include <linux/atmmpc.h> #include <sys/socket.h> #include <sys/time.h> #include <string.h> #include <unistd.h> #include <errno.h> #include <atm.h> #include <linux/if_ether.h> #include <signal.h> #include "packets.h" #include "io.h" #include "k_interf.h" #include "get_vars.h" #include "lecs.h" /* * Global struct containing sockets addresses and parameters. */ struct mpc_control mpc_control; static void create_kernel_socket(int itf); static int listen_to_MPS( struct sockaddr_atmsvc ctrl_listen_addr ); static int set_mps_mac_addr(void); static void usage(const char *progname); static void signal_handler(int sig){ struct k_message msg; memset(&msg,0,sizeof(struct k_message)); if (sig == SIGHUP) msg.type = RELOAD; else msg.type = CLEAN_UP_AND_EXIT; send_to_kernel(&msg); printf("mpcd: main.c: signal_handler() signal %d\n", sig); return; } /* * Initialize our listen addresses for * the incoming/outgoing MPOA connections */ static void init_default_addresses(struct sockaddr_atmsvc *ctrl, struct sockaddr_atmsvc *data) { struct sockaddr_atmsvc sa; struct atmif_sioc req; int fd; unsigned char wellknown_lecs[ATM_ESA_LEN]; memset(wellknown_lecs,0,ATM_ESA_LEN); wellknown_lecs[0] = 0x47; wellknown_lecs[2] = 0x79; wellknown_lecs[14] = 0xa0; wellknown_lecs[15] = 0x3e; wellknown_lecs[18] = 0x01; fd = get_socket(NULL); req.number=0; req.arg=&sa; req.length=sizeof(struct sockaddr_atmsvc); if ( ioctl(fd, ATM_GETADDR, &req) <0 ){ perror("mpcd: main.c: ioctl(ATM_GETADDR)"); exit(-1); } ctrl->sas_family = AF_ATMSVC; data->sas_family = AF_ATMSVC; mpc_control.lecs_address.sas_family = AF_ATMSVC; /* ATM address for the incoming/outgoing MPOA control connections */ sa.sas_addr.prv[ATM_ESA_LEN-1] = 50; memcpy(ctrl->sas_addr.prv, sa.sas_addr.prv, ATM_ESA_LEN); memcpy(mpc_control.OWN_ATM_ADDRESS, ctrl->sas_addr.prv, ATM_ESA_LEN); memcpy(mpc_control.lecs_address.sas_addr.prv,wellknown_lecs, ATM_ESA_LEN); /* ATM address for the incoming/outgoing MPOA shortcuts */ sa.sas_addr.prv[ATM_ESA_LEN-1] = 51; memcpy(data->sas_addr.prv, sa.sas_addr.prv, ATM_ESA_LEN); close(fd); return; } int main(int argc, char **argv){ int listen_socket; int opt_ret = 0; struct k_message msg; struct sockaddr_atmsvc control_listen_addr; struct sockaddr_atmsvc mps_ctrl_addr; struct sockaddr_atmsvc lec_addr; memset(&control_listen_addr,0,sizeof(struct sockaddr_atmsvc)); memset(&mpc_control.data_listen_addr,0,sizeof(struct sockaddr_atmsvc)); memset(&lec_addr,0,sizeof(struct sockaddr_atmsvc)); memset(&mps_ctrl_addr,0,sizeof(struct sockaddr_atmsvc)); memset(&msg,0,sizeof(struct k_message)); memset(&mpc_control,0,sizeof(mpc_control)); mpc_control.elan_name[32] = '\0'; init_default_addresses(&control_listen_addr, &mpc_control.data_listen_addr); while( opt_ret != -1 ){ opt_ret = getopt(argc, argv, "h:s:l:c:L:n:C:i:m:"); switch(opt_ret) { case 'h': usage(argv[0]); exit(0); break; case 's': if(text2atm(optarg,(struct sockaddr *)&control_listen_addr, sizeof(struct sockaddr_atmsvc),T2A_SVC | T2A_NAME)<0){ printf("mpcd: main.c: text2atm failed.\n"); usage(argv[0]); exit(1); } memcpy(mpc_control.OWN_ATM_ADDRESS,control_listen_addr.sas_addr.prv, ATM_ESA_LEN); break; case 'l': if(text2atm(optarg,(struct sockaddr *)&mpc_control.data_listen_addr, sizeof(struct sockaddr_atmsvc),T2A_SVC | T2A_NAME)<0){ printf("mpcd: main.c: text2atm failed.\n"); usage(argv[0]); exit(1); } break; case 'c': if(text2atm(optarg,(struct sockaddr *)&mps_ctrl_addr, sizeof(struct sockaddr_atmsvc),T2A_SVC | T2A_NAME)<0){ printf("mpcd: main.c: text2atm failed.\n"); usage(argv[0]); exit(1); } memcpy(mpc_control.MPS_CTRL_ATM_ADDR,mps_ctrl_addr.sas_addr.prv,ATM_ESA_LEN); mpc_control.mps_ctrl_addr_set = 1; break; case 'L': if(text2atm(optarg,(struct sockaddr *)&lec_addr, sizeof(struct sockaddr_atmsvc),T2A_SVC | T2A_NAME)<0){ printf("mpcd: main.c: text2atm failed.\n"); usage(argv[0]); exit(1); } memcpy(mpc_control.LEC_ADDRESS,lec_addr.sas_addr.prv,ATM_ESA_LEN); mpc_control.use_lecs = 1; break; case 'n': strncpy(mpc_control.elan_name,optarg,33); break; case 'C': if(text2atm(optarg,(struct sockaddr *)&mpc_control.lecs_address, sizeof(struct sockaddr_atmsvc),T2A_SVC | T2A_NAME)<0){ printf("mpcd: main.c: text2atm failed.\n"); usage(argv[0]); exit(1); } break; case 'm': strncpy(mpc_control.MPS_MAC_ADDRESS,optarg,13); mpc_control.mps_mac_addr_set = 1; break; case 'i': mpc_control.INTERFACE_NUMBER = atoi(optarg); break; } } if (argc != optind) { usage(argv[0]); exit(1); } while(1){ create_kernel_socket(mpc_control.INTERFACE_NUMBER); if(mpc_control.use_lecs){ get_mpc_config(&mpc_control.lecs_address, mpc_control.LEC_ADDRESS, mpc_control.elan_name); } msg.type = SET_MPC_CTRL_ADDR; memcpy(msg.MPS_ctrl,mpc_control.OWN_ATM_ADDRESS,ATM_ESA_LEN); if (send_to_kernel(&msg) < 0) { printf("mpcd: main.c: send_to_kernel(SET_MPC_CTRL_ADDR) failed\n"); exit(1); } if(mpc_control.mps_mac_addr_set) set_mps_mac_addr(); listen_to_MPS( control_listen_addr ); if ( (listen_socket = get_listen_socket(&mpc_control.data_listen_addr)) < 0) { printf("mpcd: main.c: listen_socket creation failed\n"); exit (1); } signal(SIGHUP, signal_handler); signal(SIGINT, signal_handler); signal(SIGQUIT, signal_handler); signal(SIGABRT, signal_handler); signal(SIGTERM, signal_handler); main_loop(listen_socket); sleep(5); printf("mpcd: main.c: going back to main loop...\n"); } return 0; } static void create_kernel_socket(int itf) { mpc_control.kernel_socket = socket(PF_ATMSVC, SOCK_DGRAM, 0); if (mpc_control.kernel_socket < 0) { printf("mpcd: main.c: kernel socket creation failed: %s\n", strerror(errno)); exit (1); } if ( ioctl(mpc_control.kernel_socket, ATMMPC_CTRL, itf) < 0) { printf("mpcd: main.c: kernel socket ioctl(ATMMPC_CTRL) failed: %s\n", strerror(errno)); exit (1); } return; } static int listen_to_MPS( struct sockaddr_atmsvc ctrl_listen_addr ){ /* soketti, joka kuuntelee MPC:n Control ATM-osoitteessa */ mpc_control.MPS_listen_socket = get_listen_socket(&ctrl_listen_addr); if (mpc_control.MPS_listen_socket < 0) return -1; return 0; } static int set_mps_mac_addr(){ char *string = mpc_control.MPS_MAC_ADDRESS; struct k_message msg; unsigned char mac_addr[ETH_ALEN]; int tmp; int i = strlen(string); memset(&msg,0,sizeof(struct k_message)); if (i != 12){ printf("mpcd: main.c: incorrect mac address.\n"); exit(1); } for(i=0;i<6;i++) { sscanf(&string[i*2],"%2x",&tmp); mac_addr[i]=(unsigned char)tmp; } msg.type = SET_MPS_MAC_ADDR; memcpy(&msg.MPS_ctrl,&mac_addr,ETH_ALEN); send_to_kernel(&msg); return 0; } static void usage( const char * progname ){ printf("Usage: %s [-s our_control_listen_ATM_Address] [-l our_data_listen_address]\n" " [-c MPS_control_ATM_Address] [-i interface_number]\n" " [-m MPS_MAC_address]\n" " [-L lec_address [-n elan_name [-C lecs_address]]]\n", progname); return; } --- NEW FILE: mpcd.8 --- .TH mpcd 8 "Nov 17, 1998" "Linux" "Maintenance Commands" .SH NAME mpcd \- ATM MPOA (Multi\-Protocol Over ATM) client daemon .SH SYNOPSIS .B mpcd .B [ -s .I Control ATM address .B ] .B [ -l .I Data ATM address .B ] .B [ -c .I MPS control ATM address .B ] .B [ -i .I Interface number .B ] .B [ -m .I MPS MAC address .B ] .B [ -L .I LEC address .B [ -n .I ELAN name .B ] .B [ -C .I LECS Address .B ]] .SH DESCRIPTION MPOA client .SM(MPC) is responsible for creating and receiving internetwork layer shortcuts. Using these shortcuts MPCs forward unicast internetwork layer packets effectively over ATM without need for routing protocols. .PP .SM MPC has two roles; ingress and egress. In ingress role .SM MPC detects flows destined outside it's own subnet and tries to establish shortcuts to those destinations. In egress role .SM MPC accepts shortcuts and packets arriving on those shortcuts. Maintaining shortcuts is done with the help of .SM MPOA server .SM(MPS). .PP Just as the Linux .SM LAN Emulation client, .SM MPOA client is also divided in two parts. The parts are kernel component and a daemon process. The daemon opens and receives data shortcuts and control connections with the kernel component. The kernel component tallies packets flowing out from the .SM LANE device and makes the decision if a packet should be forwarded using .SM LANE or .SM MPOA shortcuts. .PP If the daemon is killed with .B SIGHUP it will close all the open connections, purge ingress and egress cache entries, query .SM LECS if applicable and then restart itself. .PP Linux MPOA client only supports non-LLC-muxed shortcuts. The number of supported MPOA clients is unlimited. .SH OPTIONS .IP "-s Control ATM address" Local ATM address this MPC uses for MPOA control connections. .IP "-l Data ATM address" Local ATM address from and to which MPOA shortcuts are established. .IP "-c MPS control ATM address" ATM address of MPS. Only needed if MPS can not advertise it by itself. .IP "-i Interface number" The interface number of LEC this MPC serves. E.g. 2 for "lec2". .IP "-m MPS MAC address" MAC address of default router where MPS recides. Only useful if the MPOA server fails to advertise itself. .IP "-L LEC address" Listen address of the .SM LANE client zeppelin. mpcd uses this address as its own .SM ATM address when it queries .SM LECS for .SM MPC configuration parameters. If this option is not present then mpcd .B will not use .SM LECS to query for configuration parameters. This option is normally the same as zeppelin's -l option. .IP "-n ELAN name" Name of the .SM ELAN for which mpcd asks for parameters when it connects to .SM LECS. If this option is not given, .SM LECS should respond with parameters belonging to the default .SM ELAN if one exists. This option is normally the same as zeppelin's -n option. .IP "-C LECS address" ATM address of .SM LECS mpcd asks for parameters. If this option is left empty and -L is g... [truncated message content] |
From: Paul B. S. <pa...@us...> - 2001-09-03 18:41:11
|
Update of /cvsroot/linux-atm/linux-atm/src/switch/debug In directory usw-pr-cvs1:/tmp/cvs-serv10656/switch/debug Added Files: Tag: V2_4_0 demo debug.c README Makefile.am Log Message: --- NEW FILE: demo --- #!/usr/bin/perl @cmd = ("xterm -fn 5x7 -geometry +25+400", "xterm -fn 5x7 -geometry +25+200", "xterm -fn 5x7 -geometry +450+200", "xterm -fn 5x7 -geometry +450+400", "xterm -fn 5x7 -geometry 132x24+110+0", "xterm -fn 5x7 -geometry +475+600", "xterm -fn 5x7 -geometry +0+600"); open(IN,"README") || die "open README: $!"; while (<IN>) { if (/^---\s*(\S+)\s*/) { if ($mode eq "F") { close OUT || die "close: $!"; } open(OUT,">$1") || die "create $1: $!"; $mode = "F"; next; } if (/^Preparation/) { $mode = "P"; next; } if (/^Start/) { $mode = "S"; next; } if ($mode eq "P") { chop; $_ .= " &" if /-l/; push(@do,$') if /^\s*#\s*/; next; } if ($mode eq "S") { chop; next unless /^\s*%\s*/; $c = $'; $c =~ s/-b/-d -l stderr/; $c =~ s/isp/isp -v/; $o = $c; $c = "sh -c \"$c; sleep 300\"" if $c =~ /isp/; push(@do,shift(@cmd)." -T '$o' -e $c &"); next; } if ($mode eq "F") { print OUT $_ || die "write: $!"; } } if ($mode eq "F") { close OUT || die "close: $!"; } for (@do) { print "$_\n"; system($_); sleep(1); } --- NEW FILE: debug.c --- /* debug.c - Simple debugging "switch" */ /* Written 1998-2000 by Werner Almesberger, EPFL DI-ICA */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdlib.h> #include <atm.h> #include <atmd.h> #include "uni.h" #include "../fab.h" #define COMPONENT "FAB(debug)" #define PRV(call) ((FAB *) (call)->fab) typedef struct _fab { CALL *next; /* relay.c may not keep track of calls, but WE are */ } FAB; static CALL *calls; void fab_option(const char *name,const char *value) { diag(COMPONENT,DIAG_FATAL,"unrecognized fabric option \"%s\"",name); } void fab_start(void (*port_notify)(int number,int up)) { sig_start_all(port_notify); } void fab_init(CALL *call) { PRV(call) = alloc_t(FAB); PRV(call)->next = calls; calls = call; } void fab_destroy(CALL *call) { CALL **walk; for (walk = &calls; *walk; walk = &PRV(*walk)->next) if (*walk == call) break; if (!*walk) diag(COMPONENT,DIAG_FATAL,"fab_destroy: call %p not found",call); *walk = PRV(call)->next; free(PRV(call)); PRV(call) = NULL; } /* * This function is rather simple-minded, because it only considers a single * port. Should go directly to the fabric control. @@@ */ static int vci_exists(int vci,int threshold) { CALL *call; int found; found = 0; for (call = calls; call; call = PRV(call)->next) if (call->in.pvc.sap_addr.vci == vci || call->out.pvc.sap_addr.vci == vci) if (++found > threshold) return 1; return 0; } static int check_ci(struct sockaddr_atmpvc *pvc) { int vci; if (pvc->sap_addr.vpi == ATM_VPI_ANY) pvc->sap_addr.vpi = 0; /* that was easy :-) */ for (vci = ATM_NOT_RSV_VCI; pvc->sap_addr.vci == ATM_VCI_ANY; vci++) if (!vci_exists(vci,0)) pvc->sap_addr.vci = vci; return !vci_exists(vci,1); } void fab_op(CALL *call,int op,const struct atm_qos *qos, void (*callback)(CALL *call,int cause,void *more,void *user),void *user) { diag(COMPONENT,DIAG_INFO,"fab_op%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", !op ? " FREE" : "",op & RM_RSV(_RM_ANY) ? " RM_RSV:" : "", op & RM_IN_TX ? " IN_TX" : "",op & RM_IN_RX ? " IN_RX" : "", op & RM_OUT_TX ? " OUT_TX" : "",op & RM_OUT_RX ? " OUT_RX" : "", op & RM_PATH_TX ? " PATH_TX" : "",op & RM_PATH_RX ? " PATH_RX" : "", op & RM_CLAIM(_RM_ANY) ? " RM_CLAIM:" : "", op & _RM_SHIFT(RM_IN_TX) ? " IN_TX" : "", op & _RM_SHIFT(RM_IN_RX) ? " IN_RX" : "", op & _RM_SHIFT(RM_OUT_TX) ? " OUT_TX" : "", op & _RM_SHIFT(RM_OUT_RX) ? " OUT_RX" : "", op & _RM_SHIFT(RM_PATH_TX) ? " PATH_TX" : "", op & _RM_SHIFT(RM_PATH_RX) ? " PATH_RX" : ""); if (op & (RM_RSV(RM_IN) | RM_CLAIM(RM_IN))) if (!check_ci(&call->in.pvc)) { callback(call,ATM_CV_CI_UNAVAIL,NULL,user); return; } if (op & (RM_RSV(RM_OUT) | RM_CLAIM(RM_OUT))) if (!check_ci(&call->out.pvc)) { callback(call,ATM_CV_CI_UNAVAIL,NULL,user); return; } callback(call,0,NULL,user); } --- NEW FILE: README --- This is a little sample configuration with two terminals connected to a switch. All of the network elements are on the same host and atmtcp takes care of the the real kernel with multiple terminals on the same machine. At least not yet.) Note that no data transfer or such is possible yet. This is only signaling. This is the example setup: +-------+ +------+ +-------+ | isp | |switch| | isp | |atmsigd|-----| |-----|atmsigd| +-------+ +------+ +-------+ Preparation (only once): # atmtcp virtual 1 listen-bg 8412 # atmtcp virtual 2 connect localhost 8412 bg # atmtcp virtual 3 listen-bg 8434 # atmtcp virtual 4 connect localhost 8434 bg # atmaddr -a 1 +123 Start the "network" (no privileges required): % atmsigd -b 1.0.105 /tmp/1 % atmsigd -b -m switch 2.0.105 /tmp/2 % atmsigd -b -m switch 3.0.105 /tmp/3 % atmsigd -b 4.0.105 /tmp/4 % ./sw_debug -d % isp /tmp/4 <4.isp % isp /tmp/1 <1.isp In more detail: +------------------------------------------+ | ./sw_debug | +------------------------------------------+ | | /tmp/2 /tmp/3 | | +----------------------------------+ +----------------------------------+ | atmsigd -m switch 2.0.105 /tmp/2 | | atmsigd -m switch 3.0.105 /tmp/3 | +----------------------------------+ +----------------------------------+ | | itf 2 | | | +--------------------------------------------+ | | atmtcp virtual 2 connect localhost 8412 bg | | +--------------------------------------------+ | | atmtcp virtual 1 listen-bg 8412 | | +--------------------------------------------+ itf 3 | | itf 1 +--------------------------------------------+ | | atmtcp virtual 3 listen-bg 8434 | | +--------------------------------------------+ | | atmtcp virtual 4 connect localhost 8434 bg | | +--------------------------------------------+ | | | itf 4 | | +------------------------+ +------------------------+ | atmsigd 1.0.105 /tmp/1 | | atmsigd 4.0.105 /tmp/4 | +------------------------+ +------------------------+ | | /tmp/1 /tmp/4 | | +-------------------+ +-------------------+ | isp /tmp/1 <1.isp | | isp /tmp/4 <4.isp | +-------------------+ +-------------------+ You can use the script "demo" to run this setup. You need to build the switch library and the debug switch first: cd ..; make cd debug; make --- switch.conf -------------------------------------------------------------- socket /tmp/2 { itf 2 2.0.5 route +1 } socket /tmp/3 { itf 3 2.0.5 default } --- 1.isp -------------------------------------------------------------------- send connect vcc=1 svc=+234 local=+123 qos=ubr,aal5 receive okay vcc=1 send close vcc=1 receive close vcc=1 --- 4.isp -------------------------------------------------------------------- send listen vcc=1 svc=+234 qos=ubr,aal5 receive okay vcc=1 receive indicate listen_vcc=1 send accept vcc=2 listen_vcc=1 receive okay vcc=2 receive close vcc=2 send close vcc=2 --- NEW FILE: Makefile.am --- noinst_PROGRAMS = sw_debug INCLUDES = -I$(top_builddir)/src/qgen sw_debug_SOURCES = debug.c sw_debug_XTRAS = $(top_builddir)/src/switch/libsw.a \ $(top_builddir)/src/lib/libatmd.la \ $(top_builddir)/src/lib/libatm.la sw_debug_LDADD = $(sw_debug_XTRAS) -lfl sw_debug_DEPENDENCIES = $(sw_debug_XTRAS) EXTRA_DIST = demo README |
From: Paul B. S. <pa...@us...> - 2001-09-03 18:41:10
|
Update of /cvsroot/linux-atm/linux-atm/src/switch In directory usw-pr-cvs1:/tmp/cvs-serv10656/switch Added Files: Tag: V2_4_0 relay.c fab.h sig.c sig.h swc.c swc.h README route.c route.h control.c Makefile.am dispatch.c dispatch.h cfg_l.l cfg_y.y proto.c proto.h Log Message: --- NEW FILE: relay.c --- /* switch.c - Handles signaling an ATM switch */ /* Written 1997-1998 by Roman Pletka, EPFL SSC */ /* Modified 1998-2000 by Werner Almesberger, EPFL ICA */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <errno.h> #include <atm.h> #include "atmd.h" #include "fab.h" #include "dispatch.h" #include "sig.h" #include "route.h" #include "proto.h" #define COMPONENT "RELAY" #define CONFIG_FILE "switch.conf" extern int yyparse(void); extern FILE *yyin; static void from_fab(CALL *call,int cause,void *more,void *user) { printf("%p: fab returns cause %d\n",call,cause); print_call(call); switch (call->state) { case cs_indicated: if (!cause) { /* send connect to called and enter state cs_rm_accepted */ send_identify(call); send_connect(call); new_state(call,cs_rm_accepted); } else { /* send as_reject to caller and enter state cs_invalid */ send_reject_not_id(call->in.sig,-EREMOTEIO); /* @@@ use cause*/ new_state(call,cs_invalid); free_call(call); } break; case cs_called_accepted: if (!cause) { /* send accept to caller */ send_accept(call); new_state(call,cs_rm_accepted2); } else { /* send reject to caller and close to called */ send_reject(call,-EREMOTEIO); /* @@@ use cause */ send_close(call,CALLED); new_state(call,cs_rejected); } break; case cs_rejecting: if (cause) free_call(call); else { /* free resources */ new_state(call, cs_free_rm); fab_op(call,RM_FREE,NULL,from_fab,NULL); } break; case cs_free_rm: if (cause) printf("Error: RM couldn't free resources\n"); free_call(call); break; default: diag(COMPONENT,DIAG_FATAL,"invalid state for fab callback"); break; } } static void from_caller(CALL *call,struct atmsvc_msg *msg) { switch (call->state) { case cs_rm_accepted2: /* msg from: caller(error,okay) or called(close) */ switch(msg->type) { case as_okay: /* complete the call */ new_state(call, cs_connected); return; case as_error: /* send close called */ send_close(call, CALLED); new_state(call, cs_caller_error); return; default: break; } break; case cs_connected: if (msg->type != as_close) break; send_close(call, CALLER); send_close(call, CALLED); new_state(call, cs_caller_closed); return; case cs_called_closed: switch(msg->type) { case as_error: new_state(call, cs_free_rm); fab_op(call,RM_FREE,NULL,from_fab,NULL); break; case as_okay: send_close(call, CALLER); new_state(call, cs_caller_closing); break; default: break; } break; case cs_called_closed2: case cs_caller_closing: if (msg->type != as_close) break; new_state(call, cs_free_rm); fab_op(call,RM_FREE,NULL,from_fab,NULL); return; default: break; } diag(COMPONENT,DIAG_FATAL,"invalid combination"); } static void from_called(CALL *call,struct atmsvc_msg *msg) { switch (call->state) { case cs_rm_accepted: switch(msg->type) { case as_okay: /* save msg content in call */ call->out.qos = msg->qos; new_state(call,cs_called_accepted); fab_op(call,RM_CLAIM(_RM_ANY),&msg->qos,from_fab,NULL); return; case as_error: send_reject(call,msg->reply); new_state(call,cs_invalid); free_call(call); return; default: break; } break; case cs_rm_accepted2: /* msg from: caller(error,okay) or called(close) */ if (msg->type != as_close) break; /* send close to called */ send_close(call, CALLED); new_state(call, cs_called_closed); return; case cs_rejected: /* wait for close msg from called */ if (msg->type != as_close) break; free_call(call); return; case cs_called_accepted: if (msg->type != as_close) break; /* send reject to caller and send close to called */ send_reject(call, msg->reply); send_close(call,CALLED); new_state(call,cs_rejecting); return; case cs_connected: if (msg->type != as_close) break; send_close(call, CALLER); send_close(call, CALLED); new_state(call, cs_called_closed2); return; case cs_caller_error: case cs_caller_closed: if (msg->type != as_close) break; new_state(call, cs_free_rm); fab_op(call,RM_FREE,NULL,from_fab,NULL); return; default: break; } diag(COMPONENT,DIAG_FATAL,"invalid combination"); } static void from_listening(SIGNALING_ENTITY *sig,struct atmsvc_msg *msg) { SIGNALING_ENTITY *out; CALL *call; /* try to find a route */ out = find_route(&msg->svc,&msg->local,&msg->qos); if (!out) { send_reject_not_id(sig,-EHOSTUNREACH); return; } /* now work starts... */ call = new_call(); /* set up caller side */ call->in.sig = sig; if (atmpvc_addr_in_use(msg->pvc)) call->in.pvc = msg->pvc; else { call->in.pvc.sap_addr.itf = sig->itf; call->in.pvc.sap_addr.vpi = ATM_VPI_ANY; call->in.pvc.sap_addr.vci = ATM_VCI_ANY; } call->in.pvc.sap_family = AF_ATMPVC; call->in.svc = msg->svc; call->in.qos = msg->qos; /* set up what little we know about the called side */ call->out.sig = out; call->out.pvc.sap_family = AF_ATMPVC; call->out.pvc.sap_addr.itf = out->itf; call->out.pvc.sap_addr.vpi = ATM_VPI_ANY; call->out.pvc.sap_addr.vci = ATM_VCI_ANY; call->out.svc = msg->local; call->sap = msg->sap; new_state(call,cs_indicated); fab_op(call,RM_RSV(_RM_ANY),&msg->qos,from_fab,NULL); /* * This is bogus. txtp and rxtp are exchanged on the input and the output * side. This can be fixed by defining txtp/rxtp as meaning "forward" and * "backward", respectively, in the switch. I guess that's what I'll do. */ } int from_sigd(SIGNALING_ENTITY *sig,struct atmsvc_msg *msg) { if (msg->type == as_indicate) from_listening(sig,msg); else { CALL *call; unsigned long source; call = demux_in(&source,msg); print_msg(msg,call,source); print_call(call); switch (source) { case CALLER: from_caller(call,msg); break; case CALLED: from_called(call,msg); break; default: diag(COMPONENT,DIAG_FATAL,"unrecognized source %d\n",source); } } return 0; } /*****************************************************************************/ /* M A I N */ /*****************************************************************************/ static void usage(const char *name) { fprintf(stderr,"usage: %s [ -b ] [ -c config_file ] [ -d ]\n",name); exit(1); } int main(int argc, char *argv[]) { const char *config_file; int background; int c; background = 0; config_file = CONFIG_FILE; while ((c = getopt(argc,argv,"bc:d")) != EOF) switch (c) { case 'b': background = 1; break; case 'c': config_file = optarg; break; case 'd': set_verbosity(NULL,DIAG_DEBUG); break; default: usage(argv[0]); } if (argc != optind) usage(argv[0]); dsp_init(); /* initialize dispatcher */ /* * Later: call fab_something to scan all ports and launch atmsigds. * For now, everything is handled by static configuration. */ if (!(yyin = fopen(config_file,"r"))) diag(COMPONENT,DIAG_FATAL,"%s: %s",config_file,strerror(errno)); if (yyparse()) diag(COMPONENT,DIAG_FATAL,"Error in config file. - Aborting."); fab_start(sig_notify); if (background) { pid_t pid; pid = fork(); if (pid < 0) diag(COMPONENT,DIAG_FATAL,"fork: %s",strerror(errno)); if (pid) { diag(COMPONENT,DIAG_DEBUG,"Backgrounding (PID %d)",pid); exit(0); } } while (1) dsp_poll(); } --- NEW FILE: fab.h --- /* fab.h - Generic switch fabric interface */ /* Written 1997,1998 by Werner Almesberger, EPFL DI-ICA */ #ifndef _FAB_H #define _FAB_H #include "proto.h" #define RM_FREE 0 #define RM_IN_TX 1 #define RM_IN_RX 2 #define RM_IN (RM_IN_TX | RM_IN_RX) #define RM_OUT_TX 4 #define RM_OUT_RX 8 #define RM_OUT (RM_OUT_TX | RM_OUT_RX) #define RM_PATH_TX 16 #define RM_PATH_RX 32 #define RM_PATH (RM_PATH_TX | RM_PATH_RX) #define _RM_ANY (RM_IN | RM_OUT | RM_PATH) #define _RM_SHIFT(what) ((what) << 6) #define _RM_UNSHIFT(what) ((what) >> 6) #define RM_RSV(what) (what) #define RM_CLAIM(what) _RM_SHIFT(what) /* --- Provided by fabric control ------------------------------------------ */ /* * fab_option passes an option name/value pair from the configuration file to * the fabric control. fab_option is invoked once for each "option" clause in * the configuration file. All invocations of fab_option occur before * fab_start. */ void fab_option(const char *name,const char *value); /* * Initialize the fabric interface. The fabric control invokes port_notify * whenever a port is added to or removed from the switch. fab_start may * invoke port_notify before returning. port_notify(X,0) most not be invoked * until all fab_ops on that port have completed. */ void fab_start(void (*port_notify)(int number,int up)); /* * Initialize the fabric-specific part of a call structure, i.e. allocate a * fab-specific descriptor and attach it to call->fab. This function is called * before the first fab_op or fab_destroy. */ void fab_init(CALL *call); /* * Destroy the fab-specific part of a call structure. This function is only * invoked once per call and only after any pending fab_op has completed. */ void fab_destroy(CALL *call); /* * Allocate/change resources and set up paths in the switch fabric. fab_op may * be requested to operate on several parts of a call (i.e. the incoming side, * the outgoing side, or the path through the switch fabric) at the same time. * Internal scheduling is left to fab_op. Upon completion, fab_op invokes the * callback function (once). fab_op may invoke the callback function before * returning. Only one fab_op may be in progress at a time for a call, but any * number of concurrent calls can be processed. */ void fab_op(CALL *call,int op,const struct atm_qos *qos, void (*callback)(CALL *call,int cause,void *more,void *user),void *user); #endif --- NEW FILE: sig.c --- /* sig.c - signaling entity handling */ /* Written 1998 by Werner Almesberger, EPFL ICA */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdlib.h> #include <unistd.h> #include <string.h> #include <errno.h> #include <stdint.h> #include <linux/atmsvc.h> #include "atmd.h" #include "dispatch.h" #include "proto.h" #include "sig.h" #include "route.h" #include "fab.h" #define COMPONENT "SIG" static SIGNALING_ENTITY *entities = NULL; static int sig_check_listen(SIGNALING_ENTITY *sig,struct atmsvc_msg *msg) { return msg->type == as_okay ? 0 : msg->reply; } static int sig_recv(SIGNALING_ENTITY *sig, int (*handler)(SIGNALING_ENTITY *sig,struct atmsvc_msg *msg)) { char buf[sizeof(struct atmsvc_msg)+1]; int len; len = read(sig->s,buf,sizeof(buf)); if (len == sizeof(struct atmsvc_msg)) return handler(sig,(struct atmsvc_msg *) buf); if (len < 0) diag(COMPONENT,DIAG_ERROR,"read isp msg: %s",strerror(errno)); else diag(COMPONENT,DIAG_ERROR,"bad isp msg: %d != %d",len, sizeof(struct atmsvc_msg)); return -1; } static void sig_data(int fd,void *sig) { (void) sig_recv(sig,from_sigd); } SIGNALING_ENTITY *sig_vc(const char *command,const char *path,int itf) { SIGNALING_ENTITY *sig; sig = alloc_t(SIGNALING_ENTITY); sig->command = command; sig->path = path; sig->pvc.sap_addr.itf = -1; sig->itf = itf; sig->next = entities; entities = sig; return sig; } void sig_send(SIGNALING_ENTITY *sig,struct atmsvc_msg *msg) { int len; len = write(sig->s,msg,sizeof(*msg)); if (len == sizeof(*msg)) return; if (len < 0) diag(COMPONENT,DIAG_ERROR,"write isp msg: %s",strerror(errno)); else diag(COMPONENT,DIAG_ERROR,"bad isp msg write: %d != %d",len, sizeof(*msg)); } static void up_callback(CALL *call,int cause,void *more,void *user) { SIGNALING_ENTITY *sig = user; int error; if (cause) { diag(COMPONENT,DIAG_ERROR,"up_callback: error (cause %d)",cause); return; } if (sig->command) system(sig->command); sig->s = un_attach(sig->path); if (sig->s < 0) diag(COMPONENT,DIAG_FATAL,"un_attach %s: %s",sig->path,strerror(errno)); send_listen(sig); error = sig_recv(sig,sig_check_listen); if (error) diag(COMPONENT,DIAG_FATAL,"listen failed: %s",strerror(error)); dsp_fd_add(sig->s,sig_data,sig); route_sig(sig,&sig->call->out.pvc,1); } static void remove_entity(SIGNALING_ENTITY *sig) { struct atmsvc_msg msg; msg.type = as_terminate; sig_send(sig,&msg); dsp_fd_remove(sig->s); (void) close(sig->s); } static void down_callback(CALL *call,int cause,void *more,void *user) { if (cause) diag(COMPONENT,DIAG_ERROR,"down_callback: error (cause %d)",cause); } void sig_notify(int itf,int up) { SIGNALING_ENTITY *sig; for (sig = entities; sig; sig = sig->next) if (sig->itf == itf) break; if (!sig) { diag(COMPONENT,DIAG_ERROR,"%s notification for unknown interface %d", up ? "up" : "down",itf); return; } if (sig->pvc.sap_addr.itf == -1) return; if (up) { struct atm_qos qos; sig->call = new_call(); sig->call->in.pvc = sig->pvc; sig->call->out.pvc.sap_addr.itf = sig->itf; sig->call->out.pvc.sap_addr.vpi = 0; sig->call->out.pvc.sap_addr.vci = 5; memset(&qos,0,sizeof(qos)); qos.txtp.traffic_class = qos.rxtp.traffic_class = ATM_UBR; fab_op(sig->call,RM_CLAIM(_RM_ANY),&qos,up_callback,sig); } else { route_sig(sig,&sig->call->out.pvc,0); remove_entity(sig); fab_op(sig->call,RM_FREE,NULL,down_callback,NULL); free_call(sig->call); } } void sig_start_all(void (*port_notify)(int number,int up)) { SIGNALING_ENTITY *sig; for (sig = entities; sig; sig = sig->next) { sig->call = NULL; up_callback(NULL,0,NULL,sig); } } --- NEW FILE: sig.h --- /* sig.h - signaling entity handling */ /* Written 1998-2000 by Werner Almesberger, EPFL ICA */ #ifndef SIG_H #define SIG_H #include <atm.h> #include <linux/atmsvc.h> typedef struct _signaling_entity { int s; /* socket */ const char *command; /* command to start sigd; NULL if none */ const char *path; /* path to the Unix domain socket */ struct sockaddr_atmpvc pvc; /* signaling VC; itf = -1 if not used */ short itf; /* interface we manage */ struct _signaling_entity *next; struct _call *call; /* used to route VCI 5 to signaling */ } SIGNALING_ENTITY; SIGNALING_ENTITY *sig_vc(const char *command,const char *path,int itf); void sig_send(SIGNALING_ENTITY *sig,struct atmsvc_msg *msg); void sig_notify(int itf,int up); /* * sig_start can be called by fab_start if fab_start has no knowledge of * ports, e.g. if ports are virtual and pre-configured. */ void sig_start_all(void (*port_notify)(int number,int up)); #endif --- NEW FILE: swc.c --- /* swc.c - User switch control */ /* 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 <string.h> #include <errno.h> #include <atm.h> #include <atmd.h> #include "swc.h" static void dialog(int s,SWC_MSG *msg) { int size; size = write(s,msg,sizeof(*msg)); if (size < 0) { perror("write"); exit(1); } if (size != sizeof(*msg)) { fprintf(stderr,"bad write: %d != %d\n",size,sizeof(*msg)); exit(1); } size = read(s,msg,sizeof(*msg)); if (size < 0) { perror("read"); exit(1); } if (size != sizeof(*msg)) { fprintf(stderr,"bad read: %d != %d\n",size,sizeof(*msg)); exit(1); } } static void usage(const char *name) { fprintf(stderr,"usage: %s <socket> <command>\n",name); fprintf(stderr," commands: show\n"); fprintf(stderr," add <in_pvc> <out_pvc> [<qos>]\n"); fprintf(stderr," del <in_pvc> <out_pvc>\n"); exit(1); } int main(int argc,const char **argv) { char buffer[MAX_ATM_ADDR_LEN+1]; SWC_MSG msg; int s; if (argc < 3) usage(*argv); s = un_attach(argv[1]); if (s < 0) { perror(argv[1]); return 1; } memset(&msg,0,sizeof(msg)); if (!strcmp(argv[2],"show")) { if (argc != 3) usage(*argv); msg.type = smt_get; msg.n = 0; while (1) { dialog(s,&msg); if (msg.type != smt_get) { fprintf(stderr,"unexpeced message type %d != %d\n",msg.type, smt_get); } if (msg.n < 0) return 0; if (msg.in.sap_addr.vci != ATM_VCI_UNSPEC) printf("VC "); else { printf("VP "); msg.out.sap_addr.vci = ATM_VCI_UNSPEC; } if (atm2text(buffer,sizeof(buffer),(struct sockaddr *) &msg.in, A2T_PRETTY) < 0) strcpy(buffer,"<invalid>"); printf("%s %c-%c ",buffer,msg.qos.rxtp.traffic_class ? '<' : '-', msg.qos.txtp.traffic_class ? '>' : '-'); if (atm2text(buffer,sizeof(buffer),(struct sockaddr *) &msg.out, A2T_PRETTY) < 0) strcpy(buffer,"<invalid>"); printf("%s\n",buffer); msg.n++; } } if (!strcmp(argv[2],"add")) { msg.type = smt_add; msg.qos.txtp.traffic_class = msg.qos.rxtp.traffic_class = ATM_UBR; msg.qos.aal = ATM_AAL5; if (argc == 6) { if (text2qos(argv[5],&msg.qos,0) < 0) { fprintf(stderr,"invalid QOS specification: %s\n",argv[5]); return 1; } } else if (argc != 5) usage(*argv); } else if (!strcmp(argv[2],"del")) { if (argc != 5) usage(*argv); msg.type = smt_del; } else usage(*argv); if (text2atm(argv[3],(struct sockaddr *) &msg.in,sizeof(msg.in), T2A_PVC | T2A_UNSPEC | T2A_NAME) < 0) { fprintf(stderr,"invalid PVC address: %s\n",argv[3]); return 1; } if (text2atm(argv[4],(struct sockaddr *) &msg.out,sizeof(msg.out), T2A_PVC | T2A_UNSPEC | T2A_NAME) < 0) { fprintf(stderr,"invalid PVC address: %s\n",argv[4]); return 1; } dialog(s,&msg); if (msg.n < 0) { fprintf(stderr,"%s\n",strerror(-msg.n)); return 1; } return 0; } --- NEW FILE: swc.h --- /* swc.h - Switch control interface */ /* Written 1998 by Werner Almesberger, EPFL ICA */ #ifndef SWC_H #define SWC_H #include <atm.h> typedef enum { smt_invalid, /* catch uninitialized variables */ smt_get, /* get/return n-th entry */ smt_add, /* add one-way VC */ smt_del /* remove one-way VC */ } SWC_MSG_TYPE; typedef struct swc_msg { SWC_MSG_TYPE type; /* message type */ int n; /* index (for tmt_get) and error code (for tmt_get, tmt_set, tmt_del) */ struct sockaddr_atmpvc in; struct sockaddr_atmpvc out; struct atm_qos qos; /* currently unused */ } SWC_MSG; extern void control_init(const char *path); #endif --- NEW FILE: README --- Switch fabric control. The actual switch interfaces are in the following subdirectories: debug/ a very simple debugging switch tcp/ an ATMTCP switch, based on sw_debug See the README in the respective directory for further details. --- NEW FILE: route.c --- /* route.c - ATM switch routing database */ /* Written 1998 by Werner Almesberger, EPFL ICA */ #if HAVE_CONFIG_H #include <config.h> #endif #include <limits.h> #include "atm.h" #include "atmd.h" #include "route.h" #define COMPONENT "ROUTE" typedef struct _route { struct sockaddr_atmsvc addr; int mask; SIGNALING_ENTITY *sig; struct _route *next; } ROUTE; static ROUTE *routes = NULL; void put_route(struct sockaddr_atmsvc *addr,int addr_mask,SIGNALING_ENTITY *sig) { ROUTE *route; for (route = routes; route; route = route->next) if (route->mask == addr_mask && (!addr_mask || atm_equal((struct sockaddr *) addr, (struct sockaddr *) &route->addr,addr_mask, AXE_PRVOPT | (addr_mask == INT_MAX ? 0 : AXE_WILDCARD)))) diag(COMPONENT,DIAG_FATAL,"duplicate route"); route = alloc_t(ROUTE); if (addr) route->addr = *addr; route->mask = addr_mask; route->sig = sig; route->next = routes; routes = route; } void get_routes(SIGNALING_ENTITY *sig, void (*callback)(struct sockaddr_atmsvc *addr,int addr_mask,void *user), void *user) { ROUTE *route; for (route = routes; route; route = route->next) if (route->sig == sig) callback(&route->addr,route->mask,user); } static SIGNALING_ENTITY *dfl_find_route(struct sockaddr_atmsvc *from, struct sockaddr_atmsvc *to,struct atm_qos *qos) { ROUTE *best,*route; int best_len; best = NULL; best_len = -1; for (route = routes; route; route = route->next) if (route->mask > best_len && (!route->mask || atm_equal((struct sockaddr *) to,(struct sockaddr *) &route->addr, route->mask, AXE_PRVOPT | (route->mask == INT_MAX ? 0 : AXE_WILDCARD)))) { if (route->mask == INT_MAX) return route->sig; best_len = route->mask; best = route; } return best->sig; } static void dfl_route_sig(SIGNALING_ENTITY *sig,struct sockaddr_atmpvc *pvc, int up) { /* do nothing */ } SIGNALING_ENTITY *(*find_route)(struct sockaddr_atmsvc *from, struct sockaddr_atmsvc *to,struct atm_qos *qos) = &dfl_find_route; void (*route_sig)(SIGNALING_ENTITY *sig,struct sockaddr_atmpvc *pvc,int up) = &dfl_route_sig; --- NEW FILE: route.h --- /* route.h - ATM switch routing database */ /* Written 1998 by Werner Almesberger, EPFL ICA */ #ifndef ROUTE_H #define ROUTE_H #include "atm.h" #include "sig.h" /* * PUT_ROUTE is invoked during configuration time to add static routes. */ void put_route(struct sockaddr_atmsvc *addr,int addr_mask, SIGNALING_ENTITY *sig); /* * GET_ROUTES can be invoked to obtain static routes of a signaling entity. A * non-default routing mechanism may call GET_ROUTES from ROUTE_SIG to retrieve * pre-configured static routes. */ void get_routes(SIGNALING_ENTITY *sig, void (*callback)(struct sockaddr_atmsvc *addr,int addr_mask,void *user), void *user); /* * FIND_ROUTE obtains the signaling entity for calls from FROM to TO with the * QoS QOS. The default implementation only considers FROM for its routing * decisions. */ extern SIGNALING_ENTITY *(*find_route)(struct sockaddr_atmsvc *from, struct sockaddr_atmsvc *to,struct atm_qos *qos); /* * ROUTE_SIG is invoked whenever a signaling entity becomes operational * (UP != 0) or when it is shut down (UP == 0). This can be used to initate * routing protocol activities. */ extern void (*route_sig)(SIGNALING_ENTITY *sig,struct sockaddr_atmpvc *pvc, int up); #endif --- NEW FILE: control.c --- /* control.c - User control command processing */ /* Written 1998 by Werner Almesberger, EPFL ICA */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdlib.h> #include <string.h> #include <errno.h> #include <atm.h> #include <atmd.h> #include "fab.h" #include "dispatch.h" #include "swc.h" #define COMPONENT "COMMAND" typedef struct _user_call { CALL call; struct _user_call *next; } USER_CALL; typedef struct { USER_CALL *u_call; UN_CTX un_ctx; } CONTEXT; static int s_control = -1; static USER_CALL *calls = NULL; static USER_CALL *find_call(const struct sockaddr_atmpvc *in, const struct sockaddr_atmpvc *out) { USER_CALL *u_call; for (u_call = calls; u_call; u_call = u_call->next) if (atm_equal((struct sockaddr *) in, (struct sockaddr *) &u_call->call.in.pvc,0,0) && atm_equal((struct sockaddr *) out, (struct sockaddr *) &u_call->call.out.pvc,0,0)) break; return u_call; } static void add_cb(CALL *call,int cause,void *more,void *user) { CONTEXT *context = user; SWC_MSG msg; USER_CALL **walk; memset(&msg,0,sizeof(msg)); msg.type = smt_add; msg.n = cause ? -EIO : 0; /* @@@ */ if (cause) free(context->u_call); else { for (walk = &calls; *walk && *walk; walk = &(*walk)->next); *walk = context->u_call; } if (un_send(&context->un_ctx,&msg,sizeof(msg)) < 0) diag(COMPONENT,DIAG_ERROR,"control_msg: un_send: %s",strerror(errno)); } static void del_cb(CALL *call,int cause,void *more,void *user) { CONTEXT *context = user; SWC_MSG msg; USER_CALL **walk; memset(&msg,0,sizeof(msg)); msg.type = smt_del; msg.n = cause ? -EIO : 0; /* @@@ */ if (!cause) { for (walk = &calls; *walk && *walk != context->u_call; walk = &(*walk)->next); if (!*walk) diag(COMPONENT,DIAG_FATAL,"del_cb: call %p not found", context->u_call); *walk = (*walk)->next; free(context->u_call); } if (un_send(&context->un_ctx,&msg,sizeof(msg)) < 0) diag(COMPONENT,DIAG_ERROR,"control_msg: un_send: %s",strerror(errno)); } static void control_msg(int sock,void *dummy) { CONTEXT context; SWC_MSG msg; USER_CALL *u_call; int len,i; len = un_recv(&context.un_ctx,s_control,&msg,sizeof(msg)); if (len < 0) { diag(COMPONENT,DIAG_ERROR,"control_msg: un_recv: %s",strerror(errno)); return; } if (len != sizeof(SWC_MSG)) diag(COMPONENT,DIAG_FATAL,"control_msg: bad length (%d != %d)",len, sizeof(SWC_MSG)); switch (msg.type) { case smt_get: /* * This code only shows VCs set up using the manual configuration * interface. Any VCs set up by signaling are invisible. To fix * this we'll need a "list fabric" function in the fabric-specific * part. (The relay doesn't maintain a list of active connections, * nor should it.) */ i = msg.n; for (u_call = calls; i && u_call; u_call = u_call->next) i--; if (!u_call) { msg.n = -ENOENT; break; } msg.in = u_call->call.in.pvc; msg.out = u_call->call.out.pvc; msg.qos = u_call->call.out.qos; break; case smt_add: u_call = find_call(&msg.in,&msg.out); if (u_call) { msg.n = -EEXIST; break; } u_call = alloc_t(USER_CALL); memset(u_call,0,sizeof(USER_CALL)); u_call->call.in.pvc = msg.in; u_call->call.out.pvc = msg.out; fab_init(&u_call->call); context.u_call = u_call; fab_op(&u_call->call,RM_CLAIM(_RM_ANY) | RM_RSV(_RM_ANY),&msg.qos, add_cb,&context); return; case smt_del: u_call = find_call(&msg.in,&msg.out); if (!u_call) { msg.n = -ENOENT; break; } context.u_call = u_call; fab_op(&u_call->call,RM_FREE,NULL,del_cb,&context); return; default: diag(COMPONENT,DIAG_FATAL,"control_msg: unknown message type %d", msg.type); } if (un_send(&context.un_ctx,&msg,sizeof(msg)) < 0) diag(COMPONENT,DIAG_ERROR,"control_msg: un_send: %s",strerror(errno)); } void control_init(const char *path) { if (s_control != -1) diag(COMPONENT,DIAG_FATAL,"control channel is already set"); s_control = un_create(path,0600); if (s_control < 0) diag(COMPONENT,DIAG_FATAL,"un_create: %s",strerror(errno)); dsp_fd_add(s_control,control_msg,NULL); } --- NEW FILE: Makefile.am --- SUBDIRS = . debug tcp noinst_PROGRAMS = swc noinst_LIBRARIES = libsw.a swc_SOURCES = swc.c swc.h swc_LDADD = $(top_builddir)/src/lib/libatmd.la $(top_builddir)/src/lib/libatm.la swc_DEPENDENCIES = $(swc_LDADD) $(top_builddir)/src/include/atm.h \ $(top_builddir)/src/include/atmd.h libsw_a_SOURCES = control.c dispatch.c dispatch.h proto.c proto.h relay.c \ route.c route.h sig.c sig.h cfg_y.y cfg_l.l fab.h EXTRA_DIST = cfg_y.h README --- NEW FILE: dispatch.c --- /* dispatch.c - Event dispatcher */ /* 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/time.h> #include <sys/types.h> #include "atmd.h" #include "dispatch.h" typedef struct _fd_entry { int fd; void (*callback)(int fd,void *user); void *user; struct _fd_entry *next; } FD_ENTRY; static FD_ENTRY *fd_idle = NULL,*fd_active = NULL; static int fds = 0; static fd_set r_set; void dsp_fd_add(int fd,void (*callback)(int fd,void *user),void *user) { FD_ENTRY *entry; for (entry = fd_idle; entry; entry = entry->next) if (entry->fd == fd) break; if (!entry) for (entry = fd_active; entry; entry = entry->next) if (entry->fd == fd) break; if (entry) { fprintf(stderr,"dsp_fd_add: duplicate fd %d\n",fd); exit(1); } if (fd >= fds) fds = fd+1; FD_SET(fd,&r_set); entry = alloc_t(FD_ENTRY); entry->fd = fd; entry->callback = callback; entry->user = user; entry->next = fd_idle; fd_idle = entry; } void dsp_fd_remove(int fd) { FD_ENTRY **walk,*next; FD_CLR(fd,&r_set); for (walk = &fd_idle; *walk; walk = &(*walk)->next) { if ((*walk)->fd != fd) continue; next = (*walk)->next; free(*walk); *walk = next; return; } for (walk = &fd_active; *walk; walk = &(*walk)->next) { if ((*walk)->fd != fd) continue; next = (*walk)->next; free(*walk); *walk = next; return; } fprintf(stderr,"dsp_fd_remove: fd %d not found\n",fd); exit(1); } void dsp_init(void) { FD_ZERO(&r_set); } void dsp_poll(void) { FD_ENTRY **walk,*next,*entry; fd_set r_poll; int num; while (!fd_active) { r_poll = r_set; num = select(fds+1,&r_poll,NULL,NULL,NULL); if (num < 0) { if (errno != EINTR) perror("select"); continue; } for (walk = &fd_idle; num;) { next = (*walk)->next; if (!FD_ISSET((*walk)->fd,&r_poll)) { walk = &(*walk)->next; continue; } (*walk)->next = fd_active; fd_active = *walk; *walk = next; num--; } } entry = fd_active; fd_active = entry->next; entry->next = fd_idle; fd_idle = entry; entry->callback(entry->fd,entry->user); } --- NEW FILE: dispatch.h --- /* dispatch.h - Event dispatcher */ /* Written 1998 by Werner Almesberger, EPFL ICA */ #ifndef DISPATCH_H #define DISPATCH_H /* * Add a file descriptor to probe for reading in the central dispatcher. If * the FD if readable, the callback function is invoked. The dispatcher does * not attempt to read itself. */ void dsp_fd_add(int fd,void (*callback)(int fd,void *user),void *user); /* * Remove a file descriptor from the central dispatcher. This function can be * invoked from within a callback function. */ void dsp_fd_remove(int fd); /* * Initialize the dispatcher. */ void dsp_init(void); /* * Wait until one of the file descriptors becomes readable and execute the * callback function. dsp_poll only handles one event at a time. */ void dsp_poll(void); #endif --- NEW FILE: cfg_l.l --- %{ /* cfg.l - switch configuration language */ /* Written 1998 by Werner Almesberger, EPFL ICA */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdlib.h> #include <stdio.h> #include <string.h> #include "atm.h" #include "cfg_y.h" static int lineno = 1; static int token; /* f@#%ing flex doesn't grok return after BEGIN */ void yyerror(const char *s); %} %s N %s P %% BEGIN(N); <N>option { BEGIN(P); token = TOK_OPTION; } <N>control { BEGIN(P); token = TOK_CONTROL; } <N>command return TOK_COMMAND; <N>socket { BEGIN(P); token = TOK_SOCKET; } <N>vpci return TOK_VPCI; <N>itf return TOK_ITF; <N>route { BEGIN(P); token = TOK_ROUTE; } <N>default return TOK_DEFAULT; <N>\"[^"\t\n]*\" { yylval.str = strdup(yytext+1); *strrchr(yylval.str,'"') = 0; return TOK_STR; } <N>[0-9]+ { char *end; yylval.num = strtoul(yytext,&end,10); if (*end) yyerror("invalid number"); return TOK_NUM; } <N>[0-9]+\.[0-9]+(\.[0-9]+)? { if (text2atm(yytext,(struct sockaddr *) &yylval.pvc, sizeof(yylval.pvc),T2A_PVC) < 0) yyerror("invalid VC"); return TOK_PVC; } <P>[^\t\n ]+ { BEGIN(N); yylval.str = strdup(yytext); if (!yylval.str) { perror("strdup"); exit(1); } return token; } \n?[\t ]* lineno += *yytext == '\n'; #[^\n]*\n lineno++; <N>. return *yytext; %% void yyerror(const char *s) { fprintf(stderr,"line %d: %s near \"%s\"\n",lineno,s,yytext); exit(1); } --- NEW FILE: cfg_y.y --- %{ /* cfg.y - switch configuration language */ /* Written 1998 by Werner Almesberger, EPFL ICA */ #if HAVE_CONFIG_H #include <config.h> #endif #include <string.h> #include <errno.h> #include <limits.h> #include "atm.h" #include "fab.h" #include "sig.h" #include "route.h" #include "swc.h" static int itf; static SIGNALING_ENTITY *sig; %} %union { int num; char *str; struct sockaddr_atmpvc pvc; }; %token TOK_COMMAND TOK_VPCI TOK_ITF TOK_DEFAULT %token <str> TOK_ROUTE TOK_STR TOK_SOCKET TOK_OPTION TOK_CONTROL %token <num> TOK_NUM %token <pvc> TOK_PVC %type <str> opt_command %% all: | option all | sig all | TOK_CONTROL all { control_init($1); } ; option: TOK_OPTION TOK_STR { fab_option($1,$2); } ; sig: opt_command TOK_SOCKET '{' { itf = 0; } opt_itf { char *tmp; tmp = strdup($2); if (!tmp) yyerror(strerror(errno)); sig = sig_vc($1,tmp,itf); } opt_via routes '}' ; opt_command: { $$ = NULL; } | TOK_COMMAND TOK_STR { $$ = strdup($2); if (!$$) yyerror(strerror(errno)); } ; opt_itf: | TOK_ITF TOK_NUM { itf = $2; } ; opt_via: | TOK_PVC { sig->pvc = $1; } ; routes: | route routes | TOK_DEFAULT { put_route(NULL,0,sig); } routes ; route: TOK_ROUTE { struct sockaddr_atmsvc addr; char *mask; mask = strchr($1,'/'); if (mask) *mask++ = 0; if (text2atm($1,(struct sockaddr *) &addr,sizeof(addr), T2A_SVC | T2A_WILDCARD | T2A_NAME | T2A_LOCAL) < 0) { yyerror("invalid address"); return; } put_route(&addr,mask ? strtol(mask,NULL,10) : INT_MAX,sig); } ; --- NEW FILE: proto.c --- /* proto.c - Common protocol functions and structures */ /* Written 1997-1998 by Roman Pletka, EPFL-SSC */ /* Modified 1998,2000 by Werner Almesberger, EPFL ICA */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdarg.h> #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <string.h> #include <atm.h> #include "atmd.h" #include "sig.h" #include "fab.h" #include "proto.h" #define COMPONENT "SWITCH" static const char *as_msgs[] = { "as_catch_null", "as_bind", "as_connect", "as_accept", "as_reject","as_listen", "as_okay", "as_error", "as_indicate", "as_close", "as_itf_notify", "as_modify", "as_identify"}; static const char *cs_states[]= { "cs_invalid", "cs_null", "cs_listening", "cs_connected", "cs_indicated", "cs_called_accepted", "cs_rm_accepted", "cs_rm_accepted2", "cs_caller_error", "cs_rejected", "cs_rejected2", "cs_caller_closing", "cs_called_closed", "cs_called_closed2", "cs_free_rm", "cs_rejecting", "cs_will_close", "cs_call_indicated", "cs_caller_closed" }; static const char *sources[4] = {"CALLER","CALLED","RM"}; CALL *new_call(void) { CALL *call; call = alloc_t(CALL); memset(call,0,sizeof(CALL)); call->state = cs_invalid; fab_init(call); return call; } void free_call(CALL *call) { fab_destroy(call); call->state = cs_invalid; free(call); printf("Call 0x%p killed\n",call); } void new_state(CALL *call,STATE state) { call->state = state; print_state(call); } void send_listen(SIGNALING_ENTITY *sig) { struct atmsvc_msg msg; memset(&msg,0,sizeof(msg)); /* compose the message */ msg.type = as_listen; *(unsigned long *) &msg.vcc = (unsigned long) sig; msg.svc.sas_family = AF_ATMSVC; msg.qos.aal = ATM_AAL5; msg.qos.txtp.traffic_class = msg.qos.rxtp.traffic_class = ATM_ANYCLASS; /* msg.sap ; */ sig_send(sig,&msg); } void send_identify(CALL *call) { struct atmsvc_msg msg; /* this is always sent to caller */ memset(&msg,0,sizeof(msg)); /* compose the message */ msg.type = as_identify; *(unsigned long *) &msg.vcc = (unsigned long) call | CALLER; *(unsigned long *) &msg.listen_vcc = (unsigned long) call->in.sig; /* We have to complete the message (vci,vpi..) */ msg.pvc = call->in.pvc; sig_send(call->in.sig,&msg); } void send_connect(CALL *call) { struct atmsvc_msg msg; /* this is always sent to called */ memset(&msg,0,sizeof(msg)); /* compose the message */ msg.type = as_connect; *(unsigned long *) &msg.vcc = (unsigned long) call | CALLED; /* some kind of magic... */ msg.local = call->in.svc; msg.qos.aal = call->in.qos.aal; /* or should we rather use out.qos ? @@@ */ msg.qos.txtp = call->in.qos.rxtp; msg.qos.rxtp = call->in.qos.txtp; msg.svc = call->out.svc; msg.sap = call->sap; /* we have to give VCI/VPI */ msg.pvc = call->out.pvc; sig_send(call->out.sig,&msg); } void send_reject(CALL *call, int err_code) { struct atmsvc_msg msg; /* this is always sent to caller */ memset(&msg,0,sizeof(msg)); msg.type = as_reject; *(unsigned long *) &msg.vcc = (unsigned long) call | CALLER; msg.reply = err_code; sig_send(call->in.sig,&msg); } void send_reject_not_id(SIGNALING_ENTITY *sig, int err_code) { struct atmsvc_msg msg; /* this is always sent to caller */ memset(&msg,0,sizeof(msg)); msg.type = as_reject; *(unsigned long *) &msg.listen_vcc = (unsigned long) sig; msg.reply = err_code; sig_send(sig,&msg); } void send_close(CALL *call,int dest) { struct atmsvc_msg msg; memset(&msg,0,sizeof(msg)); msg.type = as_close; *(unsigned long *) &msg.vcc = (unsigned long) call | dest; /* dest: CALLER or CALLED */ /* msg.reply = ??!! */ sig_send(dest == CALLER ? call->in.sig : call->out.sig,&msg); } void send_accept(CALL *call) { struct atmsvc_msg msg; memset(&msg,0,sizeof(msg)); msg.type = as_accept; *(unsigned long *) &msg.vcc = (unsigned long) call | CALLER; sig_send(call->in.sig,&msg); } /*****************************************************************************/ /* Demultiplexing with magic number: caller - called - rm */ /*****************************************************************************/ CALL *demux_in(unsigned long *srce, struct atmsvc_msg *msg) { /* The multiplexing informations are in the 3 least significant bits of the call pointer. We can do this, because the compiler aligns memory reservation to pointers with 3 ls-bits = 0. */ *srce = *(unsigned long *) &msg->vcc & 3; return (CALL *) (*(unsigned long *) &msg->vcc & ~3); } /*****************************************************************************/ /* Debugging functions */ /*****************************************************************************/ void print_msg(struct atmsvc_msg *msg, CALL *call,unsigned long source) { printf("Msg '%s' received from %s vcc=%s for call 0x%p, listen: %s\n", as_msgs[msg->type], sources[source], kptr_print(&msg->vcc), call, kptr_print(&msg->listen_vcc)); } void print_state(CALL *call) { printf(" Call 0x%p entered state '%s'\n", call , cs_states[call->state]); } void print_call(CALL *call) { printf(" Call 0x%p in state %s, caller-id:%p, called-id:%p\n", call, cs_states[call->state], call->in.sig, call->out.sig); } --- NEW FILE: proto.h --- /* proto.h - Common protocol functions and structures */ /* Written 1997-1998 by Roman Pletka, EPFL SSC */ /* Modified 1998,2000 by Werner Almesberger, EPFL ICA */ #ifndef PROTO_H #define PROTO_H #define CALLER 0 /* We add this to the call pointer. It */ #define CALLED 1 /* helps us to find out the source of the */ #define RM 2 /* message. */ #include <linux/atmsvc.h> #include "atmsap.h" #include "atmd.h" #include "sig.h" typedef enum { /* call states */ cs_invalid, cs_null, cs_listening, cs_connected, cs_indicated, cs_called_accepted, cs_rm_accepted, cs_rm_accepted2, cs_caller_error, cs_rejected, cs_rejected2, cs_caller_closing, cs_called_closed, cs_called_closed2, cs_free_rm, cs_rejecting, cs_will_close, cs_call_indicated, cs_caller_closed } STATE; typedef struct _party { SIGNALING_ENTITY *sig; /* signaling entity */ struct sockaddr_atmpvc pvc; /* itf and CI */ struct sockaddr_atmsvc svc; /* remote address */ struct atm_qos qos; /* QOS parameters */ } PARTY; typedef struct _call { STATE state; PARTY in; /* caller data */ PARTY out; /* called data */ struct atm_sap sap; /* SAP (BHLI and BLLI) */ int error; /* error code for close */ /* --- switch fabric control data -------------------------------------- */ void *fab; } CALL; /* * Note that the fabric may only look at call.in.pvc, call.in.pvc, * call.out.pvc, call.out.qos, and call.fab. All other fields may be set to * arbitrary values by the signaling relay. */ void send_identify(CALL *call); void send_listen(SIGNALING_ENTITY *sig); void send_connect(CALL *call); void send_reject(CALL *call, int err_code); void send_reject_not_id(SIGNALING_ENTITY *sig, int err_code); void send_close(CALL *call,int dest); void send_accept(CALL *call); CALL *new_call(void); void free_call(CALL *call); void new_state(CALL *call,STATE state); CALL *demux_in(unsigned long *srce, struct atmsvc_msg *msg); /* some debugging functions */ void print_msg(struct atmsvc_msg *msg, CALL *call,unsigned long source); void print_state(CALL *call); void print_call(CALL *call); int from_sigd(SIGNALING_ENTITY *sig,struct atmsvc_msg *msg); #endif |
From: Paul B. S. <pa...@us...> - 2001-09-03 18:41:10
|
Update of /cvsroot/linux-atm/linux-atm/src/include In directory usw-pr-cvs1:/tmp/cvs-serv10656/include Added Files: Tag: V2_4_0 atmsap.h atm.h atmd.h Makefile.am stdint.h Log Message: --- NEW FILE: atmsap.h --- /* atmsap.h - ATM Service Access Point addressing definitions */ /* Written 1996-1998 by Werner Almesberger, EPFL LRC/ICA */ #ifndef _ATMSAP_H #define _ATMSAP_H #include <stdint.h> #include <linux/atmsap.h> /* * Selected ISO/IEC TR 9577 Network Layer Protocol Identifiers (NLPID) */ #define NLPID_IEEE802_1_SNAP 0x80 /* IEEE 802.1 SNAP */ /* * Selected Organizationally Unique Identifiers (OUIs) */ #define ATM_FORUM_OUI "\x00\xA0\x3E" /* ATM Forum */ #define EPFL_OUI "\x00\x60\xD7" /* EPF Lausanne, CH */ /* * Selected vendor-specific application identifiers (for B-HLI). Such an * identifier consists of three bytes containing the OUI, followed by four * bytes assigned by the organization owning the OUI. */ #define ANS_HLT_VS_ID ATM_FORUM_OUI "\x00\x00\x00\x01" /* ATM Name System, af-saa-0069.000 */ #define VOD_HLT_VS_ID ATM_FORUM_OUI "\x00\x00\x00\x02" /* VoD, af-saa-0049.001 */ #define AREQUIPA_HLT_VS_ID EPFL_OUI "\x01\x00\x00\x01" /* Arequipa */ #define TTCP_HLT_VS_ID EPFL_OUI "\x01\x00\x00\x03" /* ttcp_atm */ /* Mapping of "well-known" TCP, UDP, etc. port numbers to ATM BHLIs. btd-saa-api-bhli-01.02 */ void atm_tcpip_port_mapping(char *vs_id,uint8_t protocol,uint16_t port); #endif --- NEW FILE: atm.h --- /* atm.h - Functions useful for ATM applications */ /* Written 1995-2000 by Werner Almesberger, EPFL-LRC/ICA */ #ifndef _ATM_H #define _ATM_H #include <stdint.h> #include <sys/socket.h> #include <linux/atm.h> /* * For versions of glibc < 2.1 */ #ifndef AF_ATMPVC #define AF_ATMPVC 8 #endif #ifndef AF_ATMSVC #define AF_ATMSVC 20 #endif #ifndef PF_ATMPVC #define PF_ATMPVC AF_ATMPVC #endif #ifndef PF_ATMSVC #define PF_ATMSVC AF_ATMSVC #endif #ifndef SOL_ATM #define SOL_ATM 264 #endif #ifndef SOL_AAL #define SOL_AAL 265 #endif #define HOSTS_ATM "/etc/hosts.atm" /* text2atm flags */ #define T2A_PVC 1 /* address is PVC */ #define T2A_SVC 2 /* address is SVC */ #define T2A_UNSPEC 4 /* allow unspecified parts in PVC address */ #define T2A_WILDCARD 8 /* allow wildcards in PVC or SVC address */ #define T2A_NNI 16 /* allow NNI VPI range (PVC) */ #define T2A_NAME 32 /* allow name resolution */ #define T2A_REMOTE 64 /* OBSOLETE */ #define T2A_LOCAL 128 /* don't use ANS */ /* atm2text flags */ #define A2T_PRETTY 1 /* add syntactic sugar */ #define A2T_NAME 2 /* attempt name lookup */ #define A2T_REMOTE 4 /* OBSOLETE */ #define A2T_LOCAL 8 /* don't use ANS */ /* atm_equal flags */ #define AXE_WILDCARD 1 /* allow wildcard match */ #define AXE_PRVOPT 2 /* private part of SVC address is optional */ /* text2qos flags */ #define T2Q_DEFAULTS 1 /* structure contains default values */ /* text2sap flags */ #define T2S_NAME 1 /* attempt name lookup */ #define T2S_LOCAL 2 /* we may support NIS or such in the future */ /* sap2text flags */ #define S2T_NAME 1 /* attempt name lookup */ #define S2T_LOCAL 2 /* we may support NIS or such in the future */ /* sap_equal flags */ #define SXE_COMPATIBLE 1 /* check for compatibility instead of identity*/ #define SXE_NEGOTIATION 2 /* allow negotiation; requires SXE_COMPATIBLE; assumes "a" defines the available capabilities */ #define SXE_RESULT 4 /* return selected SAP */ #define MAX_ATM_ADDR_LEN (2*ATM_ESA_LEN+ATM_E164_LEN+5) /* 4 dots, 1 plus */ #define MAX_ATM_NAME_LEN 256 /* wild guess */ #define MAX_ATM_QOS_LEN 116 /* 5+4+2*(3+3*(7+9)+2)+1 */ #define MAX_ATM_SAP_LEN 255 /* BHLI(27)+1+3*BLLI(L2=33,L3=41,+1)+2 */ int text2atm(const char *text,struct sockaddr *addr,int length,int flags); int atm2text(char *buffer,int length,const struct sockaddr *addr,int flags); int atm_equal(const struct sockaddr *a,const struct sockaddr *b,int len, int flags); int sdu2cell(int s,int sizes,const int *sdu_size,int *num_sdu); int text2qos(const char *text,struct atm_qos *qos,int flags); int qos2text(char *buffer,int length,const struct atm_qos *qos,int flags); int qos_equal(const struct atm_qos *a,const struct atm_qos *b); int text2sap(const char *text,struct atm_sap *sap,int flags); int sap2text(char *buffer,int length,const struct atm_sap *sap,int flags); int sap_equal(const struct atm_sap *a,const struct atm_sap *b,int flags,...); int __t2q_get_rate(const char **text,int up); int __atmlib_fetch(const char **pos,...); /* internal use only */ #endif --- NEW FILE: atmd.h --- /* atmd.h - Functions useful for demons (and some other ATM tools) */ /* Written 1995-2000 by Werner Almesberger, EPFL-LRC/ICA */ #ifndef _ATMD_H #define _ATMD_H /*--------------------------- Common definitions ----------------------------*/ #include <stdint.h> #include <stdio.h> #include <sys/types.h> #include <sys/time.h> /* doubly linked list primitives */ #define Q_INSERT_HEAD(r,i) ({ (i)->next = r; (i)->prev = NULL; \ if (r) (r)->prev = i; r = i; }) #define Q_INSERT_AFTER(r,i,a) ({ if (a) { (i)->next = (a)->next; \ (i)->prev = a; if ((a)->next) (a)->next->prev = i; (a)->next = i; } \ else { (i)->next = r; (i)->prev = NULL; if (r) (r)->prev = i; r = i; } }) #define Q_INSERT_BEFORE(r,i,b) ({ if (b) { (i)->next = b; \ (i)->prev = (b)->prev; if ((b)->prev) (b)->prev->next = i; else r = i; \ (b)->prev = i; } else { (i)->next = r; (i)->prev = NULL; \ if (r) (r)->prev = i; r = i; } }) #define Q_REMOVE(r,i) ({ if ((i)->next) (i)->next->prev = (i)->prev; \ if ((i)->prev) (i)->prev->next = (i)->next; else r = (i)->next; }) extern struct timeval now; extern int debug; #define alloc_t(t) ((t *) alloc(sizeof(t))) void *alloc(size_t size); uint32_t read_netl(void *p); /*--------------------------- Diagnostic messages ---------------------------*/ #include <stdarg.h> #define DIAG_DEBUG 3 #define DIAG_INFO 2 #define DIAG_WARN 1 #define DIAG_ERROR 0 #define DIAG_FATAL -1 void set_application(const char *name); void set_logfile(const char *name); FILE *get_logfile(void); void set_verbosity(const char *component,int level); int get_verbosity(const char *component); void vdiag(const char *component,int severity,const char *fmt,va_list ap); void diag(const char *component,int severity,const char *fmt,...); void diag_dump(const char *component,int severity,const char *title, const unsigned char *data,int len); /*------------------------------ Timer support ------------------------------*/ #include <sys/time.h> typedef struct _timer { struct timeval expiration; void (*callback)(void *user); void *user; struct _timer *prev,*next; } TIMER; TIMER *start_timer(long usec,void (*callback)(void *user),void *user); void stop_timer(TIMER *timer); void (*timer_handler(TIMER *timer))(void *user); struct timeval *next_timer(void); void pop_timer(TIMER *timer); void expire_timers(void); /*--------------------------- Unix domain sockets ---------------------------*/ #include <sys/socket.h> #include <sys/un.h> typedef struct { int s; /* socket */ struct sockaddr_un addr; /* reply address */ int size; /* address size */ } UN_CTX; int un_create(const char *path,mode_t mode); /* * Creates a Unix domain DGRAM socket, binds it to the specified path, and * returns the socket descriptor. Returns a negative value on error. */ int un_attach(const char *path); /* * Creates a Unix domain DGRAM socket and connects it to the specified path. * The local side is bound to an ephemeral address. Returns the socket * descriptor on success, a negative value otherwise. */ int un_recv_connect(int s,void *buf,int size); /* * Performs a recv(s,buf,size,0) and connects the socket to the sender's * address. Returns a negative value on error. */ int un_reply(int s,void *buf,int size, int (*handler)(void *buf,int len,void *user),void *user); /* * Receives a message from the socket into the buffer provided by the caller, * invokes handler for processing and optionally sends back a reply. If the * handler returns a negative value or zero, no reply is sent. If the handler * returns a positive value, this is interpreted as the length of the reply to * send. The data is taken from the buffer. If any system call fails, un_reply * returns a negative value. Otherwise, it returns whatever was returned by the * handler function. */ int un_recv(UN_CTX *ctx,int s,void *buf,int size); /* * Receive a message into the specified buffer and store the information needed * to send a reply in ctx. Sets errno and returns a negative value on error. */ int un_send(const UN_CTX *ctx,void *buf,int len); /* * Send a reply to the sender identified by ctx. Sets errno and returns a * negative value on error. */ /* ------------------------- IP address operations ------------------------- */ #include <netinet/in.h> #define T2I_NAME 1 /* do a name lookup */ #define T2I_ERROR 2 /* print error messages */ uint32_t text2ip(const char *text,const char *component,int flags); /* * Converts a text string to an IP address. If resolution fails, text2ip * returns INADDR_NONE. If T2I_ERROR is set, errors messages are printed. If * component is non-NULL, they are logged using diag(). Otherwise, they are * printed on standard error. Note that T2I_NAME uses gethostbyname() which * may attempt resolution via DNS or NIS. */ /* ------------------------ Kernel pointer handles ------------------------- */ #include <atm.h> #define KPRT_PRINT_BUFS 4 /* up to that many buffers are concurrently available */ int kptr_eq(const atm_kptr_t *a,const atm_kptr_t *b); /* * Returns 1 if A and B are equal, 0 otherwise. Note that unused areas of the * handles must be initialized to a system-wide constant pattern, e.g. 0. */ const char *kptr_print(const atm_kptr_t *p); /* * Returns a pointer to a static buffer containing an ASCII representation of * a kernel pointer handle. After KPRT_PRINT_BUFS calls to kptr_print, old * buffers are reused. */ #endif --- NEW FILE: Makefile.am --- include_HEADERS = atm.h atmd.h atmsap.h noinst_HEADERS = stdint.h --- NEW FILE: stdint.h --- /* stdint.h - provides uintXX_t until glibc does */ #ifndef _STDINT_H #include <features.h> #if __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1 #include "/usr/include/stdint.h" #elif __GLIBC__ >= 2 /* Works for i386 and Alpha */ typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; #else #ifndef _LINUX_TYPES_H #include <linux/types.h> #endif #endif #ifndef _STDINT_H #define _STDINT_H #endif #endif |
From: Paul B. S. <pa...@us...> - 2001-09-03 18:41:10
|
Update of /cvsroot/linux-atm/linux-atm/src/ilmid In directory usw-pr-cvs1:/tmp/cvs-serv10656/ilmid Added Files: Tag: V2_4_0 rfc1157_snmp.c rfc1157_snmp.h io.c io.h mib.c mib.h atmf_uni.c atmf_uni.h Makefile.am sysgroup.c sysgroup.h util.c util.h rfc1155_smi.c rfc1155_smi.h message.c message.h ilmid.c COPYRIGHT Log Message: --- NEW FILE: rfc1157_snmp.c --- /* * rfc1157_snmp.c * * "RFC1157-SNMP" ASN.1 module encode/decode/print/free C src. * * This file was generated by snacc on Fri Jan 31 14:49:02 1997 * * UBC snacc written by Mike Sample * * NOTE: This is a machine generated file - editing not recommended */ #if HAVE_CONFIG_H #include <config.h> #endif #include "asn_incl.h" #include "rfc1155_smi.h" #include "rfc1157_snmp.h" AsnLen BEncVarBindContent PARAMS((b, v), BUF_TYPE b _AND_ VarBind* v) { AsnLen totalLen = 0; AsnLen itemLen; AsnLen listLen; void* component; itemLen = BEncObjectSyntaxContent( b, (v->value)); totalLen += itemLen; itemLen = BEncObjectNameContent( b, (&v->name)); itemLen += BEncDefLen( b, itemLen); itemLen += BEncTag1(b, UNIV, PRIM, 6); totalLen += itemLen; return (totalLen); } /* BEncVarBindContent */ void BDecVarBindContent PARAMS((b, tagId0, elmtLen0, v, bytesDecoded, env), BUF_TYPE b _AND_ AsnTag tagId0 _AND_ AsnLen elmtLen0 _AND_ VarBind* v _AND_ AsnLen* bytesDecoded _AND_ ENV_TYPE env) { int seqDone = FALSE; AsnLen totalElmtsLen1 = 0; AsnLen elmtLen1; AsnTag tagId1; int mandatoryElmtCount1 = 0; AsnLen totalElmtsLen2 = 0; AsnLen elmtLen2; AsnTag tagId2; tagId1 = BDecTag(b, &totalElmtsLen1, env); if ((( tagId1 == MAKE_TAG_ID( UNIV, PRIM, OID_TAG_CODE)))) { elmtLen1 = BDecLen (b, &totalElmtsLen1, env); BDecObjectNameContent( b, tagId1, elmtLen1, (&v->name), &totalElmtsLen1, env); tagId1 = BDecTag(b, &totalElmtsLen1, env); } else longjmp(env, -100); if ((( tagId1 == MAKE_TAG_ID( UNIV, PRIM, INTEGER_TAG_CODE)) || ( tagId1 ==MAKE_TAG_ID( UNIV, PRIM, OCTETSTRING_TAG_CODE))|| ( tagId1 == MAKE_TAG_ID( UNIV, CONS, OCTETSTRING_TAG_CODE)) || ( tagId1 ==MAKE_TAG_ID( UNIV, PRIM, OID_TAG_CODE)) || ( tagId1 ==MAKE_TAG_ID( UNIV, PRIM, NULLTYPE_TAG_CODE)) || ( tagId1 == MAKE_TAG_ID( APPL, PRIM, 0))|| ( tagId1 == MAKE_TAG_ID( APPL, CONS, 0)) || ( tagId1 == MAKE_TAG_ID( APPL, PRIM, 1)) || ( tagId1 == MAKE_TAG_ID( APPL, PRIM, 2)) || ( tagId1 == MAKE_TAG_ID( APPL, PRIM, 3)) || ( tagId1 == MAKE_TAG_ID( APPL, PRIM, 4))|| ( tagId1 == MAKE_TAG_ID( APPL, CONS, 4)))) { elmtLen1 = BDecLen (b, &totalElmtsLen1, env); (v->value) = (ObjectSyntax*) Asn1Alloc(sizeof(ObjectSyntax)); CheckAsn1Alloc((v->value), env); BDecObjectSyntaxContent( b, tagId1, elmtLen1, (v->value), &totalElmtsLen1, env); seqDone = TRUE; if ( elmtLen0 == INDEFINITE_LEN ) BDecEoc(b, &totalElmtsLen1, env); else if (totalElmtsLen1 != elmtLen0) longjmp(env, -101); } else longjmp(env, -102); if (!seqDone) longjmp(env, -103); (*bytesDecoded) += totalElmtsLen1; } /* BDecVarBindContent */ void PrintVarBind PARAMS((f, v, indent), FILE* f _AND_ VarBind* v _AND_ unsigned short int indent) { if (v == NULL) return; fprintf(f,"{ -- SEQUENCE --\n"); Indent(f, indent + stdIndentG); fprintf(f,"name "); PrintObjectName(f, (&v->name), indent + stdIndentG); fprintf(f, ",\n"); Indent(f, indent + stdIndentG); fprintf(f,"value "); PrintObjectSyntax(f, (v->value), indent + stdIndentG); fprintf(f,"\n"); Indent(f, indent); fprintf(f,"}"); } /* PrintVarBind */ AsnLen BEncVarBindListContent PARAMS((b, v), BUF_TYPE b _AND_ VarBindList* v) { AsnLen totalLen = 0; AsnLen itemLen; AsnLen listLen; void* component; listLen = 0; FOR_EACH_LIST_ELMT_RVS( component, v) { BEncEocIfNec(b); itemLen = BEncVarBindContent( b, component); itemLen += BEncConsLen( b, itemLen); itemLen += BEncTag1(b, UNIV, CONS, 16); listLen += itemLen; } return (listLen); } /* BEncVarBindListContent */ void BDecVarBindListContent PARAMS((b, tagId0, elmtLen0, v, bytesDecoded, env), BUF_TYPE b _AND_ AsnTag tagId0 _AND_ AsnLen elmtLen0 _AND_ VarBindList* v _AND_ AsnLen* bytesDecoded _AND_ ENV_TYPE env) { int seqDone = FALSE; AsnLen totalElmtsLen1 = 0; AsnLen elmtLen1; AsnTag tagId1; int mandatoryElmtCount1 = 0; for ( totalElmtsLen1 = 0; (totalElmtsLen1 < elmtLen0) || (elmtLen0 == INDEFINITE_LEN);) { VarBind** tmpVar; tagId1 = BDecTag(b, &totalElmtsLen1, env); if ( (tagId1 == EOC_TAG_ID) && (elmtLen0 == INDEFINITE_LEN)) { BDEC_2ND_EOC_OCTET(b, &totalElmtsLen1, env) break; /* got EOC so can exit this SET OF/SEQ OF's for loop*/ } if ( (tagId1 == MAKE_TAG_ID( UNIV, CONS, SEQ_TAG_CODE))) { elmtLen1 = BDecLen (b, &totalElmtsLen1, env); tmpVar = (VarBind**) AsnListAppend(v); (*tmpVar) = (VarBind*) Asn1Alloc(sizeof(VarBind)); CheckAsn1Alloc((*tmpVar), env); BDecVarBindContent( b, tagId1, elmtLen1, (*tmpVar), &totalElmtsLen1, env); } /* end of tag check if */ else /* wrong tag */ { Asn1Error("Unexpected Tag\n"); longjmp(env, -104); } } /* end of for */ (*bytesDecoded) += totalElmtsLen1; } /* BDecVarBindListContent */ void PrintVarBindList PARAMS((f, v, indent), FILE* f _AND_ VarBindList* v _AND_ unsigned short int indent) { VarBind* tmp; if (v == NULL) return; fprintf(f,"{ -- SEQUENCE OF -- \n"); FOR_EACH_LIST_ELMT(tmp, v) { Indent(f, indent+ stdIndentG); PrintVarBind(f, tmp, indent + stdIndentG); if (tmp != (VarBind*)LAST_LIST_ELMT(v)) fprintf(f,",\n"); } fprintf(f,"\n"); Indent(f, indent); fprintf(f,"}"); } /* PrintVarBindList */ AsnLen BEncPDUContent PARAMS((b, v), BUF_TYPE b _AND_ PDU* v) { AsnLen totalLen = 0; AsnLen itemLen; AsnLen listLen; void* component; BEncEocIfNec(b); itemLen = BEncVarBindListContent( b, (v->variable_bindings)); itemLen += BEncConsLen( b, itemLen); itemLen += BEncTag1(b, UNIV, CONS, 16); totalLen += itemLen; itemLen = BEncAsnIntContent( b, (&v->error_index)); BEncDefLenTo127( b, itemLen); itemLen++; itemLen += BEncTag1(b, UNIV, PRIM, 2); totalLen += itemLen; itemLen = BEncPDUIntContent( b, (&v->error_status)); BEncDefLenTo127( b, itemLen); itemLen++; itemLen += BEncTag1(b, UNIV, PRIM, 2); totalLen += itemLen; itemLen = BEncAsnIntContent( b, (&v->request_id)); BEncDefLenTo127( b, itemLen); itemLen++; itemLen += BEncTag1(b, UNIV, PRIM, 2); totalLen += itemLen; return (totalLen); } /* BEncPDUContent */ void BDecPDUContent PARAMS((b, tagId0, elmtLen0, v, bytesDecoded, env), BUF_TYPE b _AND_ AsnTag tagId0 _AND_ AsnLen elmtLen0 _AND_ PDU* v _AND_ AsnLen* bytesDecoded _AND_ ENV_TYPE env) { int seqDone = FALSE; AsnLen totalElmtsLen1 = 0; AsnLen elmtLen1; AsnTag tagId1; int mandatoryElmtCount1 = 0; tagId1 = BDecTag(b, &totalElmtsLen1, env); if ((( tagId1 == MAKE_TAG_ID( UNIV, PRIM, INTEGER_TAG_CODE)))) { elmtLen1 = BDecLen (b, &totalElmtsLen1, env); BDecAsnIntContent( b, tagId1, elmtLen1, (&v->request_id), &totalElmtsLen1, env); tagId1 = BDecTag(b, &totalElmtsLen1, env); } else longjmp(env, -105); if ((( tagId1 == MAKE_TAG_ID( UNIV, PRIM, INTEGER_TAG_CODE)))) { elmtLen1 = BDecLen (b, &totalElmtsLen1, env); BDecPDUIntContent( b, tagId1, elmtLen1, (&v->error_status), &totalElmtsLen1, env); tagId1 = BDecTag(b, &totalElmtsLen1, env); } else longjmp(env, -106); if ((( tagId1 == MAKE_TAG_ID( UNIV, PRIM, INTEGER_TAG_CODE)))) { elmtLen1 = BDecLen (b, &totalElmtsLen1, env); BDecAsnIntContent( b, tagId1, elmtLen1, (&v->error_index), &totalElmtsLen1, env); tagId1 = BDecTag(b, &totalElmtsLen1, env); } else longjmp(env, -107); if ((( tagId1 == MAKE_TAG_ID( UNIV, CONS, SEQ_TAG_CODE)))) { elmtLen1 = BDecLen (b, &totalElmtsLen1, env); (v->variable_bindings) = AsnListNew(sizeof(char*)); CheckAsn1Alloc((v->variable_bindings), env); BDecVarBindListContent( b, tagId1, elmtLen1, (v->variable_bindings), &totalElmtsLen1, env); seqDone = TRUE; if ( elmtLen0 == INDEFINITE_LEN ) BDecEoc(b, &totalElmtsLen1, env); else if (totalElmtsLen1 != elmtLen0) longjmp(env, -108); } else longjmp(env, -109); if (!seqDone) longjmp(env, -110); (*bytesDecoded) += totalElmtsLen1; } /* BDecPDUContent */ void PrintPDU PARAMS((f, v, indent), FILE* f _AND_ PDU* v _AND_ unsigned short int indent) { if (v == NULL) return; fprintf(f,"{ -- SEQUENCE --\n"); Indent(f, indent + stdIndentG); fprintf(f,"request-id "); PrintAsnInt(f, (&v->request_id), indent + stdIndentG); fprintf(f, ",\n"); Indent(f, indent + stdIndentG); fprintf(f,"error-status "); PrintPDUInt(f, (&v->error_status), indent + stdIndentG); fprintf(f, ",\n"); Indent(f, indent + stdIndentG); fprintf(f,"error-index "); PrintAsnInt(f, (&v->error_index), indent + stdIndentG); fprintf(f, ",\n"); Indent(f, indent + stdIndentG); fprintf(f,"variable-bindings "); PrintVarBindList(f, (v->variable_bindings), indent + stdIndentG); fprintf(f,"\n"); Indent(f, indent); fprintf(f,"}"); } /* PrintPDU */ AsnLen BEncTrap_PDUContent PARAMS((b, v), BUF_TYPE b _AND_ Trap_PDU* v) { AsnLen totalLen = 0; AsnLen itemLen; AsnLen listLen; void* component; BEncEocIfNec(b); itemLen = BEncVarBindListContent( b, (v->variable_bindings)); itemLen += BEncConsLen( b, itemLen); itemLen += BEncTag1(b, UNIV, CONS, 16); totalLen += itemLen; itemLen = BEncTimeTicksContent( b, (&v->time_stamp)); BEncDefLenTo127( b, itemLen); itemLen++; itemLen += BEncTag1(b, APPL, PRIM, 3); totalLen += itemLen; itemLen = BEncAsnIntContent( b, (&v->specific_trap)); BEncDefLenTo127( b, itemLen); itemLen++; itemLen += BEncTag1(b, UNIV, PRIM, 2); totalLen += itemLen; itemLen = BEncTrap_PDUIntContent( b, (&v->generic_trap)); BEncDefLenTo127( b, itemLen); itemLen++; itemLen += BEncTag1(b, UNIV, PRIM, 2); totalLen += itemLen; itemLen = BEncNetworkAddressContent( b, (v->agent_addr)); totalLen += itemLen; itemLen = BEncAsnOidContent( b, (&v->enterprise)); itemLen += BEncDefLen( b, itemLen); itemLen += BEncTag1(b, UNIV, PRIM, 6); totalLen += itemLen; return (totalLen); } /* BEncTrap_PDUContent */ void BDecTrap_PDUContent PARAMS((b, tagId0, elmtLen0, v, bytesDecoded, env), BUF_TYPE b _AND_ AsnTag tagId0 _AND_ AsnLen elmtLen0 _AND_ Trap_PDU* v _AND_ AsnLen* bytesDecoded _AND_ ENV_TYPE env) { int seqDone = FALSE; AsnLen totalElmtsLen1 = 0; AsnLen elmtLen1; AsnTag tagId1; int mandatoryElmtCount1 = 0; AsnLen totalElmtsLen2 = 0; AsnLen elmtLen2; AsnTag tagId2; tagId1 = BDecTag(b, &totalElmtsLen1, env); if ((( tagId1 == MAKE_TAG_ID( UNIV, PRIM, OID_TAG_CODE)))) { elmtLen1 = BDecLen (b, &totalElmtsLen1, env); BDecAsnOidContent( b, tagId1, elmtLen1, (&v->enterprise), &totalElmtsLen1, env); tagId1 = BDecTag(b, &totalElmtsLen1, env); } else longjmp(env, -111); if ((( tagId1 == MAKE_TAG_ID( APPL, PRIM, 0)) || ( tagId1 == MAKE_TAG_ID( APPL, CONS, 0)))) { elmtLen1 = BDecLen (b, &totalElmtsLen1, env); (v->agent_addr) = (NetworkAddress*) Asn1Alloc(sizeof(NetworkAddress)); CheckAsn1Alloc((v->agent_addr), env); BDecNetworkAddressContent( b, tagId1, elmtLen1, (v->agent_addr), &totalElmtsLen1, env); tagId1 = BDecTag(b, &totalElmtsLen1, env); } else longjmp(env, -112); if ((( tagId1 == MAKE_TAG_ID( UNIV, PRIM, INTEGER_TAG_CODE)))) { elmtLen1 = BDecLen (b, &totalElmtsLen1, env); BDecTrap_PDUIntContent( b, tagId1, elmtLen1, (&v->generic_trap), &totalElmtsLen1, env); tagId1 = BDecTag(b, &totalElmtsLen1, env); } else longjmp(env, -113); if ((( tagId1 == MAKE_TAG_ID( UNIV, PRIM, INTEGER_TAG_CODE)))) { elmtLen1 = BDecLen (b, &totalElmtsLen1, env); BDecAsnIntContent( b, tagId1, elmtLen1, (&v->specific_trap), &totalElmtsLen1, env); tagId1 = BDecTag(b, &totalElmtsLen1, env); } else longjmp(env, -114); if ((( tagId1 == MAKE_TAG_ID( APPL, PRIM, 3)))) { elmtLen1 = BDecLen (b, &totalElmtsLen1, env); BDecTimeTicksContent( b, tagId1, elmtLen1, (&v->time_stamp), &totalElmtsLen1, env); tagId1 = BDecTag(b, &totalElmtsLen1, env); } else longjmp(env, -115); if ((( tagId1 == MAKE_TAG_ID( UNIV, CONS, SEQ_TAG_CODE)))) { elmtLen1 = BDecLen (b, &totalElmtsLen1, env); (v->variable_bindings) = AsnListNew(sizeof(char*)); CheckAsn1Alloc((v->variable_bindings), env); BDecVarBindListContent( b, tagId1, elmtLen1, (v->variable_bindings), &totalElmtsLen1, env); seqDone = TRUE; if ( elmtLen0 == INDEFINITE_LEN ) BDecEoc(b, &totalElmtsLen1, env); else if (totalElmtsLen1 != elmtLen0) longjmp(env, -116); } else longjmp(env, -117); if (!seqDone) longjmp(env, -118); (*bytesDecoded) += totalElmtsLen1; } /* BDecTrap_PDUContent */ void PrintTrap_PDU PARAMS((f, v, indent), FILE* f _AND_ Trap_PDU* v _AND_ unsigned short int indent) { if (v == NULL) return; fprintf(f,"{ -- SEQUENCE --\n"); Indent(f, indent + stdIndentG); fprintf(f,"enterprise "); PrintAsnOid(f, (&v->enterprise), indent + stdIndentG); fprintf(f, ",\n"); Indent(f, indent + stdIndentG); fprintf(f,"agent-addr "); PrintNetworkAddress(f, (v->agent_addr), indent + stdIndentG); fprintf(f, ",\n"); Indent(f, indent + stdIndentG); fprintf(f,"generic-trap "); PrintTrap_PDUInt(f, (&v->generic_trap), indent + stdIndentG); fprintf(f, ",\n"); Indent(f, indent + stdIndentG); fprintf(f,"specific-trap "); PrintAsnInt(f, (&v->specific_trap), indent + stdIndentG); fprintf(f, ",\n"); Indent(f, indent + stdIndentG); fprintf(f,"time-stamp "); PrintTimeTicks(f, (&v->time_stamp), indent + stdIndentG); fprintf(f, ",\n"); Indent(f, indent + stdIndentG); fprintf(f,"variable-bindings "); PrintVarBindList(f, (v->variable_bindings), indent + stdIndentG); fprintf(f,"\n"); Indent(f, indent); fprintf(f,"}"); } /* PrintTrap_PDU */ AsnLen BEncPDUsContent PARAMS((b, v), BUF_TYPE b _AND_ PDUs* v) { AsnLen totalLen = 0; AsnLen itemLen; AsnLen listLen; void* component; switch(v->choiceId) { case(PDUS_GET_REQUEST): BEncEocIfNec(b); itemLen = BEncGetRequest_PDUContent( b, (v->a.get_request)); itemLen += BEncConsLen( b, itemLen); itemLen += BEncTag1(b, CNTX, CONS, 0); totalLen += itemLen; break; case(PDUS_GET_NEXT_REQUEST): BEncEocIfNec(b); itemLen = BEncGetNextRequest_PDUContent( b, (v->a.get_next_request)); itemLen += BEncConsLen( b, itemLen); itemLen += BEncTag1(b, CNTX, CONS, 1); totalLen += itemLen; break; case(PDUS_GET_RESPONSE): BEncEocIfNec(b); itemLen = BEncGetResponse_PDUContent( b, (v->a.get_response)); itemLen += BEncConsLen( b, itemLen); itemLen += BEncTag1(b, CNTX, CONS, 2); totalLen += itemLen; break; case(PDUS_SET_REQUEST): BEncEocIfNec(b); itemLen = BEncSetRequest_PDUContent( b, (v->a.set_request)); itemLen += BEncConsLen( b, itemLen); itemLen += BEncTag1(b, CNTX, CONS, 3); totalLen += itemLen; break; case(PDUS_TRAP): BEncEocIfNec(b); itemLen = BEncTrap_PDUContent( b, (v->a.trap)); itemLen += BEncConsLen( b, itemLen); itemLen += BEncTag1(b, CNTX, CONS, 4); totalLen += itemLen; break; } return (totalLen); } /* BEncPDUsContent */ void BDecPDUsContent PARAMS((b, tagId0, elmtLen0, v, bytesDecoded, env), BUF_TYPE b _AND_ AsnTag tagId0 _AND_ AsnLen elmtLen0 _AND_ PDUs* v _AND_ AsnLen* bytesDecoded _AND_ ENV_TYPE env) { int seqDone = FALSE; AsnLen totalElmtsLen1 = 0; AsnLen elmtLen1; AsnTag tagId1; int mandatoryElmtCount1 = 0; switch(tagId0) { case(MAKE_TAG_ID( CNTX, CONS, 0)): (v->choiceId) = PDUS_GET_REQUEST; (v->a.get_request) = (GetRequest_PDU*) Asn1Alloc(sizeof(GetRequest_PDU)); CheckAsn1Alloc((v->a.get_request), env); BDecGetRequest_PDUContent( b, tagId0, elmtLen0, (v->a.get_request), &totalElmtsLen1, env); break; case(MAKE_TAG_ID( CNTX, CONS, 1)): (v->choiceId) = PDUS_GET_NEXT_REQUEST; (v->a.get_next_request) = (GetNextRequest_PDU*) Asn1Alloc(sizeof(GetNextRequest_PDU)); CheckAsn1Alloc((v->a.get_next_request), env); BDecGetNextRequest_PDUContent( b, tagId0, elmtLen0, (v->a.get_next_request), &totalElmtsLen1, env); break; case(MAKE_TAG_ID( CNTX, CONS, 2)): (v->choiceId) = PDUS_GET_RESPONSE; (v->a.get_response) = (GetResponse_PDU*) Asn1Alloc(sizeof(GetResponse_PDU)); CheckAsn1Alloc((v->a.get_response), env); BDecGetResponse_PDUContent( b, tagId0, elmtLen0, (v->a.get_response), &totalElmtsLen1, env); break; case(MAKE_TAG_ID( CNTX, CONS, 3)): (v->choiceId) = PDUS_SET_REQUEST; (v->a.set_request) = (SetRequest_PDU*) Asn1Alloc(sizeof(SetRequest_PDU)); CheckAsn1Alloc((v->a.set_request), env); BDecSetRequest_PDUContent( b, tagId0, elmtLen0, (v->a.set_request), &totalElmtsLen1, env); break; case(MAKE_TAG_ID( CNTX, CONS, 4)): (v->choiceId) = PDUS_TRAP; (v->a.trap) = (Trap_PDU*) Asn1Alloc(sizeof(Trap_PDU)); CheckAsn1Alloc((v->a.trap), env); BDecTrap_PDUContent( b, tagId0, elmtLen0, (v->a.trap), &totalElmtsLen1, env); break; default: Asn1Error("ERROR - unexpected tag in CHOICE\n"); longjmp(env, -119); break; } /* end switch */ (*bytesDecoded) += totalElmtsLen1; } /* BDecPDUsContent */ void PrintPDUs PARAMS((f, v, indent), FILE* f _AND_ PDUs* v _AND_ unsigned short int indent) { switch(v->choiceId) { case(PDUS_GET_REQUEST): fprintf(f,"get-request "); PrintGetRequest_PDU(f, (v->a.get_request), indent + stdIndentG); break; case(PDUS_GET_NEXT_REQUEST): fprintf(f,"get-next-request "); PrintGetNextRequest_PDU(f, (v->a.get_next_request), indent + stdIndentG); break; case(PDUS_GET_RESPONSE): fprintf(f,"get-response "); PrintGetResponse_PDU(f, (v->a.get_response), indent + stdIndentG); break; case(PDUS_SET_REQUEST): fprintf(f,"set-request "); PrintSetRequest_PDU(f, (v->a.set_request), indent + stdIndentG); break; case(PDUS_TRAP): fprintf(f,"trap "); PrintTrap_PDU(f, (v->a.trap), indent + stdIndentG); break; } } /* PrintPDUs */ AsnLen BEncMessage PARAMS((b, v), BUF_TYPE b _AND_ Message* v) { AsnLen l; BEncEocIfNec(b); l = BEncMessageContent(b, v); l += BEncConsLen(b, l); l += BEncTag1(b, UNIV, CONS, SEQ_TAG_CODE); return(l); } /* BEncMessage */ void BDecMessage PARAMS((b, result, bytesDecoded, env), BUF_TYPE b _AND_ Message* result _AND_ AsnLen* bytesDecoded _AND_ ENV_TYPE env) { AsnTag tag; AsnLen elmtLen1; if ( ((tag = BDecTag(b, bytesDecoded, env)) != MAKE_TAG_ID(UNIV, CONS, SEQ_TAG_CODE))) { Asn1Error("BDecMessage: ERROR - wrong tag\n"); longjmp(env, -120); } elmtLen1 = BDecLen(b, bytesDecoded, env); BDecMessageContent(b, tag, elmtLen1, result, bytesDecoded, env); } /* BDecMessage */ AsnLen BEncMessageContent PARAMS((b, v), BUF_TYPE b _AND_ Message* v) { AsnLen totalLen = 0; AsnLen itemLen; AsnLen listLen; void* component; itemLen = BEncPDUsContent( b, (v->data)); totalLen += itemLen; itemLen = BEncAsnOctsContent( b, (&v->community)); itemLen += BEncDefLen( b, itemLen); itemLen += BEncTag1(b, UNIV, PRIM, 4); totalLen += itemLen; itemLen = BEncMessageIntContent( b, (&v->version)); BEncDefLenTo127( b, itemLen); itemLen++; itemLen += BEncTag1(b, UNIV, PRIM, 2); totalLen += itemLen; return (totalLen); } /* BEncMessageContent */ void BDecMessageContent PARAMS((b, tagId0, elmtLen0, v, bytesDecoded, env), BUF_TYPE b _AND_ AsnTag tagId0 _AND_ AsnLen elmtLen0 _AND_ Message* v _AND_ AsnLen* bytesDecoded _AND_ ENV_TYPE env) { int seqDone = FALSE; AsnLen totalElmtsLen1 = 0; AsnLen elmtLen1; AsnTag tagId1; int mandatoryElmtCount1 = 0; AsnLen totalElmtsLen2 = 0; AsnLen elmtLen2; AsnTag tagId2; tagId1 = BDecTag(b, &totalElmtsLen1, env); if ((( tagId1 == MAKE_TAG_ID( UNIV, PRIM, INTEGER_TAG_CODE)))) { elmtLen1 = BDecLen (b, &totalElmtsLen1, env); BDecMessageIntContent( b, tagId1, elmtLen1, (&v->version), &totalElmtsLen1, env); tagId1 = BDecTag(b, &totalElmtsLen1, env); } else longjmp(env, -121); if ((( tagId1 == MAKE_TAG_ID( UNIV, PRIM, OCTETSTRING_TAG_CODE)) || ( tagId1 == MAKE_TAG_ID( UNIV, CONS, OCTETSTRING_TAG_CODE)))) { elmtLen1 = BDecLen (b, &totalElmtsLen1, env); BDecAsnOctsContent( b, tagId1, elmtLen1, (&v->community), &totalElmtsLen1, env); tagId1 = BDecTag(b, &totalElmtsLen1, env); } else longjmp(env, -122); if ((( tagId1 == MAKE_TAG_ID( CNTX, CONS, 0)) || ( tagId1 == MAKE_TAG_ID( CNTX, CONS, 1)) || ( tagId1 == MAKE_TAG_ID( CNTX, CONS, 2)) || ( tagId1 == MAKE_TAG_ID( CNTX, CONS, 3)) || ( tagId1 == MAKE_TAG_ID( CNTX, CONS, 4)))) { elmtLen1 = BDecLen (b, &totalElmtsLen1, env); (v->data) = (PDUs*) Asn1Alloc(sizeof(PDUs)); CheckAsn1Alloc((v->data), env); BDecPDUsContent( b, tagId1, elmtLen1, (v->data), &totalElmtsLen1, env); seqDone = TRUE; if ( elmtLen0 == INDEFINITE_LEN ) BDecEoc(b, &totalElmtsLen1, env); else if (totalElmtsLen1 != elmtLen0) longjmp(env, -123); } else longjmp(env, -124); if (!seqDone) longjmp(env, -125); (*bytesDecoded) += totalElmtsLen1; } /* BDecMessageContent */ void PrintMessage PARAMS((f, v, indent), FILE* f _AND_ Message* v _AND_ unsigned short int indent) { if (v == NULL) return; fprintf(f,"{ -- SEQUENCE --\n"); Indent(f, indent + stdIndentG); fprintf(f,"version "); PrintMessageInt(f, (&v->version), indent + stdIndentG); fprintf(f, ",\n"); Indent(f, indent + stdIndentG); fprintf(f,"community "); PrintAsnOcts(f, (&v->community), indent + stdIndentG); fprintf(f, ",\n"); Indent(f, indent + stdIndentG); fprintf(f,"data "); PrintPDUs(f, (v->data), indent + stdIndentG); fprintf(f,"\n"); Indent(f, indent); fprintf(f,"}\n"); } /* PrintMessage */ --- NEW FILE: rfc1157_snmp.h --- /* * rfc1157_snmp.h * * "RFC1157-SNMP" ASN.1 module C type definitions and prototypes * * This .h file was by snacc on Fri Jan 31 14:49:02 1997 * * UBC snacc written compiler by Mike Sample * * NOTE: This is a machine generated file - editing not recommended */ #ifndef _rfc1157_snmp_h_ #define _rfc1157_snmp_h_ #define COLDSTART 0 #define WARMSTART 1 #define LINKDOWN 2 #define LINKUP 3 #define AUTHENTICATIONFAILURE 4 #define EGPNEIGHBORLOSS 5 #define ENTERPRISESPECIFIC 6 typedef AsnInt Trap_PDUInt; /* INTEGER { COLDSTART(0), WARMSTART(1), LINKDOWN(2), LINKUP(3), AUTHENTICATIONFAILURE(4), EGPNEIGHBORLOSS(5), ENTERPRISESPECIFIC(6) } */ #define BEncTrap_PDUIntContent BEncAsnIntContent #define BDecTrap_PDUIntContent BDecAsnIntContent #define PrintTrap_PDUInt PrintAsnInt #define NOERROR 0 #define TOOBIG 1 #define NOSUCHNAME 2 #define BADVALUE 3 #define READONLY 4 #define GENERR 5 typedef AsnInt PDUInt; /* INTEGER { NOERROR(0), TOOBIG(1), NOSUCHNAME(2), BADVALUE(3), READONLY(4), GENERR(5) } */ #define BEncPDUIntContent BEncAsnIntContent #define BDecPDUIntContent BDecAsnIntContent #define PrintPDUInt PrintAsnInt #define VERSION_1 0 typedef AsnInt MessageInt; /* INTEGER { VERSION_1(0) } */ #define BEncMessageIntContent BEncAsnIntContent #define BDecMessageIntContent BDecAsnIntContent #define PrintMessageInt PrintAsnInt typedef struct VarBind /* SEQUENCE */ { ObjectName name; /* ObjectName */ struct ObjectSyntax* value; /* ObjectSyntax */ } VarBind; AsnLen BEncVarBindContent PROTO((BUF_TYPE b, VarBind* v)); void BDecVarBindContent PROTO(( BUF_TYPE b, AsnTag tagId0, AsnLen elmtLen0, VarBind* v, AsnLen* bytesDecoded, ENV_TYPE env)); void PrintVarBind PROTO((FILE* f, VarBind* v, unsigned short int indent)); typedef AsnList VarBindList; /* SEQUENCE OF VarBind */ AsnLen BEncVarBindListContent PROTO((BUF_TYPE b, VarBindList* v)); void BDecVarBindListContent PROTO(( BUF_TYPE b, AsnTag tagId0, AsnLen elmtLen0, VarBindList* v, AsnLen* bytesDecoded, ENV_TYPE env)); void PrintVarBindList PROTO((FILE* f, VarBindList* v, unsigned short int indent)); typedef struct PDU /* SEQUENCE */ { AsnInt request_id; /* INTEGER */ PDUInt error_status; /* PDUInt */ AsnInt error_index; /* INTEGER */ VarBindList* variable_bindings; /* VarBindList */ } PDU; AsnLen BEncPDUContent PROTO((BUF_TYPE b, PDU* v)); void BDecPDUContent PROTO(( BUF_TYPE b, AsnTag tagId0, AsnLen elmtLen0, PDU* v, AsnLen* bytesDecoded, ENV_TYPE env)); void PrintPDU PROTO((FILE* f, PDU* v, unsigned short int indent)); typedef struct Trap_PDU /* [4] IMPLICIT SEQUENCE */ { AsnOid enterprise; /* OBJECT IDENTIFIER */ struct NetworkAddress* agent_addr; /* NetworkAddress */ Trap_PDUInt generic_trap; /* Trap-PDUInt */ AsnInt specific_trap; /* INTEGER */ TimeTicks time_stamp; /* TimeTicks */ VarBindList* variable_bindings; /* VarBindList */ } Trap_PDU; AsnLen BEncTrap_PDUContent PROTO((BUF_TYPE b, Trap_PDU* v)); void BDecTrap_PDUContent PROTO(( BUF_TYPE b, AsnTag tagId0, AsnLen elmtLen0, Trap_PDU* v, AsnLen* bytesDecoded, ENV_TYPE env)); void PrintTrap_PDU PROTO((FILE* f, Trap_PDU* v, unsigned short int indent)); typedef struct PDU GetRequest_PDU; /* [0] IMPLICIT PDU */ #define BEncGetRequest_PDUContent BEncPDUContent #define BDecGetRequest_PDUContent BDecPDUContent #define PrintGetRequest_PDU PrintPDU typedef struct PDU GetNextRequest_PDU; /* [1] IMPLICIT PDU */ #define BEncGetNextRequest_PDUContent BEncPDUContent #define BDecGetNextRequest_PDUContent BDecPDUContent #define PrintGetNextRequest_PDU PrintPDU typedef struct PDU GetResponse_PDU; /* [2] IMPLICIT PDU */ #define BEncGetResponse_PDUContent BEncPDUContent #define BDecGetResponse_PDUContent BDecPDUContent #define PrintGetResponse_PDU PrintPDU typedef struct PDU SetRequest_PDU; /* [3] IMPLICIT PDU */ #define BEncSetRequest_PDUContent BEncPDUContent #define BDecSetRequest_PDUContent BDecPDUContent #define PrintSetRequest_PDU PrintPDU typedef struct PDUs /* CHOICE */ { enum PDUsChoiceId { PDUS_GET_REQUEST, PDUS_GET_NEXT_REQUEST, PDUS_GET_RESPONSE, PDUS_SET_REQUEST, PDUS_TRAP } choiceId; union PDUsChoiceUnion { GetRequest_PDU* get_request; /* GetRequest-PDU */ GetNextRequest_PDU* get_next_request; /* GetNextRequest-PDU */ GetResponse_PDU* get_response; /* GetResponse-PDU */ SetRequest_PDU* set_request; /* SetRequest-PDU */ struct Trap_PDU* trap; /* Trap-PDU */ } a; } PDUs; AsnLen BEncPDUsContent PROTO((BUF_TYPE b, PDUs* v)); void BDecPDUsContent PROTO(( BUF_TYPE b, AsnTag tagId0, AsnLen elmtLen0, PDUs* v, AsnLen* bytesDecoded, ENV_TYPE env)); void PrintPDUs PROTO((FILE* f, PDUs* v, unsigned short int indent)); typedef struct Message /* SEQUENCE */ { MessageInt version; /* MessageInt */ AsnOcts community; /* OCTET STRING */ struct PDUs* data; /* PDUs */ } Message; AsnLen BEncMessage PROTO((BUF_TYPE b, Message* v)); void BDecMessage PROTO(( BUF_TYPE b, Message* result, AsnLen* bytesDecoded, ENV_TYPE env)); AsnLen BEncMessageContent PROTO((BUF_TYPE b, Message* v)); void BDecMessageContent PROTO(( BUF_TYPE b, AsnTag tagId0, AsnLen elmtLen0, Message* v, AsnLen* bytesDecoded, ENV_TYPE env)); void PrintMessage PROTO((FILE* f, Message* v, unsigned short int indent)); #endif /* conditional include of rfc1157_snmp.h */ --- NEW FILE: io.c --- /* * io.c - Ilmi input/output routines * * Written by Scott W. Shumate * * Copyright (c) 1995-97 All Rights Reserved. * * Permission to use, copy, modify and distribute this * software and its documentation is hereby granted, * provided that both the copyright notice and this * permission notice appear in all copies of the software, * derivative works or modified versions, and any portions * thereof, that both notices appear in supporting * documentation, and that the use of this software is * acknowledged in any publications resulting from using * the software. * * I ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION AND DISCLAIMS ANY LIABILITY OF ANY KIND FOR * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS * SOFTWARE. */ #if HAVE_CONFIG_H #include <config.h> #endif #include <sys/socket.h> #include <netinet/in.h> #include <sys/ioctl.h> #include <errno.h> #include <net/if.h> #include <atm.h> #include <linux/atmdev.h> #include "io.h" #include "atmd.h" #include "atmf_uni.h" #define SNMP_VCI 16 #define COMPONENT "IO" #define MAX_EXTRA_ADDRS 4 /* maximum number of additional addresses that can be manually configured (after ilmid has registered the "official" address) - HACK */ static short atm_itf = -1; /* bad value */ AsnOid *get_esi(int fd, int itf) { static AsnOid *name; struct atmif_sioc req; unsigned char esi[ESI_LEN]; int m, n, size; req.number = itf; req.arg = esi; req.length = ESI_LEN; if(ioctl(fd, ATM_GETESI, &req) < 0) diag(COMPONENT, DIAG_FATAL, "ioctl ATM_GETESI: %s", strerror(errno)); /* save esi to atmfMySystemIdentifierValue */ if (!atmfMySystemIdentifierValue.octs) { atmfMySystemIdentifierValue.octs = alloc(6); memcpy(atmfMySystemIdentifierValue.octs, esi, 6); } /* Convert hex string to Object ID BER */ for(m = 0, size = 0; m < ESI_LEN; esi[m++] & 0x80 ? size += 2 : size++); size++; name = alloc_t(AsnOid); name->octs = alloc(size); name->octetLen = size; for(m = 0, n = 0; m < ESI_LEN; m++, n++) { if(esi[m] & 0x80) name->octs[n++] = '\201'; name->octs[n] = esi[m] & 0x7F; } /* Add the SEL */ name->octs[n] = '\0'; return name; } void update_nsap(int itf, AsnOid *netprefix, AsnOid *esi) { struct atmif_sioc req; struct sockaddr_atmsvc addr, ouraddr[MAX_EXTRA_ADDRS+1]; char buffer[MAX_ATM_ADDR_LEN+1]; int fd, m, n; addr.sas_family = AF_ATMSVC; addr.sas_addr.pub[0] = 0; /* Convert net prefix BER to hex */ for(m = 0, n = 0; m < netprefix->octetLen; m++, n++) if(netprefix->octs[m] & 0x80) addr.sas_addr.prv[n] = netprefix->octs[++m] | 0x80; else addr.sas_addr.prv[n] = netprefix->octs[m]; /* Convert esi BER to hex */ for(m = 0; m < esi->octetLen; m++, n++) if(esi->octs[m] & 0x80) addr.sas_addr.prv[n] = esi->octs[++m] | 0x80; else addr.sas_addr.prv[n] = esi->octs[m]; if ((fd = socket(AF_ATMSVC, SOCK_DGRAM, 0)) < 0) diag(COMPONENT, DIAG_FATAL, "socket: %s", strerror(errno)); req.number = itf; req.arg = &ouraddr; req.length = sizeof(ouraddr); /* Try to get our address on that interface */ if (ioctl(fd, ATM_GETADDR, &req) <0) diag(COMPONENT, DIAG_FATAL, "ioctl ATM_GETADDR: %s", strerror(errno)); n = 0; if (req.length && atm_equal((struct sockaddr *) &addr, (struct sockaddr *) &ouraddr[0], ATM_ESA_LEN, 0)) { diag(COMPONENT, DIAG_INFO, "Primary ATM Address did not change"); n = 1; } if ((!(m = req.length)) || (!n)) { req.number = itf; req.arg = NULL; req.length = 0; if (ioctl(fd, ATM_RSTADDR, &req) < 0) diag(COMPONENT, DIAG_FATAL, "ioctl ATM_RSTADDR: %s", strerror(errno)); req.number = itf; req.arg = &addr; req.length = sizeof(addr); if (ioctl(fd, ATM_ADDADDR, &req) < 0) diag(COMPONENT, DIAG_FATAL, "ioctl ATM_ADDADDR: %s", strerror(errno)); atm2text(buffer,MAX_ATM_ADDR_LEN+1,(struct sockaddr *) &addr, A2T_PRETTY); diag(COMPONENT, DIAG_INFO, "Primary ATM Address %s added local", buffer); for (n = 0; n < m/sizeof(addr); n++) { if(n > MAX_EXTRA_ADDRS-1) break; /* We have already registered "primary" NSAP */ req.number = itf; req.arg = &ouraddr[n]; req.length = sizeof(*ouraddr); atm2text(buffer,MAX_ATM_ADDR_LEN+1,(struct sockaddr *) &ouraddr[n], A2T_PRETTY); if (ioctl(fd, ATM_ADDADDR, &req) < 0) diag(COMPONENT, DIAG_ERROR, "ioctl ATM_ADDADDR: %s", strerror(errno)); else diag(COMPONENT, DIAG_INFO, "Extra ATM Address %s added local", buffer); } } close(fd); } int wait_for_message(int fd, struct timeval *timeout) { int numfds; fd_set fdvar; FD_ZERO(&fdvar); FD_SET(fd, &fdvar); if((numfds = select(fd + 1, &fdvar, 0, 0, timeout)) < 0) diag(COMPONENT, DIAG_FATAL, "select: %s", strerror(errno)); return numfds; } int read_message(int fd, Message *message) { SBuf buffer; char data[MAX_ILMI_MSG]; AsnLen length; jmp_buf env; if ((int) (length = read(fd, data, MAX_ILMI_MSG)) < 0) diag(COMPONENT, DIAG_FATAL, "read: %s", strerror(errno)); SBufInstallData(&buffer, data, length); if (setjmp(env) == 0) { BDecMessage(&buffer, message, &length, env); } else { diag(COMPONENT, DIAG_ERROR, "message decoding error"); return -1; } diag(COMPONENT, DIAG_DEBUG, "SNMP message received:"); if(get_verbosity(NULL) == DIAG_DEBUG) PrintMessage(get_logfile(), message, 0); if(message->version != VERSION_1) { diag(COMPONENT, DIAG_ERROR, "received message with wrong version number"); return -1; } if(message->community.octetLen != 4 || memcmp(message->community.octs, "ILMI", 4)) { diag(COMPONENT, DIAG_ERROR, "received message with wrong community"); return -1; } return 0; } int send_message(int fd, Message *message) { SBuf buffer; AsnLen length; char data[MAX_ILMI_MSG]; SBufInit(&buffer, data, MAX_ILMI_MSG); SBufResetInWriteRvsMode(&buffer); if(!(length = BEncMessage(&buffer, message))) { diag(COMPONENT, DIAG_ERROR, "message encoding error"); return -1; } if(write(fd, SBufDataPtr(&buffer), length) != length) diag(COMPONENT, DIAG_FATAL, "write: %s", strerror(errno)); diag(COMPONENT, DIAG_DEBUG, "SNMP message sent:"); if(get_verbosity(NULL) == DIAG_DEBUG) PrintMessage(get_logfile(), message, 0); return 0; } int open_ilmi(int itf,const char *qos_spec) { struct sockaddr_atmpvc addr; struct atm_qos qos; int fd; if((fd = socket(PF_ATMPVC, SOCK_DGRAM, 0)) < 0) diag(COMPONENT, DIAG_FATAL, "socket: %s", strerror(errno)); atm_itf = itf; memset(&qos, 0, sizeof(qos)); qos.rxtp.max_sdu = MAX_ILMI_MSG; qos.txtp.max_sdu = MAX_ILMI_MSG; qos.aal = ATM_AAL5; if (!qos_spec) qos.rxtp.traffic_class = qos.txtp.traffic_class = ATM_UBR; else if (text2qos(qos_spec,&qos,T2Q_DEFAULTS) < 0) diag(COMPONENT,DIAG_FATAL,"invalid qos: %s",qos_spec); if (setsockopt(fd, SOL_ATM, SO_ATMQOS, &qos, sizeof(qos)) < 0) diag(COMPONENT,DIAG_FATAL,"setsockopt SO_ATMQOS: %s",strerror(errno)); memset(&addr, 0, sizeof(addr)); addr.sap_family = AF_ATMPVC; addr.sap_addr.itf = itf; addr.sap_addr.vpi = 0; addr.sap_addr.vci = SNMP_VCI; if(bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) diag(COMPONENT, DIAG_FATAL, "bind: %s", strerror(errno)); return fd; } int get_ci_range(struct atm_cirange *ci) { struct atmif_sioc req; int fd,error; fd = socket(PF_ATMPVC,SOCK_DGRAM,0); if (fd < 0) diag(COMPONENT,DIAG_FATAL,"socket: %s",strerror(errno)); req.number = atm_itf; req.length = sizeof(*ci); req.arg = ci; error = ioctl(fd,ATM_GETCIRANGE,&req); (void) close(fd); if (error < 0) { diag(COMPONENT,DIAG_ERROR,"ioctl ATM_GETCIRANGE: %s",strerror(errno)); return error; } } --- NEW FILE: io.h --- /* * io.h - Ilmi input/output routines * * Written by Scott W. Shumate * * Copyright (c) 1995-97 All Rights Reserved. * * Permission to use, copy, modify and distribute this * software and its documentation is hereby granted, * provided that both the copyright notice and this * permission notice appear in all copies of the software, * derivative works or modified versions, and any portions * thereof, that both notices appear in supporting * documentation, and that the use of this software is * acknowledged in any publications resulting from using * the software. * * I ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION AND DISCLAIMS ANY LIABILITY OF ANY KIND FOR * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS * SOFTWARE. */ #ifndef IO_H #define IO_H #include <sys/time.h> #include <atm.h> #include <linux/atmdev.h> #include "asn_incl.h" #include "rfc1155_smi.h" #include "rfc1157_snmp.h" #define MAX_ILMI_MSG 484 AsnOid *get_esi(int fd, int itf); void update_nsap(int itf, AsnOid *netprefix, AsnOid *esi); int wait_for_message(int fd, struct timeval *timeout); int read_message(int fd, Message *message); int send_message(int fd, Message *message); int open_ilmi(int itf,const char *qos_spec); int get_ci_range(struct atm_cirange *ci); #endif --- NEW FILE: mib.c --- /* * mib.c - MIB Primitives * * Written by Scott W. Shumate * * Copyright (c) 1995-97 All Rights Reserved. * * Permission to use, copy, modify and distribute this * software and its documentation is hereby granted, * provided that both the copyright notice and this * permission notice appear in all copies of the software, * derivative works or modified versions, and any portions * thereof, that both notices appear in supporting * documentation, and that the use of this software is * acknowledged in any publications resulting from using * the software. * * I ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION AND DISCLAIM ANY LIABILITY OF ANY KIND FOR * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS * SOFTWARE. */ #if HAVE_CONFIG_H #include <config.h> #endif #include "mib.h" #include "sysgroup.h" #include "atmf_uni.h" #include "util.h" #include "atmd.h" #include <unistd.h> /* gethostname() */ #include <netdb.h> /* gethostbyname() */ #define COMPONENT "MIB" static Variable variables[] = /* keep this sorted by the value of entry.name */ { { &sysDescr, getString, NULL, NULL, &sysDescrValue }, { &sysObjectID, getOid, NULL, NULL, &sysObjectIDValue }, { &sysUpTime, getUpTime, NULL, NULL, NULL }, { &sysContact, getString, NULL, NULL, &sysContactValue }, { &sysName, getString, NULL, NULL, &sysNameValue }, { &sysLocation, getString, NULL, NULL, &sysLocationValue }, { &sysServices, getInteger, NULL, NULL, &sysServicesValue }, { &atmfPortIndex, getInteger, NULL, NULL, &atmfPortIndexValue }, { &atmfPortMyIdentifier, getInteger, NULL, NULL, &atmfPortIndexValue }, { &atmfMyIpNmAddress, getIpAddr, NULL, NULL, &atmfMyIpNmAddressValue }, { &atmfMySystemIdentifier, getString, NULL, NULL, &atmfMySystemIdentifierValue }, { &atmfAtmLayerMaxVpiBits, getVpiRange, NULL, NULL, &atmfAtmLayerMaxVpiBitsValue }, { &atmfAtmLayerMaxVciBits, getVciRange, NULL, NULL, &atmfAtmLayerMaxVciBitsValue }, { &atmfAtmLayerUniVersion, getInteger, NULL, NULL, &atmfAtmLayerUniVersionValue }, { &atmfNetPrefixStatus, getNetPrefix, getnextNetPrefix, setNetPrefix, NULL }, { NULL } }; void MIBget(VarBindList *list, PDUInt *status, AsnInt *index) { VarBind *varbind; Variable *var; AsnOidResult result; *index = 1; FOR_EACH_LIST_ELMT(varbind, list) { /* Find the first MIB object not lexigraphically less than the * * requested OID */ var = variables; while(var->name != NULL) { result = AsnOidCompare(var->name, &varbind->name); if(result != AsnOidLess) break; var++; } /* Call get if the requested OID is equal to a simple MIB object */ /* OR if the requested OID is a leaf of a complex MIB object */ if((result == AsnOidEqual && var->getnext == NULL) || (result == AsnOidRoot && var->getnext != NULL)) *status = var->get(varbind, var); /* else the object was not found */ else *status = NOSUCHNAME; /* Check if the get failed */ if(*status != NOERROR) return; (*index)++; } *index = 0; return; } void MIBgetnext(VarBindList *list, PDUInt *status, AsnInt *index) { VarBind *varbind; Variable *var; AsnOidResult result; *index = 1; FOR_EACH_LIST_ELMT(varbind, list) { /* Find the first complex MIB object not lexigraphically less than * * or simple MIB object greater than the requested OID */ var = variables; while(var->name != NULL) { result = AsnOidCompare(var->name, &varbind->name); if(var->getnext == NULL) { if(result == AsnOidGreater) break; } else if(result != AsnOidLess) break; var++; } /* Find the next valid MIB object */ for(*status = NOSUCHNAME; var->name != NULL && *status == NOSUCHNAME; var++) if(var->getnext == NULL) { varbind->name.octs = Asn1Alloc(var->name->octetLen); AsnOidCopy(&varbind->name, var->name); *status = var->get(varbind, var); } else *status = var->getnext(varbind, var); /* Check if no valid MIB object found */ if(*status != NOERROR) return; (*index)++; } *index = 0; return; } void MIBset(VarBindList *list, PDUInt *status, AsnInt *index) { VarBind *varbind; Variable *var; AsnOidResult result; *index = 1; FOR_EACH_LIST_ELMT(varbind, list) { /* Find the first MIB object not lexigraphically less than the * * requested OID */ var = variables; while(var->name != NULL) { result = AsnOidCompare(var->name, &varbind->name); if(result != AsnOidLess) break; var++; } /* Call set if the requested variable is equal to a simple MIB object */ if((result == AsnOidEqual && var->getnext == NULL) || /* OR if the request variable is a leaf of a complex MIB object */ (result == AsnOidRoot && var->getnext != NULL)) /* Return read only if no set function exists */ if(var->set == NULL) *status = READONLY; else *status = var->set(varbind, var); else /* else the MIB object was not found */ *status = NOSUCHNAME; /* Check if the set failed */ if(*status != NOERROR) return; (*index)++; } *index = 0; return; } void *MIBdelete(AsnOid *oid) { Variable *var; void *value; AsnOidResult result; /* Find the first MIB object not lexigraphically less than the * * requested variable */ var = variables; while(var->name != NULL) { result = AsnOidCompare(var->name, oid); if(result != AsnOidLess) break; var++; } /* Return NULL if the MIB object is not found */ if(result != AsnOidEqual) return NULL; value = var->value; var->value = NULL; return value; } AsnInt getString(VarBind *varbind, Variable *var) { varbind->value = Asn1Alloc(sizeof(struct ObjectSyntax)); varbind->value->choiceId = OBJECTSYNTAX_SIMPLE; varbind->value->a.simple = Asn1Alloc(sizeof(struct SimpleSyntax)); varbind->value->a.simple->choiceId = SIMPLESYNTAX_STRING; varbind->value->a.simple->a.string = (AsnOcts*) var->value; return NOERROR; } AsnInt getOid(VarBind *varbind, Variable *var) { varbind->value = Asn1Alloc(sizeof(struct ObjectSyntax)); varbind->value->choiceId = OBJECTSYNTAX_SIMPLE; varbind->value->a.simple = Asn1Alloc(sizeof(struct SimpleSyntax)); varbind->value->a.simple->choiceId = SIMPLESYNTAX_OBJECT; varbind->value->a.simple->a.object = (AsnOid*) var->value; return NOERROR; } AsnInt getInteger(VarBind *varbind, Variable *var) { varbind->value = Asn1Alloc(sizeof(struct ObjectSyntax)); varbind->value->choiceId = OBJECTSYNTAX_SIMPLE; varbind->value->a.simple = Asn1Alloc(sizeof(struct SimpleSyntax)); varbind->value->a.simple->choiceId = SIMPLESYNTAX_NUMBER; varbind->value->a.simple->a.number = *((AsnInt *) var->value); return NOERROR; } #include <stdint.h> #include <string.h> #include <ctype.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/ioctl.h> #include <net/if.h> #include <netinet/in.h> #define MAX_ITFS 500 static const char *itf_types[] = { "", /* fallback */ "slip*","ppp*","eth*","lec*", /* candidates */ "atm*", "!lo", /* blacklist */ NULL /* the end */ }; static uint32_t get_local_ip(void) { struct ifconf ifc; struct ifreq ifr[MAX_ITFS]; const char **best; uint32_t best_ip; int s,i; s = socket(PF_INET,SOCK_DGRAM,0); if (s < 0) { perror("socket"); return 0; } ifc.ifc_len = MAX_ITFS*sizeof(struct ifreq); ifc.ifc_req = ifr; if (ioctl(s,SIOCGIFCONF,&ifc) < 0) { perror("SIOCGIFCONF"); return 0; } best = itf_types; best_ip = 0; for (i = 0; i < ifc.ifc_len/sizeof(struct ifreq); i++) { struct sockaddr_in *addr; const char **walk; uint32_t ip; addr = (struct sockaddr_in *) &ifr[i].ifr_addr; if (addr->sin_family != AF_INET) continue; ip = addr->sin_addr.s_addr; if (!ip) continue; if (ioctl(s,SIOCGIFFLAGS,&ifr[i]) < 0) { perror("SIOCGIFFLAGS"); continue; } if (ifr[i].ifr_flags & IFF_LOOPBACK) continue; if (!(ifr[i].ifr_flags & IFF_UP)) continue; for (walk = best+1; *walk; walk++) { const char *pos,*wc,*end; int not; if ((not = *(pos = *walk) == '!')) pos++; if (*pos) { int len; wc = strchr(pos,'*'); end = wc ? wc : strchr(pos,0); len = end-pos; if (strncmp(ifr[i].ifr_name,pos,end-pos)) continue; if (len < IFNAMSIZ && ifr[i].ifr_name[len]) if (!wc || !isdigit(ifr[i].ifr_name[len])) continue; } if (not) break; best = walk; best_ip = ip; } } return best_ip; } static uint32_t local_ip = 0; void set_local_ip(uint32_t ip) { local_ip = ip; } AsnInt getIpAddr(VarBind *varbind, Variable *var) { if (!local_ip) { local_ip = get_local_ip(); if (!local_ip) { struct hostent* h; char hostname[128]; if (!gethostname(hostname, sizeof(hostname)-1)) { h = (struct hostent*) gethostbyname(hostname); if (!h) local_ip = 0; /* give up :-( */ else memcpy(&local_ip,h->h_addr_list[0],4); } } } if (!((IpAddress*) var->value)->octs) { unsigned char *p; ((IpAddress *) var->value)->octs = p = alloc(4); memcpy(((IpAddress *) var->value)->octs,&local_ip,4); diag(COMPONENT,DIAG_DEBUG,"Local IP address is %d.%d.%d.%d",p[0],p[1], p[2],p[3]); } varbind->value = Asn1Alloc(sizeof(ObjectSyntax)); varbind->value->choiceId = OBJECTSYNTAX_APPLICATION_WIDE; varbind->value->a.application_wide = Asn1Alloc(sizeof(ApplicationSyntax)); varbind->value->a.application_wide->choiceId = APPLICATIONSYNTAX_ADDRESS; varbind->value->a.application_wide->a.address = Asn1Alloc(sizeof(NetworkAddress)); varbind->value->a.application_wide->a.address->choiceId = NETWORKADDRESS_INTERNET; varbind->value->a.application_wide->a.address->a.internet = (IpAddress*) var->value; return NOERROR; } #include <atm.h> #include <linux/atmdev.h> static AsnInt put_ci(VarBind *varbind,Variable *var, struct atm_cirange *ci,char *bits) { if (get_ci_range(ci) < 0) return GENERR; diag(COMPONENT,DIAG_DEBUG,"VPI: %d bits, VCI: %d bits",ci->vpi_bits, ci->vci_bits); varbind->value = Asn1Alloc(sizeof(struct ObjectSyntax)); varbind->value->choiceId = OBJECTSYNTAX_SIMPLE; varbind->value->a.simple = Asn1Alloc(sizeof(struct SimpleSyntax)); varbind->value->a.simple->choiceId = SIMPLESYNTAX_NUMBER; varbind->value->a.simple->a.number = *((AsnInt *) var->value) = *bits; return NOERROR; } AsnInt getVpiRange(VarBind *varbind, Variable *var) { struct atm_cirange ci; return put_ci(varbind,var,&ci,&ci.vpi_bits); } AsnInt getVciRange(VarBind *varbind, Variable *var) { struct atm_cirange ci; return put_ci(varbind,var,&ci,&ci.vci_bits); } --- NEW FILE: mib.h --- /* * mib.h - MIB Primitives * * Written by Scott W. Shumate * * Copyright (c) 1995-97 All Rights Reserved. * * Permission to use, copy, modify and distribute this * software and its documentation is hereby granted, * provided that both the copyright notice and this * permission notice appear in all copies of the software, * derivative works or modified versions, and any portions * thereof, that both notices appear in supporting * documentation, and that the use of this software is * acknowledged in any publications resulting from using * the software. * * I ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION AND DISCLAIM ANY LIABILITY OF ANY KIND FOR * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS * SOFTWARE. */ #ifndef MIB_H #define MIB_H #include "atmd.h" #include "asn_incl.h" #include "rfc1155_smi.h" #include "rfc1157_snmp.h" typedef struct Variable { AsnOid *name; AsnInt (*get)(VarBind *varbind, struct Variable *var); AsnInt (*getnext)(VarBind *varbind, struct Variable *var); AsnInt (*set)(VarBind *varbind, struct Variable *var); void *value; } Variable; void MIBget(VarBindList *list, PDUInt *status, AsnInt *index); void MIBgetnext(VarBindList *list, PDUInt *status, AsnInt *index); void MIBset(VarBindList *list, PDUInt *status, AsnInt *index); void *MIBdelete(AsnOid *oid); AsnInt getString(VarBind *varbind, Variable *var); AsnInt getOid(VarBind *varbind, Variable *var); AsnInt getInteger(VarBind *varbind, Variable *var); AsnInt getIpAddr(VarBind *varbind, Variable *var); AsnInt getVpiRange(VarBind *varbind, Variable *var); AsnInt getVciRange(VarBind *varbind, Variable *var); void set_local_ip(uint32_t ip); #endif --- NEW FILE: atmf_uni.c --- /* * atmf_uni.c - ATM Forum UNI MIB * * Written by Scott W. Shumate * * Copyright (c) 1995-97 All Rights Reserved. * * Permission to use, copy, modify and distribute this * software and its documentation is hereby granted, * provided that both the copyright notice and this * permission notice appear in all copies of the software, * derivative works or modified versions, and any portions * thereof, that both notices appear in supporting * documentation, and that the use of this software is * acknowledged in any publications resulting from using * the software. * * I ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION AND DISCLAIM ANY LIABILITY OF ANY KIND FOR * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS * SOFTWARE. */ #if HAVE_CONFIG_H #include <config.h> #endif #include "atmf_uni.h" #include "atmd.h" #include "util.h" #define COMPONENT "NETPREFIX" #define NETPREFIX_LEN 12 #define NETPREFIX_STRINGLEN '\15' #define INDEX_LEN 15 #define LOCALUNI '\0' #define VALID 1 #define INVALID 2 AsnOid atmfPortIndex = {13, "\53\06\01\04\01\202\141\02\01\01\01\01\00"}; AsnOid atmfPortMyIdentifier = {13, "\53\06\01\04\01\202\141\02\01\01\01\10\00"}; AsnOid atmfMyIpNmAddress = {11, "\53\06\01\04\01\202\141\02\01\02\00"}; AsnOid atmfMySystemIdentifier = {11, "\53\06\01\04\01\202\141\02\01\04\00"}; AsnOid atmfAtmLayerMaxVpiBits = {13, "\53\06\01\04\01\202\141\02\02\01\01\6\00"}; AsnOid atmfAtmLayerMaxVciBits = {13, "\53\06\01\04\01\202\141\02\02\01\01\7\00"}; AsnOid atmfAtmLayerUniVersion = {13, "\53\06\01\04\01\202\141\02\02\01\01\11\00"}; AsnOid atmfNetPrefixStatus = {NETPREFIX_LEN, "\53\06\01\04\01\202\141\02\07\01\01\03"}; AsnInt atmfPortIndexValue = 0; AsnOcts atmfMySystemIdentifierValue = {6 , NULL}; IpAddress atmfMyIpNmAddressValue = {4 , NULL}; /* The following two values depend on the capabilities of both the switch AND the adapter - DO THEY ?? */ AsnInt atmfAtmLayerMaxVpiBitsValue; AsnInt atmfAtmLayerMaxVciBitsValue; #if defined(UNI30) || defined(DYNAMIC_UNI) AsnInt atmfAtmLayerUniVersionValue = 2; // version3point0(2) #else #ifdef UNI31 AsnInt atmfAtmLayerUniVersionValue = 3; // version3point1(3) #else AsnInt atmfAtmLayerUniVersionValue = 4; // version4point0(4) #endif #endif static AsnOid atmNetPrefix = {0, NULL}; typedef struct NetPrefixNode { AsnOid *name; struct NetPrefixNode *prev; struct NetPrefixNode *next; } NetPrefixNode; AsnOid *accessNetPrefix(void) { if(atmNetPrefix.octs == NULL) return NULL; return(&atmNetPrefix); } void deleteNetPrefix(void) { NetPrefixNode *prefix, *nextPrefix; for(prefix = (NetPrefixNode *) MIBdelete(&atmfNetPrefixStatus); prefix != NULL; prefix = nextPrefix) { nextPrefix = prefix->next; free(prefix->name->octs); free(prefix->name); free(prefix); } if(atmNetPrefix.octs != NULL) { free(atmNetPrefix.octs); atmNetPrefix.octs = NULL; } } AsnInt getNetPrefix(VarBind *varbind, Variable *var) { int cmp; NetPrefixNode *prefix; AsnOid *varBindName; varBindName = &varbind->name; if(AsnOidSize(varBindName) != NETPREFIX_LEN + INDEX_LEN || varbind->name.octs[NETPREFIX_LEN] != LOCALUNI || varbind->name.octs[NETPREFIX_LEN + 1] != NETPREFIX_STRINGLEN) return NOSUCHNAME; for(prefix = (NetPrefixNode *) var->value, cmp = AsnOidLess; prefix != NULL && (cmp = AsnOidCompare(varBindName, prefix->name)) < AsnOidEqual; prefix = prefix->next); if(cmp != AsnOidEqual) return NOSUCHNAME; varbind->value = Asn1Alloc(sizeof(struct ObjectSyntax)); varbind->value->choiceId = OBJECTSYNTAX_SIMPLE; varbind->value->a.simple = Asn1Alloc(sizeof(struct SimpleSyntax)); varbind->value->a.simple->choiceId = SIMPLESYNTAX_NUMBER; varbind->value->a.simple->a.number = VALID; return NOERROR; } AsnInt getnextNetPrefix(VarBind *varbind, Variable *var) { NetPrefixNode *prefix; AsnOid *varBindName; varBindName = &varbind->name; for(prefix = (NetPrefixNode *) var->value; prefix != NULL && AsnOidCompare(prefix->name, varBindName) != AsnOidGreater; prefix = prefix->next); if(prefix == NULL) return NOSUCHNAME; varbind->name.octs = Asn1Alloc(prefix->name->octetLen); AsnOidCopy(varBindName, prefix->name); varbind->value = Asn1Alloc(sizeof(struct ObjectSyntax)); varbind->value->choiceId = OBJECTSYNTAX_SIMPLE; varbind->value->a.simple = Asn1Alloc(sizeof(struct SimpleSyntax)); varbind->value->a.simple->choiceId = SIMPLESYNTAX_NUMBER; varbind->value->a.simple->a.number = VALID; return NOERROR; } AsnInt setNetPrefix(VarBind *varbind, Variable *var) { int cmp; NetPrefixNode *prefix, *newPrefix; AsnOid *varBindName; varBindName = &varbind->name; if(varbind->value->choiceId != OBJECTSYNTAX_SIMPLE || varbind->value->a.simple->choiceId != SIMPLESYNTAX_NUMBER || (varbind->value->a.simple->a.number != VALID && varbind->value->a.simple->a.number != INVALID)) return BADVALUE; if(AsnOidSize(varBindName) != NETPREFIX_LEN + INDEX_LEN || varBindName->octs[NETPREFIX_LEN] != LOCALUNI || varBindName->octs[NETPREFIX_LEN + 1] != NETPREFIX_STRINGLEN) return NOSUCHNAME; for(prefix = (NetPrefixNode *) var->value, cmp = AsnOidLess; prefix != NULL && (cmp = AsnOidCompare(varBindName, prefix->name)) < AsnOidEqual; prefix = prefix->next); if(varbind->value->a.simple->a.number == VALID && cmp != AsnOidEqual) { newPrefix = alloc_t(NetPrefixNode); newPrefix->name = alloc_t(AsnOid); newPrefix->name->octs = alloc(varBindName->octetLen); AsnOidCopy(newPrefix->name, varBindName); Q_INSERT_BEFORE((NetPrefixNode *) var->value, newPrefix, prefix); if(atmNetPrefix.octs == NULL) { atmNetPrefix.octetLen = varBindName->octetLen - NETPREFIX_LEN - 2; atmNetPrefix.octs = alloc(atmNetPrefix.octetLen); memcpy(atmNetPrefix.octs, &varBindName->octs[NETPREFIX_LEN + 2], atmNetPrefix.octetLen); } } else if (varbind->value->a.simple->a.number == INVALID && cmp == AsnOidEqual) { Q_REMOVE((NetPrefixNode *) var->value, prefix); } return NOERROR; } --- NEW FILE: atmf_uni.h --- /* * atmf_uni.h - ATM Forum UNI MIB * * Written by Scott W. Shumate * * Copyright (c) 1995-97 All Rights Reserved. * * Permission to use, copy, modify and distribute this * software and its documentation is hereby granted, * provided that both the copyright notice and this * permission notice appear in all copies of the software, * derivative works or modified versions, and any portions * thereof, that both notices appear in supporting * documentation, and that the use of this software is * acknowledged in any publications resulting from using * the software. * * I ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION AND DISCLAIM ANY LIABILITY OF ANY KIND FOR * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS * SOFTWARE. */ #ifndef ATMF_UNI_H #define ATMF_UNI_H #include "asn_incl.h" #include "rfc1155_smi.h" #include "rfc1157_snmp.h" #include "mib.h" extern AsnOid atmfPortIndex; extern AsnOid atmfPortMyIdentifier; extern AsnOid atmfMyIpNmAddress; extern AsnOid atmfMySystemIdentifier; extern AsnOid atmfNetPrefixStatus; extern AsnOid atmfAtmLayerMaxVpiBits; extern AsnOid atmfAtmLayerMaxVciBits; extern AsnOid atmfAtmLayerUniVersion; extern AsnInt atmfPortIndexValue; extern IpAddress atmfMyIpNmAddressValue; extern AsnOcts atmfMySystemIdentifierValue; extern AsnInt atmfAtmLayerMaxVpiBitsValue; extern AsnInt atmfAtmLayerMaxVciBitsValue; extern AsnInt atmfAtmLayerUniVersionValue; AsnOid *accessNetPrefix(void); void deleteNetPrefix(void); AsnInt getNetPrefix(VarBind *varbind, Variable *var); AsnInt getnextNetPrefix(VarBind *varbind, Variable *var); AsnInt setNetPrefix(VarBind *varbind, Variable *var); AsnInt getMyIp(VarBind *varbind, Variable *var); #endif --- NEW FILE: Makefile.am --- SUBDIRS = asn1 INCLUDES = -I$(top_builddir)/src/ilmid/asn1 sbin_PROGRAMS = ilmid ilmid_SOURCES = rfc1157_snmp.c rfc1157_snmp.h rfc1155_smi.c rfc1155_smi.h \ util.c util.h io.c io.h message.c message.h \ atmf_uni.c atmf_uni.h mib.c mib.h \ sysgroup.c sysgroup.h ilmid.c ilmid_LDADD = $(top_builddir)/src/lib/libatmd.la \ $(top_builddir)/src/lib/libatm.la \ $(top_builddir)/src/ilmid/asn1/libasn1.a ilmid_DEPENDENCIES = $(ilmid_LDADD) EXTRA_DIST = COPYRIGHT --- NEW FILE: sysgroup.c --- /* * sysgroup.c - MIB-II system group * * Written by Scott W. Shumate * * Copyright (c) 1995-97 All Rights Reserved. * * Permission to use, copy, modify and distribute this * software and its documentation is hereby granted, * provided that both the copyright notice and this * permission notice appear in all copies of the software, * derivative works or modified versions, and any portions * thereof, that both notices appear in supporting * documentation, and that the use of this software is * acknowledged in any publications resulting from using * the software. * * I ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION AND DISCLAIM ANY LIABILITY OF ANY KIND FOR * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS * SOFTWARE. */ #if HAVE_CONFIG_H #include <config.h> #endif #include <time.h> #include "sysgroup.h" #include "string.h" AsnOid sysDescr = {8, "\53\06\01\02\01\01\01\00"}; AsnOid sysObjectID = {8, "\53\06\01\02\01\01\02\00"}; AsnOid sysUpTime = {8, "\53\06\01\02\01\01\03\00"}; AsnOid sysContact = {8, "\53\06\01\02\01\01\04\00"}; AsnOid sysName = {8, "\53\06\01\02\01\01\05\00"}; AsnOid sysLocation = {8, "\53\06\01\02\01\01\06\00"}; AsnOid sysServices = {8, "\53\06\01\02\01\01\07\00"}; AsnOcts sysDescrValue = {25, "ATM on Linux Version " VERSION}; AsnOid sysObjectIDValue = {8, "\53\06\01\04\01\03\01\01"}; AsnOcts sysContactValue = {14, "root@localhost"}; AsnOcts sysNameValue = {23, "local... [truncated message content] |
From: Paul B. S. <pa...@us...> - 2001-09-03 18:41:10
|
Update of /cvsroot/linux-atm/linux-atm/src/switch/tcp In directory usw-pr-cvs1:/tmp/cvs-serv10656/switch/tcp Added Files: Tag: V2_4_0 README tcpsw.c mkfiles Makefile.am Log Message: --- NEW FILE: README --- The following sequence works. Figuring out why is left as an exercise to the reader ;-) Commands: lrcpc4:~/w/atm/switch/tcp# ./sw_tcp -b -d lrcpc4:~# atmtcp virtual 1 switch localhost 1 bg lrcpc4:~# atmtcp virtual 2 switch localhost 2 bg lrcpc4:~# atmaddr -a 2 +1 lrcpc4:~/w/atm/switch/tcp# atmsigd -b -c 2.conf lrcpc15:~# atmtcp virtual 1 switch lrcpc4 3 bg lrcpc15:~# atmaddr -a 1 +2 lrcpc15:~/w/atm/switch/tcp# atmsigd -b -c 1.conf lrcpc15:~$ ttcp_atm -r -a lrcpc4:~$ ttcp_atm -t -a +2 --- switch.conf --------------------------------------------------------------- command "atmsigd -c s1.conf -b -m switch 1.0.100 /tmp/1" socket /tmp/1 { itf 2 1.0.100 route +1 } command "atmsigd -c s2.conf -b -m switch 1.0.101 /tmp/2" socket /tmp/2 { itf 3 1.0.101 default } --- s1.conf ------------------------------------------------------------------- debug log stderr debug level warn sig level debug sig vpci 0 itf 2 --- s2.conf ------------------------------------------------------------------- debug log stderr debug level warn sig level debug sig vpci 0 itf 3 --- 1.conf -------------------------------------------------------------------- debug log stderr debug level warn sig level debug io vc 1.0.5 sig vpci 0 itf 1 --- 2.conf -------------------------------------------------------------------- debug log stderr debug level warn sig level debug io vc 2.0.5 sig vpci 0 itf 2 --- - The following picture shows a simplified view of the configuration. Note that the command-line options have been choosen for clarity (and minor details like the vpci settings in the configuration file have been omitted) and are not identical with the ones given above. +-----------------------------------------------------------------------+ | ./sw_tcp | | | | +---------+ +----------------------------------+ 1.0.100 | | | |--/tmp/1--| atmsigd -m switch 1.0.100 /tmp/1 |---+ | | | | +----------------------------------+ | | | | <relay> | +-----+ | | | | +----------------------------------+ | | | | | |--/tmp/2--| atmsigd -m switch 1.0.101 /tmp/2 |---+ | | | +---------+ +----------------------------------+ 1.0.101 | | | | | | | | +--------------+ | | | | | | | | | | control | | | | | +----------------------| | itf 1 | | | <fabric> | | | | | | | | | 2.0.5 <--> 1.0.100 | | | | | 3.0.5 <--> 1.0.101 | 2 3 1 | | | | +--------------+ | | | | | | | | +-------------------------------|-----|----|------------------------|---+ | | | | +------------+ | | | | | | | +-----------------------------------+ | +-----------------------------------+ |atmtcp virtual 2 switch localhost 2| | |atmtcp virtual 1 switch localhost 1| +-----------------------------------+ | +-----------------------------------+ | | itf 2 (+1) +---- - - - - - ----+ | | +---------------+ | on lrcpc15: | | atmsigd 2.0.5 | | +---------------+ | | | | +--------------------------------+ | |atmtcp virtual 1 switch lrcpc4 3| | +--------------------------------+ | | itf 1 (+2) | | +---------------+ | atmsigd 1.0.5 | | +---------------+ In order to control the switch with swc, add the line control <path> to switch.conf, e.g. control /var/run/tcpswc Then invoke swc as follows: swc <path> show To add VCs, use add <itf>.<vpi>.<vci> , to add VPs, use add <itf>.<vpi>.? --- NEW FILE: tcpsw.c --- /* tcpsw.c - ATMTCP switch */ /* 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 <string.h> #include <errno.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <atm.h> #include <linux/atm_tcp.h> #include <atmd.h> #include "uni.h" #include "../fab.h" #include "../dispatch.h" #include "../swc.h" #define COMPONENT "FAB(tcp)" #define PRV(call) ((FAB *) (call)->fab) #define MAX_VCI 1024 #define PORT 2812 /* @@@ should merge with atmtcp.c */ #define MAX_PACKET (ATM_MAX_AAL5_PDU+sizeof(struct atmtcp_hdr)) #define BUFFER_SIZE (MAX_PACKET*2) typedef struct _table { struct _link *out; /* output port */ uint16_t in_vpi; /* input VPI */ int in_vci; /* input VCI (may be ATM_VCI_ANY) */ uint16_t out_vpi; /* output VPI */ uint16_t out_vci; /* output VCI */ struct _table *next; } TABLE; typedef struct _link { enum { id_none,id_set,id_reval } state; int id; /* switch port ID */ int fd; int len; /* length of data in the buffer */ char buffer[BUFFER_SIZE]; TABLE *table; /* switching table */ struct _link *next; } LINK; typedef struct _fab { int active; /* non-zero if there's an entry in the fabric */ CALL *next; /* relay.c may not keep track of calls, but WE are */ } FAB; static CALL *calls = NULL; static LINK *links = NULL; static void (*notify)(int number,int up); static LINK *find_link(int id) { LINK *lnk; for (lnk = links; lnk; lnk = lnk->next) if (lnk->state == id_set && lnk->id == id) break; return lnk; } static LINK *route(LINK *in,struct atmtcp_hdr *hdr) { TABLE *entry; for (entry = in->table; entry; entry = entry->next) if (ntohs(hdr->vpi) == entry->in_vpi && (entry->in_vci == ATM_VCI_UNSPEC || ntohs(hdr->vci) == entry->in_vci)) { hdr->vpi = htons(entry->out_vpi); if (entry->in_vci != ATM_VCI_UNSPEC) hdr->vci = htons(entry->out_vci); return entry->out; } return NULL; } static int add_entry(struct sockaddr_atmpvc *from,struct sockaddr_atmpvc *to) { LINK *l_from,*l_to; TABLE *entry; l_from = find_link(from->sap_addr.itf); l_to = find_link(to->sap_addr.itf); if (!l_from || !l_to) return -ENODEV; for (entry = l_from->table; entry; entry = entry->next) if (entry->in_vpi == from->sap_addr.vpi && (entry->in_vci == ATM_VCI_UNSPEC || from->sap_addr.vci == ATM_VCI_UNSPEC || entry->in_vci == from->sap_addr.vci)) return -EEXIST; entry = alloc_t(TABLE); entry->out = l_to; entry->in_vpi = from->sap_addr.vpi; entry->in_vci = from->sap_addr.vci; entry->out_vpi = to->sap_addr.vpi; entry->out_vci = to->sap_addr.vci; entry->next = l_from->table; l_from->table = entry; if (entry->in_vci == ATM_VCI_UNSPEC) diag(COMPONENT,DIAG_INFO,"added VP %d.%d -> %d.%d",l_from->id, entry->in_vpi,l_to->id,entry->out_vpi); else diag(COMPONENT,DIAG_INFO,"added VC %d.%d.%d -> %d.%d.%d",l_from->id, entry->in_vpi,entry->in_vci,l_to->id,entry->out_vpi,entry->out_vci); return 0; } static int del_entry(struct sockaddr_atmpvc *from,struct sockaddr_atmpvc *to) { LINK *l_from,*l_to; TABLE **entry,*this; l_from = find_link(from->sap_addr.itf); l_to = find_link(to->sap_addr.itf); if (!l_from || !l_to) return -ENODEV; for (entry = &l_from->table; *entry; entry = &(*entry)->next) if ((*entry)->out == l_to && (*entry)->in_vpi == from->sap_addr.vpi && (*entry)->in_vci == from->sap_addr.vci && ((*entry)->in_vci == ATM_VCI_UNSPEC || (*entry)->out_vci == to->sap_addr.vci)) break; if (!*entry) return -EHOSTUNREACH; this = *entry; *entry = this->next; if (this->in_vci == ATM_VCI_UNSPEC) diag(COMPONENT,DIAG_INFO,"deleted VP %d.%d -> %d.%d",l_from->id, this->in_vpi,l_to->id,this->out_vpi); else diag(COMPONENT,DIAG_INFO,"deleted VC %d.%d.%d -> %d.%d.%d",l_from->id, this->in_vpi,this->in_vci,l_to->id,this->out_vpi,this->out_vci); free(this); return 0; } static void drop_link(LINK *lnk) { diag(COMPONENT,DIAG_INFO,"dropped link %d",lnk->id); if (lnk->state == id_set) { notify(lnk->id,0); lnk->state = id_reval; } dsp_fd_remove(lnk->fd); #if 0 LINK **walk,**next_link,**entry,**next_entry; /* remove link from the list and delete all references to link */ for (walk = &links; *walk; walk = next_link) { next_link = &(*walk)->next; if (*walk == lnk) *walk = *next_link; else for (entry = &(*walk)->table; *entry; entry = next_entry) { next_entry = &(*entry)->next; if ((*entry)->out == lnk) { TABLE *this; this = *entry; *entry = *next_entry; free(this); } } } *walk = lnk->next; /* remove link's switching table */ while (lnk->table) { TABLE *next; next = lnk->table->next; free(lnk->table); lnk->table = next; } /* drop memory */ free(*lnk); #endif } static void new_data(int fd,void *user) { LINK *lnk = user; int got; got = read(fd,lnk->buffer+lnk->len,BUFFER_SIZE-lnk->len); if (got < 0) perror("read"); if (got <= 0) drop_link(lnk); lnk->len += got; if (lnk->state != id_set) { LINK *walk; char *end; int id; if (!memchr(lnk->buffer,0,lnk->len)) return; id = strtol(lnk->buffer,&end,0); if (*end) { diag(COMPONENT,DIAG_ERROR,"invalid line id \"%s\"",lnk->buffer); drop_link(lnk); return; } for (walk = links; walk; walk = walk->next) if (walk->state != id_none && id == walk->id) break; if (walk) { if (walk->state == id_set) { diag(COMPONENT,DIAG_ERROR,"line state mismatch (id %d)",id); drop_link(lnk); return; } diag(COMPONENT,DIAG_INFO,"reconnected link %d",id); walk->state = id_set; walk->fd = lnk->fd; walk->len = lnk->len; memcpy(walk->buffer,lnk->buffer,lnk->len); drop_link(lnk); lnk = walk; dsp_fd_add(lnk->fd,new_data,walk); } else { diag(COMPONENT,DIAG_INFO,"new link %d",id); lnk->state = id_set; lnk->id = id; } notify(lnk->id,1); lnk->len -= strlen(lnk->buffer)+1; memmove(lnk->buffer,lnk->buffer-strlen(lnk->buffer)-1,lnk->len); } while (lnk->len >= sizeof(struct atmtcp_hdr)) { struct atmtcp_hdr *hdr = (struct atmtcp_hdr *) lnk->buffer; LINK *out; int size; size = sizeof(struct atmtcp_hdr)+ntohl(hdr->length); if (lnk->len < size) break; out = route(lnk,hdr); if (out) { int sent; sent = write(out->fd,lnk->buffer,size); if (sent < 0) perror("write"); else if (sent != size) diag(COMPONENT,DIAG_ERROR,"bad write: %d != %d",sent,size); if (sent != size) drop_link(out); } lnk->len -= size; memmove(lnk->buffer,lnk->buffer+size,lnk->len); } } static void new_link(int sock,void *dummy) { LINK *lnk; int fd; fd = accept(sock,NULL,NULL); if (fd < 0) { perror("accept"); return; } lnk = alloc_t(LINK); lnk->state = id_none; lnk->id = -1; lnk->fd = fd; lnk->len = 0; lnk->table = NULL; lnk->next = links; links = lnk; dsp_fd_add(fd,new_data,lnk); } static int vci_exists(LINK *lnk,int vpi,int vci) { TABLE *walk; for (walk = lnk->table; walk; walk = walk->next) if (walk->in_vpi == vpi && walk->in_vci == vci) return 1; return 0; } static int check_ci(struct sockaddr_atmpvc *pvc) { LINK *lnk; TABLE *walk; int vci; lnk = find_link(pvc->sap_addr.itf); if (!lnk) return 0; if (pvc->sap_addr.vpi == ATM_VPI_ANY) pvc->sap_addr.vpi = 0; /* that was easy :-) */ for (walk = lnk->table; walk; walk = walk->next) if (walk->in_vpi == pvc->sap_addr.vpi) break; if (walk && walk->in_vci == ATM_VCI_UNSPEC) return 0; if (pvc->sap_addr.vci == ATM_VCI_UNSPEC) return !walk; if (pvc->sap_addr.vci != ATM_VCI_ANY) return !vci_exists(lnk,pvc->sap_addr.vpi,pvc->sap_addr.vci); for (vci = ATM_NOT_RSV_VCI; vci < MAX_VCI; vci++) if (!vci_exists(lnk,pvc->sap_addr.vpi,vci)) { pvc->sap_addr.vci = vci; return 1; } return 0; } void fab_option(const char *name,const char *value) { diag(COMPONENT,DIAG_FATAL,"unrecognized fabric option \"%s\"",name); } void fab_start(void (*port_notify)(int number,int up)) { struct sockaddr_in addr; int s_listen; notify = port_notify; addr.sin_family = AF_INET; addr.sin_port = htons(PORT); addr.sin_addr.s_addr = htonl(INADDR_ANY); if ((s_listen = socket(PF_INET,SOCK_STREAM,0)) < 0) diag(COMPONENT,DIAG_FATAL,"socket: %s",strerror(errno)); if (bind(s_listen,(struct sockaddr *) &addr,sizeof(addr)) < 0) diag(COMPONENT,DIAG_FATAL,"bind: %s",strerror(errno)); if (listen(s_listen,5) < 0) diag(COMPONENT,DIAG_FATAL,"listen: %s",strerror(errno)); dsp_fd_add(s_listen,new_link,NULL); } void fab_init(CALL *call) { PRV(call) = alloc_t(FAB); PRV(call)->active = 0; PRV(call)->next = calls; calls = call; } void fab_destroy(CALL *call) { CALL **walk; for (walk = &calls; *walk; walk = &PRV(*walk)->next) if (*walk == call) break; if (!*walk) diag(COMPONENT,DIAG_FATAL,"fab_destroy: call %p not found",call); *walk = PRV(call)->next; free(PRV(call)); PRV(call) = NULL; } void fab_op(CALL *call,int op,const struct atm_qos *qos, void (*callback)(CALL *call,int cause,void *more,void *user),void *user) { int error,error2; diag(COMPONENT,DIAG_INFO,"fab_op%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", !op ? " FREE" : "",op & RM_RSV(_RM_ANY) ? " RM_RSV:" : "", op & RM_IN_TX ? " IN_TX" : "",op & RM_IN_RX ? " IN_RX" : "", op & RM_OUT_TX ? " OUT_TX" : "",op & RM_OUT_RX ? " OUT_RX" : "", op & RM_PATH_TX ? " PATH_TX" : "",op & RM_PATH_RX ? " PATH_RX" : "", op & RM_CLAIM(_RM_ANY) ? " RM_CLAIM:" : "", op & _RM_SHIFT(RM_IN_TX) ? " IN_TX" : "", op & _RM_SHIFT(RM_IN_RX) ? " IN_RX" : "", op & _RM_SHIFT(RM_OUT_TX) ? " OUT_TX" : "", op & _RM_SHIFT(RM_OUT_RX) ? " OUT_RX" : "", op & _RM_SHIFT(RM_PATH_TX) ? " PATH_TX" : "", op & _RM_SHIFT(RM_PATH_RX) ? " PATH_RX" : ""); if (op & (RM_RSV(RM_IN) | RM_CLAIM(RM_IN))) { if (!check_ci(&call->in.pvc)) { callback(call,ATM_CV_CI_UNAVAIL,NULL,user); return; } call->in.qos = *qos; } if (op & (RM_RSV(RM_OUT) | RM_CLAIM(RM_OUT))) { if (!check_ci(&call->out.pvc)) { callback(call,ATM_CV_CI_UNAVAIL,NULL,user); return; } call->out.qos = *qos; } if (op & RM_CLAIM(RM_PATH)) { error = 0; if (call->in.qos.txtp.traffic_class != ATM_NONE) error = add_entry(&call->in.pvc,&call->out.pvc); if (!error) { if (call->in.qos.rxtp.traffic_class != ATM_NONE) error = add_entry(&call->out.pvc,&call->in.pvc); if (error && call->in.qos.txtp.traffic_class != ATM_NONE) { error2 = del_entry(&call->in.pvc,&call->out.pvc); if (error2) diag(COMPONENT,DIAG_ERROR,"del_entry: %s",strerror(error2)); } } if (error) { diag(COMPONENT,DIAG_ERROR,"add_entry: %s",strerror(error)); callback(call,ATM_CV_RES_UNAVAIL,NULL,user); return; } PRV(call)->active = 1; } if (!op && PRV(call)->active) { error = error2 = 0; if (call->in.qos.txtp.traffic_class != ATM_NONE) { error = del_entry(&call->in.pvc,&call->out.pvc); if (error) diag(COMPONENT,DIAG_ERROR,"del_entry: %s",strerror(error)); } if (call->in.qos.rxtp.traffic_class != ATM_NONE) { error2 = del_entry(&call->out.pvc,&call->in.pvc); if (error2) diag(COMPONENT,DIAG_ERROR,"del_entry: %s",strerror(error2)); } if (error || error2) { callback(call,ATM_CV_TEMP_FAIL,NULL,user); return; } } callback(call,0,NULL,user); } --- NEW FILE: mkfiles --- #!/usr/bin/perl open(IN,"README") || die "open README: $!"; while (<IN>) { if (/^---\s*(\S+)\s*/) { if ($writing) { close OUT || die "close: $!"; $writing = 0; } next if $1 eq "-"; open(OUT,">$1") || die "create $1: $!"; $writing = 1; next; } print OUT $_ || die "write: $!" if $writing; } close OUT || die "close: $!" if $writing; for (@do) { print "$_\n"; system($_); sleep(1); } --- NEW FILE: Makefile.am --- noinst_PROGRAMS = sw_tcp INCLUDES = -I$(top_builddir)/src/qgen sw_tcp_SOURCES = tcpsw.c sw_tcp_XTRAS = $(top_builddir)/src/switch/libsw.a \ $(top_builddir)/src/lib/libatmd.la \ $(top_builddir)/src/lib/libatm.la sw_tcp_LDADD = $(sw_tcp_XTRAS) -lfl sw_tcp_DEPENDENCIES = $(sw_tcp_XTRAS) EXTRA_DIST = mkfiles README |
Update of /cvsroot/linux-atm/linux-atm/src/ilmid/asn1 In directory usw-pr-cvs1:/tmp/cvs-serv10656/ilmid/asn1 Added Files: Tag: V2_4_0 str_stk.c str_stk.h exp_buf.c exp_buf.h README asn_bits.c asn_bits.h min_buf.h asn_incl.h asn_config.h asn_list.c asn_list.h asn_octs.c asn_octs.h asn_null.c asn_null.h nibble_alloc.c nibble_alloc.h asn_int.c asn_int.h asn_len.c asn_len.h asn_oid.c asn_oid.h asn_tag.c asn_tag.h Makefile.am sbuf.h print.c print.h Log Message: --- NEW FILE: str_stk.c --- /* * str_stk.c - maintains a stack of the components of a bit string * or octet string so they can be copied into a single chunk * * Copyright (C) 1992 Michael Sample and the University of British Columbia * * This library is free software; you can redistribute it and/or * modify it provided that this copyright/license information is retained * in original form. * * If you modify this file, you must clearly indicate your changes. * * This source code is distributed in the hope that it will be * useful, but WITHOUT ANY WARRANTY; without even the implied warranty * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */ #if HAVE_CONFIG_H #include <config.h> #endif #include "asn_config.h" #include "str_stk.h" /* global for use by AsnBits and AsnOcts */ StrStk strStkG = { NULL, 128, 0, 64, 0, 0 }; --- NEW FILE: str_stk.h --- /* * str_stk.h - maintains a stack of the components of a bit string * or octet string so they can be copied into a single chunk * * * CONSTRUCTED BIT AND OCTET STRINGS SUCK. They should be * specified in the application's ASN.1 spec as SEQUENCE OF OCTET STRING * * this stack stuff is for decoding constructed bit/octet strings * so the user gets a single contiguous bit/octet str instead of * irritating little pieces. This does not cost a lot more than * a linked octet/bit string type since we're copying from the * buffer anyway, not referencing it directly (even in simple case). * It will cost more if the string stk overflows and * needs to be enlarged via realloc - set the values of * initialStkSizeG, and stkGrowSize carefully for your application. * Once the StkSize grows, it doesn't shrink back ever. * * Only three routine use/deal with this stack garbage * BDecConsAsnOcts * BDecConsAsnBits * SetupConsBitsOctsStringStk * * Copyright (C) 1992 Michael Sample and the University of British Columbia * * This library is free software; you can redistribute it and/or * modify it provided that this copyright/license information is retained * in original form. * * If you modify this file, you must clearly indicate your changes. * * This source code is distributed in the hope that it will be * useful, but WITHOUT ANY WARRANTY; without even the implied warranty * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */ typedef struct StrStkElmt { char* str; unsigned long int len; } StrStkElmt; typedef struct StrStk { StrStkElmt* stk; /* ptr to array of SSElmts with 'size' elmts */ unsigned long int initialNumElmts; unsigned long int numElmts; /* total # of elements in str stk */ unsigned long int growElmts; /* # elmts to increase size by when nec */ unsigned long int nextFreeElmt; /* index of next free element */ unsigned long int totalByteLen; /* octet len of string stored in stk */ } StrStk; extern StrStk strStkG; /* * initializes stk (Allocates if nec.) * once stk is enlarged, it doesn't shrink */ #define RESET_STR_STK()\ {\ strStkG.nextFreeElmt = 0;\ strStkG.totalByteLen = 0;\ if (strStkG.stk == NULL){\ strStkG.stk = (StrStkElmt*) malloc((strStkG.initialNumElmts) *sizeof(StrStkElmt));\ strStkG.numElmts = strStkG.initialNumElmts;}\ } /* * add a char*,len pair to top of stack. * grows stack if necessary using realloc (!) */ #define PUSH_STR(strPtr, strsLen, env)\ {\ if (strStkG.nextFreeElmt >= strStkG.numElmts)\ {\ strStkG.stk = (StrStkElmt*) realloc(strStkG.stk, (strStkG.numElmts + strStkG.growElmts) *sizeof(StrStkElmt));\ strStkG.numElmts += strStkG.growElmts;\ }\ strStkG.totalByteLen += strsLen;\ strStkG.stk[strStkG.nextFreeElmt].str = strPtr;\ strStkG.stk[strStkG.nextFreeElmt].len = strsLen;\ strStkG.nextFreeElmt++;\ } /* * Set up size values for the stack that is used for merging constructed * octet or bit string into single strings. * **** Call this before decoding anything. ***** * Note: you don't have to call this if the default values * for initialStkSizeG and stkGrowSizeG are acceptable */ #define SetupConsBitsOctsStringStk (initialNumberOfElmts, numberOfElmtsToGrowBy)\ {\ strStkG.initialNumElmts = initialNumberOfElmts; \ strStkG.growElmts = numberOfElmtsToGrowBy;\ } --- NEW FILE: exp_buf.c --- /* * exp_buf.c - buffer routines for the buffer structure * * * --------- ---------- * | ExpBuf |<------>| ExpBuf |<------> ...ExpBufs * | |--- | |--- * ---------- | ---------- | * V V * -------- -------- * | DATA | | DATA | * | BLK | | BLK | * -------- -------- * * * ExpBuf * -------------- * | readError | * | writeError | * | dataStart |----------- * | dataEnd |-------- | * | curr |------ | | * | next | | | | * | prev | | | | data * | blkStart |=====|=|==|==>-------------------------- * | blkEnd |--- | | | | | (each line * -------------- | | | | | | reps a byte * | | | |-->| - - - - - - - - - - - -| diff in addr) * | | | | valid | * | |-|----->| | * | | | data | * | | | | * | | | - - - - - - - - - - - -| * | |----->|(one byte after last valid data byte) * | | | * | -------------------------- * |-----------> (one byte after last byte in data blk) * * * readError - set to non-zero to indicate attempt to read past end of * of data * writeError- set to non-zero to indicate write error. * Set if Alloc of new buf fails * dataStart - pts to first VALID data byte ie *dataStart is first byte * dataEnd - pts to byte AFTER last VALID byte *dataEnd is not in the data * but *(dataEnd -1) is in the data * curr - used for current read ptr - points to next byte to be read * so *curr is the next byte to be read. * next - pts to next BUF in list, NULL for last BUF in list * prev - pts to prev BUF in list, NULL for first BUF in list * blkStart - pts to start of the data blk. *blkStart is first byte * in the buffer's data blk. * blkEnd - pts to byte AFTER last writable byte of the dataBlk. * *(blkEnd-1) is the last byte in the buffer's data blk. * * NOTES: * - dataEnd is currently always the same as blkEnd * - at End Of Data (EOD) (no more data to be read) * if (curr == dataEnd) * - buffer has no valid data if (dataStart == dataEnd) * - number of valid data bytes = (dataEnd - dataStart) * - size of the data block = (blkEnd - blkStart) * * - the write reverse routines modify dataStart * - the read routines modify the curr ptr. * - there are no 'forward' write routines at the moment * (if there were they would adjust dataEnd) * * * Copyright (C) 1992 Michael Sample and the University of British Columbia * * This library is free software; you can redistribute it and/or * modify it provided that this copyright/license information is retained * in original form. * * If you modify this file, you must clearly indicate your changes. * * This source code is distributed in the hope that it will be * useful, but WITHOUT ANY WARRANTY; without even the implied warranty * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * */ #if HAVE_CONFIG_H #include <config.h> #endif #include "asn_config.h" #include "exp_buf.h" /* default buffer data block size (used when allocating) */ unsigned long expBufDataBlkSizeG = 1024; #ifdef DEBUG /* otherwise macros */ /* * sets the size of the data block to attach to * an ExpBuf when allocating a new one */ void ExpBufInit PARAMS((dataBlkSize), unsigned long dataBlkSize) { expBufDataBlkSizeG = dataBlkSize; } /* InitBuffers */ /* * Allocates and returns an uninitialized ExpBuf with * no a data attached. */ ExpBuf* ExpBufAllocBuf() { return ((ExpBuf*)malloc(sizeof(ExpBuf))); } void ExpBufFreeBuf PARAMS( (ptr), ExpBuf* ptr) { free(ptr); } char* ExpBufAllocData() { return((char*)malloc(expBufDataBlkSizeG)); } void ExpBufFreeData PARAMS( (ptr), char* ptr) { free( ptr); } ExpBuf* ExpBufNext PARAMS( (b), ExpBuf* b) { return(b->next); } ExpBuf* ExpBufPrev PARAMS( (b), ExpBuf* b) { return(b->prev); } /* * set curr ptr used in reads to the first byte * to be read */ void ExpBufResetInReadMode PARAMS((b), ExpBuf* b) { b->curr = b->dataStart; b->readError = 0; b->writeError = 1; /* catch wrong mode errors */ } /* * sets dataStart to end of buffer * so following writes (backward) * over-write any existing data associated with * the buffer */ void ExpBufResetInWriteRvsMode PARAMS((b), ExpBuf* b) { b->dataEnd = b->dataStart = b->blkEnd; b->writeError = 0; b->readError = 1; /* catch wrong mode errors */ } /* * returns true if no more data can be read from * the given buffer. only valid when buffer in read (fwd) * mode. */ int ExpBufAtEod PARAMS((b), ExpBuf* b) { return(b->curr == b->dataEnd); } /* * returns true if no more reverse writes can be done * to the buffer. Only valid when buffers in reverse * write mode */ int ExpBufFull PARAMS((b), ExpBuf* b) { return((b)->dataStart == (b)->blkStart); } /* * returns true if the given buffer has no * valid data in it's data block */ int ExpBufHasNoData PARAMS((b), ExpBuf* b) { return(b->dataStart == b->dataEnd); } /* * returns the number of valid data bytes in the * given buffer's data block */ unsigned long ExpBufDataSize PARAMS((b), ExpBuf* b) { return(b->dataEnd - b->dataStart); } /* * returns size of data block that is attached to * the given buffer. */ unsigned long ExpBufDataBlkSize PARAMS((b), ExpBuf* b) { return(b->blkEnd - b->blkStart); } /* * returns a ptr the beginning of the valid data of * the given buffer. * returns NULL is there is no valid data. */ char* ExpBufDataPtr PARAMS((b), ExpBuf* b) { if (ExpBufHasNoData(b)) return(NULL); else return(b->dataStart); } #endif /* DEBUG */ /* * returns last ExpBuf in a list of bufs. * The given buf can be any buf in the list. */ ExpBuf* ExpBufListLastBuf PARAMS((b), ExpBuf* b) { for (; b->next != NULL; b = b->next); return(b); } /* * returns first buf in a list of bufs . * The given buf can be any buf in the list */ ExpBuf* ExpBufListFirstBuf PARAMS((b), ExpBuf* b) { for (; b->prev != NULL; b = b->prev); return(b); } /* * Allocates a Buf and allocates an attaches a * data block of expBufDataBlkSizeG to that buffer. * sets up the blk for writing in that the data start * and data end point to the byte after the data blk. */ ExpBuf* ExpBufAllocBufAndData() { ExpBuf* retVal; retVal = ExpBufAllocBuf(); if (retVal == NULL) return(NULL); retVal->readError = 0; retVal->writeError = 0; retVal->blkStart = ExpBufAllocData(); if (retVal->blkStart == NULL) { ExpBufFreeBuf(retVal); return(NULL); } retVal->next = NULL; retVal->prev = NULL; retVal->curr = retVal->blkEnd = retVal->dataStart = retVal->dataEnd = retVal->blkStart + expBufDataBlkSizeG; return(retVal); } /* ExpBufAllocBufAndData */ /* * Frees ExpBuf's and associated data blocks after * after (next ptr) and including the given buffer, b. */ void ExpBufFreeBufAndDataList PARAMS( (b), ExpBuf* b) { ExpBuf* tmp; for(; b != NULL;) { tmp = b->next; ExpBufFreeBufAndData(b); b = tmp; } } /* ExpBufFreeBufAndDataList */ /* * puts the given data in a buffer and sets it up for reading * the data. This results in a "full" buffer with a data * blk size of given data's len */ void ExpBufInstallDataInBuf PARAMS( ( buf, data, len), ExpBuf* buf _AND_ char* data _AND_ unsigned long int len) { buf->readError = 0; buf->writeError = 0; buf->blkStart = buf->dataStart = buf->curr = data; buf->next = NULL; buf->prev = NULL; buf->blkEnd = buf->dataEnd = data + len; } /* ExpBufInstallDataInBuf */ /* Buf reading and writing routines follow */ /* READ * returns the next byte to be read without * advancing the pointer. No check for end of * data - this is lame */ unsigned char ExpBufPeekByte PARAMS( (b), ExpBuf** b) { if ((*b)->curr == (*b)->dataEnd) (*b)->readError = 1; return(*(*b)->curr); } /* ExpBufPeek */ /* READ * copy the next len chars in the buffer to the given * dst char string. The curr ptr in the buffer is advanced * appropriately */ int ExpBufCopy PARAMS( (dst, b, len), char* dst _AND_ ExpBuf** b _AND_ unsigned long int len) { unsigned long int gotLen; int totalGotLen = 0; char* srcPtr; gotLen = len; while (1) /* optimize std path - eg only one ExpBufGetSeg needed */ { srcPtr = ExpBufGetSeg(b, &gotLen); memcpy(dst + totalGotLen, srcPtr, gotLen); totalGotLen += gotLen; if (totalGotLen >= len) return(totalGotLen); if (gotLen == 0) /* eod */ { (*b)->readError = 1; return(totalGotLen); } gotLen = len - totalGotLen; } /* not reached */ } /* ExpBufCopy */ /* * advance the curr ptr in the given buffer over the next * len bytes */ void ExpBufSkip PARAMS( (b, len), ExpBuf** b _AND_ unsigned long int len) { unsigned long int lenRemaining; lenRemaining = len; while ((len > 0) && ExpBufGetSeg(b, &lenRemaining)) { len -= lenRemaining; if (lenRemaining == 0) { (*b)->readError = 1; return; } lenRemaining = len; } } /* ExpBufSkip */ /* READ * returns a ptr to the next "len" bytes (contiguous). * if "len" is greater than the available contiguous bytes * len is set the the number of contig. bytes the returned * ptr references. Subsequent call to ExpBufGetSeg or other ExpBufGet * routines will return ptrs to the following bytes (ie curr is advanced). * Changes *b to pt to the next buffer and sets curr for the * that buffer to dataStart if the current one has been totally read. * * if the value returned in the len param is zero or the * returned char* is NULL then at end of data (eod) * */ char* ExpBufGetSeg PARAMS( (b, len), ExpBuf** b _AND_ unsigned long int* len) { int bytesLeft; char* retVal; if (ExpBufAtEod(*b)) { *len = 0; return(NULL); } bytesLeft = (*b)->dataEnd - (*b)->curr; retVal = (*b)->curr; /* check for "buffer fault" */ if ( bytesLeft <= *len) { *len = bytesLeft; if ((*b)->next != NULL) { *b = (*b)->next; /* get next buffer with valid data */ while ( ((*b)->next != NULL) && ExpBufHasNoData(*b) ) *b = (*b)->next; /* reset current pointer to beggining of data if nec */ (*b)->curr = (*b)->dataStart; } else (*b)->curr += *len; } else (*b)->curr += *len; return(retVal); } /* ExpBufGetSeg */ /* * WRITE * Copies len bytes from the data pointer into the given buffer * * FILLS EXP_BUFFERS BACKWARDS! from the end of the data to the beginning * LINKS BUFFERS BACKWARDS! if a buf is full it allocs another an * puts it at the HEAD of the buffer list * * changes *b to pt to the new "prev" buffer if the current one * has been totally filled * Rvs is for REVERSE! * * modifies the dataStart pointer to reflect the new data */ void ExpBufPutSegRvs PARAMS( (b, data, len), ExpBuf** b _AND_ char* data _AND_ unsigned long int len) { int bytesLeft; ExpBuf* buf; char* dataPtr; buf = *b; if (buf->writeError) return; bytesLeft = buf->dataStart - buf->blkStart; dataPtr = data + len; /* pts to end of data to be written */ /* optimize fast path */ do { if (bytesLeft > len) /* enough room in this buffer for write */ { buf->dataStart -= len; memcpy(buf->dataStart, data, len); break; /* this is the normal exit from this loop */ } else { /* * going to fill this buffer completely, * so alloc other one (only if one is not * already linked in) */ dataPtr = dataPtr - bytesLeft; buf->dataStart = buf->blkStart; memcpy(buf->dataStart, dataPtr, bytesLeft); len -= bytesLeft; if (buf->prev == NULL) { /* alloc & insert new buf at head of buffer list */ buf = ExpBufAllocBufAndData(); if (buf == NULL) { (*b)->writeError = 1; return; } buf->next = *b; (*b)->prev = buf; } else buf = buf->prev; *b = buf; /* update head of list */ bytesLeft = buf->dataStart - buf->blkStart; } } while (1); /* not reached */ } /* ExpBufPutSegRvs */ /* * returns the next byte and advances the curr ptr by one. * sets the readError flag if there is no byte to read * (ie at end of data) */ unsigned char ExpBufGetByte PARAMS( (b), ExpBuf** b) { unsigned char retVal; if (ExpBufAtEod(*b)) { (*b)->readError = 1; return((unsigned char)0); } retVal = *(*b)->curr++; /* "buffer fault" - if end of this buf, go on to next, if any */ if ( ExpBufAtEod(*b) && ((*b)->next != NULL)) { *b = (*b)->next; /* get next buffer with valid data */ while ( ((*b)->next != NULL) && ExpBufHasNoData(*b) ) *b = (*b)->next; /* reset current pointer to beggining of data if nec */ (*b)->curr = (*b)->dataStart; } return(retVal); } /* ExpBufGetByte */ /* WRITE * Puts a single octet into the buffer * writes in reverse. * allocates new buffers as nec - may change * (*b) to new buffer since writing backwards */ void ExpBufPutByteRvs PARAMS( (b, byte), ExpBuf** b _AND_ unsigned char byte) { ExpBuf* new; if ((*b)->writeError) return; *(--(*b)->dataStart) = byte; /* * check if buffer is full and alloc new one if nec * and insert it before this one since writing backwards */ if (ExpBufFull(*b)) { if ((*b)->prev == NULL) { /* * no prev buf so alloc & insert * new buf as head of buffer list */ new = ExpBufAllocBufAndData(); if (new == NULL) { (*b)->writeError = 1; return; } new->next = *b; (*b)->prev = new; *b = new; } else { (*b) = (*b)->prev; ExpBufResetInWriteRvsMode(*b); } } } /* ExpBufPutByteRvs */ --- NEW FILE: exp_buf.h --- /* * exp_buf.h - read/write/alloc/free routines for a simple buffer structure * * MACROS are gross but execution speed is important * * NOTE: replacing the malloc and free with a allocs/frees * from/to buffer pools or similar tuned/fixed size * mem mgmt will improve performance. * * You should tune the buffer management to your environment * for best results * * MS 91 * Copyright (C) 1992 Michael Sample and the University of British Columbia * * This library is free software; you can redistribute it and/or * modify it provided that this copyright/license information is retained * in original form. * * If you modify this file, you must clearly indicate your changes. * * This source code is distributed in the hope that it will be * useful, but WITHOUT ANY WARRANTY; without even the implied warranty * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */ #ifndef _exp_buf_h_ #define _exp_buf_h_ typedef struct ExpBuf { char* dataStart; /* points to first valid data byte */ /* when empty, 1 byte past blk end (rvs write)*/ char* dataEnd; /* pts to first byte AFTER last valid data byte*/ char* curr; /* current location to read form */ /* points to next byte to read */ struct ExpBuf* next; /* next buf (NULL if no next buffer)*/ struct ExpBuf* prev; /* prev buf (NULL if no prev buffer)*/ char* blkStart; /* points to first byte of the blk */ char* blkEnd; /* points the first byte AFTER blks last byte */ int readError; /* non-zero is attempt to read past end of data*/ int writeError;/* non-zero is attempt write fails (no mor bufs)*/ } ExpBuf; /* init, alloc and free routines */ #ifdef DEBUG /* use fcns when debugging/macros later */ void ExpBufInit PROTO((unsigned long dataBlkSize)); ExpBuf* ExpBufAllocBuf(); void ExpBufFreeBuf PROTO((ExpBuf* ptr)); char* ExpBufAllocData(); void ExpBufFreeData PROTO((char* ptr)); void ExpBufFreeBufAndData PROTO(( ExpBuf* b)); ExpBuf* ExpBufNext PROTO((ExpBuf* b)); ExpBuf* ExpBufPrev PROTO((ExpBuf* b)); void ExpBufResetInReadMode PROTO((ExpBuf* b)); void ExpBufResetInWriteRvsMode PROTO((ExpBuf* b)); int ExpBufAtEod PROTO((ExpBuf* b)); int ExpBufFull PROTO((ExpBuf* b)); int ExpBufHasNoData PROTO((ExpBuf* b)); unsigned long ExpBufDataSize PROTO((ExpBuf* b)); unsigned long ExpBufDataBlkSize PROTO((ExpBuf* b)); char* ExpBufDataPtr PROTO((ExpBuf* b)); #else extern unsigned long expBufDataBlkSizeG; #define ExpBufInit(size) expBufDataBlkSizeG = size; #define ExpBufAllocBuf() ((ExpBuf*)malloc(sizeof(ExpBuf))) #define ExpBufFreeBuf(ptr) free(ptr) #define ExpBufAllocData() ((void*)malloc(expBufDataBlkSizeG)) #define ExpBufFreeData( ptr) free(ptr) #define ExpBufFreeBufAndData(b) { ExpBufFreeData((b)->blkStart);\ ExpBufFreeBuf(b);} #define ExpBufNext(b) ((b)->next) #define ExpBufPrev(b) ((b)->prev) #define ExpBufResetInReadMode(b) {(b)->curr = (b)->dataStart; (b)->readError = 0; (b)->writeError = 1;} #define ExpBufResetInWriteRvsMode(b) {(b)->dataStart = (b)->dataEnd = (b)->blkEnd; (b)->writeError = 0; (b)->readError = 1;} /* ExpBufAtEod only valid during reads (fwd) */ #define ExpBufAtEod(b) ((b)->curr == (b)->dataEnd) /* ExpBufFull only valid during write (reverse) */ #define ExpBufFull(b) ((b)->dataStart == (b)->blkStart) #define ExpBufHasNoData(b) ((b)->dataStart == (b)->dataEnd) #define ExpBufDataSize(b) ((b)->dataEnd - (b)->dataStart) #define ExpBufDataBlkSize(b) ((b)->blkEnd - (b)->blkStart) #define ExpBufDataPtr(b) (ExpBufHasNoData(b)? NULL: (b)->dataStart) #endif /* DEBUG */ #define ExpBufReadError(b) ((*b)->readError) #define ExpBufWriteError(b) ((*b)->writeError) ExpBuf* ExpBufAllocBufAndData(); void ExpBufInstallDataInBuf PROTO((ExpBuf* b, char* data, unsigned long int len)); void ExpBufFreeBufAndDataList PROTO(( ExpBuf* b)); ExpBuf* ExpBufListLastBuf PROTO((ExpBuf* b)); ExpBuf* ExpBufListFirstBuf PROTO((ExpBuf* b)); /* reading and writing routines */ void ExpBufSkip PROTO(( ExpBuf**, unsigned long len)); int ExpBufCopy PROTO(( char* dst, ExpBuf** b, unsigned long len)); unsigned char ExpBufPeekByte PROTO(( ExpBuf** b)); char* ExpBufGetSeg PROTO((ExpBuf** b, unsigned long* len)); void ExpBufPutSegRvs PROTO((ExpBuf** b, char* data, unsigned long len)); unsigned char ExpBufGetByte PROTO((ExpBuf** b)); void ExpBufPutByteRvs PROTO((ExpBuf** b, unsigned char byte)); #endif /* conditional include */ --- NEW FILE: README --- snacc ASN.1 Compiler Release 1.1 - (updated Jul 93) ----------------------------------------------------- This package provides the C/yacc/lex source code for snacc, an ASN.1 to C or C++ compiler. Snacc is short for "Sample Neufeld Asn.1 to C Compiler" and ASN.1 stands for Abstract Syntax Notation One (CCITT X.208/ ISO 8824). See the COPYRIGHT file for copyright information. What It Does ------------ Given an ASN.1 source file(s) snacc can produce: 1. C routines for BER encoding, decoding, printing and freeing. 2. C++ routines for BER encoding, decoding, and printing. 3. A type table that can be used with C driver routines for BER encoding, decoding, printing and freeing. 4. if you are really lucky, a core dump! :) Snacc produces reasonably efficient C or C++ routines and data structures to support BER encoding and decoding values of the given ASN.1 data structures. Printing routines for the decoded values are also generated. For C only, hierarchical freeing routines are generated (but are not recommended for efficiency reasons). When using the C or C++ (not table) options, snacc creates the following C files for each ASN.1 source file (module): 1. .h file for the C/C++ translation of the ASN.1 data structure and prototypes for the generated routines. 2. .c/.C file for the C/C++ encode, decode, print and free routines. When using the table option, snacc produces a type table file (a BER encoding) that can later be loaded at runtime by the table driven encoding and decoding routines. See the latex or PostScript version of the documentation in the snacc/doc directory for indepth information on this tool. For a quick introduction, look at the examples in snacc/c_examples, snacc/c++_examples and snacc/tbl_example. Features of ASN.1 Supported --------------------------- - parses ASN.1 '90 (subtype notation etc.) - macro definitions do not generate syntax errors but are are not processed. (retained as string) - value notation is parsed and for OBJECT IDENTIFIERs, INTEGERs and BOOLEANS (any other value in { }'s is currently kept as a string) - handles multiple ASN.1 module compiling/linking (IMPORTS/EXPORTS) - some X.400 and SNMP macros are parsed - supports ";" separted type or value definitions in the ASN.1 source. This is useful when dealing with some macros that introduce parsing problems. Does not require the ";"'s though. - ANY DEFINED BY types are handled using the SNMP OBJECT-TYPE macro to define the identifier to type mapping. Bugs are still quite likely even though this is the second release of snacc. if you find any or have other comments please email: sna...@cs... To Install It ------------- By default, the snacc makefile uses GNU bison and GNU flex (instead of yacc and lex). If you do not have these installed, see the snacc/src/README and snacc/src/makefile. Otherwise, type "make" in this directory. Hopefully this will put the snacc binary in the snacc/bin directory and build the C runtime library, the table library and the table tools. Alternatively, type "make all" to install these and the C++ library. Compiling problems may occurr on different flavours of UNIX but they should not be too difficult fix. Likely sources of problems include non-standard include files and lex, yacc and cc idiosyncrasies. If your yacc croaks with a message about too many productions use bison. Same thing with lex -> use flex. Bison and flex are both freely available from numerous ftp sites. (even cs.ubc.ca in /mirror2/gnu) The snacc compiler and the generated code will compile under ANSI and non-ANSI C compilers. See the README and the makefile in the snacc/src directory for more compiling information. Snacc has been successfully installed on Sun SPARCs, HP700s, IBM RS 6000s, MIPS, i486/Linux, and many other machines. --- NEW FILE: asn_bits.c --- /* * asn_bits.c - BER encode, decode, print and free routines for ASN.1 * BIT STRING type * * MS 92 * Copyright (C) 1992 Michael Sample and the University of British Columbia * * This library is free software; you can redistribute it and/or * modify it provided that this copyright/license information is retained * in original form. * * If you modify this file, you must clearly indicate your changes. * * This source code is distributed in the hope that it will be * useful, but WITHOUT ANY WARRANTY; without even the implied warranty * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * */ #if HAVE_CONFIG_H #include <config.h> #endif #include "asn_config.h" #include "asn_len.h" #include "asn_tag.h" #include "str_stk.h" #include "asn_bits.h" static unsigned short int unusedBitsG; char numToHexCharTblG[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd' ,'e', 'f'}; /* * encodes universal TAG LENGTH and Contents of and ASN.1 BIT STRING */ AsnLen BEncAsnBits PARAMS((b, data), BUF_TYPE b _AND_ AsnBits* data) { AsnLen len; len = BEncAsnBitsContent(b, data); len += BEncDefLen(b, len); len += BEncTag1(b, UNIV, PRIM, BITSTRING_TAG_CODE); return(len); } /* BEncAsnInt */ /* * decodes universal TAG LENGTH and Contents of and ASN.1 BIT STRING */ void BDecAsnBits PARAMS((b, result, bytesDecoded, env), BUF_TYPE b _AND_ AsnBits* result _AND_ AsnLen* bytesDecoded _AND_ jmp_buf env) { AsnTag tag; AsnLen elmtLen; if (((tag =BDecTag(b, bytesDecoded, env)) != MAKE_TAG_ID(UNIV, PRIM, BITSTRING_TAG_CODE)) && (tag != MAKE_TAG_ID(UNIV, CONS, BITSTRING_TAG_CODE))) { Asn1Error("BDecAsnBits: ERROR - wrong tag on BIT STRING.\n"); longjmp(env, -40); } elmtLen = BDecLen (b, bytesDecoded, env); BDecAsnBitsContent( b, tag, elmtLen, result, bytesDecoded, env); } /* BDecAsnBits */ /* * Encodes the BIT STRING value (including the unused bits * byte) to the given buffer. */ AsnLen BEncAsnBitsContent PARAMS((b, bits), BUF_TYPE b _AND_ AsnBits* bits) { unsigned long int unusedBits; unsigned long int byteLen; if (bits->bitLen == 0) byteLen = 0; else byteLen = ((bits->bitLen-1) / 8) + 1; BufPutSegRvs(b, bits->bits, byteLen); unusedBits = (bits->bitLen % 8); if (unusedBits != 0) unusedBits = 8 - unusedBits; BufPutByteRvs(b, unusedBits); return(byteLen + 1); } /* BEncAsnBitsContent */ /* * Used when decoding to combine constructed pieces into one * contiguous block. * Fills string stack with references to the pieces of a * construced bit string. sets unusedBitsG appropriately. * and strStkG.totalByteLenG to bytelen needed to hold the bitstring */ static void FillBitStringStk PARAMS((b, elmtLen0, bytesDecoded, env), BUF_TYPE b _AND_ AsnLen elmtLen0 _AND_ AsnLen* bytesDecoded _AND_ jmp_buf env) { unsigned long int refdLen; unsigned long int totalRefdLen; char* strPtr; unsigned long int totalElmtsLen1 = 0; unsigned long int tagId1; unsigned long int elmtLen1; unsigned long int lenToRef; unsigned long int unusedBits; for ( ; (totalElmtsLen1 < elmtLen0) || (elmtLen0 == INDEFINITE_LEN);) { tagId1 = BDecTag(b, &totalElmtsLen1, env); if ( (tagId1 == EOC_TAG_ID) && (elmtLen0 == INDEFINITE_LEN)) { BDEC_2ND_EOC_OCTET(b, &totalElmtsLen1, env); break; } elmtLen1 = BDecLen (b, &totalElmtsLen1, env); if ( tagId1 == MAKE_TAG_ID( UNIV, PRIM, BITSTRING_TAG_CODE)) { /* * primitive part of string, put references to piece(s) in * str stack */ /* * get unused bits octet */ if (unusedBitsG != 0) { /* * whoa - only allowed non-octet aligned bits on * on last piece of bits string */ Asn1Error("FillBitStringStk: ERROR - a component of a constructed BIT STRING that is not the last has non-zero unused bits\n"); longjmp(env, -1); } if (elmtLen1 != 0) unusedBitsG = BufGetByte(b); totalRefdLen = 0; lenToRef =elmtLen1-1; /* remove one octet for the unused bits oct*/ refdLen = lenToRef; while (1) { strPtr = BufGetSeg( b, &refdLen); PUSH_STR(strPtr, refdLen, env); totalRefdLen += refdLen; if (totalRefdLen == lenToRef) break; /* exit this while loop */ if (refdLen == 0) /* end of data */ { Asn1Error("FillBitStringStk: ERROR - expecting more data\n"); longjmp(env, -2); } refdLen = lenToRef - totalRefdLen; } totalElmtsLen1 += elmtLen1; } else if ( tagId1 == MAKE_TAG_ID( UNIV, CONS, BITSTRING_TAG_CODE)) { /* * constructed octets string embedding in this constructed * octet string. decode it. */ FillBitStringStk( b, elmtLen1, &totalElmtsLen1, env); } else /* wrong tag */ { Asn1Error("FillBitStringStk: ERROR - decoded non-BIT STRING tag inside a constructed BIT STRING\n"); longjmp(env, -3); } } /* end of for */ (*bytesDecoded) += totalElmtsLen1; } /* FillBitStringStk */ /* * Decodes a seq of universally tagged bits until either EOC is * encountered or the given len decoded. Returns them in a * single concatenated bit string */ static void BDecConsAsnBits PARAMS((b, len, result, bytesDecoded, env), BUF_TYPE b _AND_ AsnLen len _AND_ AsnBits* result _AND_ AsnLen* bytesDecoded _AND_ jmp_buf env) { char* bufCurr; unsigned long int curr; RESET_STR_STK(); /* * decode each piece of the octet string, puting * an entry in the octet/bit string stack for each */ FillBitStringStk(b, len, bytesDecoded, env); /* alloc single str long enough for combined bitstring */ result->bitLen = strStkG.totalByteLen*8 - unusedBitsG; bufCurr = result->bits = Asn1Alloc(strStkG.totalByteLen); /* copy bit string pieces (buffer refs) into single block */ for (curr = 0; curr < strStkG.nextFreeElmt; curr++) { memcpy(bufCurr, strStkG.stk[curr].str, strStkG.stk[curr].len); bufCurr += strStkG.stk[curr].len; } } /* BDecConsAsnBits */ /* * Decodes the content of a BIT STRING (including the unused bits octet) * Always returns a single contiguous bit string */ void BDecAsnBitsContent PARAMS((b, tagId, len, result, bytesDecoded, env), BUF_TYPE b _AND_ AsnTag tagId _AND_ AsnLen len _AND_ AsnBits* result _AND_ AsnLen* bytesDecoded _AND_ jmp_buf env) { char* tmp; /* * tagId is encoded tag shifted into long int. * if CONS bit is set then constructed bit string */ if (TAG_IS_CONS(tagId)) BDecConsAsnBits(b, len, result, bytesDecoded, env); else /* primitive octet string */ { (*bytesDecoded) += len; len--; result->bitLen = (len * 8) - (unsigned int)BufGetByte(b); result->bits = Asn1Alloc(len); BufCopy( result->bits, b, len); if (BufReadError(b)) { Asn1Error("BDecAsnBitsContent: ERROR - decoded past end of data\n"); longjmp(env, -4); } } } /* BDecAsnBitsContent */ /* * Frees the string part of a BIT STRING */ void FreeAsnBits PARAMS((v), AsnBits* v) { Asn1Free(v->bits); } /* FreeAsnBits */ /* * Prints the contents of the given BIT STRING to the * given file. indent is ignored. Always uses ASN.1 Value Notaion * Hex format. (Should be binary versions in some cases) */ void PrintAsnBits PARAMS((f,v, indent), FILE* f _AND_ AsnBits* v _AND_ unsigned short indent) { int i; unsigned long int octetLen; if (v->bitLen == 0) octetLen = 0; else octetLen = (v->bitLen-1)/8 +1; fprintf(f,"'"); for(i = 0; i < octetLen; i++) fprintf(f,"%c%c", TO_HEX(v->bits[i] >> 4), TO_HEX(v->bits[i])); fprintf(f,"'H"); } /* PrintAsnBits */ /* * Returns TRUE if the given BIT STRINGs are identical. * Otherwise returns FALSE. */ int AsnBitsEquiv PARAMS((b1, b2), AsnBits* b1 _AND_ AsnBits* b2) { int octetsLessOne; int octetBits; if ((b1->bitLen == 0) && (b2->bitLen == 0)) return(TRUE); octetsLessOne = (b1->bitLen-1)/8; octetBits = 7 - (b1->bitLen % 8); /* trailing bits may not be significant */ return ( (b1->bitLen == b2->bitLen) && (memcmp(b1->bits, b2->bits, octetsLessOne) == 0) && (( b1->bits[octetsLessOne] & (0xFF << octetBits)) == ( b1->bits[octetsLessOne] & (0xFF << octetBits)))); } /* AsnBitsEquiv */ /* * Set given bit to 1. Most significant bit is bit 0, least significant * is bit (v1->bitLen -1) */ void SetAsnBit PARAMS((b1, bit), AsnBits* b1 _AND_ unsigned long int bit) { unsigned long int octet; unsigned long int octetsBit; if (bit < b1->bitLen) { octet = bit/8; octetsBit = 7 - (bit % 8);/* bit zero is first/most sig bit in octet */ b1->bits[octet] |= 1 << octetsBit; } } /* SetAsnBit */ /* * Set given bit to 0. Most significant bit is bit 0, least significant * is bit (v1->bitLen -1) */ void ClrAsnBit PARAMS((b1, bit), AsnBits* b1 _AND_ unsigned long int bit) { unsigned long int octet; unsigned long int octetsBit; if (bit < b1->bitLen) { octet = bit/8; octetsBit = 7 - (bit % 8);/* bit zero is first/most sig bit in octet */ b1->bits[octet] &= ~(1 << octetsBit); } } /* ClrAsnBit */ /* * Get given bit. Most significant bit is bit 0, least significant * is bit (v1->bitLen -1). Returns TRUE if the bit is 1. Returns FALSE * if the bit is 0. if the bit is out of range then returns 0. */ int GetAsnBit PARAMS((b1, bit), AsnBits* b1 _AND_ unsigned long int bit) { unsigned long int octet; unsigned long int octetsBit; if (bit < b1->bitLen) { octet = bit/8; octetsBit = 7 - (bit % 8); /* bit zero is first/most sig bit in octet*/ return (b1->bits[octet] & (1 << octetsBit)); } return(0); } /* AsnBits::GetBit */ --- NEW FILE: asn_bits.h --- /* * asn_bits.h * * MS 92 * Copyright (C) 1992 Michael Sample and the University of British Columbia * * This library is free software; you can redistribute it and/or * modify it provided that this copyright/license information is retained * in original form. * * If you modify this file, you must clearly indicate your changes. * * This source code is distributed in the hope that it will be * useful, but WITHOUT ANY WARRANTY; without even the implied warranty * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * */ #ifndef _asn_bits_h_ #define _asn_bits_h_ typedef struct AsnBits { int bitLen; char* bits; } AsnBits; extern char numToHexCharTblG[]; #define TO_HEX(fourBits) (numToHexCharTblG[(fourBits) & 0x0f]) #define ASNBITS_PRESENT(abits) ((abits)->bits != NULL) AsnLen BEncAsnBits PROTO((BUF_TYPE b, AsnBits* data)); void BDecAsnBits PROTO((BUF_TYPE b, AsnBits* result, AsnLen* bytesDecoded, ENV_TYPE env)); AsnLen BEncAsnBitsContent PROTO((BUF_TYPE b, AsnBits* bits)); void BDecAsnBitsContent PROTO((BUF_TYPE b, AsnLen len, AsnTag tagId, AsnBits* result, AsnLen* bytesDecoded, ENV_TYPE env)); void FreeAsnBits PROTO((AsnBits* v)); void PrintAsnBits PROTO((FILE* f, AsnBits* b, unsigned short int indent)); int AsnBitsEquiv PROTO((AsnBits* b1, AsnBits* b2)); void SetAsnBit PROTO((AsnBits* b1, unsigned long int bit)); void ClrAsnBit PROTO((AsnBits* b1, unsigned long int bit)); int GetAsnBit PROTO((AsnBits* b1, unsigned long int bit)); #endif /* conditional include */ --- NEW FILE: min_buf.h --- /* * min_buf.h - trivial buffer routines. * only use these for * encoding - if you know you 'buffer' is big enough * to hold the encoded value * * decoding - if you know that the encoding is error * free. * * * The minimal buffer is simply a block of mem referenced * by a char** (ie BUF_TYPE char**). These are very efficient * but should only be used when it is safe (see above) or you're * willing to risk reading past the end of the buffer or writing * 'past' the beginning (segmentation faults/bus errors etc). * * No checks for reading or writing past the buffer are done. * every operation is assumed to succeed. * MS 92 * * Copyright (C) 1992 Michael Sample and the University of British Columbia * * This library is free software; you can redistribute it and/or * modify it provided that this copyright/license information is retained * in original form. * * If you modify this file, you must clearly indicate your changes. * * This source code is distributed in the hope that it will be * useful, but WITHOUT ANY WARRANTY; without even the implied warranty * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */ #ifndef _min_buf_h_ #define _min_buf_h_ #define MinBufGetByte(b)\ (unsigned char)(*((*(b))++)) #define MinBufGetSeg( b, lenPtr)\ *(b);\ (*b) += *lenPtr; #define MinBufCopy( dst, b, len)\ memcpy((dst), *(b), (len));\ (*(b)) += (len); #define MinBufSkip( b, len) ((*(b)) += len) #define MinBufPeekByte( b) (**(b)) #define MinBufPutByteRvs( b, byte)\ (*(--(*(b))) = (byte)) #define MinBufPutSegRvs( b, data, len)\ ((*(b)) = (*(b)) - (len));\ memcpy(*(b), (data), (len)); #define MinBufReadError(b) 0 /* always false */ #define MinBufWriteError(b) 0 /* always false */ #endif /* conditional include */ --- NEW FILE: asn_incl.h --- /* * asn_incl.h * includes hdr files nec for a user prg that calls the generated * encoding/decoding routines. * * Copyright (C) 1992 Michael Sample and the University of British Columbia * * This library is free software; you can redistribute it and/or * modify it provided that this copyright/license information is retained * in original form. * * If you modify this file, you must clearly indicate your changes. * * This source code is distributed in the hope that it will be * useful, but WITHOUT ANY WARRANTY; without even the implied warranty * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * */ #include "asn_config.h" #include "asn_len.h" #include "asn_tag.h" #include "asn_int.h" #include "asn_octs.h" #include "asn_bits.h" #include "asn_oid.h" #include "asn_null.h" #include "asn_list.h" --- NEW FILE: asn_config.h --- /* * asn_config.h - configures the ANSI/non ansi, defines * decoder alloc routines and buffer routines * * MS 91 * Copyright (C) 1992 Michael Sample and the University of British Columbia * * This library is free software; you can redistribute it and/or * modify it provided that this copyright/license information is retained * in original form. * * If you modify this file, you must clearly indicate your changes. * * This source code is distributed in the hope that it will be * useful, but WITHOUT ANY WARRANTY; without even the implied warranty * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * */ #ifndef _asn_config_h_ #define _asn_config_h_ #include <stdio.h> #include <ctype.h> /* for isprint() in asn_octs.c */ #include <setjmp.h> /* for jmp_buf type, setjmp and longjmp */ /* for pow() used in asn_real.c - must include to avoid casting err on pow */ #include <math.h> /* * define IEEE_REAL_FMT if your system/compiler uses the native ieee double * this should improve the performance of encoding reals. * If your system has the IEEE library routines (iszero, isinf etc) * then define IEEE_REAL_LIB. If neither are defined then * frexp is used. Performance is probaby best for IEEE_REAL_FMT. * * #define IEEE_REAL_FMT * #define IEEE_REAL_LIB */ /* * define __USE_ANSI_C__ if your compiler supports it */ #define __USE_ANSI_C__ #ifndef TRUE #define TRUE 1 #endif #ifndef FALSE #define FALSE 0 #endif #ifndef NULL #define NULL 0 #endif /* * Inspired by gdb 4.0, for better or worse... * (grabbed from Barry Brachman - MS) * * These macros munge C routine declarations such * that they work for ANSI or non-ANSI C compilers */ #ifdef __USE_ANSI_C__ #define PROTO(X) X #define PARAMS(arglist, args) (args) #define NOPARAMS() (void) #define _AND_ , #define DOTS , ... #else #define PROTO(X) () #define PARAMS(arglist, args) arglist args; #define NOPARAMS() () #define _AND_ ; #define DOTS #define void char #endif /* used to test if optionals are present */ #define NOT_NULL(ptr) ((ptr) != NULL) /* * Asn1Error(char* str) - configure error handler */ #define Asn1Error(str) fprintf(stderr,"%s", str); /* * Asn1Warning(char* str) - configure warning mechanism * (currently never called) */ #define Asn1Warning(str) fprintf(stderr,"%s", str); /* * configure memory scheme used by decoder to allocate memory * for the decoded value. * The Asn1Free will be called in the optionally generated * hierachical free routines. * * nibble_alloc allocs from a single buffer and EVERYTHING * is freed by a single fcn call. Individual elmts cannot be freed */ #include "nibble_alloc.h" #define Asn1Alloc(size) NibbleAlloc(size) #define Asn1Free(ptr) /* empty */ #define CheckAsn1Alloc(ptr, env)\ if ((ptr) == NULL)\ longjmp(env, -27); #define ENV_TYPE jmp_buf /* * configure buffer routines that the encoders (write) * and decoders(read) use. This config technique kind * of bites but is allows efficient macro calls. The * Generated code & lib routines call/use the "Buf????" * version of the macro - you define their meaning here. */ #ifdef USE_EXP_BUF #include "exp_buf.h" #define BUF_TYPE ExpBuf** #define BufGetByte(b) ExpBufGetByte(b) #define BufGetSeg(b, lenPtr) ExpBufGetSeg(b, lenPtr) #define BufCopy(dst, b, len) ExpBufCopy( dst, b, len) #define BufSkip(b, len) ExpBufSkip(b, len) #define BufPeekByte(b) ExpBufPeekByte( b) #define BufPutByteRvs(b, byte) ExpBufPutByteRvs( b, byte) #define BufPutSegRvs(b, data, len) ExpBufPutSegRvs( b, data, len) #define BufReadError(b) ExpBufReadError(b) #define BufWriteError(b) ExpBufWriteError(b) #else /* SBUF or MIN_BUF */ #ifdef USE_MIN_BUF #include "min_buf.h" #define BUF_TYPE char** #define BufGetByte(b) MinBufGetByte(b) #define BufGetSeg(b, lenPtr) MinBufGetSeg(b, lenPtr) #define BufCopy(dst, b, len) MinBufCopy(dst, b, len) #define BufSkip(b, len) MinBufSkip(b, len) #define BufPeekByte(b) MinBufPeekByte(b) #define BufPutByteRvs(b, byte) MinBufPutByteRvs(b, byte) #define BufPutSegRvs(b, data, len) MinBufPutSegRvs(b, data, len) #define BufReadError(b) MinBufReadError(b) #define BufWriteError(b) MinBufWriteError(b) #else /* SBUF */ #include "sbuf.h" #define BUF_TYPE SBuf* #define BufGetByte(b) SBufGetByte(b) #define BufGetSeg(b, lenPtr) SBufGetSeg(b, lenPtr) #define BufCopy(dst, b, len) SBufCopy(dst, b, len) #define BufSkip(b, len) SBufSkip(b, len) #define BufPeekByte(b) SBufPeekByte(b) #define BufPutByteRvs(b, byte) SBufPutByteRvs(b, byte) #define BufPutSegRvs(b, data, len) SBufPutSegRvs(b, data, len) #define BufReadError(b) SBufReadError(b) #define BufWriteError(b) SBufWriteError(b) #endif #endif #include "print.h" /* for printing set up */ #endif /* conditional include */ --- NEW FILE: asn_list.c --- /* * asn_list.c - borrowed from Murray Goldberg * * the following routines implement the list data structure * * Copyright (C) 1992 the University of British Columbia * * This library is free software; you can redistribute it and/or * modify it provided that this copyright/license information is retained * in original form. * * If you modify this file, you must clearly indicate your changes. * * This source code is distributed in the hope that it will be * useful, but WITHOUT ANY WARRANTY; without even the implied warranty * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */ #if HAVE_CONFIG_H #include <config.h> #endif #include "asn_config.h" #include "asn_list.h" /* * this routine removes the current node from the list. After removal the * current pointer will point to the next node in line, or NULL if the * removed item was at the tail of the list. */ void AsnListRemove PARAMS( (list), AsnList* list ) { AsnListNode* node; if( list->curr ) { if( list->curr->next ) list->curr->next->prev = list->curr->prev; else list->last = list->curr->prev; if( list->curr->prev ) list->curr->prev->next = list->curr->next; else list->first = list->curr->next; node = list->curr; list->curr = list->curr->next; list->count--; free( node ); } } /* * this creates a new node after the current node and returns the * address of the memory allocated for data. The current pointer is changed * to point to the newly added node in the list. If the current pointer is * initially off the list then this operation fails. */ void* AsnListAdd PARAMS((list), AsnList* list ) { AsnListNode* newNode; void* dataAddr; if( list->curr ) { newNode = (AsnListNode *) Asn1Alloc( sizeof(AsnListNode) + list->dataSize ); dataAddr = (void *) &(newNode->data); newNode->next = list->curr->next; newNode->prev = list->curr; if( list->curr->next ) list->curr->next->prev = newNode; else list->last = newNode; list->curr->next = newNode; list->curr = newNode; list->count++; } else dataAddr = NULL; return( dataAddr ); } /* * this creates a new node before the current node and returns the * address of the memory allocated for data. The current pointer is changed * to point to the newly added node in the list. If the current pointer is * initially off the list then this operation fails. */ void* AsnListInsert PARAMS( (list), AsnList* list ) { AsnListNode* newNode; void* dataAddr; if( list->curr ) { newNode = (AsnListNode *) Asn1Alloc( sizeof(AsnListNode) + list->dataSize ); dataAddr = (void *) &(newNode->data); newNode->next = list->curr; newNode->prev = list->curr->prev; if( list->curr->prev ) list->curr->prev->next = newNode; else list->first = newNode; list->curr->prev = newNode; list->curr = newNode; list->count++; } else dataAddr = NULL; return( dataAddr ); } void AsnListInit PARAMS((list, dataSize), AsnList* list _AND_ int dataSize) { list->first = list->last = list->curr = NULL; list->count = 0; list->dataSize = dataSize; } /* AsnListInit */ AsnList* AsnListNew PARAMS( (dataSize), int dataSize ) { AsnList* list; list = (AsnList *) Asn1Alloc( sizeof(AsnList) ); list->first = list->last = list->curr = NULL; list->count = 0; list->dataSize = dataSize; return( list ); } /* * backs up the current pointer by one and returns the data address of the new * current node. If the current pointer is off the list, the new current node * will be the last node of the list (unless the list is empty). */ void* AsnListPrev PARAMS( (list), AsnList* list ) { void* retVal; if( list->curr == NULL ) list->curr = list->last; else list->curr = list->curr->prev; if( list->curr == NULL ) retVal = NULL; else retVal = (void *) &(list->curr->data); return( retVal ); } /* * advances the current pointer by one and returns the data address of the new * current node. If the current pointer is off the list, the new current node * will be the first node of the list (unless the list is empty). */ void* AsnListNext PARAMS( (list), AsnList* list ) { void* retVal; if( list->curr == NULL ) list->curr = list->first; else list->curr = list->curr->next; if( list->curr == NULL ) retVal = NULL; else retVal = (void *) &(list->curr->data); return( retVal ); } /* * returns the data address of the last node (if there is one) and sets the * current pointer to this node. */ void* AsnListLast PARAMS((list), AsnList* list ) { void* retVal; list->curr = list->last; if( list->curr == NULL ) retVal = NULL; else retVal = (void *) &(list->curr->data); return( retVal ); } /* * returns the data address of the first node (if there is one) and sets the * current pointer to this node. */ void* AsnListFirst PARAMS( (list), AsnList* list ) { void* retVal; list->curr = list->first; if( list->curr == NULL ) retVal = NULL; else retVal = (void *) &(list->curr->data); return( retVal ); } /* * this creates a new node at the beginning of the list and returns the * address of the memory allocated for data. The current pointer is changed * to point to the newly added node in the list. */ void* AsnListPrepend PARAMS( (list), AsnList* list ) { AsnListNode* newNode; void* dataAddr; newNode = (AsnListNode *) Asn1Alloc( sizeof(AsnListNode) + list->dataSize ); dataAddr = (void *) &(newNode->data); newNode->prev = NULL; if( list->first == NULL ) { newNode->next = NULL; list->first = list->last = newNode; } else { newNode->next = list->first; list->first->prev = newNode; list->first = newNode; } list->curr = newNode; list->count++; return( dataAddr ); } /* * this creates a new node at the end of the list and returns the * address of the memory allocated for data. The current pointer is changed * to point to the newly added node in the list. */ void* AsnListAppend PARAMS( (list), AsnList* list ) { AsnListNode* newNode; void* dataAddr; newNode = (AsnListNode *) Asn1Alloc( sizeof(AsnListNode) + list->dataSize ); dataAddr = (void *) &(newNode->data); newNode->next = NULL; if( list->last == NULL ) { newNode->prev = NULL; list->first = list->last = newNode; } else { newNode->prev = list->last; list->last->next = newNode; list->last = newNode; } list->curr = newNode; list->count++; return( dataAddr ); } void* AsnListCurr PARAMS( (list), AsnList* list ) { void* retVal; if( list->curr ) retVal = (void *) &(list->curr->data); else retVal = NULL; return( retVal ); } int AsnListCount PARAMS( (list), AsnList* list ) { return( list->count ); } --- NEW FILE: asn_list.h --- /* * asn_list.h * * --------- * | AsnList | * | last |-------------------------------------------| * | curr |--------------------------| | * | first|--------| | | * --------- | | | * V V V * --------- --------- --------- * |AsnListNode |AsnListNode |AsnListNode * | next |---...->| next |--...-->| next |-----|i. * .i|----| prev |<--...--| prev |<--...--| prev | * | data | | data | | data | * --------- --------- --------- * * Originally by Murray Goldberg * Modified for ASN.1 use. * MS 92 * Copyright (C) 1992 the University of British Columbia * * This library is free software; you can redistribute it and/or * modify it provided that this copyright/license information is retained * in original form. * * If you modify this file, you must clearly indicate your changes. * * This source code is distributed in the hope that it will be * useful, but WITHOUT ANY WARRANTY; without even the implied warranty * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */ #ifndef _asn_list_h_ #define _asn_list_h_ typedef struct AsnListNode { struct AsnListNode *prev; struct AsnListNode *next; void *data; /* this must be the last field of this structure */ } AsnListNode; typedef struct AsnList { AsnListNode *first; AsnListNode *last; AsnListNode *curr; int count; /* number of elements in list */ int dataSize; /* space required in each node for the data */ } AsnList; #define FOR_EACH_LIST_ELMT( elmt, al)\ if ((al) != NULL)\ for ((al)->curr = (al)->first;\ ((al)->curr != NULL) && (((elmt) =(void*)(al)->curr->data) != NULL);\ (al)->curr = (al)->curr->next ) #define FOR_EACH_LIST_ELMT_RVS( elmt, al)\ if ((al) != NULL)\ for ((al)->curr = (al)->last;\ (((al)->curr != NULL)) && (((elmt) =(void*)(al)->curr->data) != NULL);\ (al)->curr = (al)->curr->prev ) #define FOR_REST_LIST_ELMT( elmt, al)\ if ((al) != NULL)\ for (; (((al)->curr != NULL)) && (((elmt) =(void*)(al)->curr->data) != NULL);\ (al)->curr = (al)->curr->next ) /* * The following macros return the pointer stored in the * data part of the listNode. The do not change the current * list pointer. */ #define CURR_LIST_ELMT(al) ((al)->curr->data) #define NEXT_LIST_ELMT(al) ((al)->curr->next->data) #define PREV_LIST_ELMT(al) ((al)->curr->prev->data) #define LAST_LIST_ELMT(al) ((al)->last->data) #define FIRST_LIST_ELMT(al) ((al)->first->data) #define LIST_EMPTY(al) ((al)->count == 0) #define LIST_COUNT(al) ((al)->count) /* * list nodes are the parts of the list that contain ptrs/data * to/of the list elmts. */ #define CURR_LIST_NODE(al) ((al)->curr) #define FIRST_LIST_NODE(al) ((al)->first) #define LAST_LIST_NODE(al) ((al)->last) #define PREV_LIST_NODE(al) ((al)->curr->prev) #define NEXT_LIST_NODE(al) ((al)->curr->next) #define SET_CURR_LIST_NODE(al, listNode) ((al)->curr = (listNode)) void AsnListRemove PROTO(( AsnList * )); void *AsnListAdd PROTO(( AsnList * )); void *AsnListInsert PROTO(( AsnList * )); void AsnListInit PROTO((AsnList* list, int dataSize)); AsnList *AsnListNew PROTO(( int )); void *AsnListPrev PROTO(( AsnList * )); void *AsnListNext PROTO(( AsnList * )); void *AsnListLast PROTO(( AsnList * )); void *AsnListFirst PROTO(( AsnList * )); void *AsnListPrepend PROTO(( AsnList * )); void *AsnListAppend PROTO(( AsnList * )); void *AsnListCurr PROTO(( AsnList * )); int AsnListCount PROTO(( AsnList * )); AsnList* AsnListConcat PROTO((AsnList*, AsnList*)); #endif /* conditional include */ --- NEW FILE: asn_octs.c --- /* * asn_octs.c - BER encode, decode, print and free routines for the * ASN.1 OCTET STRING type. * * MS 92 * Copyright (C) 1992 Michael Sample and the University of British Columbia * * This library is free software; you can redistribute it and/or * modify it provided that this copyright/license information is retained * in original form. * * If you modify this file, you must clearly indicate your changes. * * This source code is distributed in the hope that it will be * usefu... [truncated message content] |
From: Paul B. S. <pa...@us...> - 2001-09-03 18:41:10
|
Update of /cvsroot/linux-atm/linux-atm/src/test In directory usw-pr-cvs1:/tmp/cvs-serv10656/test Added Files: Tag: V2_4_0 br.c bw.c isp.c isp.h awrite.c Makefile.am mkerrnos.pl README.isp window.c ispl_l.l ispl_y.y ttcp.c align.c aping.c aread.c Log Message: --- NEW FILE: br.c --- /* br.c - block read */ /* Written 1995-2000 by Werner Almesberger, EPFL-LRC/ICA */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <string.h> #include <errno.h> #include <sys/types.h> #include <sys/socket.h> #include <atm.h> #define BSIZE 8192 static void usage(const char *name) { fprintf(stderr,"usage: %s [itf.]vpi.vci\n",name); exit(1); } int main(int argc,char **argv) { struct sockaddr_atmpvc addr; struct atm_qos qos; int s; if (argc != 2) usage(argv[0]); if ((s = socket(PF_ATMPVC,SOCK_DGRAM,0)) < 0) { perror("socket"); return 1; } memset(&addr,0,sizeof(addr)); if (text2atm(argv[1],(struct sockaddr *) &addr,sizeof(addr),T2A_PVC) < 0) usage(argv[0]); memset(&qos,0,sizeof(qos)); qos.aal = ATM_AAL5; qos.rxtp.traffic_class = ATM_UBR; qos.rxtp.max_sdu = BSIZE; if (setsockopt(s,SOL_ATM,SO_ATMQOS,&qos,sizeof(qos)) < 0) { perror("setsockopt SO_ATMQOS"); return 1; } if (bind(s,(struct sockaddr *) &addr,sizeof(addr)) < 0) { perror("bind"); return 1; } while (1) { unsigned char buf[BSIZE+4096]; unsigned char *start; ssize_t size; start = (unsigned char *) (((unsigned long) buf+4095) & ~4095U); size = read(s,start,BSIZE); if (size > 0 && write(1,start,size) != size) return 1; } } --- NEW FILE: bw.c --- /* bw.c - block write */ /* Written 1995-2000 by Werner Almesberger, EPFL-LRC/ICA */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <string.h> #include <errno.h> #include <sys/types.h> #include <sys/socket.h> #include <atm.h> #define BSIZE 8192 static void usage(const char *name) { fprintf(stderr,"usage: %s [itf.]vpi.vci [ blocks ]\n",name); exit(1); } int main(int argc,char **argv) { struct sockaddr_atmpvc addr; struct atm_qos qos; char buffer[BSIZE]; int blocks,s; ssize_t size; if (argc != 2 && argc != 3) usage(argv[0]); if (argc == 2) blocks = 0; else blocks = atoi(argv[2]); if ((s = socket(PF_ATMPVC,SOCK_DGRAM,0)) < 0) { perror("socket"); return 1; } memset(&addr,0,sizeof(addr)); if (text2atm(argv[1],(struct sockaddr *) &addr,sizeof(addr),T2A_PVC) < 0) usage(argv[0]); memset(&qos,0,sizeof(qos)); qos.aal = ATM_AAL5; qos.txtp.traffic_class = ATM_UBR; qos.txtp.max_sdu = BSIZE; if (setsockopt(s,SOL_ATM,SO_ATMQOS,&qos,sizeof(qos)) < 0) { perror("setsockopt SO_ATMQOS"); return 1; } if (connect(s,(struct sockaddr *) &addr,sizeof(addr)) < 0) { perror("bind"); return 1; } if (blocks) while (blocks--) (void) write(s,buffer,BSIZE); else while ((size = read(0,buffer,BSIZE)) > 0) (void) write(s,buffer,size); return 0; } --- NEW FILE: isp.c --- /* isp.c - Internal Signaling Protocol test generator */ /* Written 1997-2000 by Werner Almesberger, EPFL-ICA */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <string.h> #include <errno.h> #include <fcntl.h> #include <sys/types.h> #include <atm.h> #include <atmd.h> #include <linux/atmsvc.h> #include "isp.h" extern int yyparse(void); int quiet = 0; int verbose = 0; VAR *variables = NULL; static int sock; void send_msg(const struct atmsvc_msg *msg) { int wrote; wrote = write(sock,msg,sizeof(*msg)); if (wrote == sizeof(*msg)) return; if (wrote < 0) perror("write"); else fprintf(stderr,"bad write: %d != %d\n",wrote,sizeof(*msg)); exit(1); } void recv_msg(struct atmsvc_msg *msg) { int got; got = read(sock,msg,sizeof(*msg)); if (got == sizeof(*msg)) return; if (got < 0) perror("read"); else fprintf(stderr,"bad read: %d != %d\n",got,sizeof(*msg)); exit(1); } static struct errno_table { const char *name; int value; } table[] = { #include "errnos.inc" { NULL, 0 } }; static const char *errno2str(int code) { static char buf[30]; /* probably large enough :) */ const struct errno_table *walk; for (walk = table; walk->name; walk++) { if (walk->value == code) return walk->name; if (walk->value == -code) { sprintf(buf,"-%s",walk->name); return buf; } } sprintf(buf,"%d (0x%x)",code,code); return buf; } /* Synchronized with include/linux/atmsvc.h:enum atmsvc_msg_type */ static struct { const char *name; int fields; } types[] = { { "<invalid>", 0 }, { "bind", F_VCC | F_SVC | F_SAP }, { "connect", F_VCC | F_PVC | F_LOCAL | F_QOS | F_SVC | F_SAP }, { "accept", F_VCC | F_LISTEN_VCC }, { "reject", F_VCC | F_LISTEN_VCC | F_REPLY }, { "listen", F_VCC | F_QOS | F_SVC | F_SAP }, { "okay", F_VCC | F_PVC | F_LOCAL | F_QOS | F_SVC | F_SAP }, { "error", F_VCC | F_REPLY }, { "indicate", F_LISTEN_VCC | F_PVC | F_LOCAL | F_QOS | F_SVC | F_SAP}, { "close", F_VCC | F_REPLY }, { "itf_notify", F_PVC }, { "modify", F_VCC | F_REPLY | F_QOS }, { "identify", F_VCC | F_LISTEN_VCC | F_PVC }, { "terminate", 0 }}; #define MSG_TYPES (sizeof(types)/sizeof(*types)) void print_value(VALUE val) { char buf[1000]; /* bigger than any MAX_ATM_*_LEN */ switch (val.type) { case vt_text: printf("\"%s\"",val.u.text); return; case vt_vcc: printf("%s",kptr_print(&val.u.id)); return; case vt_error: printf("%s",errno2str(val.u.num)); return; case vt_pvc: if (atm2text(buf,sizeof(buf),(struct sockaddr *) &val.u.pvc, A2T_PRETTY | A2T_NAME) < 0) strcpy(buf,"<invalid>"); printf("%s",buf); return; case vt_svc: if (atm2text(buf,sizeof(buf),(struct sockaddr *) &val.u.svc, A2T_PRETTY | A2T_NAME) < 0) strcpy(buf,"<invalid>"); printf("%s",buf); return; case vt_qos: if (qos2text(buf,sizeof(buf),&val.u.qos,0) < 0) strcpy(buf,"<invalid>"); printf("%s",buf); return; case vt_sap: if (sap2text(buf,sizeof(buf),&val.u.sap,S2T_NAME) < 0) strcpy(buf,"<invalid>"); printf("%s",buf); return; default: fprintf(stderr,"\ninvalid value type %d\n",val.type); exit(1); } } #define FIELD(FLD,MSG) \ if (fields & FLD) { \ printf("%s",MSG); \ print_value(pick(msg,FLD)); \ putchar('\n'); \ } void dump_msg(const char *prefix,const struct atmsvc_msg *msg) { int fields; if (msg->type >= MSG_TYPES) { printf("%s: unknown message type %d\n",prefix,msg->type); return; } fields = types[msg->type].fields; printf("%s: %s\n",prefix,types[msg->type].name); FIELD(F_VCC, " vcc = "); FIELD(F_LISTEN_VCC, " listen_vcc = "); FIELD(F_REPLY, " reply = "); FIELD(F_PVC, " pvc = "); FIELD(F_LOCAL, " local = "); FIELD(F_QOS, " qos = "); FIELD(F_SVC, " svc = "); FIELD(F_SAP, " sap = "); } #undef FIELD VAR *create_var(const char *name) { VAR *var,**walk; var = malloc(sizeof(VAR)); if (!var) { perror("malloc"); exit(1); } var->name = name; /* strdup'ed */ var->value.type = vt_none; for (walk = &variables; *walk; walk = &(*walk)->next) if (strcmp(name,(*walk)->name) > 0) break; var->next = *walk; *walk = var; return var; } VAR *lookup(const char *name) { VAR *var; for (var = variables; var; var = var->next) if (!strcmp(var->name,name)) break; return var; } static void destroy(VALUE value) { if (value.type == vt_text) free((char *) value.u.text); } void assign(VAR *var,VALUE value) { destroy(var->value); var->value = value; } static int str2errno(const char *str) { const struct errno_table *walk; for (walk = table; walk->name; walk++) if (!strcmp(walk->name,str)) break; return walk->value; } static VALUE convert(VALUE in,VALUE_TYPE type) { VALUE out; char *end; if (in.type == type) { if (type == vt_text) { in.u.text = strdup(in.u.text); if (!in.u.text) { perror("strdup"); exit(1); } } return in; } if (in.type != vt_text) yyerror("type conflict"); out.type = type; switch (type) { case vt_vcc: memset(&out.u.id,0,sizeof(out.u.id)); *(unsigned long *) &out.u.id = strtoul(in.u.text,&end,0); if (*end) yyerror("invalid number"); break; case vt_error: out.u.num = strtoul(in.u.text,&end,0); if (*end) { out.u.num = str2errno(*in.u.text == '-' ? in.u.text+1 : in.u.text); if (!out.u.num) yyerror("invalid error code"); if (*in.u.text == '-') out.u.num = -out.u.num; } break; case vt_svc: if (text2atm(in.u.text,(struct sockaddr *) &out.u.svc, sizeof(out.u.svc), T2A_SVC | T2A_NAME) < 0) yyerror("invalid SVC address"); break; case vt_pvc: if (text2atm(in.u.text,(struct sockaddr *) &out.u.pvc, sizeof(out.u.pvc),T2A_PVC | T2A_NNI | T2A_NAME) < 0) yyerror("invalid PVC address"); break; case vt_qos: if (text2qos(in.u.text,&out.u.qos,0) < 0) yyerror("invalid QOS"); break; case vt_sap: if (text2sap(in.u.text,&out.u.sap,T2S_NAME) < 0) yyerror("invalid SAP address"); break; default: fprintf(stderr,"unexpected conversion type %d\n",type); exit(1); } return out; } void check(VALUE a,VALUE b) { if (a.type == vt_text) a = convert(a,b.type); if (b.type == vt_text) b = convert(b,a.type); if (a.type != b.type) yyerror("type conflict"); switch (a.type) { case vt_vcc: case vt_error: if (kptr_eq(&a.u.id,&b.u.id)) return; break; case vt_svc: if (atm_equal((struct sockaddr *) &a.u.svc, (struct sockaddr *) &b.u.svc,0,0)) return; break; case vt_pvc: if (atm_equal((struct sockaddr *) &a.u.pvc, (struct sockaddr *) &b.u.pvc,0,0)) return; break; case vt_qos: if (qos_equal(&a.u.qos,&b.u.qos)) return; break; case vt_sap: if (sap_equal(&a.u.sap,&b.u.sap,0)) return; break; default: fprintf(stderr,"unexpected conversion type %d\n",a.type); exit(1); } printf("Expected "); print_value(b); printf(",\nbut message contains "); print_value(a); printf("\n"); exit(1); } #define COPY_MSG_VAL(V) \ switch (field) { \ case F_VCC: _COPY(V.u.id,msg->vcc); break; \ case F_LISTEN_VCC: _COPY(V.u.id,msg->listen_vcc); break; \ case F_REPLY: _COPY(V.u.num,msg->reply); break; \ case F_PVC: _COPY(V.u.pvc,msg->pvc); break; \ case F_LOCAL: _COPY(V.u.svc,msg->local); break; \ case F_QOS: _COPY(V.u.qos,msg->qos); break; \ case F_SVC: _COPY(V.u.svc,msg->svc); break; \ case F_SAP: _COPY(V.u.sap,msg->sap); break; \ default: fprintf(stderr,"unexpected field type 0x%x\n",field); \ exit(1); \ } VALUE pick(const struct atmsvc_msg *msg,int field) { VALUE out; if (msg->type >= MSG_TYPES) { fprintf(stderr,"invalid message type %d",msg->type); exit(1); } if (!(types[msg->type].fields & field)) yyerror("no such field in message"); out.type = type_of(field); #define _COPY(V,M) V = M COPY_MSG_VAL(out) #undef _COPY return out; } void store(struct atmsvc_msg *msg,int field,VALUE val) { if (msg->type >= MSG_TYPES) { fprintf(stderr,"invalid message type %d",msg->type); exit(1); } if (!(types[msg->type].fields & field)) yyerror("no such field in message"); if (val.type != type_of(field)) yyerror("type conflict"); #define _COPY(V,M) M = V COPY_MSG_VAL(val) #undef _COPY } #undef COPY_MSG_VAL VALUE eval(VALUE_TYPE type,const char *str) { VALUE a,b; a.type = vt_text; a.u.text = strdup(str); if (!a.u.text) { perror("strdup"); exit(1); } b = convert(a,type); destroy(a); return b; } void cast(VAR *var,VALUE_TYPE type) { VALUE old; if (var->value.type == type) return; old = var->value; var->value = convert(var->value,type); destroy(old); } VALUE_TYPE type_of(int field) { switch (field) { case F_VCC: case F_LISTEN_VCC: return vt_vcc; case F_REPLY: return vt_error; case F_PVC: return vt_pvc; case F_LOCAL: case F_SVC: return vt_svc; case F_QOS: return vt_qos; case F_SAP: return vt_sap; default: fprintf(stderr,"unexpected field type 0x%x\n",field); exit(1); } } int main(int argc,char **argv) { const char *name; name = *argv; if (argc > 2 && !strcmp(argv[1],"-q")) { quiet = 1; argc--; argv++; } if (argc > 2 && !strcmp(argv[1],"-v")) { verbose = 1; argc--; argv++; } if (argc != 2 || (quiet && verbose)) { fprintf(stderr,"usage: %s [-q | -v] socket\n",name); return 1; } sock = un_attach(argv[1]); if (sock < 0) { perror(argv[1]); return 1; } return yyparse(); } --- NEW FILE: isp.h --- /* isp.h - Internal Signaling Protocol test generator */ /* Written 1997-2000 by Werner Almesberger, EPFL-ICA */ #ifndef ISP_H #define ISP_H #include <atm.h> #include <linux/atmsvc.h> /* Field type values */ #define F_VCC 0x00000001 #define F_LISTEN_VCC 0x00000002 #define F_REPLY 0x00000004 #define F_PVC 0x00000008 #define F_LOCAL 0x00000010 #define F_QOS 0x00000020 #define F_SVC 0x00000040 #define F_SAP 0x00000080 typedef enum { vt_none,vt_text,vt_vcc,vt_error,vt_svc,vt_pvc,vt_qos,vt_sap } VALUE_TYPE; typedef struct { VALUE_TYPE type; union { const char *text; atm_kptr_t id; int num; struct sockaddr_atmsvc svc; struct sockaddr_atmpvc pvc; struct atm_qos qos; struct atm_sap sap; } u; } VALUE; typedef struct _var { const char *name; VALUE value; struct _var *next; } VAR; extern int quiet,verbose; extern VAR *variables; void yyerror(const char *s); void print_value(VALUE val); VAR *create_var(const char *name); VAR *lookup(const char *name); void assign(VAR *var,VALUE value); void check(VALUE a,VALUE b); VALUE pick(const struct atmsvc_msg *msg,int field); void store(struct atmsvc_msg *msg,int field,VALUE val); VALUE eval(VALUE_TYPE type,const char *str); void cast(VAR *var,VALUE_TYPE type); VALUE_TYPE type_of(int field); void send_msg(const struct atmsvc_msg *msg); void recv_msg(struct atmsvc_msg *msg); void dump_msg(const char *prefix,const struct atmsvc_msg *msg); #endif --- NEW FILE: awrite.c --- /* awrite.c - send AAL5 PDU */ /* Written 1995-1998 by Werner Almesberger, EPFL-LRC/ICA */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <string.h> #include <errno.h> #include <sys/types.h> #include <sys/socket.h> #include <atm.h> static void usage(const char *name) { fprintf(stderr,"usage: %s [itf.]vpi.vci data [ offset ] \n",name); exit(1); } int main(int argc,char **argv) { struct sockaddr_atmpvc addr; struct atm_qos qos; int s,size,offset; if (argc != 3 && argc != 4) usage(argv[0]); if ((s = socket(PF_ATMPVC,SOCK_DGRAM,0)) < 0) { perror("socket"); return 1; } memset(&addr,0,sizeof(addr)); if (text2atm(argv[1],(struct sockaddr *) &addr,sizeof(addr),T2A_PVC) < 0) usage(argv[0]); offset = argc == 3 ? 0 : atoi(argv[3]); memset(&qos,0,sizeof(qos)); qos.aal = ATM_AAL5; qos.txtp.traffic_class = ATM_UBR; qos.txtp.max_sdu = strlen(argv[2])-offset; if (setsockopt(s,SOL_ATM,SO_ATMQOS,&qos,sizeof(qos)) < 0) { perror("setsockopt SO_ATMQOS"); return 1; } if (connect(s,(struct sockaddr *) &addr,sizeof(addr)) < 0) { perror("connect"); return 1; } size = write(s,argv[2]+offset,strlen(argv[2])-offset); printf("%d",size); if (size < 0) printf(" (%s)",strerror(errno)); putchar('\n'); return 0; } --- NEW FILE: Makefile.am --- USRPGMS = aread awrite ttcp_atm PGMS = align aping br bw isp window bin_PROGRAMS = $(USRPGMS) noinst_PROGRAMS = $(PGMS) LDADD = $(top_builddir)/src/lib/libatm.la aread_SOURCES = aread.c awrite_SOURCES = awrite.c ttcp_atm_SOURCES = ttcp.c align_SOURCES = align.c aping_SOURCES = aping.c br_SOURCES = br.c bw_SOURCES = bw.c isp_SOURCES = isp.c isp.h ispl_y.y ispl_l.l isp_XTRAS = $(LDADD) $(top_builddir)/src/lib/libatmd.la isp_LDADD = $(isp_XTRAS) -lfl isp_DEPENDENCIES = $(isp_XTRAS) errnos.inc window_SOURCES = window.c CLEANFILES = errnos.inc EXTRA_DIST = ispl_y.h README.isp mkerrnos.pl isp.o: errnos.inc errnos.inc: mkerrnos.pl @PERL@ ./mkerrnos.pl </usr/include/asm/errno.h \ >errnos.inc || { rm -f errnos.inc; exit 1; } --- NEW FILE: mkerrnos.pl --- #!/usr/bin/perl while (<>) { next unless /^#define\s+(E\S+)\s*/; printf(" { \"%s\", %s },\n",$1,$1) || die "print: $!"; } --- NEW FILE: README.isp --- No man page yet. "isp" is a tool for sending and receiving ISP messages, e.g. to test atmsigd. Although it can be used interactively, its poor error handling makes it more suitable for script use. Commands: send msg_type [field=value|field=$var ...] receive [msg_type [field=value|field=$var|$var=field ...]] set $var=value show echo value help where msg_type: bind, connect, accept, reject, listen, okay, error, indicate, close, itf_notify, modify, identify, terminate field: vcc, listen_vcc, reply, pvc, local, qos, svc, sap Variable syntax is like in Perl, i.e. a variable is always prefixed by a dollar sign, even where it is not expanded. Fields and variables are typed. Fields with compatible input have the same type (e.g. "svc" and "local", and "vcc" and "listen_vcc"). The type of variables which are set with "set" is determined the first time they're used in a "send" or "receive" command. Fields which do not exist in a message cannot be accessed (see isp.c, types[] for all valid combinations). Unspecified fields are set to zero. isp does not enforce setting of mandatory fields (yet). "receive" accepts three types of arguments: field=value field must be equal to the value field=$var field must be equal to the content of the variable $var=field content of field is assigned to variable Values can contain pretty much any characters except for whitespace, and they must not begin with dollar, equal, or hash signs. ispl.l contains some hacks (e.g. {tail}) to make things work anyway. There is no way to include whitespace in a value, so things like echo it works don't work (but echo ?$\=# does). Examples: receive bind $VCC=vcc send okay vcc=$VCC set $SAP = blli:l3=tr9577,ipi=snap,oui=0x00A03E,pid=0x0002 send indicate listen_vcc=$VCC svc=+1007 qos=ubr:pcr=123kcps sap=$SAP isp normally pretty-prints all messages. This can be suppressed with -q. A hint for regression test development: To test for pass, put echo PASSED after the command To test for fail, put echo PASSED before and echo FAILED after Check the last echo'ed string for PASSED (or nothing) The absence of conditional execution in isp's language is considered a feature. --- NEW FILE: window.c --- /* window.c, M. Welsh (md...@cl...) * A simple bandwidth/latency benchmark for Linux/ATM. Usage: * window [send | recv] <addr-data> <addr-ack> <num> <msg_size> <window_size> * where * <addr-data> is the VPI/VCI to transmit data on * <addr-ack> is the VPI/VCI to transmit ACKs on * <num> is the number of iterations to run * <msg_size> is the size of each message to send * <window_size> is the number of messages to send between ACKs * * Two VC's are used so that the program can be run between two processes * on the same machine. * * Example: * apple% window recv 0.32 0.33 1000 1024 10 * banana% window send 0.32 0.33 1000 1024 10 * * Copyright (c) 1996 University of Cambridge Computer Laboratory * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * M. Welsh, 6 July 1996 * */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/time.h> #include <sys/uio.h> #include <unistd.h> #include <stdio.h> #include <fcntl.h> #include <assert.h> #include <sys/ioctl.h> #include <sys/socket.h> #include <atm.h> #undef MDW_DEBUG #undef TERSE_OUTPUT #define REPLY_SIZE 40 #define MAX_WINDOW_SIZE 100 static double get_seconds(void) { struct timeval t; gettimeofday(&t,NULL); return (double)t.tv_sec+((double)t.tv_usec/(double)1e6); } int main(int argc, char **argv) { struct sockaddr_atmpvc addr1, addr2; struct atm_qos qos1, qos2; char *buffer; char buffer2[REPLY_SIZE]; int s1, s2; ssize_t size; char *theaddr1, *theaddr2; int NUM_WINDOWS; int PINGPONG_SIZE; int WINDOW_SIZE; int i, w; int sending = 0; double t1, t2; if (argc != 7) { fprintf(stderr,"Usage: window [send | recv] <addr-data> <addr-ack> <num_windows> <message_size> <window_size>\n"); exit(-1); } if (!strcmp(argv[1],"send")) sending = 1; theaddr1 = argv[2]; theaddr2 = argv[3]; NUM_WINDOWS = atoi(argv[4]); PINGPONG_SIZE = atoi(argv[5]); WINDOW_SIZE = atoi(argv[6]); if (WINDOW_SIZE > MAX_WINDOW_SIZE) { fprintf(stderr,"Maximum window size is %d.\n",MAX_WINDOW_SIZE); exit(-1); } if ((s1 = socket(PF_ATMPVC,SOCK_DGRAM,0)) < 0) { perror("socket"); exit(-1); } if ((s2 = socket(PF_ATMPVC,SOCK_DGRAM,0)) < 0) { perror("socket"); exit(-1); } memset(&addr1, 0, sizeof(addr1)); memset(&addr2, 0, sizeof(addr2)); if (text2atm(theaddr1, (struct sockaddr *)&addr1, sizeof(addr1), T2A_PVC | T2A_UNSPEC | T2A_WILDCARD) < 0) { fprintf(stderr,"window: invalid address syntax\n"); exit(-1); } if (text2atm(theaddr2, (struct sockaddr *)&addr2, sizeof(addr2), T2A_PVC | T2A_UNSPEC | T2A_WILDCARD) < 0) { fprintf(stderr,"window: invalid address syntax\n"); exit(-1); } /* Do a lot of them */ if (sending) { buffer = (char *)malloc(PINGPONG_SIZE); if (!buffer) { fprintf(stderr,"Can't malloc buffer\n"); exit(-1); } for (i = 0; i < PINGPONG_SIZE; i++) { buffer[i] = i&0xff; } memset(&qos1,0,sizeof(qos1)); memset(&qos2,0,sizeof(qos2)); qos1.aal = ATM_AAL5; qos1.txtp.traffic_class = ATM_UBR; qos1.txtp.max_sdu = PINGPONG_SIZE; qos2.aal = ATM_AAL5; qos2.rxtp.traffic_class = ATM_UBR; qos2.rxtp.max_sdu = REPLY_SIZE; if (setsockopt(s1,SOL_ATM,SO_ATMQOS,&qos1,sizeof(qos1)) < 0) { perror("setsockopt SO_ATMQOS1"); exit(-1); } if (setsockopt(s2,SOL_ATM,SO_ATMQOS,&qos2,sizeof(qos2)) < 0) { perror("setsockopt SO_ATMQOS2"); exit(-1); } if (connect(s1, (struct sockaddr *)&addr1, sizeof(addr1)) < 0) { perror("connect"); exit(-1); } if (bind(s2, (struct sockaddr *)&addr2, sizeof(addr1)) < 0) { perror("bind"); exit(-1); } #ifndef TERSE_OUTPUT fprintf(stderr,"Sending %d %d-byte messages, window size %d.\n", NUM_WINDOWS*WINDOW_SIZE,PINGPONG_SIZE,WINDOW_SIZE); #endif t1 = get_seconds(); for (i = 0; i < NUM_WINDOWS; i++) { #ifdef MDW_DEBUG fprintf(stderr,"Sending %d...",i); #endif for (w = 0; w < WINDOW_SIZE; w++) { (void)write(s1, buffer, PINGPONG_SIZE); } #ifdef MDW_DEBUG fprintf(stderr,"sent!..."); #endif #if 1 /* XXX mdw testing! XXX XXX */ /* Get a reply */ size = read(s2, buffer2, REPLY_SIZE); if (size != REPLY_SIZE) { fprintf(stderr,"Received reply of length %d, should be %d.\n", size,REPLY_SIZE); } #endif } t2 = get_seconds(); #ifdef TERSE_OUTPUT fprintf(stderr,"%d %d %d %f %f %f\n", NUM_WINDOWS, PINGPONG_SIZE, WINDOW_SIZE, (t2-t1), ((t2-t1)*1e6)/(NUM_WINDOWS*WINDOW_SIZE), (NUM_WINDOWS*WINDOW_SIZE*PINGPONG_SIZE*8)/(1e6*(t2-t1))); #else fprintf(stderr,"Sent %d %d-byte messages (window size %d) in %f seconds.\n", NUM_WINDOWS*WINDOW_SIZE,PINGPONG_SIZE,WINDOW_SIZE,(t2-t1)); fprintf(stderr,"%f usec/message or %f Mbit/sec\n", ((t2-t1)*1e6)/(NUM_WINDOWS*WINDOW_SIZE), (NUM_WINDOWS*WINDOW_SIZE*PINGPONG_SIZE*8)/(1e6*(t2-t1))); #endif } else { buffer = (char *)malloc(PINGPONG_SIZE); if (!buffer) { fprintf(stderr,"Can't malloc buffer\n"); exit(-1); } memset(&qos1,0,sizeof(qos1)); memset(&qos2,0,sizeof(qos2)); qos1.rxtp.traffic_class = ATM_UBR; qos1.rxtp.max_sdu = PINGPONG_SIZE; qos2.txtp.traffic_class = ATM_UBR; qos2.txtp.max_sdu = REPLY_SIZE; if (setsockopt(s1,SOL_ATM,SO_ATMQOS,&qos1,sizeof(qos1)) < 0) { perror("setsockopt SO_ATMQOS1"); exit(-1); } if (setsockopt(s2,SOL_ATM,SO_ATMQOS,&qos2,sizeof(qos2)) < 0) { perror("setsockopt SO_ATMQOS2"); exit(-1); } if (bind(s1, (struct sockaddr *)&addr1, sizeof(addr1)) < 0) { perror("bind"); exit(-1); } if (connect(s2, (struct sockaddr *)&addr2, sizeof(addr2)) < 0) { perror("connect"); exit(-1); } i = 0; while (i < NUM_WINDOWS*WINDOW_SIZE) { #ifdef MDW_DEBUG fprintf(stderr,"Receiving %d... ",i); #endif size = read(s1, buffer, PINGPONG_SIZE); #ifdef MDW_DEBUG fprintf(stderr,"received!\n"); #endif if (size == PINGPONG_SIZE) { i++; if ((i % WINDOW_SIZE) == 0) { /* Send reply */ #ifdef MDW_DEBUG fprintf(stderr,"Sending reply..."); #endif (void)write(s2, buffer2, REPLY_SIZE); #ifdef MDW_DEBUG fprintf(stderr,"sent!\n"); #endif } } else { fprintf(stderr,"Received message of length %d, should be %d.\n", size,PINGPONG_SIZE); } } } return 0; } --- NEW FILE: ispl_l.l --- %{ /* isp.l - Internal Signaling Protocol test generator language */ /* Written 1997,1998 by Werner Almesberger, EPFL-ICA */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdlib.h> #include <stdio.h> #include <string.h> #include <stdint.h> #include <linux/atmsvc.h> #include "isp.h" #include "ispl_y.h" static int lineno = 1; %} tail ([^a-zA-Z0-9]|$|[ \t\n]*=.*) %% send return TOK_SEND; wait return TOK_WAIT; receive return TOK_RECEIVE; help return TOK_HELP; set return TOK_SET; show return TOK_SHOW; echo return TOK_ECHO; vcc/{tail} return TOK_VCC; listen_vcc/{tail} return TOK_LISTEN_VCC; reply/{tail} return TOK_REPLY; pvc/{tail} return TOK_PVC; local/{tail} return TOK_LOCAL; qos/{tail} return TOK_QOS; svc/{tail} return TOK_SVC; sap/{tail} return TOK_SAP; listen return TOK_LISTEN; bind return TOK_BIND; connect return TOK_CONNECT; accept return TOK_ACCEPT; reject return TOK_REJECT; okay return TOK_OKAY; error return TOK_ERROR; indicate return TOK_INDICATE; close return TOK_CLOSE; itf_notify return TOK_ITF_NOTIFY; modify return TOK_MODIFY; identify return TOK_IDENTIFY; terminate return TOK_TERMINATE; \\[\t ]*\n lineno++; #[^\n]*\n lineno++; [^ \t\n\$=][^ \t\n]* { yylval.str = strdup(yytext); if (!yylval.str) { perror("strdup"); exit(1); } return TOK_VALUE; } \$[0-9a-zA-Z_]+ { yylval.str = strdup(yytext+1); if (!yylval.str) { perror("strdup"); exit(1); } return TOK_VARIABLE; } \n { lineno++; return TOK_EOL; } [\t ]* ; . return *yytext; %% void yyerror(const char *s) { fprintf(stderr,"line %d: %s near \"%s\"\n",lineno,s,yytext); exit(1); } --- NEW FILE: ispl_y.y --- %{ /* isp.y - Internal Signaling Protocol test generator language */ /* Written 1997,1998 by Werner Almesberger, EPFL-ICA */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <string.h> #include <atm.h> #include <linux/atmsvc.h> #include "isp.h" static struct atmsvc_msg msg; %} %union { char *str; int num; enum atmsvc_msg_type type; VAR *var; }; %token TOK_SEND TOK_WAIT TOK_RECEIVE TOK_HELP TOK_SET TOK_SHOW TOK_ECHO %token TOK_VCC TOK_LISTEN TOK_LISTEN_VCC TOK_REPLY TOK_PVC %token TOK_LOCAL TOK_QOS TOK_SVC TOK_BIND TOK_CONNECT TOK_ACCEPT %token TOK_REJECT TOK_LISTEN TOK_OKAY TOK_ERROR TOK_INDICATE %token TOK_CLOSE TOK_ITF_NOTIFY TOK_MODIFY TOK_SAP %token TOK_IDENTIFY TOK_TERMINATE TOK_EOL %token <str> TOK_VALUE TOK_VARIABLE %type <type> type %type <num> field_type number %type <var> new_var old_var %% all: | command all ; command: TOK_SEND type { memset(&msg,0,sizeof(msg)); msg.type = $2; } values { send_msg(&msg); if (verbose) dump_msg("SENT",&msg); } | TOK_RECEIVE { recv_msg(&msg); if (!quiet) dump_msg("RECV",&msg); } opt_recv | TOK_WAIT number { sleep($2); } | TOK_SET new_var '=' TOK_VALUE { assign($2,eval(vt_text,$4)); free($4); } | TOK_SHOW { VAR *var; for (var = variables; var; var = var->next) { printf("%s = ",var->name); print_value(var->value); putchar('\n'); } } | TOK_ECHO TOK_VALUE { printf("%s\n",$2); free($2); } | help { fprintf(stderr, "Commands:\n" " send msg_type [field=value|field=$var ...]\n" " receive [msg_type [field=value|field=$var|$var=field ...]]\n" " set $var=value\n" " show\n" " echo value\n" " help\n\n" "msg_type: bind, connect, accept, reject, listen, okay, error, indicate,\n" " close, itf_notify, modify, identify, terminate\n" "field: vcc, listen_vcc, reply, pvc, local, qos, svc, sap\n"); } | TOK_EOL ; type: TOK_BIND { $$ = as_bind; } | TOK_CONNECT { $$ = as_connect; } | TOK_ACCEPT { $$ = as_accept; } | TOK_REJECT { $$ = as_reject; } | TOK_LISTEN { $$ = as_listen; } | TOK_OKAY { $$ = as_okay; } | TOK_ERROR { $$ = as_error; } | TOK_INDICATE { $$ = as_indicate; } | TOK_CLOSE { $$ = as_close; } | TOK_ITF_NOTIFY { $$ = as_itf_notify; } | TOK_MODIFY { $$ = as_modify; } | TOK_IDENTIFY { $$ = as_identify; } | TOK_TERMINATE { $$ = as_terminate; } ; values: | value values ; value: field_type '=' old_var { cast($3,type_of($1)); store(&msg,$1,$3->value); } | field_type '=' TOK_VALUE { store(&msg,$1,eval(type_of($1),$3)); free($3); } ; number: TOK_VALUE { char *end; $$ = strtol($1,&end,10); if (*end) yyerror("invalid number"); free($1); } ; opt_recv: | type { if (msg.type != $1) yyerror("wrong message type"); } fields ; fields: | field fields ; field: new_var '=' field_type { assign($1,pick(&msg,$3)); } | field_type '=' old_var { cast($3,type_of($1)); check(pick(&msg,$1),$3->value); } | field_type '=' TOK_VALUE { check(pick(&msg,$1),eval(type_of($1),$3)); free($3); } ; field_type: TOK_VCC { $$ = F_VCC; } | TOK_LISTEN_VCC { $$ = F_LISTEN_VCC; } | TOK_REPLY { $$ = F_REPLY; } | TOK_PVC { $$ = F_PVC; } | TOK_LOCAL { $$ = F_LOCAL; } | TOK_QOS { $$ = F_QOS; } | TOK_SVC { $$ = F_SVC; } | TOK_SAP { $$ = F_SAP; } ; help: TOK_HELP | '?' ; new_var: TOK_VARIABLE { $$ = lookup($1); if ($$) free($1); else $$ = create_var($1); } ; old_var: TOK_VARIABLE { $$ = lookup($1); if (!$$) yyerror("no such variable"); free($1); } ; --- NEW FILE: ttcp.c --- /* * T T C P . C * * Test TCP connection. Makes a connection on port 5013 * and transfers fabricated buffers or data copied from stdin. * * Usable on 4.2, 4.3, and 4.1a systems by defining one of * BSD42 BSD43 (BSD41a) * Machines using System V with BSD sockets should define SYSV. * * Modified for operation under 4.2BSD, 18 Dec 84 * T.C. Slattery, USNA * Minor improvements, Mike Muuss and Terry Slattery, 16-Oct-85. * Modified in 1989 at Silicon Graphics, Inc. * catch SIGPIPE to be able to print stats when receiver has died * for tcp, don't look for sentinel during reads to allow small transfers * increased default buffer size to 8K, nbuf to 2K to transfer 16MB * moved default port to 5013, beyond IPPORT_USERRESERVED * make sinkmode default because it is more popular, [...1025 lines suppressed...] unsigned n; { register unsigned count = 0; register int nread; do { nread = read(fd, bufp, n-count); numCalls++; if(nread < 0) { perror("ttcp_mread"); return(-1); } if(nread == 0) return((int)count); count += (unsigned)nread; bufp += nread; } while(count < n); return((int)count); } --- NEW FILE: align.c --- /* align.c - Exercise PDU mis-alignment handling by the NIC */ /* Written 1997,1998 by Werner Almesberger, EPFL-LRC/ICA */ /* * This program requires a kernel modification: if the first byte of the PDU * to send is a small decimal digit N < 8, the first N bytes of the PDU are * removed and the start address is shifted accordingly. This forces * mis-alignment of the PDU. * * The expected network configuration is a loopback between the TXer and the * RXer of the NIC under test. */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <string.h> #include <errno.h> #include <signal.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/errno.h> #include <atm.h> #define MAX_SDU 20000 #define MAX_OFFSET 8 static void handler(int dummy) { (void) signal(SIGALRM,&handler); } static void torture(int s) { static unsigned long done[MAX_SDU*MAX_OFFSET/8/sizeof(unsigned long)]; unsigned char in[MAX_SDU],out[MAX_SDU]; unsigned char ch; int todo; todo = MAX_SDU*MAX_OFFSET-(MAX_OFFSET+1)*MAX_OFFSET/2; handler(0); while (todo) { int length,offset; int word,bit; int i,sent,got; length = (random() % MAX_SDU)+1; offset = random() % MAX_OFFSET; ch = random() & 0xff; bit = (length-1)*MAX_OFFSET+offset; word = bit/sizeof(unsigned long)/8; bit &= sizeof(unsigned long)*8-1; if (length <= offset || (done[word] & (1 << bit))) continue; out[0] = offset+'0'; for (i = 1; i < length; i++) out[i] = ch++; sent = write(s,out,length); if (sent < 0) { perror("write"); exit(1); } if (sent != length) { fprintf(stderr,"bad write: %d != %d\n",sent,length); exit(1); } alarm(1); got = read(s,in,length); alarm(0); if (got < 0 && errno == EINTR) { fprintf(stderr,"timed out at length %d, offset %d\n",length,offset); continue; } if (got < 0) { perror("read"); exit(1); } if (got != length-offset) { fprintf(stderr,"bad read: %d != %d-%d\n",got,length,offset); exit(1); } if (memcmp(out+offset,in,length-offset)) { fprintf(stderr,"bad compare: length %d, offset %d\n",length, offset); exit(1); } done[word] |= 1 << bit; todo--; if (!(todo % 100)) fprintf(stderr,"%6d\r",todo); } } static void usage(const char *name) { fprintf(stderr,"usage: %s [itf.]vpi.vci\n",name); exit(1); } int main(int argc,char **argv) { struct sockaddr_atmpvc addr; struct atm_qos qos; int s; if (argc != 2) usage(argv[0]); if ((s = socket(PF_ATMPVC,SOCK_DGRAM,0)) < 0) { perror("socket"); return 1; } memset(&addr,0,sizeof(addr)); if (text2atm(argv[1],(struct sockaddr *) &addr,sizeof(addr),T2A_PVC) < 0) usage(argv[0]); memset(&qos,0,sizeof(qos)); qos.aal = ATM_AAL5; qos.txtp.traffic_class = qos.rxtp.traffic_class = ATM_UBR; qos.txtp.max_sdu = qos.rxtp.max_sdu = MAX_SDU; if (setsockopt(s,SOL_ATM,SO_ATMQOS,&qos,sizeof(qos)) < 0) { perror("setsockopt SO_ATMQOS"); return 1; } if (connect(s,(struct sockaddr *) &addr,sizeof(addr)) < 0) { perror("connect"); return 1; } srandom(0); /* we want it to be deterministic */ torture(s); return 0; } --- NEW FILE: aping.c --- /* aping.c - simple round-trip tester */ /* Written 1996,1997 by Werner Almesberger, EPFL-LRC */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <string.h> #include <errno.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/time.h> #include <atm.h> #define SEND 25*1000 #define RECV 70*1000 #define RECOVER 10 static const char *rotor[] = { "|\r","/\r","-\r","\\\r" }; static void usage(const char *name) { fprintf(stderr,"usage: %s [itf.]vpi.vci\n",name); exit(1); } int main(int argc,char **argv) { struct timeval delta,now,next,fail; struct sockaddr_atmpvc addr; struct atm_qos qos; int s,i,len; if (argc != 2) usage(argv[0]); if ((s = socket(PF_ATMPVC,SOCK_DGRAM,0)) < 0) { perror("socket"); return 1; } memset(&addr,0,sizeof(addr)); if (text2atm(argv[1],(struct sockaddr *) &addr,sizeof(addr), T2A_PVC | T2A_UNSPEC | T2A_WILDCARD) < 0) usage(argv[0]); memset(&qos,0,sizeof(qos)); qos.aal = ATM_AAL5; qos.txtp.traffic_class = ATM_UBR; qos.txtp.traffic_class = ATM_UBR; qos.txtp.max_sdu = 1; qos.rxtp = qos.txtp; if (setsockopt(s,SOL_ATM,SO_ATMQOS,&qos,sizeof(qos)) < 0) { perror("setsockopt SO_ATMQOS"); return 1; } if (bind(s,(struct sockaddr *) &addr,sizeof(addr)) < 0) { perror("bind"); return 1; } if (gettimeofday(&next,NULL) < 0) { perror("gettimeofday"); return 1; } fail = next; fail.tv_sec += RECOVER; delta.tv_sec = delta.tv_usec = 0; i = 0; len = 1; /* length varies to make losses more visible in the kernel */ while (1) { fd_set set; FD_ZERO(&set); FD_SET(s,&set); (void) select(s+1,&set,NULL,NULL,&delta); if (gettimeofday(&now,NULL) < 0) { perror("gettimeofday"); return 1; } if (FD_ISSET(s,&set)) { char dummy[2]; int size; size = read(s,dummy,2); if (size < 0) { perror("read"); return 1; } if (size != 1) { fprintf(stderr,"bad RX (%d)\n",size); #if 0 if (size > 1) return 1; #endif } fail = now; fail.tv_usec += RECV; while (fail.tv_usec >= 1000000) { fail.tv_usec -= 1000000; fail.tv_sec++; } (void) write(1,rotor[i = (i+1) & 3],2); len = 1; } if (fail.tv_sec < now.tv_sec || (fail.tv_sec == now.tv_sec && fail.tv_usec < now.tv_usec)) { fprintf(stderr,"RX timed out\n"); fail.tv_sec += RECOVER; #if 0 #if 1 len++; #else len = 2 /*1+(len % 3)*/; #endif #endif } while (next.tv_sec < now.tv_sec || (next.tv_sec == now.tv_sec && next.tv_usec < now.tv_usec)) { if (write(s,"XYZ...",len) != len) { perror("write"); return 1; } next.tv_usec += SEND; while (next.tv_usec >= 1000000) { next.tv_usec -= 1000000; next.tv_sec++; } } delta.tv_sec = next.tv_sec-now.tv_sec; delta.tv_usec = next.tv_usec-now.tv_usec; while (delta.tv_usec < 0) { delta.tv_sec--; delta.tv_usec += 1000000; } } return 0; } --- NEW FILE: aread.c --- /* aread.c - receive AAL5 PDU */ /* Written 1995-1998 by Werner Almesberger, EPFL-LRC/ICA */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <string.h> #include <errno.h> #include <sys/types.h> #include <sys/socket.h> #include <atm.h> #define BSIZE 1024 static void usage(const char *name) { fprintf(stderr,"usage: %s [-c] [itf.]vpi.vci\n",name); exit(1); } int main(int argc,char **argv) { const char *name; struct sockaddr_atmpvc addr; struct atm_qos qos; int chars,s; name = argv[0]; chars = argc == 3 && !strcmp(argv[1],"-c"); if (chars) { argc--; argv++; } if (argc != 2) usage(name); if ((s = socket(PF_ATMPVC,SOCK_DGRAM,0)) < 0) { perror("socket"); return 1; } memset(&addr,0,sizeof(addr)); if (text2atm(argv[1],(struct sockaddr *) &addr,sizeof(addr), T2A_PVC | T2A_UNSPEC | T2A_WILDCARD) < 0) usage(name); memset(&qos,0,sizeof(qos)); qos.aal = ATM_AAL5; qos.rxtp.traffic_class = ATM_UBR; qos.rxtp.max_sdu = BSIZE; if (setsockopt(s,SOL_ATM,SO_ATMQOS,&qos,sizeof(qos)) < 0) { perror("setsockopt SO_ATMQOS"); return 1; } if (bind(s,(struct sockaddr *) &addr,sizeof(addr)) < 0) { perror("bind"); return 1; } while (1) { unsigned char buf[BSIZE+4096]; unsigned char *start; int size,i; /* Make sure the buffer is aligned. This can be trivially extended to play with alignments. */ start = (unsigned char *) (((unsigned long) buf+4095) & ~4095UL); size = read(s,start,BSIZE); printf("%d",size); if (size < 0) printf(" (%s)",strerror(errno)); printf(": "); for (i = 0; i < size; i++) if (chars) if (start[i] > ' ' && start[i] < 127) printf(" %c",start[i]); else printf(" \\%03o",start[i]); else printf(" %02X",start[i]); putchar('\n'); } } |